This documentation supports the 20.02 version of BMC Helix Platform. 
To view an earlier version, select 19.11 from the Product version menu.

Best practices for developing application code

For a shared system, the objective is to write clean service implementation code for BMC Helix Platform. Once the application code is developed, the developer can then upload the Digital Service application in a central repository, called Marketplace, from where other developers can download them for reuse. While the application code is being uploaded, BMC Helix Platform verifies whether the application code complies with the development rules and uploads only the compliant application codes to the Marketplace. The noncompliant application codes are rejected and are not uploaded to the Marketplace.

This topic lists the rules required for writing Java-based services that are secure, performant, and safe for use on a shared system. Refer the rules while developing your application code and ensure that the application code complies with the development rules. The examples provide references to the BMC Helix Platform API in a few cases.

For example, the BMC Helix Platform Services must possess the following attributes:

  • Manage the resources effectively
  • Avoid being stateful 
  • Avoid blocking
  • Avoid performing an end-run around the platform architecture

The best practices for developing application code are defined for the following categories:

Architecture and Design

DosDon'ts

Use the core platform services and extend them if needed by using Java code that is deployed in a bundle or by using connectors.

Do not introduce new elements to the BMC Helix Platform container technology stack that run out of processor start threads, such as the following elements:

  • another database
  • job scheduler
  • caching framework

Use the standard platform technology stack

Do not affect the configuration of the technology stack, such as the Jersey, Spring, OSGi or Jetty configuration.

Use platform services which are safe for shared systems.

Do not write the code in a tenant-agnostic manner. The code does not need to be aware of the tenant or reference any Tenant ID.

Not available
  • Do not create any code which would affect other code in some cross-cutting transparent manner.
  • Do not use aspects.
  • Do not write your own servlets, servlet filters, or Jersey filters or interceptors.

Use HTTP integration to access services that use third-party libraries.

Enhancement requests for the platform to include new functionality.

Can use provided dependencies, without version dependencies, at own risk

Do not include any third party libraries for Java. Use only documented approved third-party libraries for JavaScript that are already provided with the SDK.

Use Rx APIs to access data on BMC Helix Platform. It is OK to use theAR RESTAPI to access data on other Remedy servers as an integration.

  • Do not use Core AR-API or API-Clients (other than Mid-Tier for configuration cases). That is, do not use Developer Studio to create Forms and Workflow.
  • Do not install or use an older version, to attempt to connect to BMC Helix Platform.

Supportability

DosDon'ts

Code should log all errors appropriately. Debug level logging should be implemented to
provide sufficient information to troubleshoot problems.

For example,

