Section 11.2. Example: Employee Benefits Message Broker


11.2. Example: Employee Benefits Message Broker

This example illustrates how a hypothetical company might use BPM to implement a message broker. Company X is building a new messaging infrastructure for its various employee benefits systems. As illustrated in Figure 11-3, at the center of this infrastructure is a BPM-based message broker for medical and life insurance that manages interactions between the Human Resources department (HR), the Payroll department, and HR Portal applications and systems (see following explanation).

Enterprise Service Bus

A message broker is a central hub for application communication in a single enterprise. The grander notion of Enterprise Service Bus (ESB) , being promised currently by seemingly every integration vendor and solution provider, describes a decentralized, distributed, extended-enterprise messaging router. Applications scattered across several distinct companies can plug into a common ESB bus and communicate with one another. This model, if and when it becomes real, is a marked improvement over today's state of affairs, in which most companies do not even have an intraenterprise broker, and even for those that do, communicating with other enterprises is a comparatively complicated solution.

A good presentation of ESB, including the use of BPEL for orchestration, is found in O'Reilly's Enterprise Service Bus by Dave Chappell.


Figure 11-3. Employee benefits broker architecture


The main source of messages is HR Portal, a new web application that allows the company's employees to manage some of their own HR needs. A few of the tasks that HR Portal allows include:

  • Recording various life events that affect coverage, such as births or marriages

  • Modifying pension contributions

  • Adjusting medical insurance coverage; for instance, increasing dental coverage or decreasing vision care

The changes are sent to the broker, which applies rules in its processes to route them to HR, Payroll, and insurance companies. Communications with the broker are through web services. Messages are represented in a canonical XML form.

11.2.1. BPMN Process Models

In this example, the broker has three main processes: a Life Event process to handle life events, a Pension process to handle pension changes, and a Medical process to handle insurance changes. Although we will code the processes in BPEL, we begin by modeling them in the leading graphical notation standard, BPMN; design should always precede implementation! The BPMN modeling tool that we will use is ITpearls' Process Modeler 2.0, which is nothing more than a stencil for Microsoft Visio 2000 . To draw a BPMN diagram, create a new Visio drawing and drag symbols from the BPMN stencil onto the page. The software, and a free evaluation license, can be downloaded from http://www.itp-commerce.com/processmodeler/. The tool is shown in Figure 11-4.

Figure 11-4. BPMN Modeler using ITpearls' in MS Visio


NOTE

Alas! ITpearls' product does not currently support BPEL export, so it cannot generate BPEL code directly from our BPMN diagrams. We will use BPMN strictly for visual design, and code the BPEL processes from scratch, guided by the BPMN blueprints.

11.2.1.1 The Life Event process

Figure 11-5 shows the BPMN diagram for the Life Event process . The process is started on receipt of a Life Event message, which is then sent in successive steps to the medical and life insurance companies. Although exceedingly simple, the process performs an important publish-subscribe function; if it did not exist, some other, less elegant, ad hoc mechanism would be required to deliver life events to the insurance companies.

Figure 11-5. BPMN diagram for the Life Event process


11.2.1.2 The Pension process

The Pension process, shown in Figure 11-6, is more complicated and exhibits several workflow and EAI patterns. The process begins by receiving an event requesting a change in pension contribution amount. The process then branches into two conditional paths using an inclusive-OR gateway (the topmost diamond with a circle inside). If the contribution to be changed is the company's contribution, the path beginning with the Send HR activity is followed. If the change is to the employee's contribution, the Send payroll activity is run. If both conditions hold, both paths are followed. The bottommost inclusive-OR gateway joins the paths, waiting for both to complete before allowing the process to complete. The split and join patterns used here are, respectively, the Multiple Choice and Synchronizing Merge patterns (documented in Chapter 4).

The process also exhibits the Content-Based Routing EAI patterns described in Gregor Hohpe's catalog at http://www.eaipatterns.com.[*] The process examines its initial pension event for information that determines whether the change is for the company, the employee, or both. Based on that decision, the process proceeds to send the message to HR (for company contribution), Payroll (for employee contribution), or both; in other words, the process routes the message based on content.

