Section 10.3. Developing the Example


10.3. Developing the Example

Because the insurance process is not trivial and uses new and possibly unfamiliar tools, its implementation (the topic of this section) is divided into several iterations. The discussion covers not only the proper BPEL implementation of the insurance process but also how to use Process Manager to build it. At a high level, the steps are:

  1. Create the project and define its WSDL.

  2. Create the variables, partner links, correlation, and receive node.

  3. Add flow and a manual task.

  4. Complete the additional coding.

These steps all assume the default configuration for all required software.

10.3.1. Create the Project and Define its WSDL

The first step is to create a new project in BPEL designer and to establish its WSDL interface. The steps in this process are:

  1. Start the BPEL server and the BPEL designer; click on the links Start BPEL PM Server and BPEL PM Designer in the folder Oracle BPEL Process Manager in the Windows Start Menu. (Note: the latter link starts Eclipse, for which Designer is a plug-in.)

  2. Create a new BPEL application in Designer by choosing File New Project. In the dialog box, select Oracle BPEL Project and click Next. On the next page, in the Name edit field, enter InsuranceClaim and click the Finish button.

  3. Other, and in the dialog box, select File, under Simple. Name the file Example 10-1. messages.wsdl

     1    <?xml version="1.0"?> 2    <definitions name="IMSG" 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             <!-- Our XML message type, InsuranceClaimMsg consists of 16                  an id and a data 17               --> 18             <element name="InsuranceClaimMsg"> 19                <complexType> 20                   <sequence> 21                      <element name="id" type="string" /> 22                      <element name="data" type="string" /> 23                   </sequence> 24                </complexType> 25             </element> 26          </schema> 27       </types> 28 29       <!-- The WSDL message is just the InsuranceClaimMsg described earlier --> 30       <message name="InsuranceClaimMsg"> 31          <part name="payload" element="tns:InsuranceClaimMsg"/> 32       </message> 33 34       <!-- Define  a BPEL property alias for the ID field --> 35       <bpws:property name="claimID" type="xsd:string"/> 36       <bpws:propertyAlias propertyName="tns:claimID" 37          messageType="tns:InsuranceClaimMsg" part="payload" 38          query="/tns:InsuranceClaimMsg/tns:id"/> 39    </definitions>

  4. Edit the file InsuranceClaim.wsdl. Double-click on that file, found in the Navigator Menu under Insurance Claim. Replace its current contents with the code in Example 10-2.

Example 10-2. InsuranceClaim.wsdl
 1    <?xml version="1.0"?> 2 3    <definitions name="InsuranceClaim" 4       targetNamespace="http://acm.org/samples" 5       xmlns:tns="http://acm.org/samples" 6       xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" 7       xmlns="http://schemas.xmlsoap.org/wsdl/" 8       xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/" 9       xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 10 11       <!-- Import messages.wsdl for access to InsuranceClaimMsg type --> 12       <import namespace="http://acm.org/samples" location="messages.wsdl"/> 13 14       <!-- port type, InsuranceClaim, has operations initiate and kill --> 15       <portType name="InsuranceClaim"> 16          <operation name="initiate"> 17             <input message="tns:InsuranceClaimMsg"/> 18          </operation> 19          <operation name="kill"> 20             <input message="tns:InsuranceClaimMsg"/> 21          </operation> 22       </portType> 23 24       <!-- Define a partner link type with role "InsuranceClaimProvider". 25            This role implements the InsuranceClaim port type. 26       --> 27       <plnk:partnerLinkType name="InsuranceClaim"> 28          <plnk:role name="InsuranceClaimProvider"> 29             <plnk:portType name="tns:InsuranceClaim"/> 30          </plnk:role> 31       </plnk:partnerLinkType> 32    </definitions>

The file InsuranceClaim.wsdl in Example 10-2 defines the service interface for client applications of the InsuranceClaim process. This interface has one port type, called InsuranceClaim, with two operations, initiate and kill (lines 15-22). A partner link type is defined in lines 27-31 that maps the port type to a role called InsuranceClaimProvider. As will be seen later, the process adopts this role; it acts as InsuranceClaimProvider to clients. The message type passed into the operations is called InsuranceClaimMsg, which is defined in messages.wsdl; the InsuranceClaim.wsdl file uses the import statement in line 12 to reference it.

The WSDL message type InsuranceClaimMsg is defined in lines 30-32 of messages.wsdl (Example 10-1), and has only one message part, payload, of a type whose schema is listed in lines 18-25. The type consists of two fields: id and data. A BPEL property and alias for the id field, required for message correlation, as we will discover later, is stipulated in lines 35-38.