catch RxException (e) {
    ServiceLocator.getLogger().error("Could not calculate 
service values 
with " + paramA + ", " + paramB + ":  failed because of " + e.getLocalizedMessage());
    // Handle the error.
}
  • Do not handle error conditions without logging them.
  • Do not log to error level anything which is not an error.
  • Do not log to info level anything which will cause a large amount of logging and negatively impact performance.

Persistence

DosDon'ts
Use the Record Service, including Attachment Fields, or HTTP-based integration

Do not use the file system

Example:

Do not read or write from File I/O streams, for resources, configuration, or any other purpose.

// DON'T DO THIS
BufferedReader br = new BufferedReader(new FileReader(FILENAME));
while ((sCurrentLine = br.readLine()) != null) {
 // do something with sCurrentLine
}

Threads and Concurrency

DosDon'ts

Use Time-Based Rules to trigger workflow in the background.

Do not start threads.

For example, do not implement Runnable to start in a thread

(new Thread(new MyRunnable())).start();

Also do not extend the thread as follows:

public class HelloThread extends Thread { .. . . }

Consider how using the Process Service can help synchronize activities without writing this as Java code.

Do not use thread synchronization mechanisms, such as sleep or the synchronized keyword. In fact, do not interact with threading APIs for any other reason.

Do not use the synchronized keyword, or sleep() your current thread.

public class SynchronizedCounter {
    private int c = 0;
    public synchronized void increment() {
       c++;
    }
    public int getCount() { return c; }
}

Avoid code that can take a long time to execute. Instead, break long background processing into smaller actions or processes. Each one can be started by a time-based rule, so they can be configured to run in parallel.

Do not block threads on any long-running operation.

As some examples, avoid nested loops where the number of iterations is unknown in advance. Additionally, do not block a thread waiting a long time on a response from a network resource.

solveTravellingSalesmanProblem();

Use BMC Integration Service to integrate with any third-party systems outside of BMC Helix Platform.

Do not make any network calls.

Memory Management

DosDon'ts

Store tenant-specific information persistently by using Records and Associations or use the platform-provided Cache Service.

Do not allow information to be shared across threads or client requests. The code should be written such that it is stateless.

For example: 

  • Do store data in static variables. 
  • Do not create a data caching mechanism.
  • Do not create member variables for services or JAX-RS resources.

Do not store information in members of your Service or JAX-RS resource as displayed in the following example:

public class MyService implements Service {

	// DO NOT do this - static variable may leak across tenants
	private static int lastRate = 0;
	
	// DO NOT do this - A member variable which implements a cache.
	private Map rateCache;
	
	public MyService() {
		rateCache = new HashMap();
	}

	/**
	 * A service action
	 */
	@Action
	public Integer computeCost(
		@ActionParameter(name = "id") @NotBlank @NotNull String id, 
	    @ActionParameter(name = "hours") @NotBlank @NotNull int hours, 
		@ActionParameter(name = "rate") @NotBlank @NotNull int rate	) {
		
		if (lastRate != rate) {
			// DO NOT do this - this can leak between tenants
			lastRate = rate;
			ServiceLocator.getLogger().info("rate has changed from " + lastRate + " to " + rate);
		}
		
		// DO NOT do this - information may leak across tenants		
		Integer cost = rateCache.get(id);
		if (cost == null) {
			cost = hours * rate;

			rateCache.put(id, cost);
		}
		return cost;
	}
}

Use DataPageQuery pattern

Requests for data should be chunked using the DataPageQuery pattern (or some other pattern that supports pagination). Furthermore, the processing of data in preparing the response should use RecordInstanceDataPageQuery. Avoid processing an arbitrary amount of data in a single request.

    // Get a chunk of data (error handling not shown here)
    DataPageQueryParameters params = new DataPageQueryParameters(50, 0, propertySelections, null, queryPredicatesByName);
    DataPage result = ServiceLocator.getRecordService().getRecordInstancesByIdDataPage(params);

	// Process the chunk
	List<?> records = result.getData();
	List<ResultInfo> resultList = new LinkedList<ResultInfo>();	
    for (Object record : records){
		// Construct the object to be returned.
		String id = (String)mappedRecord.get(ID);		
		resultList.add(new ResultInfo( (HashMap<String, Object>)record );
	}
		
	// Return the chunk of data
	return new DataPage(resultList.size(), resultList);

Do not minimize the loading of large amounts of data into memory.

Use the Record Service to persist data between calls

Do not interact with thread local storage.

Thread local storage is just as bad as using a static variable. That is because threads are not allocated to a particular tenant and must not share any state.

public class MyService implements Service {

	// DO NOT use ThreadLocal.
	private ThreadLocal someData;
	public MyService() {
		someData = new ThreadLocal();
	}

	//  Something that updates thread storage.
	// DO NOT do this. Can interfere with other tenants. 
	@Action
	public void setData(@ActionParameter(name = "data") @NotBlank @NotNull String data) { 
		someData.set(data);

	}
	
	// Something that accesses thread storage.
	// DO NOT do this. Can expose data from other tenants. 
	@Action
	public String getData() { 
		return (String) someData.get(); 
	}
}

HTTP

DosDon'ts

Follow the standard syntax as shown in the samples and tutorial.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import com.bmc.arsys.rx.services.common.RestfulResource;
 
@Path("example/myresource")
public class MyResource implements RestfulResource {
    @GET
    @Path("/{id}")
    public String get(@PathParam("id") String id) {
 
    	// Do some processing with id.
		String result = something();

        return result;
    }
}

Use standard, supported JAX/RS techniques for custom REST interfaces

Deploy services as application or library bundles

Do not include additional servlet containers or legacy Mid-tier HTTP services, by configuration changes or any other method.

Security

DosDon'ts
Use the platform permissions constructs

Do not create your own permission enforcement mechanism.

For example, do not attempt to parse group lists and implement a new model.

Use the security context provided by the platform

Do not attempt authorization impersonation or any other changes to any security context.

Related topics

Developing and deploying code-based applications

Preparing to develop a Digital Service application

Was this page helpful? Yes No Submitting... Thank you

Comments