Activiti faqs

User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

bpmn 2.0 activiti bpmAre you using Activiti to model your processes ? here is a list of technical faqs which will guide you to some most common development issues.

 

#What is Activiti ?

Activiti is an opensource BPM (Business Process Management) framework distributed under Apache license. It delivers BPMN2.0 compliant processes. However, the Activiti engine Activiti leverages also a lot of limited and dedicated process languages for specific use cases.

#Are Activiti processes synchronous or asynchronous ?

By default, Activiti Engine uses the thread of the client to perform it's work. If you need to spawn several instances of a process you can use Java Threads.

If you want async behaviour you have to add an async attribute to the service task configuration:

<serviceTask id="MyTaskAsync"
name="Async Service" 
activiti:async="true" 
activiti:class="com.sample.AsyncServuce"/>


When we define a Service Task with the async attribute set to true, the execution of the service task logic will be launched in a separate transaction and thread. The process state is persisted to the Activiti database and a job is created to handle the service task execution

#How to start and manage a process from another application (also non-Java application) ?
The easiest way would be to use Activiti's REST API. See http://www.activiti.org/userguide/index.html#N11FB3

#What kind of variables can be used in an Activiti process ?

Basically two types: Process variables and Task Variables.
Process variables are visibile throughout the process, while Task variable are local to the Task.
Example Process variable (set in a serviceTask):

public class ToUppercase implements JavaDelegate {
 
   public void execute(DelegateExecution execution) throws Exception {
     String var = (String) execution.getVariable("input");
     var = var.toUpperCase();
     execution.setVariable("input", var);
   }
}

Task local variable example:

From the TaskService Api:

taskService.setVariableLocal("123", "myVariable", "Variable value");


Or inside a TaskListener, using DelegateTask

public void notify(DelegateTask delegateTask) {
   delegateTask.setVariableLocal("123", "myVariable", "Variable value");
}


#Are class level variables defined in a serviceTask thread safe ?
No. As stated in the docs "there will be only one instance of that Java class created for the serviceTask it is defined on".

public class ToUppercase implements JavaDelegate {


 private int sharedCounter; 
 public void execute(DelegateExecution execution) throws Exception {
  synchronized (this) {
     // modify sharedCounter
  }
 }
 
}

 

For this reason, any class member variable will be shared between all process instances. It's your responsibility to synchronize access their access.


#How to persist process variables ?
Process variables are automatically stored in the database. Check the ACT_RU_VARIABLE table.

#How to propagate Task variables to the process ?
Add a listener to the task, that simply injects the task local variable to the process.

#How to read a process variable programmatically?
Supposing you set this variable in a serviceTask:

public void execute(DelegateExecution arg0) throws Exception {
 . . . . 
 arg0.setVariable("user", rs.getString(1));
}

You should use the runtimeService for this and fetch the variables for the execution you want:
runtimeService.getVariables(execution.getId());  // Get all variables
runtimeService.getVariable(execution.getId()."user")   // get user variable

#How to read a process variable from the Process Instance ?


ProcessInstance processInstance = startProcessInstance();
RuntimeService runtimeService = processEngine.getRuntimeService();

Date validatetime = (Date) runtimeService.getVariable(processInstance.getId(), "validatetime");


#How to invoke REST Api programmatically

--without authentication
DefaultHttpClient dhc = new DefaultHttpClient();
HttpPost hp = new HttpPost("http://localhost:8080/activiti-rest/service/process-instance");
hp.setEntity(new StringEntity("{\"processDefinitionId\":\"helloworld:1\"}", "UTF-8"));

HttpResponse processResponse = dhc.execute(hp);
System.out.println(IOUtils.toString(processResponse.getEntity().getContent()));
dhc.getConnectionManager().shutdown();

--   With basic authentication:
DefaultHttpClient dhc = new DefaultHttpClient();
dhc.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM), new UsernamePasswordCredentials("kermit", "kermit"));

HttpPost hp = new HttpPost("http://localhost:8080/activiti-rest/service/process-instance");
hp.setEntity(new StringEntity("{\"processDefinitionId\":\"helloworld:1\"}", "UTF-8"));
HttpResponse processResponse = dhc.execute(hp);
System.out.println(IOUtils.toString(processResponse.getEntity().getContent()));
dhc.getConnectionManager().shutdown();

#How to re-assign a task from a user to another ?
You can change the assignee (user assigned to the user task) via the TaskService interface. Just call the setAssignee method with the taskId and the new assignee name.

#How to delete Process Engine History old data ?
Programmatically, it's possible to remove just HistoricTaskInstances (runtimeService.deleteHistoricTaskInstance).

