No Registration required. Use your FB account to add comments to articles.

Twitter Button

Poll

Which is your favourite JSF library?
 
Top Programming Sites
Home

Activiti faqs

Article Index
Activiti faqs
Activiti faqs - part 2
All Pages
  

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.


In the future releases of Activiti, Async continuations  will be available: putting the first activity asycn would cause the thread to immediately return and hence the process starts are put in a queue.

At the moment, a simple ThreadExecutorPool in Java could be used as workaround.

 

#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 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 ?


Add the following libraries to your project (You can find them in the files/dependancies/libs of your Activiti installation)

- stax-api-1.0-2.jar
- vaadin-6.4.8.jar
- activiti-engine-5.1.jar
- jaxb-api-2.2.1.jar
- jaxb-impl-2.2.1.jar
- mybatis-3.0.1.jar
- spring-asm-3.0.3.RELEASE.jar
- spring-beans-3.0.3.RELEASE.jar
- spring-core-3.0.3.RELEASE.jar
- activity.cfg.jar
- mail-1.4.1.jar
- activation-1.1.jar
- commons-email-1.2.jar
- commons-logging-1.1.1.jar
- livetribe-jsr223-2.0.6.jar
- activity.cfg.jar 

#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);
 }
 }
}