16.8. Runtime Manager

16.8.1. The RuntimeManager Interface

The RuntimeManager interface simplifies and empowers the usage of knowledge API in context of processes. It provides configurable strategies that control actual runtime execution and by default provides following:
  • Singleton: RuntimeManager maintains single KieSession regardless of number of processes available.
  • Per Request: RuntimeManager delivers new KieSession for every request.
  • Per Process Instance: RuntimeManager maintains mapping between process instance and KieSession and always provides same KieSession whenever working with given process instance.
package org.kie.api.runtime.manager;
public interface RuntimeManager {


    /**

     * Returns <code>RuntimeEngine</code> instance that is fully initialized:

    

     *  KiseSession is created or loaded depending on the strategy

     *  TaskService is initialized and attached to ksession (via listener)

     *  WorkItemHandlers are initialized and registered on ksession

     *  EventListeners (process, agenda, working memory) are initialized and added to ksession

    

     * @param context the concrete implementation of the context that is supported by given <code>RuntimeManager</code>

     * @return instance of the <code>RuntimeEngine</code>

     */

    RuntimeEngine getRuntimeEngine(Context<?> context);

    

    /**

     * Unique identifier of the <code>RuntimeManager</code>

     * @return

     */

    String getIdentifier();

   

    /**

     * Disposes <code>RuntimeEngine</code> and notifies all listeners about that fact.

     * This method should always be used to dispose <code>RuntimeEngine</code> that is not needed

     * anymore. 

     * ksession.dispose() shall never be used with RuntimeManager as it will break the internal

     * mechanisms of the manager responsible for clear and efficient disposal.<br/>

     * Dispose is not needed if <code>RuntimeEngine</code> was obtained within active JTA transaction, 

     * this means that when getRuntimeEngine method was invoked during active JTA transaction then dispose of

     * the runtime engine will happen automatically on transaction completion.

     * @param runtime

     */

    void disposeRuntimeEngine(RuntimeEngine runtime);

    

    /**

     * Closes <code>RuntimeManager</code> and releases its resources. Shall always be called when

     * runtime manager is not needed any more. Otherwise it will still be active and operational.

     */

    void close();

    

}

RuntimeManager is responsible for managing and delivering instances of RuntimeEngine to the caller. In turn, RuntimeEngine encapsulates two the most important elements of JBoss BPM Suite engine:
  • KieSession
  • TaskService
Both these components are already configured to work with each other smoothly without additional configuration from end user. So you do not need to register human task handler or keep track of it's connection to the service. RuntimeManager ensures that regardless of the strategy, it will provide same capabilities when it comes to initialization and configuration of the RuntimeEngine. This means:
  • KieSession will be loaded with same factories (either in memory or JPA based)
  • WorkItemHandlers will be registered on every KieSession (either loaded from db or newly created)
  • Event listeners (Process, Agenda, WorkingMemory) will be registered on every KieSession (either loaded from db or newly created)
  • TaskService will be configured with:
    • JTA transaction manager
    • Same entity manager factory as for the KieSession
    • UserGroupCallback from environment
Additionally, RuntimeManager maintains the engine disposal by providing dedicated methods to dispose RuntimeEngine when it is no more required to release any resources it might have acquired.

16.8.2. The RuntimeEngine Interface

The RuntimeEngine interface provides the following methods access the engine components:
public interface RuntimeEngine {


    /**

     * Returns <code>KieSession</code> configured for this <code>RuntimeEngine</code>

     * @return

     */

    KieSession getKieSession();

    

    /**

     * Returns <code>TaskService</code> configured for this <code>RuntimeEngine</code>

     * @return

     */

    TaskService getTaskService();   

}

16.8.3. Strategies

Singleton strategy

