Context is about process variables. Process variables are key-value pairs that maintain information related to the process instance. Since the context must be storable in a database, some minor limitations apply.
org.jbpm.context.exe.ContextInstance serves as the central interface to work with process variables. You can obtain the ContextInstance from a ProcessInstance like this :
ProcessInstance processInstance = ...; ContextInstance contextInstance = (ContextInstance) processInstance.getInstance(ContextInstance.class);
The most basic operations are
void ContextInstance.setVariable(String variableName, Object value); void ContextInstance.setVariable(String variableName, Object value, Token token); Object ContextInstance.getVariable(String variableName); Object ContextInstance.getVariable(String variableName, Token token);
The variable names are java.lang.String. By default, jBPM supports the following value types:
To configure jBPM for storing hibernate persistent objects in the variables, see Storing hibernate persistent objects.
Variables do not have to be declared in the process archive. At runtime, you can just put any java object in the variables. If that variable was not present, it will be created. Just the same as with a plain java.util.Map.
Variables can be deleted with
ContextInstance.deleteVariable(String variableName); ContextInstance.deleteVariable(String variableName, Token token);
Known limitation: Automatic changing of types is not yet supported. This means that its not allowed to overwrite a variable with a value of a different type. To do this, the old variable has to be deleted first. Overwriting variables with values of the same type is, of course, supported.
The variables are a part of the process instance. Saving the process instance in the database, brings the database in sync with the process instance. The variables are created, updated and deleted from the database as a result of saving (=updating) the process instance in the database. For more information, see Chapter 6, Persistence.
Each path of execution (read: token) has its own set of process variables. Requesting a variable is always done on a token. Process instances have a tree of tokens (see graph oriented programming). When requesting a variable without specifying a token, the default token is the root token.
The variable lookup is done recursively over the parents of the given token. The behaviour is similar to the scoping of variables in programming languages.
When a non-existing variable is set on a token, the variable is created on the root-token. This means that each variable has by default process scope. To make a variable token-local, you have to create it explicitely with:
ContextInstance.createVariable(String variableName, Token token);
Variable overloading means that each path of execution can have its own copy of a variable with the same name. They are treated as independant and hence can be of different types. Variable overloading can be interesting if you launch multiple concurrent paths of execution over the same transition. Then the only thing that distinguishes those paths of executions are their respective set of variables.
Variable overriding means that variables of nested paths of execution override variables in more global paths of execution. Generally, nested paths of execution relate to concurrency : the paths of execution between a fork and a join are children (nested) of the path of execution that arrived in the fork. For example, if you have a variable 'contact' in the process instance scope, you can override this variable in the nested paths of execution 'shipping' and 'billing'.
When a process instance is persisted in the database, normal variables are also persisted as part of the process instance. In some situations you might want to use a variable in a delegation class, but you don't want to store it in the database. An example could be a database connection that you want to pass from outside of jBPM to a delegation class. This can be done with transient variables.
The lifetime of transient variables is the same as the ProcessInstance java object.
Because of their nature, transient variables are not related to a token. So there is only one map of transient variables for a process instance object.
The transient variables are accessable with their own set of methods in the context instance, and don't need to be declared in the processdefinition.xml
Object ContextInstance.getTransientVariable(String name); void ContextInstance.setTransientVariable(String name, Object value);
Variables are stored in the database in a 2-step approach :
user-java-object <---> converter <---> variable instance
Variables are stored in VariableInstances. The members of VariableInstances are mapped to fields in the database with hibernate. In the default configuration of jBPM, 6 types of VariableInstances are used:
DateInstance (with one java.lang.Date field that is mapped to a Types.TIMESTAMP in the database)
DoubleInstance (with one java.lang.Double field that is mapped to a Types.DOUBLE in the database)
StringInstance (with one java.lang.String field that is mapped to a Types.VARCHAR in the database)
LongInstance (with one java.lang.Long field that is mapped to a Types.BIGINT in the database)
HibernateLongInstance (this is used for hibernatable types with a long id field. one java.lang.Object field is mapped as a reference to a hibernate entity in the database)
HibernateStringInstance (this is used for hibernatable types with a string id field. one java.lang.Object field is mapped as a reference to a hibernate entity in the database)
Converters convert between java-user-objects and the java objects that can be stored by the VariableInstances. So when a process variable is set with e.g. ContextInstance.setVariable(String variableName, Object value), the value will optionally be converted with a converted and then the converted object will be stored in a VariableInstance. Converters are implementations of the following interface:
public interface Converter extends Serializable { boolean supports(Class clazz); Object convert(Object o); Object revert(Object o); }
Converters are optional. Converters must be available to the jBPM class loader
The way that user-java-objects are converted and stored in variable instances is configured in the file org/jbpm/context/exe/jbpm.varmapping.properties. To customize this property file, put a modified version in the root of the classpath, as explained in Section 5.2, “Configuration files” Each line of the properties file specifies 2 or 3 class-names separated by spaces : the classname of the user-java-object, optionally the classname of the converter and the classname of the variable instance. When you refer your custom converters, make sure they are in the jBPM class path. When you refer to your custom variable instances, they also have to be in the the jBPM class path and the hibernate mapping file for org/jbpm/context/exe/VariableInstance.hbm.xml has to be updated to include the custom subclass of VariableInstance.
For example, take a look at the following line in the file org/jbpm/context/exe/jbpm.varmapping.properties.
java.lang.Boolean org.jbpm.context.exe.converter.BooleanToStringConverter org.jbpm.context.exe.variableinstance.StringInstance
This line specifies that all objects of type Boolean have to be converted with the converter BooleanToStringConverter and that the resulting object (a String) will be stored in a variable instance object of type StringInstance.
If no converter is specified as in
java.lang.Long org.jbpm.context.exe.variableinstance.LongInstance
that means that the Long objects that are put in the variables are just stored in a variable instance of type LongInstance without being converted.