[*] See also G. Hohpe, B. Woolf, Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions, Addison-Wesley, 2003 (http://ww.eaipatterns.com).

On the HR path, after sending the message to the HR system, the process waits for a confirmation event. The Payroll path is simpler, having a send to Payroll but no confirmation.

Figure 11-6. BPMN diagram for the Pension process


11.2.1.3 The Medical process

The process handling medical coverage changes is the hardest and most interesting of our examples. The HR portal gathers information from the employee on five separate web pageseach gathering information on employees, spouses, dependents, coordination of benefits (COB), and beneficiaries, respectivelyand sends a message for each page to the broker. But the HR back-end system requires a single, consolidated message. The responsibility of the broker process is to gather each of the portal messages, combine them, and submit to HR.

The BPMN diagram is shown in Figure 11-7. Because of the complexity (contrived complexity, rigged to make the process more interesting), the logic is divided into two processes, Main and Helper, drawn as swim lanes in the pool Medical Benefits Application. The Main process simply listens for one of the five message types, adds to it a special Session ID field, and sends the modified message to the Helper process. The Session ID has the same value for each message in a five-message sequence but is unique to that sequence. The field is calculated based on the field MsgID, a unique number found in each HR portal message; related messages are indexed off this base value. As we've defined it in this example, the MsgID for an Employee message is always a multiple of five (e.g., 30); the Spousal message is that number plus 1 (e.g., 31); the Dependent message that number plus 2 (e.g., 32); the COB message that number plus 3 (e.g., 33); and the Beneficiaries message that number plus 4 (e.g., 34). The Session ID is calculated as MsgID div 5, which means the value of the MsgID field divided by 5, truncated to an integer (e.g., 6 for any MsgId value in the range 30 to 34).

Table 11-1 demonstrates the math for two sequences.

Figure 11-7. BPMN diagram for Medical process


Table 11-1. Message ID and Session ID for medical sequences

Message ID

Message type

Session ID

30

Employee

6

31

Spousal

6

32

Dependents

6

33

COB

6

34

Beneficiaries

6

35

Employee

7

36

Spousal

7

37

Dependents

7

38

COB

7

39

Beneficiaries

7


The Helper process begins by receiving the first message in the session, Employee data, and then waits in parallel for each of the remaining four messages, correlating on the Session ID. When each of the messages has been gathered, the process combines them and sends to HR. Among the BPMN constructs used in this example are message links (dotted arrows depicting the flow of messages from Main to Helper), an expanded subprocess (Get remaining messages), and the use of the AND gateway (a diamond with a plus sign) to model the workflow patterns Parallel Split and Synchronization. On the subject of patterns, the combining of messages into a single message is essentially the EAI pattern Resequencer, also described in the EAI patterns catalog.

11.2.2. BPEL Processes

Now that we have a BPMN model for each major process, we're ready to implement the Message Broker using the Oracle BPEL Process Manager (introduced in Chapter 10). The full implementation consists of eight processes: one for Life Events; one for Pension; two for Medical (main and helper); and one to simulate, or stub for test purposes, each of the target systemsHR, Payroll, the life insurance company, and the medical insurance company. Table 11-2 lists each process. Because some processes under development require the interfaces of others, the processes should be developed in the order they appear in the table.

Table 11-2. BPEL process summary

Process

Purpose

Design notes

Pension service

Simulates service interface of company's pension system.

 

HR service

Simulates service interface of company's HR system.

When called, automatically sends back confirmation.

Life insurance company

Simulates life insurance company Life Event service.

Implements standard WSDL interface for Life Event subscription.

Medical insurance company

Simulates medical insurance company Life Event service.

Implements standard WSDL interface for Life Event subscription.

MB Life Event publisher

Publishes life event messages to life and medical insurance companies.

Uses dynamic addressing.

MB Pension

Routes pension adjustment messages to HR and/or Payroll systems.

 

MB Med Helper

Aggregates a five-message medical adjustment sequence and sends it to the HR system.

 

MB Med Main

Listens for medical adjustment messages and routes them to MB Med Helper, adding a correlating Session ID to each.

 


This chapter walks you through the step-by-step mechanics of developing processes in Oracle BPEL Process Designer. You can also refer to Chapter 10 for a click-by-click account of how to create, code, and build processes in this tool.

11.2.2.1 Canonical XML

The first step in the implementation is to define a canonical XML message structure called CanonicalBenefits that describes how information is exchanged between broker processes and systems. This type, defined in lines 9-32 in the code sample Example 11-1 (the complete listing of canon.wsdl), captures information about the employee (empid, empname, empdivision) and the type of message (msgtype, msgsubtype), and contains numeric message identifiers (msgid, sesid), and a free-text field (data) whose meaning is application-specific. The listing also defines a WSDL message type, BenefitsMessage (lines 35-37), intended as the input or output type of every web service operation used in this example. Lines 41-48 define BPEL properties for use in correlation of the msgid or sesid fields of the canonical message.

Example 11-1. canon.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="canon" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/" 6       xmlns:xsd="http://www.w3.org/2001/XMLSchema" 7       xmlns="http://schemas.xmlsoap.org/wsdl/"> 8 9       <types> 10          <schema attributeFormDefault="qualified" 11             elementFormDefault="qualified" 12             targetNamespace="http://acm.org/samples" 13             xmlns="http://www.w3.org/2001/XMLSchema"> 14 15             <!-- The schema definition for the CanonicalBenefits message, to be 16                  used by all participants.  --> 17             <element name="CanonicalBenefits"> 18                <complexType> 19                   <sequence> 20                      <element name="msgid" type="string" /> 21                      <element name="sesid" type="string" /> 22                      <element name="empid" type="string" /> 23                      <element name="empname" type="string" /> 24                      <element name="empdivision" type="string" /> 25                      <element name="msgtype" type="string" /> 26                      <element name="msgsubtype" type="string" /> 27                      <element name="data" type="string"/> 28                   </sequence> 29                </complexType> 30             </element> 31          </schema> 32       </types> 33 34       <!-- The WSDL message type for the XML CanonicalBenefits message --> 35       <message name="BenefitsMessage"> 36          <part name="payload" element="tns:CanonicalBenefits"/> 37       </message> 38 39       <!-- BPEL property aliases defined for both sesid and msgid.  Correlation 40            to be performed on each. --> 41       <bpws:property name="msgid" type="xsd:string"/> 42       <bpws:property name="sesid" type="xsd:string"/> 43       <bpws:propertyAlias propertyName="tns:msgid" 44          messageType="tns:BenefitsMessage" part="payload" 45          query="/tns:CanonicalBenefits/tns:msgid"/> 46       <bpws:propertyAlias propertyName="tns:sesid" 47          messageType="tns:BenefitsMessage" part="payload" 48          query="/tns:CanonicalBenefits/tns:sesid"/> 49    </definitions>

The greatest challenge in the construction of canonical XML is satisfying the data requirements of all participants. In this example, stakeholders from the HR Portal, the HR and Payroll systems, and the life and medical insurance companies would have met numerous times to agree upon the correct set of fields. Sometimes the diversity of these disparate applications makes complete consensus impossible, necessitating compromises such as the data field, which can be used in place of a more formal hierarchical structure because not everyone could agree on that structure.

11.2.2.2 The Life Event process

Once the canonical form is established, we can implement the processes themselves. The WSDL for Life Events is shown in Example 11-2. In its port type, declared in lines 26-30, the WSDL refers to the canonical message type BenefitsMessage, defined in canon.wsdl; the import in line 10 makes the artifacts of canon.wsdl available to this WSDL. The port type contains a single operation, called initiate.

The types declaration in lines 12-23 includes a second import, this time of the standard WS-Addressing schema. The relevance of this will be examined shortly.

Example 11-2. MBLifeEventPublisher.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="MBLifeEventPublisher" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/" 7       xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"> 8 9       <!-- Import canon.wsdl, because we need to reference its artifacts. --> 10       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 11 12       <types> 13          <schema attributeFormDefault="qualified" 14             elementFormDefault="qualified" 15             targetNamespace="http://samples.otn.com" 16             xmlns="http://www.w3.org/2001/XMLSchema"> 17 18             <!-- Need accesss to WS-addressing stuff too. --> 19             <import namespace=http://schemas.xmlsoap.org/ws/2003/03/addressing 20              schemaLocation="http://localhost:9700/orabpel/xmllib/ws-addressing.xsd"/> 21 22          </schema> 23       </types> 24 25       <!-- Supports a single operation "initiate" --> 26       <portType name="MBLifeEventPublisher"> 27          <operation name="initiate"> 28             <input message="tns:BenefitsMessage"/> 29          </operation> 30       </portType> 31 32       <!-- Define partner link type for the port type  --> 33       <plnk:partnerLinkType name="MBLifeEventPublisher"> 34          <plnk:role name="LifeEventPublisher"> 35             <plnk:portType name="tns:MBLifeEventPublisher"/> 36          </plnk:role> 37       </plnk:partnerLinkType> 38    </definitions>

The process itself (Example 11-3) is a modest 78 lines, and the implementation logic starts with a receive activity on line 27, which corresponds to the WSDL-defined initiate operation. The canonical message passed to the process here originates in HR Portal and is routed to the medical and life insurance companies, in lines 33-54 and lines 56-76, respectively. The partner links for these companies are defined dynamically rather than statically, as is commonplace. The dynamic definition is achieved by building a WS-Addressing EndpointReference structure (lines 34-45 and 57-68), stipulating an explicit service address and name, and setting that structure as the value of the partner link (lines 46-49 and 69-72).

Example 11-3. MBLifeEventPublisher.bpel
 1    <process name="MBLifeEventPublisher" 2       targetNamespace="http://acm.org/samples" 3       suppressJoinFailure="yes" xmlns:tns=http://acm.org/samples 4       xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 5       xmlns:bpelx=http://schemas.oracle.com/bpel/extension 6       xmlns:ora=http://schemas.oracle.com/xpath/extension 7       xmlns:wsa=http://schemas.xmlsoap.org/ws/2003/03/addressing 8       xmlns:xsd=http://www.w3.org/2001/XMLSchema 9       xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"> 10 11       <!-- Two partner links: one for the client that initates the process, the other 12             ("dynamicSubscriber") a placeholder for each registered subcriber --> 13       <partnerLinks> 14          <partnerLink name="client" partnerLinkType="tns:MBLifeEventPublisher" 15             myRole="LifeEventPublisher"/> 16          <partnerLink name="dynamicSubscriber" 17             partnerLinkType="tns:MBLifeEventSubscriber" 18             partnerRole="LifeEventSubscriber"/> 19       </partnerLinks> 20       <variables> 21          <variable name="input" messageType="tns:BenefitsMessage"/> 22          <!-- partnerRef is a pointer to a dynamic subscriber --> 23          <variable name="partnerRef" element="wsa:EndpointReference"/> 24       </variables> 25       <sequence name="main"> 26          <!-- Step 1: Start by getting message from client via initiate method --> 27          <receive name="receiveInput" partnerLink="client" operation="initiate" 28             variable="input" createInstance="yes" 29             portType="tns:MBLifeEventPublisher"/> 30          <!-- Step 2: Set partnerRef with the value of the first subscriber: 31                the medical company. Two data: (a) URL, 32                (b) must conform LifeEventSubscriber role --> 33          <assign name="assignPartner"> 34             <copy> 35                <from> 36                   <wsa:EndpointReference 37                      xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing"> 38    <wsa:Address>http://localhost:9700/orabpel/default/MedicalInsuranceCompany 39    </wsa:Address> 40    <wsa:ServiceName xmlns:ns1="http://services.otn.com">ns1:MedicalInsuranceCompany 41    </wsa:ServiceName> 42                   </wsa:EndpointReference> 43                </from> 44                <to variable="partnerRef"/> 45             </copy> 46             <copy> 47                <from variable="partnerRef"/> 48                <to partnerLink="dynamicSubscriber"/> 49             </copy> 50          </assign> 51          <!-- Step 3: Call the dynamic subscriber's serrvice --> 52          <invoke name="callPartner" partnerLink="dynamicSubscriber" 53             portType="tns:MBLifeEventSubscriber" operation="initiate" 54             inputVariable="input"/> 55          <!-- Step 4: repeat of Step 2, but URL is that of life insurance company --> 56          <assign name="assignPartner2"> 57             <copy> 58                <from> 59                   <wsa:EndpointReference 60                      xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing"> 61    <wsa:Address>http://localhost:9700/orabpel/default/LifeInsuranceCompany 62    </wsa:Address> 63    <wsa:ServiceName xmlns:ns1="http://services.otn.com">ns1:LifeInsuranceCompany 64    </wsa:ServiceName> 65                   </wsa:EndpointReference> 66                </from> 67                <to variable="partnerRef"/> 68             </copy> 69             <copy> 70                <from variable="partnerRef"/> 71                <to partnerLink="dynamicSubscriber"/> 72             </copy> 73          </assign> 74          <!-- Step 5: repeat of step 3 --> 75          <invoke partnerLink="dynamicSubscriber" portType="tns:MBLifeEventSubscriber" 76             operation="initiate" inputVariable="input" name="callPartner2"/> 77       </sequence> 78    </process>

The curious use of dynamic addressing in this example has the following advantage: the list of subscribers can be expanded without the need to create new partner links. One partner link suffices, and as the process iterates through its list of subscribers, it sets the link's endpoint, invokes the service, and continues. Each subscriber, of course, must implement a service of the type expected by the process. Although the endpoint is dynamic, the service definition is not. Each subscriber must build to the same WSDL, using the partner link type (in this case, MBLifeEventSubscriber) and the role (LifeEventSubscriber) specified in lines 16-18. In the subscriber WSDL, listed in Example 11-4, the operation initate takes as input the canonical BenefitsMessage payload.

Example 11-4. MBLifeEventSubscriber.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="MBLifeEventSubscriber" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/" 7       xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"> 8 9       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 10 11       <portType name="MBLifeEventSubscriber"> 12          <operation name="initiate"> 13             <input message="tns:BenefitsMessage"/>  <!-- canonical type --> 14          </operation> 15       </portType> 16 17       <!-- dynamic partner link referenced in BPEL above. --> 18       <plnk:partnerLinkType name="MBLifeEventSubscriber"> 19          <plnk:role name="LifeEventSubscriber"> 20             <plnk:portType name="tns:MBLifeEventSubscriber"/> 21          </plnk:role> 22       </plnk:partnerLinkType> 23    </definitions>

For test purposes, simple processes simulating services of the life and medical insurance companies are provided. Example 11-5 shows the life insurance process; the process simply swallows the Life Event process (received in lines 19-21) and exits. The code for the medical insurance company (not shown, but left as an exercise for the reader) is nearly identical.

Example 11-5. LifeInsuranceCompany.bpel
 1    <process 2       name="LifeInsuranceCompany" targetNamespace=http://acm.org/samples 3       suppressJoinFailure="yes" 4       xmlns:tns=http://acm.org/samples 5       xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 6       xmlns:bpelx=http://schemas.oracle.com/bpel/extension 7       xmlns:ora="http://schemas.oracle.com/xpath/extension"> 8 9       <!-- supports MBLifeEventSubscriber partner link type --> 10       <partnerLinks> 11          <partnerLink name="client" myRole="LifeEventSubscriber" 12             partnerLinkType="tns:MBLifeEventSubscriber"/> 13       </partnerLinks> 14       <variables> 15          <variable name="input" messageType="tns:BenefitsMessage"/> 16       </variables> 17       <sequence name="main"> 18         <!-- the simplest process possible: receive the message, and that's it --> 19          <receive name="receiveInput" partnerLink="client" 20             portType="tns:MBLifeEventSubscriber" operation="initiate" variable="input" 21             createInstance="yes"/> 22       </sequence> 23    </process>

11.2.2.3 The Pension process

The service interface of the Pension process, specified in the WSDL listing in Example 11-6, consists of a single operation, called initiate, that accepts a canonical benefits message.

Example 11-6. MBPension.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="MBPension" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/"> 7 8       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 9 10       <portType name="MBPension"> 11          <operation name="initiate"> 12              <input message="tns:BenefitsMessage"/> 13          </operation> 14       </portType> 15 16       <plnk:partnerLinkType name="MBPension"> 17          <plnk:role name="PensionProvider"> 18             <plnk:portType name="tns:MBPension"/> 19          </plnk:role> 20       </plnk:partnerLinkType> 21    </definitions>

In the BPEL code for the process (Example 11-7), the receive activity in lines 27-28 starts the process when the initiate operation is invoked. The remainder of the process (lines 29-60) implements an inclusive OR split and join with two switch statements inside a flow, or two conditional sets of logic running in parallel. The first switch (lines 30-45) searches the msgsubtype element of the initiating benefits message for the text "company"; if the pattern matches, the notify operation of the HR service is called (lines 35-36), and the process waits for a confirmation (lines 37-39). The second switch (lines 46-57) calls the pensionUpdate operation of the Pension service if the original benefits message contains "employee."

Example 11-7. MBPension.bpel
 1    <process name="MBPension" 2       targetNamespace="http://acm.org/samples" 3       suppressJoinFailure="yes" 4       xmlns:tns=http://acm.org/samples 5       xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 6       xmlns:bpelx=http://schemas.oracle.com/bpel/extension 7       xmlns:ora=http://schemas.oracle.com/xpath/extension 8       xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"> 9 10       <!--  three partner links: one for client that starts this process, 11             one for payroll and one for HR, each of which is conditionally 12             called by this process. --> 13       <partnerLinks> 14          <partnerLink name="client" partnerLinkType="tns:MBPension" 15             myRole="PensionProvider"/> 16          <partnerLink name="payroll" partnerLinkType="tns:PayrollService" 17             partnerRole="PayrollService"/> 18          <partnerLink name="hr" partnerLinkType="tns:HRPartnerLink" 19             partnerRole="HR" myRole="HRListener"/> 20       </partnerLinks> 21       <variables> 22          <variable name="input" messageType="tns:BenefitsMessage"/> 23          <variable name="hrConfirmation" messageType="tns:BenefitsMessage"/> 24       </variables> 25       <sequence name="main"> 26          <!-- Step 1: the process is started by a client initate --> 27          <receive name="receiveInput" partnerLink="client" portType="tns:MBPension" 28             operation="initiate" variable="input" createInstance="yes"/> 29          <flow name="InclOR"> 30             <switch name="companyContrib"> 31              <!-- Step 2a: if "company" appears in the "msgsubtype" field, execute 32                    the sequence that invokes HR and waits for its confirmation --> 33                <case condition="contains(bpws:getVariableData(&quot;input&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:msgsubtype&quot;), string(&quot;company&quot;))"> 34                   <sequence> 35                      <invoke name="sendHR" partnerLink="hr" operation="notify" 36                         portType="tns:HRService" inputVariable="input"/> 37                      <receive createInstance="no" name="confirm" partnerLink="hr" 38                         portType="tns:HRCallback" operation="confirm" 39                         variable="hrConfirmation"/> 40                   </sequence> 41                </case> 42                <otherwise> 43                   <empty name="nop"/> 44                </otherwise> 45             </switch> 46             <switch name="empContrib"> 47             <!-- Step 2b: if "employee" appears in the "msgsubtype" field, execute 48                      the sequence that invokes pension --> 49                <case condition="contains(bpws:getVariableData(&quot;input&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:msgsubtype&quot;), string(&quot;employee&quot;))"> 50                   <invoke name="sendPayroll" partnerLink="payroll" 51                     portType="tns:PayrollService" operation="pensionUpdate" 52                     inputVariable="input"/> 53                </case> 54                <otherwise> 55                   <empty name="nop"/> 56                </otherwise> 57             </switch> 58          </flow> 59       </sequence> 60    </process>

Stubbed implementations of the Payroll and HR services are shown in the next listings. The Payroll service is exceedingly simple, listening on its pensionUpdate endpoint (defined in lines 12-14 the WSDL in Example 11-8, and implemented as a receive activity in lines 18-20 of the BPEL in Example 11-9), and exiting immediately thereafter.

Example 11-8. PayrollService.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="PayrollService" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/"> 7 8       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 9 10       <!-- Payroll port type supports pensionUpdate operation --> 11       <portType name="PayrollService"> 12          <operation name="pensionUpdate"> 13             <input message="tns:BenefitsMessage"/> 14          </operation> 15       </portType> 16 17       <!-- And here is its partner link type --> 18       <plnk:partnerLinkType name="PayrollService"> 19          <plnk:role name="PayrollService"> 20             <plnk:portType name="tns:PayrollService"/> 21          </plnk:role> 22       </plnk:partnerLinkType> 23    </definitions>

The next code listing is for Example 11-9.

Example 11-9. PayrollService.bpel
 1    <process name="PayrollService" 2       targetNamespace="http://acm.org/samples" 3       suppressJoinFailure="yes" 4       xmlns:tns=http://acm.org/samples 5       xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 6       xmlns:bpelx=http://schemas.oracle.com/bpel/extension 7       xmlns:ora="http://schemas.oracle.com/xpath/extension"> 8       <!-- PayrollService partner link type is the one defined in the WSDL. --> 9       <partnerLinks> 10          <partnerLink name="client" partnerLinkType="tns:PayrollService" 11             myRole="PayrollService"/> 12       </partnerLinks> 13       <variables> 14          <variable name="input" messageType="tns:BenefitsMessage"/> 15       </variables> 16       <sequence name="main"> 17          <!-- A simple process: get the message and then exit --> 18          <receive name="receiveInput" partnerLink="client" 19             portType="tns:PayrollService" variable="input" createInstance="yes" 20             operation="pensionUpdate"/> 21       </sequence> 22    </process>

The HR service is similar, except upon the trigger of its notify service (declared in lines 12-14 of the WSDL in Example 11-10 and implemented in the BPEL in lines 17-19 of Example 11-11), it immediately sends back a confirmation on its callback port type (the invoke activity is shown in lines 21-23 of Example 11-11. The next listing, Example 11-10, is for HRService.wsdl.

Example 11-10. HRService.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="MBPension" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/"> 7 8       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 9 10       <!-- Two port types: the service and its callback --> 11       <portType name="HRService"> 12          <operation name="notify"> 13             <input message="tns:BenefitsMessage"/> 14          </operation> 15       </portType> 16       <portType name="HRCallback"> 17          <operation name="confirm"> 18             <input message="tns:BenefitsMessage"/> 19          </operation> 20       </portType> 21 22       <!-- A partner link type for each port type --> 23       <plnk:partnerLinkType name="HRPartnerLink"> 24          <plnk:role name="HR"> 25             <plnk:portType name="tns:HRService"/> 26          </plnk:role> 27          <plnk:role name="HRListener"> 28             <plnk:portType name="tns:HRCallback"/> 29          </plnk:role> 30       </plnk:partnerLinkType> 31    </definitions>

The next listing, Example 11-11, is for HRService.bpel.

Example 11-11. HRService.bpel
 1    <process name="HRService" 2       targetNamespace="http://acm.org/samples" 3       suppressJoinFailure="yes" 4       xmlns:tns="http://acm.org/samples" 5       xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/" 6       xmlns:bpelx="http://schemas.oracle.com/bpel/extension" 7       xmlns:ora="http://schemas.oracle.com/xpath/extension"> 8       <partnerLinks> 9          <partnerLink name="client" partnerLinkType="tns:HRPartnerLink" 10             partnerRole="HRListener" myRole="HR"/> 11       </partnerLinks> 12       <variables> 13          <variable name="input" messageType="tns:BenefitsMessage"/> 14       </variables> 15       <sequence name="main"> 16          <!-- Step 1: client interface receiveInput is called --> 17          <receive name="receiveInput" partnerLink="client" 18             portType="tns:HRService" variable="input" 19             createInstance="yes" operation="notify"/> 20        <!-- Step 2: immediately invoke callback confirm, passing back same msg --> 21          <invoke name="confirm" partnerLink="client" 22             portType="tns:HRCallback" operation="confirm" 23             inputVariable="input"/> 24       </sequence> 25    </process>

11.2.2.4 The Medical process

As described at the beginning of this chapter, the Medical process is divided into two sections, Main and Helper (discussed in the next two sections), to simplify the implementation.

Main. The Main medical process, when it receives a benefits message, adds to the message a session ID, and sends that message to the Helper process. The WSDL for the main process (Example 11-12) is simple, having but one port type operation, called initiate, declared in line 11.

Example 11-12. MBMedMain.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="MBMedMain" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/"> 7 8       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 9 10       <portType name="MBMedMain"> 11          <operation name="initiate"> 12             <input message="tns:BenefitsMessage"/> 13          </operation> 14       </portType> 15 16       <plnk:partnerLinkType name="MBMedMain"> 17          <plnk:role name="MedMainProvider"> 18             <plnk:portType name="tns:MBMedMain"/> 19          </plnk:role> 20       </plnk:partnerLinkType> 21    </definitions>

In the BPEL implementation (Example 11-13), the receive activity in lines 23-24 is the entry point mapping to the initiate operation. The long assign activity that follows it, spanning lines 25-45, calculates the value of MsgID div 5 (lines 27-31), then sets the SesID field with that value (lines 39-44). It also calculates MsgId mod 5 (lines 33-37), a value representing the remainder when dividing the message ID by 5. This value is zero for the first message in the five-message medical sequence, and nonzero for subsequent messages. The switch statement in lines 46-59 tests this number to determine how to call the helper process; if the value is zero, it calls the Helper's first operation (lines 49-51); otherwise, it calls the Helper's next operation (lines 55-57).

Example 11-13. MBMedMain.bpel
 1    <process name="MBMedMain" 2       targetNamespace="http://acm.org/samples" 3       suppressJoinFailure="yes" 4       xmlns:tns=http://acm.org/samples 5       xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 6       xmlns:bpelx=http://schemas.oracle.com/bpel/extension 7       xmlns:ora=http://schemas.oracle.com/xpath/extension 8       xmlns:bpws=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 9       xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 10       <partnerLinks> 11          <partnerLink name="client" partnerLinkType="tns:MBMedMain" 12             myRole="MedMainProvider"/> 13          <partnerLink name="helper" partnerLinkType="tns:MBMedHelper" 14             partnerRole="MedHelperProvider"/> 15       </partnerLinks> 16       <variables> 17          <variable name="input" messageType="tns:BenefitsMessage"/> 18          <variable name="msgDiv" type="xsd:int"/> 19          <variable name="msgMod" type="xsd:int"/> 20       </variables> 21       <sequence name="main"> 22          <!-- Step 1: get the message from the HR portal --> 23          <receive name="receiveInput" partnerLink="client" portType="tns:MBMedMain" 24             operation="initiate" variable="input" createInstance="yes"/> 25          <assign name="assignVars"> 26             <!-- Step 2a: set variable msgDiv to MsgId div 5 --> 27             <copy> 28                <from expression="floor(bpws:getVariableData(&quot;input&quot;,&quot;payload&quot;,&quot;/tns:CanonicalBenefits/tns:msgid&quot;) div 5)"> 29                </from> 30                <to variable="msgDiv"/> 31             </copy> 32             <!-- Step 2b: set variable msgMod to MsgId mod 5 --> 33             <copy> 34                <from expression="bpws:getVariableData(&quot;input&quot;,&quot;payload&quot;,&quot;/tns:CanonicalBenefits/tns:msgid&quot;) mod 5"> 35                </from> 36                <to variable="msgMod"/> 37             </copy> 38             <!-- Step 2c: populate SesId field with msgDiv --> 39             <copy> 40                <from expression="bpws:getVariableData(&quot;msgDiv&quot;)"> 41                </from> 42                <to variable="input" part="payload" 43                   query="/tns:CanonicalBenefits/tns:sesid"/> 44             </copy> 45          </assign> 46          <switch name="switch-1"> 47             <!-- If MsgMod = 0, call helper's "first" operation --> 48             <case condition="bpws:getVariableData(&quot;msgMod&quot;)='0'"> 49                <invoke name="invoke-1" partnerLink="helper" 50                   portType="tns:MBMedHelper" operation="first" 51                   inputVariable="input"/> 52             </case> 53             <!-- If MsgMod != 0, call helper's "next" operation --> 54             <otherwise> 55                <invoke name="invoke-1" partnerLink="helper" 56                   portType="tns:MBMedHelper" operation="next" 57                   inputVariable="input"/> 58             </otherwise> 59          </switch> 60       </sequence> 61    </process>

Helper. The Helper's first and next operations are declared in lines 11 and 14, respectively, of its WSDL in Example 11-14.

Example 11-14. MBMedHelper.wsdl
 1    <?xml version="1.0"?> 2    <definitions name="MBMedHelper" 3       targetNamespace="http://acm.org/samples" 4       xmlns:tns="http://acm.org/samples" 5       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 6       xmlns="http://schemas.xmlsoap.org/wsdl/"> 7 8       <import namespace="http://acm.org/samples" location="canon.wsdl"/> 9 10       <portType name="MBMedHelper"> 11          <operation name="first"> 12             <input message="tns:BenefitsMessage"/> 13          </operation> 14          <operation name="next"> 15             <input message="tns:BenefitsMessage"/> 16          </operation> 17       </portType> 18 19       <plnk:partnerLinkType name="MBMedHelper"> 20          <plnk:role name="MedHelperProvider"> 21             <plnk:portType name="tns:MBMedHelper"/> 22          </plnk:role> 23       </plnk:partnerLinkType> 24    </definitions>

Example 11-15, is initiated in the receive activity in lines 30-36; the receive is mapped to the first operation and initializes a correlation set on the session ID field. The flow activity in lines 39-68 has four receive operations, running in parallel, each mapped to the next operation and correlating on session ID. The flow activity waits for each receive to complete, whereupon the process has gathered all five of the original messages, stored in process variables msg1, msg2, msg3, msg4, and msg5. The assign activity in lines 71-101 combines them into a single message, stored in the variable combinedMsg; it first copies msg1 to combinedMsg (lines 73-76), then appends the element called data of each other message to the data element of combinedMsg. In lines 103-104, combinedMsg is sent to the notify operation of the HR Service.

Example 11-15. MBMedHelper.bpel
 1    <process name="MBMedHelper" 2       targetNamespace="http://acm.org/samples" 3       suppressJoinFailure="yes" 4       xmlns:tns=http://acm.org/samples 5       xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 6       xmlns:bpelx=http://schemas.oracle.com/bpel/extension 7       xmlns:ora=http://schemas.oracle.com/xpath/extension 8       xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"> 9 10       <partnerLinks> 11          <partnerLink name="client" partnerLinkType="tns:MBMedHelper" 12             myRole="MedHelperProvider"/> 13          <partnerLink name="hr" partnerLinkType="tns:HRPartnerLink" partnerRole="HR"/> 14       </partnerLinks> 15       <variables> 16          <variable name="msg1" messageType="tns:BenefitsMessage"/> 17          <variable name="msg2" messageType="tns:BenefitsMessage"/> 18          <variable name="msg3" messageType="tns:BenefitsMessage"/> 19          <variable name="msg4" messageType="tns:BenefitsMessage"/> 20          <variable name="msg5" messageType="tns:BenefitsMessage"/> 21          <variable name="combinedMsg" messageType="tns:BenefitsMessage"/> 22       </variables> 23       <correlationSets> 24          <correlationSet name="ses" properties="tns:sesid"/> 25       </correlationSets> 26       <sequence> 27          <sequence name="main"> 28             <!-- Step 1: the "first" operation called.  Store the message in "msg1". 29                   Correlate on SesId --> 30             <receive name="receiveInput" partnerLink="client" 31                portType="tns:MBMedHelper" variable="msg1" createInstance="yes" 32                operation="first"> 33                <correlations> 34                   <correlation set="ses" initiate="yes"/> 35                </correlations> 36             </receive> 37             <!-- Step 2: wait for 4 calls of next, where each correlates on sesId. 38                   Store results in msg2, msg3, msg4, msg5 --> 39             <flow> 40                <receive name="receiveInput" partnerLink="client" 41                   portType="tns:MBMedHelper" operation="next" variable="msg2" 42                   createInstance="no"> 43                   <correlations> 44                      <correlation set="ses" initiate="no"/> 45                   </correlations> 46                </receive> 47                <receive name="receiveInput" partnerLink="client" 48                   portType="tns:MBMedHelper" operation="next" variable="msg3" 49                   createInstance="no"> 50                   <correlations> 51                      <correlation set="ses" initiate="no"/> 52                   </correlations> 53                </receive> 54                <receive name="receiveInput" partnerLink="client" 55                   portType="tns:MBMedHelper" operation="next" variable="msg4" 56                   createInstance="no"> 57                   <correlations> 58                      <correlation set="ses" initiate="no"/> 59                   </correlations> 60                </receive> 61                <receive name="receiveInput" partnerLink="client" 62                   portType="tns:MBMedHelper" operation="next" variable="msg5" 63                   createInstance="no"> 64                   <correlations> 65                      <correlation set="ses" initiate="no"/> 66                   </correlations> 67                </receive> 68             </flow> 69          </sequence> 70          <!-- Step 3: Build "combinedMsg" out of msg1 . . msg 5 --> 71          <assign xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/" 72             name="buildMsg"> 73             <copy> 74                <from variable="msg1"></from> 75                <to variable="combinedMsg"/> 76             </copy> 77             <copy> 78                <from expression="concat(bpws:getVariableData(&quot; combinedMsg&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns: data&quot;), bpws:getVariableData(&quot;msg2&quot;, &quot;payload& quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;))"> 79                </from> 80                <to variable="combinedMsg" part="payload" 81                   query="/tns:CanonicalBenefits/tns:data"/> 82             </copy> 83             <copy> 84                <from expression="concat(bpws:getVariableData(&quot;combinedMsg&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;), bpws:getVariableData(&quot;msg3&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;))"> 85                </from> 86                <to variable="combinedMsg" part="payload" 87                   query="/tns:CanonicalBenefits/tns:data"/> 88             </copy> 89             <copy> 90                <from expression="concat(bpws:getVariableData(&quot;combinedMsg&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;), bpws:getVariableData(&quot;msg4&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;))"> 91                </from> 92                <to variable="combinedMsg" part="payload" 93                   query="/tns:CanonicalBenefits/tns:data"/> 94             </copy> 95             <copy> 96                <from expression="concat(bpws:getVariableData(&quot;combinedMsg&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;), bpws:getVariableData(&quot;msg5&quot;, &quot;payload&quot;, &quot;/tns:CanonicalBenefits/tns:data&quot;))"> 97                </from> 98                <to variable="combinedMsg" part="payload" 99                   query="/tns:CanonicalBenefits/tns:data"/> 100             </copy> 101          </assign> 102          <!-- Step 4: call HR service, passing "combinedMsg" --> 103          <invoke name="sendHR" partnerLink="hr" portType="tns:HRService" 104             operation="notify" inputVariable="combinedMsg"/> 105       </sequence> 106    </process>

11.2.2.5 Testing the Broker

The Initiate Process page in the Oracle BPEL administrative console can be the source of events driving broker interactions to simulate the HR Portal. Figure 11-8 shows the page to test the Life Events process. The text edit fields (msgid, sesid) are the elements of the canonical XML structure, the message type used by all broker processes. To trigger Life Events, enter data in some or all of the fields, and click Post XML Message. The process does not validate the data, so any input will suffice.

If successful, the Life Events process will start the processes Life Insurance Company and Medical Insurance Company. To confirm this, navigate to the Dashboard tab and check for these processes under Recently Completed BPEL Process Instances. In Figure 11-9, Life Event (instance 703) is immediately followed by Medical Insurance Company (704) and Life Insurance Company (705), implying that Life Event functioned properly.

The procedure to test the Pension process is similar. Pension checks the value of the field msgsubtype. If the field contains the text "company," Pension starts the HR Service process; if it contains "employee," Pension triggers Payroll Service; if it contains both (e.g., "company and employee"), Pension launches both. As with Life Events, the Dashboard is

Figure 11-8. Oracle BPEL Console test utility


Figure 11-9. Dashboard confirmation of Life Event process


the quickest indicator of success: check for target processes immediately following the initiation of Pension.

To exercise Medical, run five initiations of Medical Main using values of msgid that follow the rules described in the earlier section "BPMN Process Models"; the values should follow an ascending sequence at a multiple of five (e.g., 30, 31, 32, 33, 34). Check the Dashboard for five instances of Medical Main, one Medical Helper, and one HR Service, as in instances 801 to 807 in Figure 11-10.



    Essential Business Process Modeling
    Essential Business Process Modeling
    ISBN: 0596008430
    EAN: 2147483647
    Year: 2003
    Pages: 122
    Authors: Michael Havey

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net