However, since there are timestamps included in all history tables (start/end times), so if you need to purge the whole process engine you can create a batch-process that runs every day and cleans up the history for X days ago using plain old SQL

#Should my serviceTask implement JavaDelegate  or ActivityBehavior ?
Implementing org.activiti.engine.delegate.JavaDelegate is considered the best practice and should be used in most cases.
public class SampleServiceTask implements JavaDelegate {
 
   public void execute(DelegateExecution execution) throws Exception {
    . . .
   }
}


Implementing org.activiti.engine.impl.pvm.delegate.ActivityBehavior gives access to the powerful ActivityExecution which allows to manipulate the flow of execution. This however would apply to a smaller set of cases as it hides to business analysts the actual rules behind the process flow.

public class ThrowsExceptionBehavior implements ActivityBehavior {

   public void execute(ActivityExecution execution) throws Exception {
   String var = (String) execution.getVariable("var");

 PvmTransition transition = null;
 try {
      executeLogic(var);
      transition = execution.getActivity().findOutgoingTransition("no-exception");
 }   catch (Exception e) {
      transition = execution.getActivity().findOutgoingTransition("exception");
 }
     execution.take(transition);
 }

}

#How to read the result from a serviceTask?
You can simply place the result in a process variable. If the process variable is the last node in the process, as a workaround you can place a dummy userTask between the serviceTask and the end, you will be able to use and query the value of your 'result' variable.

#Can I start a Task with external code?
You can use the REST-API to start up a process or complete a task

#Activiti Modeler: export/print a diagram
The Activiti Modeler does support exporting a process to both png and pdf.

One way to access the rendered process image is to load the URL of the modeler as follows:

http://{URL to activiti-modeler}/p/model/{path to process xml}/{format}

e.g.:
http://localhost:8080/activiti-modeler/ ... yx.xml/png
http://localhost:8080/activiti-modeler/ ... yx.xml/pdf
#How to use Activiti in my web/ejb application ?

We suggest using Maven and adding the following dependencies in your pom.xml


<dependency>
   <groupId>org.activiti</groupId>
   <artifactId>activiti-engine</artifactId>
   <version>${activiti-version}</version>

</dependency>
<dependency>
   <groupId>org.activiti</groupId>
   <artifactId>activiti-spring</artifactId>
   <version>${activiti-version}</version>

</dependency>
<dependency>
   <groupId>org.codehaus.groovy</groupId>
   <artifactId>groovy-all</artifactId>
   <version>2.0.4</version>
</dependency>
<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <version>1.3.168</version>
</dependency>

#The installation cannot find the JDBC Driver

Verify that you have copied the jdbc driver (for example ojdbc5.jar) to setup/files/dependencies/libs/

#How to invoke a JAX-WS Web service from Activiti ?
See this link
http://www.bpm-guide.de/2010/12/09/how-to-call-a-webservice-from-bpmn/
Basically, you can wrap the Web service invocation in a serviceTask and use JaxWsDynamicClientFactory to invoke the Web service.

<definitions>
 <process name="SimpleWS" id="SimpleWS">
 ...
 <serviceTask id="Call_WS" name="Call WS" activiti:class="com.camunda.training.delegate.WsDelegate" >
 <extensionElements>
 <activiti:field name="wsdl" expression="http://localhost:18080/VacationService?wsdl" />
 <activiti:field name="operation" expression="saveVacationApproval" />
 <activiti:field name="parameters" expression="${user}, ${days}" />
 <activiti:field name="returnValue" expression="myReturn" />
 </extensionElements>
 </serviceTask>
 ...
 </process>
</definitions>

public class WsDelegate implements org.activiti.engine.delegate.JavaDelegate {
 private Expression wsdl;
 private Expression operation;
 private Expression parameters;
 private Expression returnValue;

 public void execute(DelegateExecution execution) throws Exception {
 String wsdlString = (String)wsdl.getValue(execution);

 JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
 Client client = dcf.createClient(wsdlString);

 ArrayList paramStrings = new ArrayList();
 if (parameters!=null) {
 StringTokenizer st = new StringTokenizer( (String)parameters.getValue(execution), ",");
 while (st.hasMoreTokens()) {
 paramStrings.add(st.nextToken().trim());
 }
 }
 Object response = client.invoke((String)operation.getValue(execution), paramStrings.toArray(new Object[0]));
 if (returnValue!=null) {
 String returnVariableName = (String) returnValue.getValue(execution);
 execution.setVariable(returnVariableName, response);
 }
 }
}

Follow us on Twitter