This instructs the RuntimeManager to maintain single instance of RuntimeEngine and in turn single instance of KieSession and TaskService. Access to the RuntimeEngine is synchronized and the thread is safe although it comes with a performance penalty due to synchronization. This strategy is similar to what was available by default in JBoss Enterprise BRMS Platform version 5.x and it is considered the easiest strategy and recommended to start with. It has the following characteristics:

  • Small memory footprint, that is a single instance of runtime engine and task service.
  • Simple and compact in design and usage.
  • Good fit for low to medium load on process engine due to synchronized access.
  • Due to single KieSession instance, all state objects (such as facts) are directly visible to all process instances and vice versa.
  • Not contextual, that is when retrieving instances of RuntimeEngine from singleton RuntimeManager, Context instance is not important and usually the EmptyContext.get() method is used, although null argument is acceptable as well.
  • Keeps track of the ID of the KieSession used between RuntimeManager restarts, to ensure it uses the same session. This ID is stored as serialized file on disc in a temporary location that depends on the environment.
Per request strategy

This instructs the RuntimeManager to provide new instance of RuntimeEngine for every request. As the RuntimeManager request considers one or more invocations within single transaction. It must return same instance of RuntimeEngine within single transaction to ensure correctness of state as otherwise the operation in one call would not be visible in the other. This is sort of a stateless strategy that provides only request scope state. Once the request is completed, the RuntimeEngineis permanently destroyed. The KieSession informationis thene removed from the database in case you used persistence. It has following characteristics:

  • Completely isolated process engine and task service operations for every request.
  • Completely stateless, storing facts makes sense only for the duration of the request.
  • A good fit for high load, stateless processes (no facts or timers involved that shall be preserved between requests).
  • KieSession is only available during life time of request and at the end is destroyed
  • Not contextual, that is when retrieving instances of RuntimeEngine from per request RuntimeManager, Context instance is not important and usually the EmptyContext.get() method is used, although null argument is acceptable as well.
Per process instance strategy

This instructs the RuntimeManager to maintain a strict relationship between KieSession and ProcessInstance. That means that the KieSession will be available as long as the ProcessInstance that it belongs to is active. This strategy provides the most flexible approach to use advanced capabilities of the engine like rule evaluation in isolation (for given process instance only). It provides maximum performance and reduction of potential bottlenecks introduced by synchronization. Additionally, it reduces number of KieSessions to the actual number of process instances, rather than number of requests (in contrast to per request strategy). It has the following characteristics:

  • Most advanced strategy to provide isolation to given process instance only.
  • Maintains strict relationship between KieSession and ProcessInstance to ensure it will always deliver same KieSession for given ProcessInstance.
  • Merges life cycle of KieSession with ProcessInstance making both to be disposed on process instance completion (complete or abort).
  • Allows to maintain data (such as facts, timers) in scope of process instance, that is, only process instance will have access to that data.
  • Introduces a bit of overhead due to need to look up and load KieSession for process instance.
  • Validates usage of KieSession, so it can not be used for other process instances. In such cases, an exception is thrown.
  • Is contextual. It accepts EmptyContext, ProcessInstanceIdContext, and CorrelationKeyContext context instances.

16.8.4. Usage Scenario for RuntimeManager Interface

Regular usage scenario for RuntimeManager is:
  • At application startup
    • Build the RuntimeManager and keep it for entire life time of the application. It is thread safe and you can access it concurrently.
  • At request
    • Get RuntimeEngine from RuntimeManager using proper context instance dedicated to strategy of RuntimeManager.
    • Get KieSession or TaskService from RuntimeEngine.
    • Perform operations on KieSession or TaskService such as startProcess and completeTask.
    • Once done with processing, dispose RuntimeEngine using the RuntimeManager.disposeRuntimeEngine method.
  • At application shutdown
    • Close RuntimeManager.

Note

When the RuntimeEngine is obtained from RuntimeManager within an active JTA transaction, then there is no need to dispose RuntimeEngine at the end, as it automatically disposes the RuntimeEngine on transaction completion (regardless of the completion status commit or rollback).

16.8.5. Building RuntimeManager