Oracle BPEL PM sometimes gets confused when the WSDL interface of a process that has already been deployed is changed in Designer. If the change makes the new version incompatible with the old, Designer generates errors during the process build. To work around this, try the following:

  1. Delete the temporary directory that holds the version of the process used by the runtime engine. The directory is of the form <BPEL_DIR>\domains\default\tmp\.bpel_<PROCESSNAME>_1.0.jar, where <BPEL_DIR> is the directory in which you installed PM, and <PROCESSNAME> matches the name of the Designer project. For example: C:\orabpel211\domains\default\tmp\.bpel_InsuranceClaim_1.0.jar.

  2. If the problem remains, open the administrative console and undeploy the process by selecting the Processes tab process name Undeploy button.

    1. Double click on InsuranceClaim.bpel (created in the previous section) in the Navigator panel. Your screen should resemble Figure 10-5.

      Figure 10-5. Initial process screen


    2. Click on the client in the leftmost box and fill in the edits on the dialog box with the values shown in Figure 10-6. Click Done.

      Figure 10-6. Client configuration


    3. Click Add Partner Link and fill in the dialog box with the data in Figure 10-7, using the name evalWorklist. Repeat twice more with exactly the same data, except the names are anaWorklist and esWorklist.

      Figure 10-7. Task Manager partnerLink configuration


    4. Open bpel.xml by right-clicking on it from the Navigator and selecting Open With Text Editor from the context menu. Add to it the italicized pieces shown in Example 10-3 to enable correlation in the process.

      Example 10-3. bpel.xml
       1    <?xml version="1.0"?> 2    <BPELSuitcase> 3       <BPELProcess  src="/books/1/165/1/html/2/InsuranceClaim.bpel" useCorrelationSet="yes"> 4          <partnerLinkBindings> 5             <partnerLinkBinding name="client"> 6                <property name="correlation">correlationSet</property> 7                <property name="wsdlLocation">InsuranceClaim.wsdl</property> 8             </partnerLinkBinding> 9             <partnerLinkBinding name="evalWorklist"> 10                <property name="wsdlLocation"> 11    http://localhost:9700/orabpel/default/TaskManager/TaskManager?wsdl</property> 12             </partnerLinkBinding> 13             <partnerLinkBinding name="anaWorklist"> 14                <property name="wsdlLocation"> 15    http://localhost:9700/orabpel/default/TaskManager/TaskManager?wsdl</property> 16             </partnerLinkBinding> 17             <partnerLinkBinding name="esWorklist"> 18                <property name="wsdlLocation"> 19    http://localhost:9700/orabpel/default/TaskManager/TaskManager?wsdl</property> 20             </partnerLinkBinding> 21          </partnerLinkBindings> 22       </BPELProcess> 23    </BPELSuitcase>

    5. Back in InsuranceClaim.bpel, right-click on the global variable output and select Delete Element from the context menu. Next, right click on the variable input and select Edit XML Variable from the context menu. In the dialog box, change the name to initiateMsg and the message type to tns:InsuranceClaimMsg. Click Done to commit. Create two additional variables, in each case by clicking Add XML Variable. Name the first variable status and set its Simple XML Type to xsd:string. Name the second variable killEv, and set its Message Type to tns:InsuranceClaimMsg.

    6. Click Edit Process Map, which opens the screen shown in Figure 10-8. Right-click on the invoke activity, and select Delete Element from the context menu.

      Figure 10-8. Initial process map


    7. Click on the BPEL Source tab to switch to the source code view of the process. To the existing code, add the following definition of a correlation set between the variables section and the sequence section:

              <correlationSets>           <correlationSet name="claim" properties="tns:claimID"/>        </correlationSets>

    8. Add correlation to the current receive activity; replace the current receive element with the following code:

           <receive xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/        partnerLink="client" portType="tns:InsuranceClaim"  operation="initiate"        variable="initiateMsg" createInstance="yes" name="initiateEvent">        <correlations>           <correlation set="claim" initiate="yes"/>        </correlations>     </receive>

    9. Build the process by selecting the menu item BPEL Build and Deploy BPEL Project. Track the build output in the Console tab at the bottom of the screen; look for the text "BUILD SUCCESSFUL."

    10.3.3. Add Flow and a Manual Task

    Although the basic elements are now defined, the process currently does very little. It is started with the receive activity that maps to the WSDL operation initiate and then immediately finishes. Expanding the process involves dragging shapes from the BPEL Palette into the Process Map or by editing the code directly. We will use a combination of these approaches to complete the coding effort. In this section, we will use drag and drop to create the flow activity and one of its manual tasks .

    1. Drag a flow activity from the Core tab of BPEL Palette to the Process Map just below the receive activity. In the property editor (BPEL Inspector) on the right side, set the name of the flow to MainFlow, and add three branches using the menu item Add Branch, accessible when clicking on the down arrow next to <flow>. We now have a skeletal flow containing five parallel activities; a portion of this element is shown in Figure 10-9.

    2. Change the names of the five sequences to EvalSeq, AnalyzeSeq, EscalateSeq, RejectSeq, and ActivateSeq. To do this, click on each sequence and edit the Name field in the property editor.

    3. Drag a User Task Macro from the Macros tab of BPEL Palette into the EvalSeq sequence. In the dialog box entitled User Task, enter the name EvaluateClaim, and click Done. Notice that the activity created is a scope activity. Click on it and in the property editor, change the name of the scope to EvaluateClaim.

    4. Expand the scope activity and select the assign activity configureTask. Edit the copy rule for assignee; in the Expression edit, replace assignee@acm.org with agent and click Done. Next, edit the copy rule for attachment-type bpws:getVariableData("initiateMsg","payload","/tns:InsuranceClaimMsg") in the Expression edit, and click Done. Delete the copy rule for duration.

    5. The scope EvaluateClaim has an inner scope named EvaluateClaimUserInteraction. Expand it and select the activity initiateTask; in the property editor change the partner link to evalWorklist. Do the same thing with the activity onTaskResult. Finally, select the activity readPayload, change its name to setStatus, and edit its copy rule; enter $taskResponse/payload/task:task/task:conclusion for the "From Variable, Part and Query" and $status for the" To Variable, Part and Query." Click done. Figure 10-10 shows a fully expanded view of the task.

    Figure 10-9. Main flow in BPEL Designer


    The complex logic for a manual task created by the macro from the palette works as follows:

    • The configurationTask assign activity sets the input value, a complex datatype that includes name, assignee, priority, and an arbitrary attachment. The person who works the task uses this data to determine the nature of the work required.

    • The inner scope's job is to initiate the task by invoking the Task Manager service (with an invoke activity), and then to wait for its completion (with a receive). Behind the scenes, the invoke causes the task to be published to a task list, accessible to the assignee through a custom user interface. In that interface, the assignee completes the task, passing back relevant data; the Task Manager, in turn, invokes the callback that triggers the receive, passing the response data from the assignee.

    Figure 10-10. EvaluateClaim task in BPEL Designer


    The setStatus assign activity is not part of the macro but a custom step in our implementation. It extracts the Conclusion field from the response data and sets it as the value of the global variable status. As will be seen later, the value of that variable determines the conditional linking of the flow.

    The section "Testing the Example" later in this chapter describes how to view and complete tasks in the BPEL administrative console.

    10.3.4. Complete the Coding

    Many additional drags and drops are still required, but for brevity, we will complete the coding by editing the source view directly, replacing the current contents with the listing in Example 10-4. The highlights of the codeignoring, for the time being, the italicized linesare the following:

    • Lines 79-85 show the receive activity designed previously. The receive responds to the initiate operation and creates the correlation set claim.

    • Lines 87-93: The assign activity sets the global variable status to indicate that the process has initiated.

    • The flow links, representing the transitions within the flow activity, are declared in lines 97-106. This section must be coded by hand; BPEL Designer does not support the graphical manipulation of flow links.

    • EvalSeq, from lines 109-196, which we composed graphically in the previous section, are expanded here with the introduction of source flow links in lines 114-119. Notice that the links are conditional, guarded by a check on the value of the variable status. The link evalAnalysis, for example, is followed only if status is set to requiresAnalysis.

    • AnalyzeSeq, in lines 197-292, is similar to EvalSeq, except in addition to being the source of links, it is also a target (line 198). Next, after invoking the Task Manager, rather than waiting merely for task completion, AnalyzeSeq uses a pick activity (lines 256-287) to wait either for completion or for a timeout, and sets the status variable to different values depending on the outcome.

    • EscalateSeq, in lines 293-365 is very similar to EvalSeq.

    • Lines 366-384: RejectSeq is the target of any link that evaluates a status of rejected. Notice the use of the proprietary Java extension bpelx:exec in lines 378-382 to print the message CLAIM REJECTED to the standard output of the BPEL server.

      NOTE

      The Oracle Java extension does not follow the BPELJ recommendation, and hence cannot be ported to other Java-enabled BPEL containers. (The Oracle exec tag appears to roughly match the BPELJ snippet.)

    • Lines 385-403: ActivateSeq is similar to RejectSeq, except that it is the target of accepted links

    Example 10-4. Final BPEL code
     1    <process name="InsuranceClaim" 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:xsd=http://www.w3.org/2001/XMLSchema 9       xmlns:services=http://services.otn.com 10       xmlns:task=http://services.oracle.com/bpel/task 11       xmlns:addressing=http://schemas.xmlsoap.org/ws/2003/03/addressing 12       xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"> 13 14       <!-- 15          Partners in the process: 16            client       - app that can initiate and kill 17            evalWorklist - service that this process calls to initiate 18                           a human workflow task to evaluate a claim 19            anaWorklist  - similar to evalWorklist, but for analysis of a claim 20            esWorklist   - similar, but for escalation of a claim 21       --> 22       <partnerLinks> 23          <!-- 24          <partnerLink name="client" partnerLinkType="tns:InsuranceClaim" 25             myRole="InsuranceClaimProvider"/> 26          <partnerLink name="evalWorklist" partnerLinkType="task:TaskManager" 27             partnerRole="TaskManager" myRole="TaskManagerRequester"/> 28          <partnerLink name="anaWorklist" partnerLinkType="task:TaskManager" 29             partnerRole="TaskManager" myRole="TaskManagerRequester"/> 30          <partnerLink name="esWorklist" partnerLinkType="task:TaskManager" 31             partnerRole="TaskManager" myRole="TaskManagerRequester"/> 32       </partnerLinks> 33       <variables> 34          <variable name="status" type="xsd:string"/> 35          <variable messageType="tns:InsuranceClaimMsg" name="initiateMsg"/> 36          <variable messageType="tns:InsuranceClaimMsg" name="killEv"/> 37       </variables> 38 39       <!-- Message correlation to be performed on the ClaimID field --> 40       <correlationSets> 41          <correlationSet name="claim" properties="tns:claimID"/> 42       </correlationSets> 43 44      <!--This code is commented out because it does not work.  See note below. 45          Its purpose is to globally receive a kill event (correlated with the claim ID from the 46           original initate) and terminate the process. 47       <eventHandlers> 48          <onMessage xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 49             partnerLink="client" portType="tns:InsuranceClaim" operation="kill" 50             variable="killEv"> 51             <correlations> 52                <correlation set="claim" initiate="no"/> 53             </correlations> 54             <sequence> 55                <assign name="setStatusKilled"> 56                   <copy> 57                      <from expression="string('killed')"> 58                      </from> 59                      <to variable="status"/> 60                   </copy> 61                </assign> 62                <bpelx:exec xmlns:bpelx=http://schemas.oracle.com/bpel/extension 63                   language="java" version="1.4" name="jkill"> 64                   <![CDATA[ 65               System.out.println("**** CLAIM KILLED ****"); 66            ]]> 67                </bpelx:exec> 68                <terminate name="killClaim"/> 69             </sequence> 70          </onMessage> 71       </eventHandlers> 72       --> 73 74       <sequence> 75 76          <!-- We start with a receive activity: get the initiate message.  Will 77             correlate on claim set defined earlier 78          --> 79          <receive xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 80             partnerLink="client" portType="tns:InsuranceClaim" operation="initiate" 81             variable="initiateMsg" createInstance="yes" name="initiateEvent"> 82             <correlations> 83                <correlation set="claim" initiate="yes"/> 84             </correlations> 85          </receive> 86          <!-- keep track of where we are: set variable 'status' to 'initiated' --> 87          <assign name="setStatus"> 88             <copy> 89                <from expression="string('initiated')"> 90                </from> 91                <to variable="status"/> 92             </copy> 93          </assign> 94 95          <!-- The flow, described in detail earlier in this chapter --> 96          <flow name="MainFlow"> 97             <links> 98                <link name="evalReject"/> 99                <link name="evalAccept"/> 100                <link name="evalAnalysis"/> 101                <link name="anaReject"/> 102                <link name="anaAccept"/> 103                <link name="anaTO"/> 104                <link name="esReject"/> 105                <link name="esAccept"/> 106             </links> 107 108             <!-- This sequence has the logic for evaluation of a claim. --> 109             <sequence name="EvalSeq"> 110                <!-- 111                   The three outcomes, based on the value of the variable 'status'. 112                   Each link is a "target" in a sequence later. 113                --> 114                <source linkName="evalReject" 115                  transitionCondition="bpws:getVariableData('status')='rejected'"/> 116                <source linkName="evalAccept" 117                  transitionCondition="bpws:getVariableData('status')='accepted'"/> 118                <source linkName="evalAnalysis" 119              transitionCondition="bpws:getVariableData('status')='requiresAnalysis'"/> 120                <scope name="EvaluateClaim" variableAccessSerializable="no"> 121                   <variables> 122                      <variable name="EvaluateClaimTask" element="task:task"/> 123                   </variables> 124                   <sequence> 125                  <!-- Set the variable EvaluateClaimTask with data specific to the 126                         analysis task: e.g., title, assignee, priority, attachment 127                   --> 128                      <assign name="configureTask"> 129                         <copy> 130                            <from expression="string( 'EvaluateClaim' )"/> 131                            <to variable="EvaluateClaimTask" 132                               query="/task:task/task:title"/> 133                         </copy> 134                         <copy> 135                            <from expression="string( 'InsuranceClaim' )"/> 136                            <to variable="EvaluateClaimTask" 137                               query="/task:task/task:creator"/> 138                         </copy> 139                         <copy> 140                            <from expression="string( 'agent' )"/> 141                            <to variable="EvaluateClaimTask" 142                               query="/task:task/task:assignee"/> 143                         </copy> 144                         <copy> 145                            <from expression="3"/> 146                            <to variable="EvaluateClaimTask" 147                               query="/task:task/task:priority"/> 148                         </copy> 149                         <copy> 150                            <from variable="initiateMsg" part="payload" 151                               query="/tns:InsuranceClaimMsg/tns:data"/> 152                            <to variable="EvaluateClaimTask" 153                               query="/task:task/task:attachment"/> 154                         </copy> 155                      </assign> 156                      <scope name="EvaluateClaimUserInteraction" 157                         variableAccessSerializable="no"> 158                         <variables> 159                            <variable name="taskRequest" 160                               messageType="task:taskMessage"/> 161                            <variable name="taskResponse" 162                               messageType="task:taskMessage"/> 163                         </variables> 164                         <sequence> 165                            <assign name="setPayload"> 166                               <copy> 167                                  <from variable="EvaluateClaimTask"/> 168                                  <to variable="taskRequest" part="payload"/> 169                               </copy> 170                            </assign> 171 172                       <!--call evalWorklist partner to initiate the task, passing 173                               the data defined above. 174                       --> 175                            <invoke name="initiateTask" partnerLink="evalWorklist" 176                               portType="task:TaskManager" operation="initiateTask" 177                               inputVariable="taskRequest"/> 178                        <!-- get back the result, possibly a long time later --> 179                            <receive name="receiveTaskResult" 180                               partnerLink="evalWorklist" 181                               portType="task:TaskManagerCallback" 182                               operation="onTaskResult" variable="taskResponse"/> 183                        <!-- set variable 'status' with result.Use for routing --> 184                            <assign name="setStatus"> 185                               <copy> 186                                  <from variable="taskResponse" part="payload" 187                                     query="/task:task/task:conclusion"> 188                                  </from> 189                                  <to variable="status"/> 190                               </copy> 191                            </assign> 192                         </sequence> 193                      </scope> 194                   </sequence> 195                </scope> 196             </sequence> 197             <sequence name="AnalyzeSeq"> 198                <target linkName="evalAnalysis"/> 199                <source linkName="anaReject" 200                  transitionCondition="bpws:getVariableData('status')='rejected'"/> 201                <source linkName="anaAccept" 202                  transitionCondition="bpws:getVariableData('status')='accepted'"/> 203                <source linkName="anaTO" 204                   transitionCondition="bpws:getVariableData('status')='timeout'"/> 205                <scope name="AnalyzeClaim" variableAccessSerializable="no"> 206                   <variables> 207                      <variable name="AnalyzeClaimTask" element="task:task"/> 208                   </variables> 209                   <sequence> 210                      <assign name="configureTask"> 211                         <copy> 212                            <from expression="string( 'AnalyzeClaim' )"/> 213                            <to variable="AnalyzeClaimTask" 214                               query="/task:task/task:title"/> 215                         </copy> 216                         <copy> 217                            <from expression="string( 'InsuranceClaim' )"/> 218                            <to variable="AnalyzeClaimTask" 219                               query="/task:task/task:creator"/> 220                         </copy> 221                         <copy> 222                            <from expression="string( 'adjuster' )"/> 223                            <to variable="AnalyzeClaimTask" 224                               query="/task:task/task:assignee"/> 225                         </copy> 226                         <copy> 227                            <from expression="3"/> 228                            <to variable="AnalyzeClaimTask" 229                               query="/task:task/task:priority"/> 230                         </copy> 231                         <copy> 232                            <from variable="initiateMsg" part="payload" 233                               query="/tns:InsuranceClaimMsg/tns:data"/> 234                            <to variable="AnalyzeClaimTask" 235                               query="/task:task/task:attachment"/> 236                         </copy> 237                      </assign> 238                      <scope name="AnalyzeClaimUserInteraction" 239                         variableAccessSerializable="no"> 240                         <variables> 241                            <variable name="taskRequest" 242                               messageType="task:taskMessage"/> 243                            <variable name="taskResponse" 244                               messageType="task:taskMessage"/> 245                         </variables> 246                         <sequence> 247                            <assign name="setPayload"> 248                               <copy> 249                                  <from variable="AnalyzeClaimTask"/> 250                                  <to variable="taskRequest" part="payload"/> 251                               </copy> 252                            </assign> 253                            <invoke name="initiateTask" partnerLink="anaWorklist" 254                               portType="task:TaskManager" operation="initiateTask" 255                               inputVariable="taskRequest"/> 256                            <pick name="analyzePick"> 257                               <onMessage partnerLink="anaWorklist" 258                                  portType="task:TaskManagerCallback" 259                                  operation="onTaskResult" variable="taskResponse"> 260                                  <sequence> 261                                     <assign name="setStatusEvaluated"> 262                                        <copy> 263                                           <from variable="taskResponse" part="payload" 264                                               query="/task:task/task:conclusion"> 265                                           </from> 266                                           <to variable="status"/> 267                                        </copy> 268                                     </assign> 269                                  </sequence> 270                               </onMessage> 271                               <onAlarm for="PT1M"> 272                                  <sequence> 273                                     <invoke name="stopEvalTask" 274                                        partnerLink="anaWorklist" 275                                        portType="task:TaskManager" 276                                        operation="completeTask" 277                                        inputVariable="taskRequest"/> 278                                     <assign name="setStatusAnalyzeTimeout"> 279                                        <copy> 280                                           <from expression="string('timeout')"> 281                                           </from> 282                                           <to variable="status"/> 283                                        </copy> 284                                     </assign> 285                                  </sequence> 286                               </onAlarm> 287                            </pick> 288                         </sequence> 289                      </scope> 290                   </sequence> 291                </scope> 292             </sequence> 293             <sequence name="EscalateSeq"> 294                <target linkName="anaTO"/> 295                <source linkName="esReject" 296                  transitionCondition="bpws:getVariableData('status')='rejected'"/> 297                <source linkName="esAccept" 298                  transitionCondition="bpws:getVariableData('status')='accepted'"/> 299                <scope name="EscalateClaim" variableAccessSerializable="no"> 300                   <variables> 301                      <variable name="EscalateClaimTask" element="task:task"/> 302                   </variables> 303                   <sequence> 304                      <assign name="configureTask"> 305                         <copy> 306                            <from expression="string( 'EvaluateClaim' )"/> 307                            <to variable="EscalateClaimTask" 308                               query="/task:task/task:title"/> 309                         </copy> 310                         <copy> 311                            <from expression="string( 'InsuranceClaim' )"/> 312                            <to variable="EscalateClaimTask" 313                               query="/task:task/task:creator"/> 314                         </copy> 315                         <copy> 316                            <from expression="string( 'manager' )"/> 317                            <to variable="EscalateClaimTask" 318                               query="/task:task/task:assignee"/> 319                         </copy> 320                         <copy> 321                            <from expression="1"/> 322                            <to variable="EscalateClaimTask" 323                               query="/task:task/task:priority"/> 324                         </copy> 325                         <copy> 326                            <from variable="initiateMsg" part="payload" 327                               query="/tns:InsuranceClaimMsg/tns:data"/> 328                            <to variable="EscalateClaimTask" 329                               query="/task:task/task:attachment"/> 330                         </copy> 331                      </assign> 332                      <scope name="EscalateClaimUserInteraction" 333                         variableAccessSerializable="no"> 334                         <variables> 335                            <variable name="taskRequest" 336                               messageType="task:taskMessage"/> 337                            <variable name="taskResponse" 338                               messageType="task:taskMessage"/> 339                         </variables> 340                         <sequence> 341                            <assign name="setPayload"> 342                               <copy> 343                                  <from variable="EscalateClaimTask"/> 344                                  <to variable="taskRequest" part="payload"/> 345                               </copy> 346                            </assign> 347                            <invoke name="initiateTask" partnerLink="esWorklist" 348                               portType="task:TaskManager" operation="initiateTask" 349                               inputVariable="taskRequest"/> 350                            <receive name="receiveTaskResult" partnerLink="esWorklist" 351                               portType="task:TaskManagerCallback" 352                               operation="onTaskResult" variable="taskResponse"/> 353                            <assign name="setStatus"> 354                               <copy> 355                                  <from variable="taskResponse" part="payload" 356                                     query="/task:task/task:conclusion"> 357                                  </from> 358                                  <to variable="status"/> 359                               </copy> 360                            </assign> 361                         </sequence> 362                      </scope> 363                   </sequence> 364                </scope> 365             </sequence> 366             <sequence name="RejectSeq"> 367                <target linkName="evalReject"/> 368                <target linkName="anaReject"/> 369                <target linkName="esReject"/> 370                <assign xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 371                   name="setStatusRejectComplete"> 372                   <copy> 373                      <from expression="string('Reject Letter Sent')"> 374                      </from> 375                      <to variable="status"/> 376                   </copy> 377                </assign> 378                <bpelx:exec xmlns:bpelx=http://schemas.oracle.com/bpel/extension 379                   language="java" version="1.4" name="jreject"> 380                   <![CDATA[ 381               System.out.println("**** CLAIM REJECTED ****");        ]]> 382                </bpelx:exec> 383                <!-- terminate the process, see following note -->   <terminate/> 384             </sequence> 385             <sequence name="ActivateSeq"> 386                <target linkName="evalAccept"/> 387                <target linkName="anaAccept"/> 388                <target linkName="esAccept"/> 389                <assign xmlns=http://schemas.xmlsoap.org/ws/2003/03/business-process/ 390                   name="setStatusAcceptComplete"> 391                   <copy> 392                      <from expression="string('Letter and Reimbursement Sent')"> 393                      </from> 394                      <to variable="status"/> 395                   </copy> 396                </assign> 397                <bpelx:exec xmlns:bpelx=http://schemas.oracle.com/bpel/extension 398                   language="java" version="1.4" name="jactivate"> 399                   <![CDATA[ 400               System.out.println("**** CLAIM ACCEPTED AND ACTIVATED ****");        ]]> 401                </bpelx:exec> 402                <!-- terminate the process, see following note --> <terminate/> 403             </sequence>              <!-- at any time in the flow, respond to the kill event by terminating the                   process. See note below --> 404             <sequence name="CancelSeq"> 405                <receive 406                   xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/" 407                   partnerLink="client" portType="tns:InsuranceClaim" 408                   operation="initiate" variable="initiateMsg" createInstance="no" 409                   name="initiateEvent"> 410                   <correlations> 411                      <correlation set="claim" initiate="no"/> 412                   </correlations> 413                </receive> 414                <assign name="setStatus"> 415                   <copy> 416                      <from expression="string('killed')"> 417                      </from> 418                      <to variable="status"/> 419                   </copy> 420                </assign> 421                <bpelx:exec xmlns:bpelx=http://schemas.oracle.com/bpel/extension 422                   language="java" version="1.4" name="jkill"> 423                   <![CDATA[ 424               System.out.println("**** CLAIM KILLED ****"); 425            ]]> 426                </bpelx:exec> 427                <terminate/> 428             </sequence> 429          </flow> 430       </sequence> 431    </process>

    If you read that code in Example 10-4 carefully, you will notice that it does not conform to the design prescribed in Figure 10-2. earlier; specifically, it does not use an eventHandlers block to process cancellation. (The eventHandlers code is commented out in lines 44-72.) During unit testing, it was discovered that the BPEL engine did not properly route kill messages to the eventHandler. The changes required to work around the problem are italicized in Example 10-4:

    • A new block called CancelSeq (lines 405-429) is added to the flow statement. The logic of CancelSeq is nearly identical to the onMessage handler for the kill operation in the preferred implementation, except it is not globally scoped but works only while the flow activity is running, which, thankfully, covers most of the duration of the process anyway.

    • To handle cases where no kill event arrives, and the claim is either rejected or activated successfully, terminate activities are added to RejectSeq (line 383) and ActivateSeq (line 402), respectively. Without explicit termination, the event wait in CancelSeq would block interminably, preventing the process from completing. The process would hang forever, despite having successfully handled the claim.

    WS-Addressing and Correlation

    Notice that in the code generated by the task macro, there is no explicit correlation tying together the invoke-receive sequence of activities (e.g., lines 112-119 in Example 10-4). When the Task Manager service invokes the callback onTaskResult implemented by the InsuranceClaim process, how does the BPEL engine know which instance of the process to trigger? The absence of an explicit correlation makes it impossible for the BPEL engine to compare data in the message with data held in a process correlation set.

    The answer is WS-Addressing, a web services standard under construction by Microsoft, IBM, and other companies. Under the covers, when the InsuranceClaim process invokes the Task Manager, the BPEL engine, using syntax specified in the WS-Addressing specification, embeds information into the SOAP header such as a universally unique identifier (UUID) and a reply address. When Task Manager responds, the engine uses the original reply address and UUID to route the message to the correct instance of InsuranceClaims process.

    Though Oracle PM supports both WS-Addressing and BPEL correlation, Oracle's samples and tutorials emphasize the former approach.

    For more on WS-Addressing, see D. Box, et al., "Web Services Addressing," http://msdn.microsoft.com/webservices/default.aspx?pull=/library/en-us/dnglobspec/html/ws-addressing.asp.


    10.3.5. A Killer App

    As you will see later inthe section "Testing the Example," of the two operations in the client interface of the InsuranceClaim process, only initiate can be exercised out of the box with the Oracle BPEL administrative console. The console provides a test HTML form to start a process, but no equivalent form to inject into the process an arbitrary intermediate event. Thus, in order to test the InsuranceClaim's kill operation, we need to write a simple client application that calls it. This application can be written in Java or .NET, but that requires additional tools, not to mention additional skills. Instead, we will write a process called InsuranceClaimKiller that acts as a simple pass through to InsuranceClaim, calling its kill method with an invoke activity immediately after starting. Admittedly a heavyweight, contrived solution, our killer process can be developed and deployed rapidly, and when it is started using the console's process initiation test form, a kill message is sent directly to an in-flight InsuranceClaim process, achieving our original objective. The source code of the InsuranceClaimKiller process is provided in three listings:

    In the first listing, InsuranceClaimKiller.wsdl, the process supports a single operation, called kill (lines 13-15), whose input is the same WSDL type that is input by the kill operation of the InsuranceClaim process. Example 10-5 shows the listing.

    Example 10-5. InsuranceClaimKiller.wsdl
     1    <?xml version="1.0"?> 2    <definitions name="InsuranceClaimKillTester" 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 to get definition of InsuranceClaimMsg --> 9      <import namespace="http://acm.org/samples" location="messages.wsdl"/> 10 11       <!-- the tester has a kill operation in its port type --> 12       <portType name="InsuranceClaimKillTester"> 13          <operation name="kill"> 14             <input message="tns:InsuranceClaimMsg"/> 15          </operation> 16       </portType> 17 18       <!-- Partner link type for the killer --> _  _ 19       <plnk:partnerLinkType name="InsuranceClaimKillTester"> 20          <plnk:role name="InsuranceClaimKillTesterProvider"> 21             <plnk:portType name="tns:InsuranceClaimKillTester"/> 22          </plnk:role> 23       </plnk:partnerLinkType> 24    </definitions>

    The second listing, bpel.xml, specifies the partner link bindings for the process. In lines 10-14, the partner link Claims Process is mapped to the InsuranceClaim process. Example 10-6 shows the listing.

    Example 10-6. bpel.xml for InsuranceClaimKiller
     1    <?xml version="1.0"?> 2    <!-- Two partners: client is the killer, ClaimProcess the process to be killed --> 3    <BPELSuitcase> 4       <BPELProcess useCorrelationSet="yes"  5          src="/books/1/165/1/html/2/InsuranceClaimKiller.bpel"> 6          <partnerLinkBindings> 7             <partnerLinkBinding name="client"> 8                <property name="wsdlLocation">InsuranceClaimKiller.wsdl</property> 9             </partnerLinkBinding> 10             <partnerLinkBinding name="ClaimProcess"> 11                <property name="wsdlLocation"> 12    http://localhost:9700/orabpel/default/InsuranceClaim/InsuranceClaim?wsdl 13                </property> 14             </partnerLinkBinding> 15          </partnerLinkBindings> 16       </BPELProcess> 17    </BPELSuitcase>

    The third listing, InsuranceClaimKiller.bpel, is the heart of the killer process and is simplicity itself, having but two atomic activities. It begins with a receive activity (lines 21-24) that responds to the killer's kill operation. Next, and last, is an invoke (lines 26-28) that calls the kill operation of InsuranceClaim, passing as input the same value received in the previous step. Example 10-7 contains the listing.

    Example 10-7. InsuranceClaimKiller.bpel
     1    <process name="InsuranceClaimKiller" targetNamespace=http://acm.org/samples 2       suppressJoinFailure="yes" 3       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:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"> 8 9       <!--Two partners: This process is the killer. --> 10       <partnerLinks> 11          <partnerLink name="client" partnerLinkType="tns:InsuranceClaimKillTester" 12             myRole="InsuranceClaimKillTesterProvider"/> 13          <partnerLink name="ClaimProcess" partnerLinkType="tns:InsuranceClaim" 14             partnerRole="InsuranceClaimProvider"/> 15       </partnerLinks> 16       <variables> 17          <variable name="input" messageType="tns:InsuranceClaimMsg"/> 18       </variables> 19       <sequence name="main"> 20          <!-- Process starts when a kill message comes into the process --> 21          <receive name="receiveInput" partnerLink="client" operation="kill" 22             variable="input" createInstance="yes" 23             portType="tns:InsuranceClaimKillTester"> 24          </receive> 25          <!-- When that happens, send kill event to claims process --> 26          <invoke partnerLink="ClaimProcess" portType="tns:InsuranceClaim" 27             operation="kill" name="callKill" inputVariable="input"> 28          </invoke> 29       </sequence> 30    </process>



    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