AnsweredAssumed Answered

Getting process output message

Question asked by yosu on Aug 19, 2011
Hi,
i am testing the execution of a BPMN 2.0 process that has a ServiceTask that invokes an external WS. The process defines its I/O messages in a ioSpecification element.
Using the Activiti API, and following activiti-cxf-examples, i can invoke this process feeding the process input and retrieving its output.
This is my process code:
<definitions id="definitions" targetNamespace="eu.atosresearch.webn1.bpmn.examples"
   xmlns:activiti="http://activiti.org/bpmn" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns:imath="http://services.examples.bpmn.webn1.atosresearch.eu/"   
   xmlns:tns="eu.atosresearch.webn1.bpmn.examples">


  <import importType="http://schemas.xmlsoap.org/wsdl/"
          location="http://localhost:63081/math?wsdl"
          namespace="http://services.examples.bpmn.webn1.atosresearch.eu/" />
         
   <process id="BPMN20TestVersion2" name="BPMN 2.0 Test">

<!–
      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="processInput" itemSubjectRef="tns:processInputItem" />
           <dataOutput id="processOutput" itemSubjectRef="tns:processOutputItem" />
           <inputSet>
              <dataInputRefs>processInput</dataInputRefs>
           </inputSet>
           <outputSet>
              <dataOutputRefs>processOutput</dataOutputRefs>
           </outputSet>
        </ioSpecification>
        
        <!– Process variables. Workaround to return complex data structures –>
      <dataObject id="processOutput1" itemSubjectRef="xsd:int"/>
      <dataObject id="processOutput2" itemSubjectRef="imath:squareResponse"/>
        
        <startEvent id="theStart"/>
      
      <sequenceFlow id='flow1' sourceRef='theStart' targetRef='square' />
            
       <serviceTask id="square"
                    name="IMath Service square invocation"
                    implementation="##WebService"
                    operationRef="tns:squareOperation" >
           <!– The BPMN 2.0 Meta Model requires an Input/Output Specification –>
           <!– Describing Task I/O –>
          <ioSpecification>
                   <dataInput id="taskInput" itemSubjectRef="tns:squareRequestItem" />
                   <dataOutput id="taskOutput" itemSubjectRef="tns:squareResponseItem" />
                   <inputSet>
                       <dataInputRefs>taskInput</dataInputRefs>
                   </inputSet>
                   <outputSet>
                      <dataOutputRefs>taskOutput</dataOutputRefs>
                   </outputSet>
           </ioSpecification>
          
           <!– Data flow mapping –>
           <dataInputAssociation>
                <sourceRef>processInput</sourceRef>
                <targetRef>taskInput</targetRef>
               <assignment>
                  <from>${processInput.num}</from>
                  <to>${taskInput.num}</to>
               </assignment>
           </dataInputAssociation>
        
           <dataOutputAssociation>
              <targetRef>processOutput</targetRef>
              <transformation>${taskOutput}</transformation>
           </dataOutputAssociation>
          
           <dataOutputAssociation>
              <targetRef>processOutput1</targetRef>
              <transformation>${taskOutput.square}</transformation>
           </dataOutputAssociation>
          
           <dataOutputAssociation>
              <targetRef>processOutput2</targetRef>
              <transformation>${taskOutput}</transformation>
           </dataOutputAssociation>
          
       </serviceTask>         
      
      <sequenceFlow id='flow2' sourceRef='square' targetRef='waitState' />
      
      <!– Needed to read process output programmatically for test classes. Needed further investigation –>
      <receiveTask id="waitState"/>
   
       <sequenceFlow id="flow3" sourceRef="waitState" targetRef="theEnd" />
   
      <endEvent id="theEnd" />

   </process>

 
 
  <!– Process I/O message types –>
  <itemDefinition id="processInputItem" structureRef="imath:square" />
  <itemDefinition id="processOutputItem" structureRef="imath:squareResponse" />

  <!– Task Service message and types –>
  <itemDefinition id="squareRequestItem" structureRef="imath:square" />
  <itemDefinition id="squareResponseItem" structureRef="imath:squareResponse" />

  <message id="squareRequestMessage" itemRef="tns:squareRequestItem" />
  <message id="squareResponseMessage" itemRef="tns:squareResponseItem" />


  <!– Service Task interface –>
  <interface name="IMath Interface">
    <!– Operation: implementationRef = QName of WSDL Operation –>
    <operation id="squareOperation" name="Square" implementationRef="imath:square">
      <inMessageRef>tns:squareRequestMessage</inMessageRef>
      <outMessageRef>tns:squareResponseMessage</outMessageRef>
    </operation>
  </interface>
 
