The BPM Component is a pluggable container in SwitchYard which allows a business process to be exposed as a service. One fronts their business process with a custom interface and, if desired, can easily annotate it's methods to define which should start a process, signal a process event, or abort a process.
Note
Configuration of SwitchYard's BPM Component has been overhauled greatly between 0.6 and 0.7. Documentation on this page reflects 0.7. The wiki article: "BPM & Rules Component Configuration Changes" is a useful resource to consult.
Providing a Service
To provide a service with the BPM component, you will have to:
-
Define your process using BPMN2.
-
Create a java interface, fronting your BPMN2 process, which can be exposed to other services, and/or to your binding(s).
-
Add the component containing the implementation and service interface to the SwitchYard configuration. This step can be automated using annotations and the SwitchYard plugin, explained below.
Here is an example of the component section of the SwitchYard configuration:
<component name="MyService">
<implementation.bpm xmlns="urn:switchyard-component-bpm:config:1.0" processId="MyService">
<manifest>
<resources>
<resource location="META-INF/MyService.bpmn" type="BPMN2">
</resources>
</manifest>
<workItemHandlers>
<workItemHandler class="org.switchyard.component.bpm.work.SwitchYardServiceWorkItemHandler" name="SwitchYard Service"/>
</workItemHandlers>
</implementation.bpm>
<service name="MyService">
<interface.java interface="org.switchyard.userguide.MyService"/>
</service>
</component>
The MyService interface can be as simple as this, with no SwitchYard-specific imports:
package org.switchyard.userguide;
public interface MyService {
public void start(String data);
}
However, if you want to have the SwitchYard configuration for this section auto-generated for you, you can use annotations and the SwitchYard Maven Plugin. To do this, you can either add SwitchYard-specific annotations to your interface directly, or (and this is the recommended approach) you can create a separate interface for this purpose. Let's do that:
package org.switchyard.userguide;
import org.switchyard.component.bpm.annotation.BPM;
import org.switchyard.component.bpm.work.SwitchYardServiceWorkItemHandler;
import org.switchyard.component.common.knowledge.annotation.Manifest;
import org.switchayrd.component.common.knowledge.annotation.Resource;
@BPM(
value=MyService.class,
processId="MyService",
manifest=@Manifest(resources={
@Resource(location="META-INF/MyService.bpmn", type="BPMN2")
}),
workItemHandlers={@WorkItemHandler(value=SwitchYardServiceWorkItemHandler.class)}
)
public interface MyServiceProcess {}
At this point you might be wondering what the resources and workItemHandlers attributes of the annotations are.
First, a Resource represents an additional artifact that is required by your BPM process. It could be anything you could think of, including a properties file, a Drools Rule Language file, or whatever. But it needs to be available to the BPM component's runtime for that process. You can either add the resource to the XML yourself, or use the annotation, similar to the examples above.
Next, a WorkItemHandler is a way for you to add your own code into the business process. Simply implement the org.kie.runtime.process.WorkItemHandler interface, and add it to the SwitchYard configuration, either manually in XML, or by referencing your implementation via the workItemHandlers attribute of the BPM annotation, similarly to how we did with resources above.
By default, the SwitchYardServiceWorkItemHandler is always added for you by the SwitchYard Maven plugin. That handler allows you to easily call out to other SwitchYard services by name within your business process. Please see the section "Consuming a BPM Service" below for more information.
Process Interaction
In addition to the interface-level Process annotation, there are also three method-level annotations available to you. Here is an example:
package org.switchyard.userguide;
public interface MyService {
public void start(String data);
public void signal(String data);
public void stop(String data);
}
package org.switchyard.userguide;
import org.switchyard.component.bpm.annotation.AbortProcessInstance;
import org.switchyard.component.bpm.annotation.BPM;
import org.switchyard.component.bpm.annotation.SignalEvent;
import org.switchyard.component.bpm.annotation.StartProcess;
@BPM(MyService.class)
public interface MyServiceProcess extends MyService {
@StartProcess @Override
public void start(String data);
@SignalEvent("myEvent") @Override
public void signal(String data);
@AbortProcessInstance @Override
public void stop(String data);
}
This will then create the following SwitchYard configuration (note that the default processAction type is START_PROCESS for a method, which is why in our original version of this example we didn't have to use the @StartProcess annotation):
<component name="MyService">
<implementation.bpm xmlns="urn:switchyard-component-bpm:config:1.0" processId="MyService">
<actions>
<action operation="start" type="START_PROCESS"/>
<action id="myEvent" operation="signal" type="SIGNAL_EVENT"/>
<action operation="stop" type="ABORT_PROCESS_INSTANCE"/>
</actions>
<manifest>
<resources>
<resource location="META-INF/MyService.bpmn" type="BPMN2"/>
</resources>
</manifest>
<workItemHandlers>
<workItemHandler class="org.switchyard.component.bpm.work.SwitchYardServiceWorkItemHandler" name="SwitchYard Service"/>
</workItemHandlers>
</implementation.bpm>
<service name="MyService">
<interface.java interface="org.switchyard.userguide.MyService"/>
</service>
</component>
@StartProcess
Methods annotated this way (or have the associated xml) will start new process instances.
When you start your process (actually, any interaction with a service whose implementation is bpm), the processInstanceId will be put into the Switchyard Context at Scope.EXCHANGE, and will be fed back to your client in a binding-specific way. For soap, it will be in the form of a soap header in the soap response envelope:
<soap:Header>
<bpm:processInstanceId xmlns:bpm="urn:switchyard-component-bpm:bpm:1.0">1</bpm:processInstanceId>
</soap:Header>
In future process interactions, you will need to send back that same processInstanceId, so that the correlation is done properly. For soap, that means including the same soap header that was returned in the response to be sent back with subsequent requests.
Important
If you are using persistence, the sessionId will also be available in the Context, and will need to be fed back as well. It would look the same way in the soap header as the processInstanceId does.
@SignalEvent
Methods annotated this way (or have the associated xml) will have the associated process instance signaled. As above, the processInstanceId will need to have been available in the Context so the correct process instance is correlated.
There are two other pieces of information when signaling an event:
-
The "id". In BPMN2 lexicon, this is known as the "signal id", but in jBPM can also be known as the "event type". This is set as the id of the annotation.
-
Note: In BPMN2, a signal looks like this: <signal id="foo" value="bar"/> In jBPM, it is the signal id that is respected, not the name. This might require you to tweak a tooling-generated id to whatever you want it called.
-
The "event object". This is the data representing the event itself. There are two ways to pass in the event object:
-
Via a Context object, passed similar to the processInstanceId, known as "signalEvent". If this is the case, you are limited to a String type.
-
Via the Message content object itself (your payload). If the signalEvent Context property is absent, the content of the Message is used as the event object.
@AbortProcessInstance
Methods annotated this way (or have the associated xml) will cause associated process instances to be aborted. As above, the processInstanceId will need to have been available in the Context so the correct process instance is correlated.
Auditing a Process
Please see the Listeners and Loggers sections found in the Knowledge Services documentation.
Process Variables
Important
For you to be able to use variables inside your process, you have to declare your variable names at the process level, as well as in the Parameter Mapping (and possibly Result Mapping) of any process node that wants access to those variables. This can be done easily in the jBPM Eclipse tooling by using the Properties view when clicking on either the whitespace around the process, or on any of your process nodes. For more information, please refer to the jBPM documentation.
Mapping Parameter/Result Variables
Mapping variables from your SwitchYard Exchange, Context or Message into jBPM process variables can be done via expressions, the default (and only currently supported) type is MVEL. This can be done via the following XML:
<implementation.bpm ...>
<actions>
<action ...>
<inputs>
<mapping expression="exchange.serviceName.localPart" expressionType="MVEL" variable="service"/>
<mapping expression="context['org.switchyard.messageId']" variable="messageId" contextScope="IN"/>
<mapping expression="message.content" variable="contentIn"/>
</inputs>
<outputs>
<mapping expression="message.content" variable="contentOut"/>
</outputs>
</action>
</actions>
...
</implementation.bpm>
The same can be done via annotations:
@StartProcess(...
inputs={
@Mapping(expression="exchange.serviceName.localPart", expressionType=ExpressionType.MVEL, variable="service"),
@Mapping(expression="context['org.switchyard.messageId']", variable="messageId", contextScope=Scope.IN),
@Mapping(expression="message.content", variable="contentIn")},
outputs={
@Mapping=(expression="message.content", variable="contentOut")
})
public MyDataResponse process(MyData data);
For more information on mapping variables, please see the Mappings sections of the Knowledge Services documentation.
Consuming a Service
There are two ways of consuming Services with the SwitchYard BPM component:
-
Invoking the BPM implementation through a gateway binding. Since the BPM component exposes a java interface fronting the business process, you can use any of the bindings provided by SwitchYard. This could be a SOAP Binding or a Camel Binding, for example. (Please refer to those sections of this guide for more information.)
-
Invoking other SwitchYard Services from inside a BPM process itself. To do this, you can use the SwitchYardServiceWorkItemHandler, which is provided out-of-the-box. To make authoring BPMN2 processes easier, SwitchYard provides a new widget for the Eclipse BPMN2 Modeler visual editor palette. Here is a screenshot from the "Help Desk" demo quickstart:
On the bottom right hand side under "Custom Task", you can see the SwitchYard Service widget. On the left hand side, you can see the various points of the business process where SwitchYard Services are being invoked. Once you have dropped a SwitchYard Service task in the main window, you can customize it via the Eclipse Properties Editor.
SwitchYard Service Task Properties
The following are properties you can use to configure the SwitchYard Service task:
Service Naming Properties
-
ServiceName: (required)
The name of the SwitchYard service to invoke.
-
ServiceOperationName: (optional; default=use the single method name in the service interface, if there is just one)
The name of the operation within the SwitchYard service to invoke.
Content I/O Properties
-
ContentInputName: (optional; default=contentInput) The process variable which the message content will be placed in.
-
ContentOutputName: (optional; default=contentOutput) The process variable which the message content will be gotten from.
Fault-Handling Properties (see SwitchYard Service Fault Handling below)
-
FaultResultName: (optional)
The name of the output parameter (result variable) the fault (Exception) will be stored under.
-
FaultSignalId: (optional)
The bpmn signal id ("event type" in jbpm lingo) that will be used to signal an event in the same process instance. The event object will be the fault (Exception). Please see
@SignalEvent
above.
-
FaultWorkItemAction: (optional; default=null) After a fault occurs, what should be done? If null, nothing is done. If complete, the current work item (SwitchYard Service task) is completed. If abort, the current work item is aborted.
You can read a more detailed explanation of the Help Desk quickstart demo, as well as how to set up Eclipse to make use of new widget, on this wiki page.
SwitchYard Service Fault Handling
During your process execution, the SwitchYardServiceWorkItemHandler class is used to handle Switchyard Service tasks. It executes service references, per the properties specified in the panel above. Pay particular attention to the list of Fault-Handling Properties. These properties define the behavior of the SwitchYardServiceWorkItemHandler in the case were a fault is encountered when executing the service reference. There are 2 scenarios that the fault-handling covers:
-
"In my process flow, after the SwitchYard Service task, I would like a split gateway where I can inspect a process variable (a "flag") that can tell me that a fault occurred, so that I can diverge one way or another."
-
To do this, specify the FaultResultName property. The SwitchYardServiceWorkItemHandler will make the fault itself available as an output parameter of the task, so that it can be associated with a process variable, and inspected for existence in your split gateway. You must also set the FaultWorkItemAction property to complete, so that the process will continue on to your split gateway!
-
An example bpmn2 process can be found in our JUnit test suite here: BPMWorkTests-FaultResultProcess.bpmn
-
"In my process flow, I have multiple places where faults could occur, and I want to have one shared path of fault-handling."
-
To do this, specify the FaultSignalId property. This must match a signal id you specify in your bpmn2 process definition. You can then add an event node in your process that is triggered with this signal id; the flow from that event node on is your fault-handling path. The SwitchYardServiceWorkItemHandler will then signal the proper event with the configured id.
-
An example bpmn2 process can be found in our JUnit test suite here: BPMWorkTests-FaultEventrocess.bpmn
Whether you choose scenario 1 or 2 above, the question remains "What next?" If you don't specify a FaultWorkItemAction property, nothing is done. The work item is not completed, nor is it aborted. You can set the property to complete to complete the work item after a fault, or you can set the property to abort to abort the work item after a fault.
Important
The FaultWorkItemAction property was added in SwitchYard 0.8, replacing the CompleteAfterFault property of 0.7 and earlier, at which point the default was to complete the work item.