Calling an Activiti service from within a BPMN service task

Something which we see happen a lot in the Activiti forum, is that people try to use the Activiti Service API from within a Java Service task in a bpmn 2.0 process. We always had to say that this was not a ‘best practice’, and there were technical reasons not to do it. And yes, this was true. But we had some long thought and discussion over it, and decided it is indeed counter-intuitive the way it is today. So sorry for any confusion created by the past implementation.

For example, if we would like to start a process instance ourselves using the RuntimeService (I know, stupid example because we have the call activity, but just bear with my limited imagination):

<serviceTask id="myServiceTask" activiti:class="org.activiti.MyJavaDelegate" />

To which the delegate class will look something like:

public class MyJavaDelegate implements JavaDelegate {

   public void execute(DelegateExecution execution) throws Exception {

    ... // Somehow acquire the Runtimeservice ... (injection, static getters or other magic)

    runtimeService.startProcessInstanceByKey("oneTaskProcess");
  }

}

In the versions up till the current Activiti version, this would work ‘sometimes’. The problem is that the Activiti internally uses ‘commands’ when you execute an operation through one of the services (TaskService, RuntimeService, etc.). Each of these commands go through an ‘interceptor stack’ to add functionality to the command. One of such interceptors is the ‘transaction interceptor’ whose job it is to make sure to start and commit/rollback transactions for each API call. In the example above, this basically means that a new transaction is created for the nested service call. Which could lead to nasty problems. Take for example the following process:

Here, there will be two transactions going on: one from start to service and script task before ending. And one when the runtime service is used to start the new process instance. But what happens if something goes wrong in the first process, for example in the script task following the service task?

Yes, the first process instance will be rolled back, but since the second one is started using another transaction, this process instance will be committed! This is hardly the behaviour you would expect, of course.

But of course, there wouldn’t be a blog if we hadn’t fixed this. So from now on, if you use any Activiti service within a Java service task, it will use the current transaction if it finds one. We even provided convience access to the services:

public class StartProcessInstanceTestDelegate implements JavaDelegate {

  public void execute(DelegateExecution execution) throws Exception {
    RuntimeService runtimeService = execution.getEngineServices().getRuntimeService();
    runtimeService.startProcessInstanceByKey("oneTaskProcess");
}

}

This works in all environments, including the ones with dependency injections and jta. Take for example the following delegate class used in one of our Spring tests, where the RuntimeService is injected by Spring:

@Component("startProcessInstanceDelegate")
public class StartProcessInstanceTestDelegateWithInjection {

    @Autowired
    private RuntimeService runtimeService;

    public void startProcess() {
      runtimeService.startProcessInstanceByKey("oneTaskProcess");
    }

}

This code will work, even if the datasource is Springwrapped and if JTA is used (we have QA tests for that).

Happy Coding!

7 Comments

  1. Shizanu March 4, 2013

    Hello,

    I tried to use this feature with the 5.11 activiti version. Is it already included there?

    best wishes
    Shizanu

  2. Joram Barrez March 28, 2013

    Yes. It was released with 5.11.

  3. Sindhu March 2, 2016

    Thanks for the post. It helped!

  4. rajan March 4, 2016

    i want to use a java code from a bpmn a process.
    simple one .
    like service task will call a java code and executes it and returns with some output.

  5. Joram Barrez March 4, 2016

    Sure, that’s just a regular Java Service task, nothing special to it. What’s the problem you’re facing?

  6. rajan March 5, 2016

    like i want to call an external rest web service from my service task.

  7. Joram Barrez March 8, 2016

    Not sure what you’re looking for … you need the code to call a webservice in the service task (in java logic).
    You can use abstractions for webservices like Spring has for example to make that easier.

Leave a Reply

Your email address will not be published. Required fields are marked *