Keep informed?
Subscribe for our newsletter now!

How to call a Webservice from BPMN

Outdated!

Please note that this blog post is outdated, since we forked Activiti in March 2013 and started a new Open Source BPM project called camunda BPM (www.camunda.org). You will find this topic and loads of more best practices, blueprints etc. there, so you should just have a look 🙂


We have recently been asked by quite a couple of customers, how to interact with Webservices from within a BPMN process (in Activiti) best. And – as always – there are multiple answers to that question 🙂 Today I want to write a more technical post (haven’t done that for too long already) looking at the various options: The (verbose) BPMN 2.0 standard way, the (neat but Java specific) Activiti-Java -Extension and the (heavy) SOA/ESB alternative. And as always there are several nuances in between. To tell you that in advance: I am neither a big fan of the verbose standard nor of the heavy ESB way 😉 But let’s have a look into that in more detail and what it means for your architecture.

An easy process calling a Webservice

An easy process calling a Webservice

Okay, the idea is simple: In a process we want to call a Webservice. Maybe we “just” want to orchestrate Webservices using BPMN or maybe we have bigger business processes having to call a Webservice from time to time. BPMN as a standard isn’t tied to Webservices, but recommends to use them to be standard compliant. Okay, sounds good, so let’s do it the standard way. Luckily Activiti already can do that, even if it is not completely stable and therefor not officially released yet. I use a process contained as test case in Activiti, calling a very simple WS. The process is very simple as well, you can see it on the right (we will use that process for all the further examples). Here you see the BPMN 2.0 XML:

<definitions>
...
  <import importType="http://schemas.xmlsoap.org/wsdl/"
          location="http://localhost:63081/counter?wsdl"
          namespace="http://webservice.activiti.org/" />
          
  <process id="asyncWebServiceInvocationWithDataFlowUEL">
	  <!--
		  The Data Inputs and Outputs of a Process have to be explicitly
		  declared with their type to be valid BPMN 2.0
	  -->
  	<ioSpecification>
  		<dataInput id="dataInputOfProcess" itemSubjectRef="tns:setToRequestItem" />
  		<inputSet>
  			<dataInputRefs>dataInputOfProcess</dataInputRefs>
  		</inputSet>
        <outputSet />
  	</ioSpecification>
    ...      
    <serviceTask id="webService" 
                 name="Call WS"
                 implementation="##WebService"
                 operationRef="tns:setToOperation">
            <!-- The BPMN 2.0 Meta Model requires an Input/Output Specification -->
            <ioSpecification>
                <dataInput itemSubjectRef="tns:setToRequestItem" id="dataInputOfServiceTask" />
                <inputSet>
                    <dataInputRefs>dataInputOfServiceTask</dataInputRefs>
                </inputSet>
                <outputSet />
            </ioSpecification>
            <dataInputAssociation>
                <sourceRef>dataInputOfProcess</sourceRef>
                <targetRef>dataInputOfServiceTask</targetRef>
   				<assignment>
   					<from>${dataInputOfProcess.newCounterValue}</from>
   					<to>${dataInputOfServiceTask.value}</to>
   				</assignment>
            </dataInputAssociation>
    </serviceTask>    
    ...
  </process>
  <!-- Interface: implementationRef = QName of WSDL Port Type -->
  <interface name="Counter Interface" implementationRef="counter:Counter">
    <!-- Operation: implementationRef = QName of WSDL Operation -->
    <operation id="setToOperation" name="setTo Operation" implementationRef="counter:setTo">
      <inMessageRef>tns:setToRequestMessage</inMessageRef>
    </operation>
  </interface>  
  <message id="setToRequestMessage" itemRef="tns:setToRequestItem" />  
  <itemDefinition id="setToRequestItem" structureRef="counter:setTo" /><!-- QName of input element -->
</definitions>

I don’t want to explain the BPN 2.0 XML in detail here, actually I could recommend a good book on it 😉

As you can see the XML is pretty verbose. But sure, there is a good reason for that: There are a lot of indirections to define the data, the data input and output mappings, the interface of the service in a technology neutral way and so on. So there is a reason, but without good graphical tooling, it is hard to handle.

Java-Alternative

