This activity allows you to start multiple subprocess instances determined dynamically based on data (such as service orders) at run time. The subprocess instances may be of same process definition, different process definition, or a combination of them.
At runtime this activity uses an XML document, called the execution plan, to control which subprocesses to launch. Typically the execution plan is created by a preceding activity, possibly by consulting with an external product/service catalog.
If you are not already familiar with concepts such as Smart Subprocess Versions, and parameter binding modes, please refer to Invoke Subprocess Activity for a description of these concepts, which are the same for single and multiple subprocesses. Here we focus on aspects specific to multiple subprocess invocation, especially the syntax and semantics involved in creating an execution plan.
Note: To open the subprocess definition, double-click on the process icon for a row under Subprocesses.
The following attributes pertain:
The execution plan is an XML document and its XSD looks like (extracted from MDW source code)
<?xml version="1.0"?> <xsd:schema xmlns = "http://mdw.centurylink.com/bpm" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://mdw.centurylink.com/bpm" elementFormDefault="unqualified" attributeFormDefault="unqualified"> <xsd:element name="Parameter"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="Name" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> <xsd:element name="LogicalProcessName" type="xsd:string"/> <xsd:element name="ProcessId" type="xsd:string"/> <xsd:element name="InstanceId" type="xsd:string"/> <xsd:element name="StatusCode" type="xsd:int"/> <xsd:element name="SubprocessInstance"> <xsd:complexType> <xsd:sequence> <xsd:element ref="LogicalProcessName"/> <xsd:element ref="ProcessId"/> <xsd:element ref="InstanceId"/> <xsd:element ref="StatusCode"/> <xsd:element ref="Parameter" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="ProcessExecutionPlan"> <xsd:complexType> <xsd:sequence> <xsd:element ref="SubprocessInstance" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
MDW has already created an XMLBean for this XSD, so you do not normally need
to deal with the XSD. The following shows a piece of sample code using XMLBeans
to construct the execution plan that contains 3 subprocess instances, 2
for UniSubProcess
and 1 for EvcSubProcess
:
String createExecutionPlan() { ProcessExecutionPlanDocument exeplan_doc = ProcessExecutionPlanDocument.Factory.newInstance(); ProcessExecutionPlan exeplan = exeplan_doc.addNewProcessExecutionPlan(); SubprocessInstance subprocinst = exeplan.addNewSubprocessInstance(); subprocinst.setLogicalProcessName("UniSubProcess"); subprocinst.setStatusCode(WorkStatus.STATUS_PENDING_PROCESS.intValue()); addParameter(subprocinst, "OrderNumber", "C30234456"); addParameter(subprocinst, "UNI_ID", "UNI-101"); addParameter(subprocinst, "OrderContent", "$orderContent"); subprocinst = exeplan.addNewSubprocessInstance(); subprocinst.setLogicalProcessName("UniSubProcess"); subprocinst.setStatusCode(WorkStatus.STATUS_PENDING_PROCESS.intValue()); addParameter(subprocinst, "OrderNumber", "C30234456"); addParameter(subprocinst, "UNI_ID", "UNI-102"); addParameter(subprocinst, "OrderContent", "$orderContent"); subprocinst = exeplan.addNewSubprocessInstance(); subprocinst.setLogicalProcessName("EvcSubProcess"); subprocinst.setStatusCode(WorkStatus.STATUS_PENDING_PROCESS.intValue()); addParameter(subprocinst, "OrderNumber", "C30234456"); addParameter(subprocinst, "EVC_ID", "EVC-A"); addParameter(subprocinst, "OrderContent", "$orderContent"); addParameter(subprocinst, "DueDate", "$due_date"); return exeplan_doc.xmlText(); }
Note: In Groovy script the $ character is used for templating and must be escaped. So, for example, the call to addParameter() should pass "\$orderContent" instead of "$orderContent"). Here is an example to call: addParameter(subprocinst, "orderContent", "\$orderContent");
The utility method addParameter()
above is defined as
void addParameter(SubprocessInstance subprocinst, String name, String value) { Parameter param = subprocinst.addNewParameter(); param.setName(name); param.setStringValue(value); }
The following points need to be emphasized:
WorkStatus.STATUS_PENDING_PROCESS
,
as this entry will be updated by MDW engine to reflect the status of the subprocess execution$orderContent
in the above example,
just like for single subprocess invocation. If you do bind constant values, the values must
contain just letters, numbers, "_
", and space. Otherwise the value may
be misinterpretted as an expression. If you do have a need to pass constant values
with special characters, you can still do so by enclosing the value in double quotes (this will
not work if the value itself contains double quotesBecause the activity can potentially launch multiple instances of
the same subprocess, you may need multiple variables in the parent
process to receive the bindings. For example, if one
subprocess defines an output variable foo
, the parent
process cannot just have a single variable, say parent_foo
,
to receive the value of foo
as there can be multiple
instances of the variable (one for each subprocess). The number
of parent process variables needed to receive the values may not
even be known at design time.
To alleviate the problem, the activity allows, in addition, a special binding
for output variables in the execution plan, $
(a single dollar sign without
being followed by a parent process variable name).
The output variable value will be set in the execution plan itself
(replacing the binding specification $
), instead of to a parent variable.
The application specific logic can retrieve the values as needed from the execution
plan. The following sample code shows how to retrieve the variable
bindings from the first subprocess instance:
protected String getParameter(SubprocessInstance subprocinst, String name) { if (subprocinst.getParameterList()==null) return null; for (Parameter p : subprocinst.getParameterList()) { if (p.getName().equals(name)) return p.getStringValue(); } return null; } ProcessExecutionPlanDocument plan = getProcessExecutionPlan(); SubprocessInstance subprocinst = plan.getProcessExecutionPlan().getSubprocessInstanceList().get(0); super.setParameterValue(binding_varialbe_name, getParameter(subprocinst, output_variable_name));
The processing logic can be implemented in a subsequent activity,
or can be implemented by overriding the method onFinish()
.
The following lists attributes that may need to be configured:
org.apache.xmlbeans.XmlObject
EventWaitActivity
to register
the event waits (following this link
for details of event wait registration and additional details).
When the activity instance receives an event before the timer expires, it can be left in one of the 2 statuses:
To provide custom code handling unsolicited events, you will need to override
TimerWaitActivity.processOtherMessage(String message)
.
The method is passed in with one argument, which is the entire message. The default
method does nothing. The completion code after processing the message is configured
in the MDW Studio, but you can override it in the code by invoking setReturnCode()
.