Here is how you can build RuntimeManager and get RuntimeEngine (that encapsulates KieSession and TaskService) from it:


    // first configure environment that will be used by RuntimeManager

    RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get()

    .newDefaultInMemoryBuilder()

    .addAsset(ResourceFactory.newClassPathResource("BPMN2-ScriptTask.bpmn2"), ResourceType.BPMN2)

    .get();


    // next create RuntimeManager - in this case singleton strategy is chosen

    RuntimeManager manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(environment);


    // then get RuntimeEngine out of manager - using empty context as singleton does not keep track

    // of runtime engine as there is only one

    RuntimeEngine runtime = manager.getRuntimeEngine(EmptyContext.get());


    // get KieSession from runtime runtimeEngine - already initialized with all handlers, listeners, etc that were configured

    // on the environment

    KieSession ksession = runtimeEngine.getKieSession();


    // add invocations to the process engine here,

    // e.g. ksession.startProcess(processId);


    // and last dispose the runtime engine

    manager.disposeRuntimeEngine(runtimeEngine);

16.8.6. RuntimeEnvironment Configuration

The complexity of knowing when to create, dispose, and register handlers is taken away from the end user and moved to the runtime manager that knows when and how to perform such operations. But it still allows to have a fine grained control over this process by providing comprehensive configuration of the RuntimeEnvironment.


  public interface RuntimeEnvironment {


    /**

     * Returns <code>KieBase</code> that shall be used by the manager

     * @return

     */

    KieBase getKieBase();

    

    /**

     * KieSession environment that shall be used to create instances of <code>KieSession</code>

     * @return

     */

    Environment getEnvironment();

    

    /**

     * KieSession configuration that shall be used to create instances of <code>KieSession</code>

     * @return

     */

    KieSessionConfiguration getConfiguration();

    

    /**

     * Indicates if persistence shall be used for the KieSession instances

     * @return

     */

    boolean usePersistence();

    

    /**

     * Delivers concrete implementation of <code>RegisterableItemsFactory</code> to obtain handlers and listeners

     * that shall be registered on instances of <code>KieSession</code>

     * @return

     */

    RegisterableItemsFactory getRegisterableItemsFactory();

    

    /**

     * Delivers concrete implementation of <code>UserGroupCallback</code> that shall be registered on instances 

     * of <code>TaskService</code> for managing users and groups.

     * @return

     */

    UserGroupCallback getUserGroupCallback();

    

    /**

     * Delivers custom class loader that shall be used by the process engine and task service instances

     * @return

     */

    ClassLoader getClassLoader();

    

    /**

     * Closes the environment allowing to close all depending components such as ksession factories, etc 

     */

    void close();

16.8.7. Building RuntimeEnvironment

The RuntimeEnvironment interface provides access to the data kept as part of the environment. You can use the builder style class that provides fluent API to configure RuntimeEnvironment with predefined settings:
package org.kie.api.runtime.manager;

public interface RuntimeEnvironmentBuilder {


    public RuntimeEnvironmentBuilder persistence(boolean persistenceEnabled);


    public RuntimeEnvironmentBuilder entityManagerFactory(Object emf);


    public RuntimeEnvironmentBuilder addAsset(Resource asset, ResourceType type);


    public RuntimeEnvironmentBuilder addEnvironmentEntry(String name, Object value);


    public RuntimeEnvironmentBuilder addConfiguration(String name, String value);


    public RuntimeEnvironmentBuilder knowledgeBase(KieBase kbase);


    public RuntimeEnvironmentBuilder userGroupCallback(UserGroupCallback callback);


    public RuntimeEnvironmentBuilder registerableItemsFactory(RegisterableItemsFactory factory);


    public RuntimeEnvironment get();


    public RuntimeEnvironmentBuilder classLoader(ClassLoader cl);

    public RuntimeEnvironmentBuilder schedulerService(Object globalScheduler);
You can obtain instances of the RuntimeEnvironmentBuilder via RuntimeEnvironmentBuilderFactory that provides preconfigured sets of builder to simplify and help you build the environment for the RuntimeManager.
public interface RuntimeEnvironmentBuilderFactory {


    /**

     * Provides completely empty <code>RuntimeEnvironmentBuilder</code> instance that allows to manually

     * set all required components instead of relying on any defaults.

     * @return new instance of <code>RuntimeEnvironmentBuilder</code>

     */

    public RuntimeEnvironmentBuilder newEmptyBuilder();

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     * DefaultRuntimeEnvironment

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newDefaultBuilder();

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     * DefaultRuntimeEnvironment

     * but it does not have persistence for process engine configured so it will only store process instances in memory

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newDefaultInMemoryBuilder();

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     *  DefaultRuntimeEnvironment

     * This one is tailored to works smoothly with kjars as the notion of kbase and ksessions

     * @param groupId group id of kjar

     * @param artifactId artifact id of kjar

     * @param version version number of kjar

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newDefaultBuilder(String groupId, String artifactId, String version);

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     *  DefaultRuntimeEnvironment


     * This one is tailored to works smoothly with kjars as the notion of kbase and ksessions

     * @param groupId group id of kjar

     * @param artifactId artifact id of kjar

     * @param version version number of kjar

     * @param kbaseName name of the kbase defined in kmodule.xml stored in kjar

     * @param ksessionName name of the ksession define in kmodule.xml stored in kjar

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newDefaultBuilder(String groupId, String artifactId, String version, String kbaseName, String ksessionName);

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     *  DefaultRuntimeEnvironment

     * This one is tailored to works smoothly with kjars as the notion of kbase and ksessions

     * @param releaseId <code>ReleaseId</code> that described the kjar

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newDefaultBuilder(ReleaseId releaseId);

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     * DefaultRuntimeEnvironment

     * This one is tailored to works smoothly with kjars as the notion of kbase and ksessions

     * @param releaseId <code>ReleaseId</code> that described the kjar

     * @param kbaseName name of the kbase defined in kmodule.xml stored in kjar

     * @param ksessionName name of the ksession define in kmodule.xml stored in kjar

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newDefaultBuilder(ReleaseId releaseId, String kbaseName, String ksessionName);

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     *  DefaultRuntimeEnvironment

     * It relies on KieClasspathContainer that requires to have kmodule.xml present in META-INF folder which 

     * defines the kjar itself.

     * Expects to use default kbase and ksession from kmodule.

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     * @see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newClasspathKmoduleDefaultBuilder();

    

    /**

     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:

     *  DefaultRuntimeEnvironment

  
     * It relies on KieClasspathContainer that requires to have kmodule.xml present in META-INF folder which 

     * defines the kjar itself.

     * @param kbaseName name of the kbase defined in kmodule.xml

     * @param ksessionName name of the ksession define in kmodule.xml   

     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults

     *@see DefaultRuntimeEnvironment

     */

    public RuntimeEnvironmentBuilder newClasspathKmoduleDefaultBuilder(String kbaseName, String ksessionName);
Besides KieSession, Runtime Manager also provides access to TaskService. The default builder comes with predefined set of elements that consists of:
  • Persistence unit name: It is set to org.jbpm.persistence.jpa (for both process engine and task service).
  • Human Task handler: This is automatically registered on the KieSession.
  • JPA based history log event listener: This is automatically registered on the KieSession.
  • Event listener to trigger rule task evaluation (fireAllRules): This is automatically registered on the KieSession.

16.8.8. Registering Handlers and Listeners through RegisterableItemsFactory

The implementation of RegisterableItemsFactory provides you a dedicated mechanism to create your own handlers or listeners.
    /**

     * Returns new instances of <code>WorkItemHandler</code> that will be registered on <code>RuntimeEngine</code>

     * @param runtime provides <code>RuntimeEngine</code> in case handler need to make use of it internally

     * @return map of handlers to be registered - in case of no handlers empty map shall be returned.

     */

    Map<String, WorkItemHandler> getWorkItemHandlers(RuntimeEngine runtime);

    

    /**

     * Returns new instances of <code>ProcessEventListener</code> that will be registered on <code>RuntimeEngine</code>

     * @param runtime provides <code>RuntimeEngine</code> in case listeners need to make use of it internally

     * @return list of listeners to be registered - in case of no listeners empty list shall be returned.

     */

    List<ProcessEventListener> getProcessEventListeners(RuntimeEngine runtime);

    

    /**

     * Returns new instances of <code>AgendaEventListener</code> that will be registered on <code>RuntimeEngine</code>

     * @param runtime provides <code>RuntimeEngine</code> in case listeners need to make use of it internally

     * @return list of listeners to be registered - in case of no listeners empty list shall be returned.

     */

    List<AgendaEventListener> getAgendaEventListeners(RuntimeEngine runtime);

    

    /**

     * Returns new instances of <code>WorkingMemoryEventListener</code> that will be registered on <code>RuntimeEngine</code>

     * @param runtime provides <code>RuntimeEngine</code> in case listeners need to make use of it internally

     * @return list of listeners to be registered - in case of no listeners empty list shall be returned.

     */

    List<WorkingMemoryEventListener> getWorkingMemoryEventListeners(RuntimeEngine runtime);
Extending out-of-the-box implementation and adding your own is a good practice. You may not always need extensions, as the default implementations of RegisterableItemsFactory provides a mechanism to define custom handlers and listeners. Following is a list of available implementations ordered in the hierarchy of inheritance:
  • org.jbpm.runtime.manager.impl.SimpleRegisterableItemsFactory: This is the simplest possible implementation that comes empty and is based on a reflection to produce instances of handlers and listeners based on given class names.
  • org.jbpm.runtime.manager.impl.DefaultRegisterableItemsFactory: This is an extension of the simple implementation(org.jbpm.runtime.manager.impl.SimpleRegisterableItemsFactory) that introduces defaults described above and still provides same capabilities as the org.jbpm.runtime.manager.impl.SimpleRegisterableItemsFactory implementation.
  • org.jbpm.runtime.manager.impl.KModuleRegisterableItemsFactory: This is an extension of the default implementation (org.jbpm.runtime.manager.impl.DefaultRegisterableItemsFactory) that provides specific capabilities for kmodule and still provides same capabilities as the Simple implementation (org.jbpm.runtime.manager.impl.SimpleRegisterableItemsFactory).
  • org.jbpm.runtime.manager.impl.cdi.InjectableRegisterableItemsFactory: This is an extension of the default implementation ( org.jbpm.runtime.manager.impl.DefaultRegisterableItemsFactory) that is tailored for CDI environments and provides CDI style approach to finding handlers and listeners through producers.

16.8.9. Registering Handlers through Configuration Files

Alternatively, you may also register simple (stateless or requiring only KieSession) work item handlers by defining them as part of CustomWorkItem.conf file and update the class path. To use this approach do the following:
  1. Create a file called drools.session.conf inside META-INF of the root of the class path (WEB-INF/classes/META-INF for web applications).
  2. Add the following line to the drools.session.conf file:
    drools.workItemHandlers = CustomWorkItemHandlers.conf
    
  3. Create a file called CustomWorkItemHandlers.conf inside META-INF of the root of the class path (WEB-INF/classes/META-INF for web applications).
  4. Define custom work item handlers in MVEL format inside the CustomWorkItemHandlers.conf file:
    [
      "Log": new org.jbpm.process.instance.impl.demo.SystemOutWorkItemHandler(),
      "WebService": new org.jbpm.process.workitem.webservice.WebServiceWorkItemHandler(ksession),
      "Rest": new org.jbpm.process.workitem.rest.RESTWorkItemHandler(),
      "Service Task" : new org.jbpm.process.workitem.bpmn2.ServiceTaskHandler(ksession)
    ]
These steps register the work item handlers for any KieSession created by the application, regardless of it using the RuntimeManager or not.

16.8.10. Registering Handlers and Listeners in CDI Environment

When you are using RuntimeManager in a CDI environment, you can use the dedicated interfaces to provide custom WorkItemHandlers and EventListeners to the RuntimeEngine.
public interface WorkItemHandlerProducer {


    /**

     * Returns map of (key = work item name, value work item handler instance) of work items 

     * to be registered on KieSession

     * Parameters that might be given are as follows:

     * ksessiontaskService

     * runtimeManager

     * @param identifier - identifier of the owner - usually RuntimeManager that allows the producer to filter out

     * and provide valid instances for given owner

     * @param params - owner might provide some parameters, usually KieSession, TaskService, RuntimeManager instances

     * @return map of work item handler instances (recommendation is to always return new instances when this method is invoked)

     */

    Map<String, WorkItemHandler> getWorkItemHandlers(String identifier, Map<String, Object> params);

}
The Event listener producer is annotated with proper qualifier to indicate what type of listeners they provide. You can select one of following to indicate the type:
  • @Process for ProcessEventListener
  • @Agenda for AgendaEventListener
  • @WorkingMemory for WorkingMemoryEventListener
public interface EventListenerProducer<T> {


    /**

     * Returns list of instances for given (T) type of listeners

     * <br/>

     * Parameters that might be given are as follows:

     * ksession

     *  taskServiceruntimeManager

     * @param identifier - identifier of the owner - usually RuntimeManager that allows the producer to filter out

     * and provide valid instances for given owner

     * @param params - owner might provide some parameters, usually KieSession, TaskService, RuntimeManager instances

     * @return list of listener instances (recommendation is to always return new instances when this method is invoked)

     */

    List<T> getEventListeners(String identifier, Map<String, Object>  params);

}
Package these interface implementations as bean archive that includes beans.xml inside META-INF folder and update the application classpath (for example, WEB-INF/lib for web application). This enables the CDI based RuntimeManager to discover them and register on every KieSession that is created or loaded from the data store.
All the components (KieSession, TaskService, and RuntimeManager) are provided to the producers to allow handlers or listeners to be more stateful and be able to do more advanced things with the engine. You can also apply filtering based on the identifier (that is given as argument to the methods) to decide if the given RuntimeManager can receive handlers or listeners or not.

Note

Whenever there is a need to interact with the process engine or task service from within handler or listener, recommended approach is to use RuntimeManager and retrieve RuntimeEngine (and then KieSession or TaskService) from it as that ensures a proper state.

16.8.11. Control Parameters to Alter Default Engine Behavior

The following control parameters available to alter engine default behavior:

Table 16.18. Table Title

Name Possible Values Default Value Description
jbpm.ut.jndi.lookup String   Alternative JNDI name to be used when there is no access to the default one (java:comp/UserTransaction).
jbpm.enable.multi.con true|false false Enables multiple incoming/outgoing sequence flows support for activities.
jbpm.business.calendar.properties String /jbpm.business.calendar.properties Allows to provide alternative classpath location of business calendar configuration file.
jbpm.overdue.timer.delay Long 2000 Specifies delay for overdue timers to allow proper initialization, in milliseconds.
jbpm.process.name.comparator String   Allows to provide alternative comparator class to empower start process by name feature. If not set, NumberVersionComparator is used.
jbpm.loop.level.disabled true|false true Allows to enable or disable loop iteration tracking, to allow advanced loop support when using XOR gateways.
org.kie.mail.session String mail/jbpmMailSession Allows to provide alternative JNDI name for mail session used by Task Deadlines.
jbpm.usergroup.callback.properties String /jbpm.usergroup.callback.properties Allows to provide alternative classpath location for user group callback implementation (LDAP, DB).
jbpm.user.group.mapping String ${jboss.server.config.dir}/roles.properties Allows to provide alternative classpath location of user info configuration (used by LDAPUserInfoImpl).
jbpm.user.info.properties String /jbpm.user.info.properties Allows to provide alternative classpath location for user group callback implementation (LDAP, DB).
org.jbpm.ht.user.separator String , Allows to provide alternative separator of actors and groups for user tasks, default is comma (,).
org.quartz.properties String   Allows to provide location of the quartz config file to activate quartz based timer service.
jbpm.data.dir String ${jboss.server.data.dir} is available otherwise ${java.io.tmpdir} Allows to provide location where data files produced by JBoss BPM Suite must be stored.
org.kie.executor.pool.size Integer 1 Allows to provide thread pool size for JBoss BPM Suite executor.
org.kie.executor.retry.count Integer 3 Allows to provide number of retries attempted in case of error by JBoss BPM Suite executor.
org.kie.executor.interval Integer 3 Allows to provide frequency used to check for pending jobs by JBoss BPM Suite executor, in seconds.
org.kie.executor.disabled true|false true Enables or disable JBoss BPM Suite executor.
These allows you to fine tune the execution for the environment needs and actual requirements. All of these parameters are set as JVM system properties, usually with -D when starting a program such as an application server.

16.8.12. Storing Process Variables Without Serialization

Objects in JBoss BPM Suite that are used as process variables must be serializable. That is, they must implement the java.io.Serializable interface. Objects that are not serializable can be used as process variables but for these you must implement and use a marshaling strategy and register it. The default strategy will not convert these variables into bytes. By default all objects need to be serializable.
For internal objects, which are modified only by the engine, it is sufficient if java.io.Serializable is implemented. The variable will be transformed into a byte stream and stored in a database.
For external data that can be modified by external systems and people (like documents from a CMS, or other database entities), other strategies need to be implemented.
JBoss BPM Suite uses what is known as the pluggable Variable Persistence Strategy - that is, it uses serialization for objects that do implement the java.io.Serializable interface but uses the Java Persistence Architecture (JPA) based JPAPlaceholderResolverStrategy class to work on objects that are entities (not implementing the java.io.Serializable interface).

Configuring Variable Persistence Strategy

To use this strategy, configure it by placing it in your Runtime Environment used for creating your Knowledge Sessions. This strategy should be set as the first one and the serialization based strategy as the last, default one. An example on how to set this is shown here:
// create entity manager factory
EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.redhat.sample");

RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
  .entityManagerFactory(emf) 
  .addEnvironmentEntry(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES, 
    new ObjectMarshallingStrategy[] {
// set the entity manager factory to JPA strategy so it knows how to store and read entities     
      new JPAPlaceholderResolverStrategy(emf),
// set the serialization based strategy as last one to deal with non entity classes
      new SerializablePlaceholderResolverStrategy(ClassObjectMarshallingStrategyAcceptor.DEFAULT)})  
     .addAsset(ResourceFactory.newClassPathResource("example.bpmn"), ResourceType.BPMN2)
     .get();

// now create the runtime manager and start using entities as part of your process  
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(environment);

Note

Make sure to add your entity classes into persistence.xml configuration file that will be used by the JPA strategy.

How Does the JPA Strategy Work?

At runtime, process variables that need persisting are evaluated using the available strategy. It is up to the strategy to accept or reject the variable. If the variable is rejected by the first strategy, it is passed on till it reaches the default strategy.
A JPA based strategy will only accept classes that declare a field with the @Id annotation (javax.persistence.Id) This is the unique id that is used to retrieve the variable. On the other hand, a serialization based strategy simply accepts all variables by default.
Once the variable has been accepted, a JPA marshalling operation to store the variable is performed by the marshal() method, while the unmarshal() method will retrieve the variable from the storage.

Creating Your Own Persistence Strategy

The previous section alluded to the two methods that are used to marshal() and unmarshal() objects. These methods are part of the org.kie.api.marshalling.ObjectMarshallingStrategy interface and you can implement this interface to create a custom persistence strategy.
public interface ObjectMarshallingStrategy {
    
  public boolean accept(Object object);

  public void write(ObjectOutputStream os,
                  Object object) throws IOException;
    
  public Object read(ObjectInputStream os) throws IOException, ClassNotFoundException;

  public byte[] marshal(Context context,
                        ObjectOutputStream os,
                        Object object ) throws IOException;
    
  public Object unmarshal(Context context,
                          ObjectInputStream is,
                          byte[] object,
                          ClassLoader classloader ) throws IOException, ClassNotFoundException;

  public Context createContext();
}
The methods read() and write() are for backwards compatibility. Use the methods accept(), marshal() and unmarshal() to create your strategy.