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



#Where is my activiti configuration stored ?
Activiti configuration is stored in the file activiti.cfg.xml. On the default applications (Activiti Probe/Explorer/Cycle/REST Api) the activiti configuration
is deployed as a jar file named activiti.cfg.jar.
So for example if you want to change the settings of your Activiti REST Api, you have to place a new activiti.cfg.jar into /apps/tomcat/webapps/activiti-rest/lib/
#How to change the configuration of Activiti web applications (Activiti Explorer, Activiti Probe etc.) ?
If you have already built yout activiti demo suite and you need to change the configuration,just issue :

ant cfg.create demo.stop build.webapps demo.start

#Updating Activiti database
To upgrade, at first you have to set the following configuration property in your activiti.cfg.xml configuration file:

<beans ... > 
 
 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> 
 <!-- ... --> 
 <property name="databaseSchemaUpdate" value="true" />     
 <!-- ... --> 
 </bean> 
 
</beans>

 


Then just upgrade the Activiti libraries in your application. Or start up a new version of Activiti and point it to a database that contains an older version. With databaseSchemaUpdate set to true, Activiti will automatically upgrade the DB schema to the newer version the first time when it notices that libraries and DB schema are out of sync.

#How to use Process variables in a Script ?
All process variables that are accessible through the execution that arrives in the script task, can be used within the script.
See this sample:

public class ServiceTask implements JavaDelegate {
 public void execute(DelegateExecution execution) throws Exception {
 execution.setVariable("command", "executable arg1 arg2 arg3");
 }
}

{xtypo_code}<scriptTask id="theScriptTask" name="Execute script" scriptFormat="groovy">
<script>

def proc = command.execute()                 // Call *execute* on the string
proc.waitFor()                               // Wait for the command to finish

// Obtain status and output
def exitValue =  proc.exitValue();
println "stderr: ${proc.err.text}"
println "stdout: ${proc.in.text}" // *out* from the external program is *in* for groovy
</script>
</scriptTask>{/xtypo_code}
#How to set Process variables in a Script ?
Conversely, it is possible to set process variables from inside the script. In the above example, the "exitValue" variable
is defined as the exit value of the command.

In a script-task, you can just declare a variable and it will be stored as process-variable, eg:

Code:
<scriptTask id="theScriptTask" name="Execute script" scriptFormat="js">
<script>
var myVariable = 'this is a value';
</script>
</scriptTask>

Quick tip:
For a quick process variable setting you can use the current execution, which is available as a reserved variable called 'execution'.

<script>
def scriptVar = "test123"
execution.setVariable("myVar", scriptVar)
</script>

#Using another script language in Activiti
You can use any JSR-223 compliant language. For example, in order to use JYthon, just add it to the classpath and change the 'scriptFormat' value.
 

#Is it possible to use Beans, like Spring Beans in scripting ?
Using beans in scripts is available in activiti 5.3 (http://jira.codehaus.org/browse/ACT-97).

#How to intercept Process End Event
If you need to perform some activity at the end of the process, then the simplest thing is using an executionListener that listens to the end of the process instance.

#How to handle exceptions raised in a Java ServiceTask ?
It depends on the type of Exception. Basically a business exception (which means an exception raised by a business case) should be visible in the diagram and designed as boundaryEvent.
In this example, the application exception raised by the "javaService" are intercepted by the boundaryEvent "catchError" and lead to a different sequenceFlow, named "catchError":

<serviceTask id="javaService" .../>
<boundaryEvent id="catchError" attachedToRef="javaService">
<errorEventDefinition/>
</boundaryEvent>
<sequenceFlow id="errorFlow" sourceRef="catchError" targetRef="someOtherTask"/>

When the nature of Exception is not of matter to the analyst, or the other stakeholder of the process, you can just handle the exception inside the serviceTask (using ActivityBehavior interface) the and route process execution through another path in case some exception occurs. The following example,taken from the user guide, shows how this is done.
<serviceTask id="javaService" 
 name="Java service invocation" 
 activiti:class="org.activiti.ThrowsExceptionBehavior">            
</serviceTask>
 
<sequenceFlow id="no-exception" sourceRef="javaService" targetRef="theEnd" />
<sequenceFlow id="exception" sourceRef="javaService" targetRef="fixException" />

Here, the service task has two outgoing sequence flow, called exception and no-exception. This sequence flow id will be used to direct process flow in case of an exception:
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);
 }
 
}

#When are transactions committed in Activiti ?
An Activiti process commits its transactions either when the process ends or when it needs to wait for an external trigger (f.e. when a human task needs to be performed). That is when the execution state is persisted and then the transaction commit.

#What happens when an Exception is raised in Java service node ?
In case of exceptions, Activiti will rollback the ongoing transaction.The database will rollback to the previous state in the database.
So the last action (runtimeService.startProcessInstance or runtimeService.signal or task.complete) will return with an exception.

#How to use a Custom ELResolver?
Sometimes you would need to inject your own custom ELResolver into Activiti engine. For example, if you use a very flexible bean structure with configurable classes and properties, it would be difficult to implement this with simple setter and getters.
In Activiti, you can use the ProcessEngineFactoryBean, which uses a custom SpringExpressionManagers. This adds an ELResolver to handle spring-beans. This way, you can use all your spring-beans. If using spring-beans doesn't cut it, you could write a similar mechanism as done there: creating your own expression-manager, which creates composite EL-resolver containing your custom EL-resolving logic.

#How to deploy project from designer
Actually, you can prepare you artifacts from the Designer and then connect to Activiti Probe to deploy the archive.

1. Go to the Package Explorer (not to be confused with the Project Explorer)
2. Right-click on the project and select "Create deployment artifacts"
3. The .bar file will then be created in a folder called "deployment"

Now use Activiti Probe to upload the artifact.


#How to monitor the process graphically ?
Activiti offers the process-instance visualisation in activiti Probe, or through the REST-API:
http://www.jorambarrez.be/blog/2011/02/01/screencast-proc-inst-visual/


#How to download the Eclipse designer ?
If you cannot use Eclipse designer update site, just download Eclipse designer from activiti achive :
http://www.activiti.org/designer/archived/activiti-designer-0.8.0.zip


#How to use a checkbox in a task form ?
Code:
<input type="checkbox" name="bwVideo" ${(bwVideo ? 'CHECKED' : ''} />

#Adding new form property types
There is a property available on the ProcessEngineConfigutionImpl which allows plugging in your own types, called 'customFormTypes'. It expects a list of org.activiti.engine.impl.form.AbstractFormType subclasses, which are added to the default types which you have mentioned.

#How to create in a form a Boolean property?

<select name="vacationApproved">
 <option value="true">Yes</option>
 <option value="false">No</option>
</select>
<input type="hidden" name="vacationApproved_type" value="Boolean" />

#How to cluster Activiti
Nothing prevents running several instances of Activiti. All application instances are independent, effectively knowing nothing of each other. As a matter of fact Activiti uses optimistic locking on the DB to deal with concurrency.
Job distribution happens through use of database-level locks and job ownership includes information about thread name and host.
When a job is ready to be executed and not locked yet, JobExecutors will try to put a lock on it. Due to use of optimistic locking, only one of them will succeed, the ones that got an OptimisticLockingException will pause for a defined time before acquiring new jobs.
For this reason you are adviced to use a JobExecutor on a single machine to prevent that multiple JobExecutor compete for the same job, causing unnecessary optimistic locking failures.

References: http://activiti.org/userguide

0
0
0
s2smodern