Part 1 of this two-article series presented a two-layer model for analyzing dynamic business workflows and discussed how to implement the layers using IoC and Web Services Business Process Execution Language (WS-BPEL). Here in Part 2, I explain how to express a workflow's business logic using BPEL and show how to deploy IoC and BPEL to control the behavior of your business workflows.
I start by explaining how to use BPEL to express a business workflow's dynamic behavior. Then, I demonstrate the procedure for hosting your BPEL file on Apache ODE (a Java™-based open source BPEL implementation). Next, I explain the steps needed to expose the services of individual Java beans of the task layer as Web services. Finally, I present a working sample application based on BPEL and IoC.
Recall the <variables> and <sequence> tags that you saw in Listing 2 of Part 1. These two BPEL tags work together to express a business workflow's logic. This section explains the use of the <variables> tag.
Defining variables for the merged production workflow
You need to define variables to hold the business data that you want to process during the execution of your workflow. For example, you can use a variable to hold the list of items included in a production order. I use the following variables for implementing the merged production workflow:
productionOrderholds the production order received by the merged production workflow.responseholds the final response of the merged production workflow after execution of all tasks in the task layer.listOfItemsholds the list of items included in a production order.- A
itemTypespecifies the type of a production item. I use it to check whether production items are large-variety or bulk-production. processDetailsholds process details for large-variety items.workOrderholds work orders.manufacturingScheduleholds the manufacturing schedule for bulk-production items.- A few other variables hold temporary processing data.
I discuss the use of these variables while explaining the processing logic defined in a BPEL file.
Listing 1 shows how to define these variables in a BPEL file:
Listing 1. Defining variables for the merged production workflow
<?xml version="1.0" encoding="UTF-8"?>
<process name="MergedProductionWorkflow">
<import />
<!-- other import tags -->
<partnerLinks />
<variables>
<variable name="productionOrder"
messageType="prod:ProductionOrderMessage"/>
<variable name="response"
messageType="prod:ProductionResponseMessage"/>
<variable name="productionItems"
messageType="prod:ProductionItemsMessage"/>
<variable name="itemType" type="xsd:string"/>
<variable name="processDetails"
messageType="prod:ProcessDetailsMessage"/>
<variable name="workOrder"
messageType="prod:WorkOrderMessage"/>
<variable name="manufacturingSchedule"
messageType="prod:ManufacturingScheduleMessage"/>
<variable name="productionItem"
messageType="prod:ProductionItemMessage"/>
<!-- A few other variables to hold temporary data -->
</variables>
<sequence />
</process>
|
Listing 1 shows the expanded form of the <variables> tag that you saw in Listing 2 of Part 1. The <variables> tag contains several <variable> tags, one for each variable you define for your production workflow.
Each <variable> tag defines that variable's name and data type. The name attribute defines the variable's name. For example, the name of the first <variable> tag in Listing 1 is productionOrder.
The messageType attribute defines the variable's data type. For
example, the productionOrder variable's data type is prod:ProductionOrderMessage, defined by a prod namespace. Next, I explain how BPEL variables' data types map to messages exchanged between a BPEL application and its partner services.
Linking your variables to partner services
Recall from Part 1 that your BPEL file is linked to partner services (see the Linking to your service partners section). Each partner service provides the functionality of an individual task of the task layer, exposing its functionality using a Web Service Definition Language (WSDL) interface. (All the WSDL files of each partner service are included in this article's source code download; see Download).
The data held by variables used in your BPEL file is passed to partner services for processing. For example, the BPEL engine passes the production-order data held by the productionOrder variable to a partner service named Items2BProducedPartnerService, which extracts the list of items from the production order. The data type of the productionOrder variable should match the WSDL data type defined as input to the Items2BProducedPartnerService.
To help you see how BPEL variables' data types match WSDL messages, Listing 2 shows the WSDL file for Items2BProducedPartnerService:
Listing 2. WSDL interface for
Items2BProducedPartnerService
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions ...>
<wsdl:import namespace="http://fictitiousManufacturingEnterprise.com/pms"
location="ProductionOrderRecivingService.wsdl" />
<wsdl:types>
<xsd:element name="productionItem">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="itemID" type="xsd:string" />
<xsd:element name="itemName" type="xsd:string" />
<xsd:element name="itemType" type="xsd:string" />
<xsd:element name="itemQuantity" type="xsd:string"/>
<xsd:element ref="processDetails" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="productionItems">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="productionItem"
minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</wsdl:types>
<wsdl:message name="ProductionOrderMessage">
<wsdl:part name="productionOrder" element="prod:productionOrder" />
</wsdl:message>
<wsdl:message name="ProductionItemsMessage">
<wsdl:part name="productionItems" element="prod:productionItems" />
</wsdl:message>
<wsdl:portType />
<wsdl:binding />
<wsdl:service />
<plnk:partnerLinkType name="Items2BProducedPartnerLinkType">
<plnk:role name="items2BProducedService"
portType="prod:Items2BProducedPortType"/>
</plnk:partnerLinkType>
</wsdl:definitions>
|
Note that Listing 2 is the same WSDL file that you saw in Listing 4 of Part 1. In Listing 2, I've included a <wsdl:types> tag and expanded the <wsdl:message> tags of Part 1.
The <wdl:types> tag in Listing 2 defines an XML schema for the Item2BProducedPartnerService, which I describe momentarily. The two <wsdl:message> tags in Listing 2 define the input and output messages for Items2BProducedPartnerService.
The first <wsdl:message> tag defines input (that is, a production order) for Items2BProducedPartnerService. This is why the value of the name attribute of the first <wsdl:message> tag (ProductionOrderMessage) in Listing 2 matches the data type of the first variable defined in Listing 1.
The second <wsdl:message> tag defines the output of Items2BProducedPartnerService, which is the list of items to be produced. Accordingly, the name attribute value of the second <wsdl:message> tag (ProductionItemsMessage) matches the data type of the listOfItems variable defined in the BPEL file in Listing 1.
Similarly, all WSDL files for the task layer define the same data types defined as the variables in the BPEL file in Listing 1. In this way, variables' data types provide interoperability between a BPEL application and its partner services.
Defining an XML schema for the merged production workflow
Now I present the XML schema for the merged production workflow. The BPEL and WSDL files of the workflow both use this schema. The schema contains five data types ((productionOrder, productionItem, processDetails, workOrder, and manufacturingSchedule), as shown in Listing 3:
Listing 3. Data types used in the merged production workflow
<xsd:element name="productionOrder">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="orderID" type="xsd:string" />
<xsd:element name="orderDate" type="xsd:date" />
<xsd:element name="departmentID" type="xsd:string" />
<xsd:element name="orderItems" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="productionItem">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="itemID" type="xsd:string" />
<xsd:element name="itemName" type="xsd:string" />
<xsd:element ref="itemType" />
<xsd:element name="itemQuantity" type="xsd:string"/>
<xsd:element name="processDetails" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="itemType" type="xsd:string"/>
<xsd:element name="processDetails">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="processID" type="xsd:string" />
<xsd:element name="processType" type="xsd:string" />
<xsd:element name="processDescription" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="workOrder">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="workOrderID" type="xsd:string" />
<xsd:element name="orderData" type="xsd:string" />
<xsd:element ref="productionOrder" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="manufacturingSchedule">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="itemID" type="xsd:string" />
<xsd:element name="scheduleDate" type="xsd:string" />
<xsd:element name="itemQuantity" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
|
BPEL uses the XML Schema specification to define variables' data types — a topic that's beyond this article's scope. (See Resources for a link to an article that discusses how to write XML schemas.)
Note from Listing 3 that the name of each data type is specified by the <xsd:element> tag's name attribute. Listing 3 provides all the data types used by partner services' various input and output messages. For example, notice that the name attribute of the first <xsd:element> tag in Listing 3 is productionOrder. It matches the element attribute of the <wsdl:part> child of the first <wsdl:message> tag in Listing 2.
The input message to Items2BProducedPartnerService simply wraps the <productionOrder> tag defined by the first <xsd:element> tag of Listing 3. You can see this in Listing 4, which is the SOAP request message that your BPEL application sends to Items2BProducedPartnerService:
Listing 4. SOAP request message for
Items2BProducedPartnerService
<?xml version='1.0' encoding='utf-8'?>
<soap:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
<soap:Body>
<sns:productionOrder xmlns:sns="http://fictitiousManufacturingEnterprise.com/pms">
<!-- production order data -->
</sns:productionOrder >
</soap:Body>
</soap:Envelope>
|
Defining a sequence of tasks in a business workflow
You have defined variables to be used in your BPEL file for the merged production workflow. Now I'll show how to define the sequence of tasks in your merged production workflow using the <sequence> tag that you saw in Listing 2 of Part 1. The sequence uses the variables defined in Listing 1.
Recall the nine process-execution steps that I presented in the Operations of the process-execution layer section of Part 1. You need to expand the <sequence> tag and its child tags for each of the nine tasks.
Step 1: Receiving a production order
The first step in the merged production workflow is to receive a production order. For this purpose, you need a <receive> child tag in your sequence, as shown in Listing 5:
Listing 5. Receiving a production order
<process name="MergedProductionWorkflow">
<import />
<partnerLinks />
<variables />
<sequence>
<!-- Step 1: The process-execution layer receives a production order from
a client application. -->
<receive
name="receiveProductionOrder"
partnerLink="productionManagementPartnerLink"
portType="prod:ProductionManagementPortType"
operation="receiveProductionOrder"
createInstance="yes"
variable="productionOrder"/>
<!-- Other steps to process the production order -->
<!-- Response back to requesting client application-->
<reply
name="replyPurchaseOrder"
partnerLink="productionManagementPartnerLink"
portType="prod:ProductionManagementPortType"
operation="receiveProductionOrder"
variable="responseMessage" />
</sequence>
</process>
|
Listing 5 shows a <receive> as well as a <reply> tag. The <receive> tag receives a production order from an external client application (such as a software module used in the company's sales department). After receiving the production order, the BPEL engine executes all the steps of the merged production workflow, which I discuss in a moment. After the workflow steps are executed, the <reply> tag sends a reply to the external client.
The <receive> and <reply> tags form a wrapper around the entire workflow, exposing it to the external clients via a WSDL interface (shown as an overall WSDL file for the production management system in Figure 3 of Part 1).
After receiving the production order request and before sending a reply to the external client application, the merged production workflow processes the production order with the help of partner services. I discuss production-order processing in the next few sections.
You can see that the <receive> tag in Listing 5 has the following six attributes:
namespecifies the name of the task or activity being executed (receiveProductionOrder, in this case).partnerLinkspecifies a link to the partner service (the overall WSDL file shown in Figure 3 of Part 1) that will receive the production order.portTypeidentifies the port type where the partner service listens for requests.operationidentifies the operation of the partner service that will receive the production order. ThereceiveProductionOrderoperation of the production-order receiving service will receive the production order.createInstancespecifies whether the BPEL engine will create a new instance of the process being executed. The value ofcreateInstancein Listing 5 isyes, which means a new instance of the merged production workflow will be created upon receipt of every new production order.variablespecifies the name of the variable that will receive the production order. In this case, the variable name isproductionOrder(first variable that's defined in Listing 1), which means thereceiveProductionOrderoperation will receive the production order and the BPEL engine will store the purchase order in theproductionOrdervariable, so that later activities of the workflow can process the purchase order.
The <reply> tag in Listing 5 also has the same attributes except createInstance, which is not required in the <reply> tag.
Step 2: Extracting a list of production items
The second step is to extract a list of items to be produced from the production order you
received in Step 1. The merged production workflow uses a Java bean named items2BProduced to do this. A partner service named items2BProducedPartenerService exposes the functionality of the items2BProduced bean. You define an <invoke> activity to invoke the Items2BProduced partner service, as shown in Listing 6:
Listing 6. Extracting a list of items from a production order
<process name="MergedProductionWorkflow">
<import />
<partnerLinks />
<variables />
<sequence>
<!-- Step 1: The process-execution layer receives a production order from
a client application. -->
<receive />
<!-- Step 2: The process-execution layer uses the items2BProduced Java bean
to extract the list of items that need to be produced from the
production order. -->
<invoke name="getListOfProductionItems"
partnerLink="productionItemsListPartnerLink"
portType="list:ProductionItemsListPortType"
operation="getListOfProductionItems"
inputVariable="productionOrder"
outputVariable="productionItems">
</invoke>
<!-- Other steps to process the production order -->
<!-- Response back to requesting client application-->
<reply />
</sequence>
</process>
|
The <invoke> tag in Listing 6 invokes Items2BProducedPartnerService.
The <invoke> tag's name, partnerLink, portType, and operation attributes are similar to attributes of the <receive> tag in Listing 5. The <invoke> tag in a BPEL file results in a client-side Web service operation. It invokes the partner service by sending a SOAP request message. In response, the partner service responds by sending a SOAP response back to the BPEL engine.
Just two attributes of the <invoke> tag need explanation:
inputVariablespecifies the input parameter required by the partner service. In this case,Items2BProducedPartnerServicetakes the production order as input, so I've specifiedproductionOrderas theinputVariableattribute's value. Note thatproductionOrderis the same variable that receives the production order during the receive activity.outputVariablespecifies the BPEL variable that will hold the response received from the partner service. In this case, the response is a list of items to be produced. So, I have specifiedproductionItemsas the value of theoutputVariableattribute in Listing 6.
Step 3: Checking type of production items
The third step of the merged production workflow is to check the type of each item to be produced (that is, whether it belongs to the large-variety category or the bulk-production category). This requires a number of substeps, as shown in Listing 7:
Listing 7. Checking the types of production items
<process name="MergedProductionWorkflow">
<import />
<partnerLinks />
<variables />
<sequence>
<!-- Step 1: The process-execution layer receives a production order from
a client application. -->
<receive />
<!-- Step 2: The process-execution layer uses the items2BProduced Java bean
to extract the list of items that need to be produced from the
production order. -->
<invoke />
<!-- Step 3: For each item in the production order, the process-execution
layer uses the typeOfItem Java bean to check whether the item belongs
to the large-variety category or the bulk-production category. -->
<!-- Sub-step 3-1: Check how many items are in the list of items to be
produced -->
<assign>
<copy>
<!-- Copy items size in a local variable named numberOfItems-->
<from>
count($productionItems.productionItems/prod:productionItem)
</from>
<to variable="numberOfItems"/>
</copy>
</assign>
<!-- Sub-step 3-2: Run a loop to check each item in the list-->
<while>
<condition>$numberOfItems > 0</condition>
<scope>
<sequence>
<!-- Sub-step 3-3: Copy an item from the list to a local variable-->
<assign>
<copy>
<from>$productionItems.productionItems[$numberOfItems]</from>
<to variable="productionItem" part="productionItem"/>
</copy>
</assign>
<!-- Sub-step 3-4: Invoke typeOfItemPartner service-->
<invoke name="getItemType"
partnerLink="typeOfItemPartnerLink"
portType="type:ProductionItemTypePortType"
operation="getTypeOfProductionItem"
inputVariable="productionItem"
outputVariable="itemType">
</invoke>
</sequence>
</scope>
</condition>
</while>
<!-- Response back to requesting client application-->
<reply />
</sequence>
</process>
|
As you can see from Listing 7, the first substep is to check how many items are in the list of items to be produced. An <assign> tag does this job in Listing 7 by assigning values to variables. In substep 3-1 of Listing 7, a <copy> child of the <assign> tag copies a value into a variable. You can see <from> and <to> children of the <copy> tag, which define the value and the variable, respectively. The <from> tag uses an XPath expression to specify the value that you want to copy into the variable. The XPath expression simply evaluates how many items exist in the list of items to be produced (see Resources for a link to XPath details).
The <copy> tag's <to> child simply defines the variable (numberOfItems) to which you want to copy the value.
After substep 3-1, the number of items in the list is copied into the numberOfItems variable. Substep 3-2 is to run a while loop for each item in the list. The <while> tag, along with its <condition> child, runs the loop.
Now look at step 3-3 in Listing 7. It is another copy operation, applied to each individual item in the list of items. The purpose is to produce a local copy of the list items.
Finally, in step 3-4, typeOfItemPartnerService is invoked, passing the local item copy to the partner service. The typeOfItemPartnerService partner service returns the item type (large-variety or bulk-production).
Steps 4 through 9: Processing large-variety and bulk-production items
The remaining processing steps for the merged production workflow (Steps 4 to 9 of the Operations of the process-execution layer section of Part 1) are shown in Listing 8:
Listing 8. Processing large-variety and bulk-production items
<process name="MergedProductionWorkflow">
<import />
<partnerLinks />
<variables />
<sequence>
<!-- Steps 1, 2 and 3-1 go here. -->
<!-- Sub-step 3-2: Run a loop to check each item in the list-->
<while> <condition /> <scope /> <sequence />
<!-- Sub-steps 3-3 and 3-4 go here-->
<!-- Steps 4 to 9: Rest of the workflow steps. -->
<if>
<condition>'LARGE_VARIETY' = $typeOfItem </condition>
<flow>
<invoke name="fetchProcessDetails"
partnerLink="processDetailsPartnerLink"
portType="prod:ProcessDetailsPortType"
operation="getProcessDetailsOfLargeVarietyItem"
inputVariable="productionItem"
outputVariable="processDetails">
</invoke>
<invoke name="issueLargeVarietyWO"
partnerLink="largeVarietyWOPartnerLink"
portType="prod:LargeVarietyWOPortType"
operation="issueLargeVarietyWO"
inputVariable="largeVarietyWO"
outputVariable="workOrder">
</invoke>
</flow>
</if>
<if>
<condition>'BULK_PRODUCTION' = $typeOfItem </condition>
<flow>
<invoke name="checkManufacturingSchedule"
partnerLink="manufacturingSchedulePartnerLink"
portType="prod:ManufacturingSchedulePortType"
operation="getManufacturingSchedule"
inputVariable="itemID"
outputVariable="manufacturingSchedule">
</invoke>
<assign>
<copy>
<from>
$productionItem.productionItem
/prod:productionItem/prod:itemQuantity
</from>
<to variable="itemQuantity" />
</copy>
</assign>
<invoke name="checkAdditionalProductionRequirement"
partnerLink="additionalProductionRequirementPartnerLink"
portType="prod:AdditionalProductionRequirementPortType"
operation="checkAdditionalProductionRequirement"
inputVariable="bulkProdRequirement"
outputVariable="itemQuantity2Produce">
</invoke>
<assign>
<copy>
<from variable="itemQuantity2Produce"
part="quantity2Produce"/>
<to variable="qty2Produce"/>
</copy>
</assign>
<if>
<condition> $qty2Produce > 0 </condition>
<invoke name="reserveProduction"
partnerLink="productionReservationPartnerLink"
portType="prod:ProductionReservationPortType"
operation="reserveProductionInCurrentMS"
inputVariable="qty2Reserve"
outputVariable="reservationResponse">
</invoke>
</if>
<invoke name="issueBulkProductionWO"
partnerLink="bulkProductionWOPartnerLink"
portType="prod:BulkProductionWOPortType"
operation="issueWorkOrderForBulkProductionItem"
inputVariable="itemID"
outputVariable="reservationAck">
</invoke>
</flow>
</if>
</sequence> </scope> </condition> </while>
<!-- Response back to requesting client application-->
<reply />
</sequence>
</process>
|
You can see from Listing 8 that you just need an <if> tag to make conditional decisions before processing each production item according to its type.
Deploying the merged production workflow's BPEL
Now you know how to use BPEL to express the business logic of your merged production workflow. You're ready deploy your BPEL file on the Apache ODE BPEL engine.
ODE requires you to write a deployment descriptor for your BPEL application. The deployment descriptor is an XML file, shown in Listing 9:
Listing 9. Deployment descriptor for the merged production workflow's partner services
<deploy xmlns="http://www.apache.org/ode/schemas/dd/2007/03"
xmlns:prod="http:// http://fictitiousManufacturingEnterprise.com/bpel"
xmlns:sns="http://fictitiousManufacturingEnterprise.com/pms">
<process name="prod:MergedProductionOrder">
<provide partnerLink="productionOrderReceivingPartnerLink">
<service name="sns:productionOrderReceivingService"
port="productionOrderReceivingPort"/>
</provide>
<invoke partnerLink="items2BProducedPartnerLink">
<service name="sns:items2BProducedService" port="items2BProducedPort"/>
</invoke>
<invoke partnerLink="typeOfItemPartnerLink">
<service name="sns:typeOfItemService" port="typeOfItemPort"/>
</invoke>
<invoke partnerLink="processDetailsPartnerLink">
<service name="sns:processDetailsService" port="processDetailsPort"/>
</invoke>
<!-- other services invoked by merged production workflow -->
</process>
</deploy>
|
Listing 9 has a root tag named <deploy>, which has a single child named <process>. The <process> tag has a number of child tags. The first child of the <process> tag is <provide>.
The <provide> tag describes the service provided by your merged production workflow. There is only one service that merged production workflow provides; that is, it receives and processes a production order. So Listing 9 contains only one <provide> tag.
The <provide> tag has a partnerLink attribute, which specifies the partner service that receives the production order. The <provide> tag's <service> child specifies the partner service's name and port.
Now look at the various <invoke> tags in Listing 9. Each one describes a partner service that the merged production workflow invokes. The <invoke> tag specifies the partner service's partner link, name, and port.
The BPEL file and the deployment descriptor for the merged production workflow are included in this article's source code (see Download).
Hosting task layer for the merged production workflow
Recall from the IoC configurations for the task layer section in Part 1 that you have already configured the task layer's eight Java beans as IoC beans in Spring. Now you need to configure Spring so that the IoC beans expose their services through Web service interfaces.
Apache ODE is built on Apache Axis2 — another popular open source project. Axis2 can host Java objects (such as your IoC beans) as XML and SOAP-based Web services. ODE only implements the functionality required by BPEL and uses Axis2 for all low-level Web service-related functionality such as authoring, sending, receiving, and processing SOAP messages. This means you just need to configure your IoC beans to work with Axis2. ODE will automatically start using the IoC beans.
Configuring IoC beans with Axis2
To expose the functionality of an IoC bean as an Axis2 Web service, you need to:
- Wrap the IoC bean in a wrapper class, which can communicate with the Axis2 framework.
- Enhance the bean definition in the Spring configuration file to reflect the wrapper class.
Axis2 implements an XML processing model named Axis Object Model (AXIOM) according to a Java Specification Request (JSR) 173 (see Resources).
The AXIOM architecture of Axis2 requires that any Web service operation accept an instance
of an AXIOM class named OMElement as input and return another
object of the same class as output. This means the signature of any Web service is:
OMElement myWebServiceOperation (OMElement input2MyWebServiceOperation){ }
Axis2 implements the functionality to accept, author, and process XML data in its OMElement class.
You must wrap your IoC beans in a method that has a signature according to the Axis2 AXIOM architecture. Listing 10 shows a class named AxisAwareItems2BProduced, which wraps the items2BProduced IoC bean (part of the task layer) configured in the IoC configurations for the task layer section of Part 1:
Listing 10. Axis-aware wrapper for the
Items2BProduced Web service
package sample.wf.;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMText;
public class AxisAwareItems2BProduced {
private Items2BProduced items2BProduced= null;
public void setItems2BProduced(Items2BProduced items2BProduced) {
this.items2BProduced = items2BProduced;
}
//The getListOfItems operation of Items2BProduced web service
public OMElement getListOfItems(OMElement productionOrderOMElement) {
//Step 1: Getting production order request data from OMElement object
OMElement productionOrderRequest =
productionOrderOM.getFirstElement();
//Step 2: Invoking the IoC bean
OMElement itemsList =
factory.createOMElement(
this.items2BProduced.getListOfItems(productionOrderRequest));
//Step 3: Create an empty OMElement response object using a factory class
OMFactory Factory=
OMAbstractFactory.getOMFactory();
OMNamespace items2ProduceNs= factory.createOMNamespace(
"http:// http://fictitiousManufacturingEnterprise.com/items2BProduced",
"productionOrder");
OMElement responseWrapper =
factory.createOMElement("itemsList", items2ProduceNs);
//Step 4: Populate response object with response data
responseWrapper.addChild(itemsList);
//Step 5: Return response object
return responseWrapper;
}
}
|
Whenever Items2BProducedPartnerService receives a request, Axis2 invokes the AxisAwareItems2BProduced class's getListOfItems() method, which in turn invokes the Items2BProduced IoC bean. The Axis2 framework wraps the request data in an OMElement object and passes the OMElement object as an input parameter to the getListOfItems() method.
Listing 10 shows a five-step processing strategy for processing the OMElement object in the getListOfItems() method:
- Extract request data from the
OMElementobject. - Invoke the
items2BProducedIoC bean'sgetListOfItems()method, passing the request data from Step 1 along with the method call. - Create an empty
OMElementobject using a factory class. - Populate the empty
OMElementresponse object from Step 3 using data received from the IoC bean in Step 2. - Return the
OMElementresponse object to the BPEL engine.
I have provided similar wrapper classes for all the IoC beans in the article's source code (see Download). The next section describes how to enhance the beans definition in the Spring configuration to reflect these wrapper classes.
Enhancing the Spring configuration for Axis-aware wrapper classes
Now I'll update the IoC bean definitions for the wrapper classes you just created. This is simple. You just need a <bean> tag for each wrapper class in your Spring configuration file, as shown in Listing 11:
Listing 11. Configuring Axis-aware beans in Spring's XML configuration file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ....>
<!-- Axis-aware wrapper for items2BProduced bean -->
<bean id="axisAwareItems2BProduced"
class="sample.wf.Axis.AxisAwareItems2BProduced" >
<property name="items2BProduced" ref="items2BProduced"/>
</bean>
<bean id="items2BProduced" class="sample.wf.Items2BProduced" />
<bean id="typeOfItem" class="sample.wf.TypeOfItem" />
<!-- Other beans of task layer -->
</beans>
|
You can see from Listing 11 that the wrapper bean (axisAwareItems2BProduced) definition refers to its corresponding IoC bean (items2BProduced) through a property named items2BProduced.
You're now all set to try your merged production workflow. The article source code includes everything your workflow needs (see Download). Follow these steps to prepare to try your workflow:
- Copy your partner services into your Axis2 installation:
- Copy .aar files for all partner service into your Axis2 installation's Web-INF/services folder.
- Copy .jar files (containing IoC beans of the task layer) into your Axis2 installation's Web-INF/lib folder.
- The source code includes an applicationContext.xml file, which contains IoC bean configurations. Copy the file to the root of Web-INF folder in your Axis2 installation.
- Download the spring.jar file (see Resources) and copy it into
the Web-INF/lib folder of your Axis2 installation.
- Copy your BPEL application into ODE by copying the MergedProductionWorkflow folder from the source code download into your ODE installation Web-INF/processes folder.
Start Tomcat and run the BPELClient.bat file, which you'll find in the BPELClient folder of the source code download. BPELClient.bat sends a production order to the merged workflow application to start the workflow sequence. You will see every step in the sequence on the console output of both Axis2 and ODE. The BPEL client will also display the response received from the merged production workflow.
This series of articles has explained how to analyze dynamic business workflows in a two-layer model. You have learned how to break down your workflows into fine-grained tasks to implement and configure each task as an IoC bean. You've also seen how to express your workflow's business logic using BPEL. Finally, you put the pieces together to build a production-management workflow application.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample code for this article | j-bpelioc2.zip | 56KB | HTTP |
Information about download methods
Learn
-
"Build configurable workflows with WS-BPEL and IoC, Part 1: Understanding dynamic business workflows" (Bilal Siddiqui, developerWorks, July 2008): Read Part 1 of this article.
- Axis2 Integration With The Spring Framework: A guide to integrating Axis2 with Spring's IoC framework.
-
"Design XML schemas for enterprise data" (Bilal Siddiqui, developerWorks, October 2006): This tutorial demonstrates how to write XML schemas for enterprise applications.
-
"Securing Java applications with Acegi, Part 1: Architectural overview and security filters" (Bilal Siddiqui, developerWorks, March 2007): This article includes a detailed discussion of XML configurations for Spring.
-
"Java Web services, Part 2: Digging into Axis2: AXIOM" (Dennis Sosnoski, developerWorks, November 2006): Get an inside view of AXIOM.
- Apache AXIOM: Visit the AXIOM project site for more AXIOM resources.
- JSR 173: Streaming API for XML: You can read the specification that AXIOM is based on.
- Web Services Business Process Execution Language Version 2.0: The official WS-BPEL specification is available from OASIS.
- XML Path Language (XPath)
Version 1.0: The official specification for XPath, maintained by the World Wide Web Consortium.
-
Browse the
technology bookstore for books on these and other technical topics.
- developerWorks Java technology zone: Find hundreds of articles about every aspect of Java programming.
- developerWorks SOA and Web services zone: Find hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.
Get products and technologies
- ODE and Axis2: Download these Apache frameworks.
- spring.jar: Download the latest Spring Framework release.
-
Download
IBM product evaluation versions and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
-
Check out developerWorks blogs and get involved in the developerWorks community.
Bilal Siddiqui is an electronics engineer, an XML consultant, and the co-founder of WaxSys, a company focused on simplifying e-business. After graduating in 1995 with a degree in electronics engineering from the University of Engineering and Technology, Lahore, he began designing software solutions for industrial control systems. Later, he turned to XML and used his experience programming in C++ to build Web- and Wap-based XML processing tools, server-side parsing solutions, and service applications. Bilal is a technology evangelist and a frequently-published technical author.