So the next thought is: Hey, we are Java developers, why not do it much easier in a Java way? We could leverage Apache CXF (like the Activiti Webservice implementation does internally as well) and hook it into our BPMN process by an Activiti extension. Wait: An Activiti extension? That doesn’t sound standard compliant. Right, it is not. But actually look what you get out of it, this is the same process calling the Webservice directly:

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

Isn’t that a huge difference? Okay, the downside is, that this isn’t standard compatible any more. But actually I have never seen somebody really exchanging the process engine without any effort. I haven’t even seen that with Databases or Application servers often (and these are stone age technologies compared to BPMN), so I don’t think that this is such a huge disadvantage. But that differs in every project…

Now, in order to get the above process to work we need a so called JavaDelegate (a small Java class we can attach to the BPMN process, which is executed when the process instance runs through the service task). This just takes the parameters I configured and calls the Webservice. Agreed, the parameter gathering is a bit hacky and not powerful enough yet, but hey, it is a 15 minutes prototype. And it was really only 15 minutes with all components. Here you can see the code of that piece of Java Code:

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

By the way: We are currently discussing if we include this possibility of calling Webservices in the Activiti engine intself. But currently we want to finish the standard way first, which is for sure important to support. But I guess later on we will go for something like that as well, since that is really developer friendly 🙂

Location transparency

With our neat little Webservice call in the process we face a problem now: We have the WSDL-Address written in the process definition (actually in both of the examples above). What if the host for that service changes? Do I have to change all running processes? Not a good idea actually. Wait, location transparency, routing, that must be a job for an ESB! I would say: Maybe. Very often not 😉 If I just want to hide the host of that Webservice to my process, what I need is a Registry. A Registry is included in every ESB, so the ESB may make sense. But very often I see the ESB as too unhandy, complex and oversized. Especially if you only need it as a Registry. Don’t get me wrong, there are use cases for ESBs, but only a Registry is not enough.

So to finish my quick post today, I extended the Webservice example with Mule Galaxy, an open source Registry. Therefor I just add the WSDL to the registry and access it from there now:

<serviceTask id="Call_WS" name="Call WS" activiti:class="com.camunda.training.delegate.WsDelegate" >
  <extensionElements>
    <activiti:field name="wsdl" expression="http://my-registry-cluster/galaxy-web-1.5.3-embed/api/registry/Demo/VacationService.wsdl" />
    <activiti:field name="operation" expression="saveVacationApproval" />
    <activiti:field name="parameters" expression="${user}, ${days}" />
  </extensionElements>
</serviceTask>

Now I could configure everything centrally in the registry but keep the neat simple Webservice mechanism I just developed 🙂

Or using ESB?

Calling a Webservice frm the process but using a Registry

Calling a Webservice frm the process but using a Registry

Calling a Webservice directly from the process

Calling a Webservice directly from the process

Calling a Webservice via the Mule ESB

Calling a Webservice via the Mule ESB

As a quick wrap up I want to talk about using the ESB in that scenario. Because we face that situation very often: In order to call a Webservice the customer wants to include the ESB. Often it is not completely clear why, maybe because the ESB marketing still makes a good job 🙂 On the right I added three small pictures, showing how we can access a Webservice from our BPMN process in Activiti. With the Mule integration currently being built calling a Webservice means, that we have to create a Mule service for it. This Mule service is exposed as a Webservice, which is then hooked in the process. I leave it up to you to think about if that makes sense to you… Let me know your opinions!

Bernd Rücker

About Bernd Rücker, CEO

Bernd Rücker is co-founder and CEO of camunda. But he is also software developer, trainer and consultant who was activley contributing to the Open Source Workflow engines jBPM 3 and Activiti before starting camunda BPM. He has profound experience in BPM projects and Java Enterprise. He worked with Process Engines and BPM for over 10 years in countless real-life projects. He is author of several books, numerous articles and regular speaker on conferences.

Already read?

Scientific performance benchmark of open source BPMN engines

Why BPMN is not enough

Decision Model and Notation (DMN) – the new Business Rules Standard. An introduction by example.

New Whitepaper: The Zero-Code BPM Myth

27 Responses

Leave a reply