</definitions>

and this one is my Java class test:

public class BPMN20Test extends AbstractWebServiceTaskTest {
  @Deployment
  public void testBPMN20Version2() throws Exception {
    ProcessDefinitionEntity processDefinition = processEngineConfiguration
      .getCommandExecutorTxRequiresNew()
      .execute(new Command<ProcessDefinitionEntity>() {
        public ProcessDefinitionEntity execute(CommandContext commandContext) {
          return Context
            .getProcessEngineConfiguration()
            .getDeploymentCache()
            .findDeployedLatestProcessDefinitionByKey("BPMN20TestVersion2");
        }
      });
   
    ItemDefinition itemDefinition = processDefinition.getIoSpecification().getDataInputs().get(0).getDefinition();
    ItemInstance itemInstance = itemDefinition.createInstance();
    FieldBaseStructureInstance structureInstance = (FieldBaseStructureInstance) itemInstance.getStructureInstance();
    structureInstance.setFieldValue("num", 11);

    Map<String, Object> parameters = new HashMap<String, Object>();
   parameters.put("processInput", itemInstance);

    ProcessInstance instance = processEngine.getRuntimeService().startProcessInstanceByKey("BPMN20TestVersion2", parameters);
    waitForJobExecutorToProcessAllJobs(10000L, 250L);

    Object result = processEngine.getRuntimeService().getVariable(instance.getId(), "processOutput");
 
    System.out.println ("Executed process BPMN20Test with input " + itemInstance.getFieldValue("num") + " . Result obtained: " + result);
  
  }
}

WS types are defined in this wsdl excerpt:

<xsd:element name="square" type="tns:square" />
    <xsd:complexType name="square">
        <xsd:sequence>
            <xsd:element name="num" type="xsd:int" />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:element name="squareResponse" type="tns:squareResponse" />
    <xsd:complexType name="squareResponse">
        <xsd:sequence>
            <xsd:element name="square" type="xsd:int" />
        </xsd:sequence>
    </xsd:complexType>

However, i have a couple of questions:
- In the examples, the bpmn process last task is a <receiveTask>, i guess required to allow the API to retrieve process variables, including the process output, before the process dies. Does the API support to retrieve the process output once it has finished? I refer to process output as specified in the process ioSpecification, not other variables. In other words, a more RPC oriented API. Or whenever i need to get data from the process this one needs to be alive?
- I have found impossible to retrieve complex process outputs. My example works when the process output is a simple XSD type, for instance xsd:int, but fails when the process returns a complex XSD type. In the example i use different variables (processOutput, processOutput1, processOutput2) to store the process output. The Java test only receives correctly the variable assigned to the xsd:int type (processOutput1). I use this line of code:

Object result = processEngine.getRuntimeService().getVariable(instance.getId(), "processOutput");
However, debugging the test, i realised that when i request a BPMN variable of complex type (processOutput, processOutput2), even if i get a null, the org.activiti.engine.impl.persistence.entity.VariableInstanceEntity value property contains a not null cachedValue, which structureInstance (org.activiti.engine.impl.bpmn.data.FieldBaseStructureInstance) stores the correct complex value, but through the API i don't know how to get it.
Inspecting its source code, it seems it should return the cachedValue.


Thank you very much for your answers.

Yosu

Outcomes