Tuesday, May 29, 2012

WS-BPEL Spec Sample using WSO2 BPS

In this article, we will look at how to implement a simplified version of the Purchase Order Process sample provided in the WS-BPEL 2.0 specification using WSO2 Business Process Server (BPS) & WSO2 Developer Studio. WSO2 BPS is based on the Apache ODE business process engine.

Here is the description of this process from the spec.

"The operation of the process is very simple, and is represented in Figure 1: Purchase Order Process Outline. Dotted lines represent sequencing. Free grouping of sequences represents concurrent sequences. Solid arrows represent control links used for synchronization across concurrent activities. Note that this is not meant to be a definitive graphical notation for WSBPEL processes. It is used here informally as an aid to understanding. On receiving the purchase order from a customer, the process initiates three paths concurrently: calculating the final price for the order, selecting a shipper, and
scheduling the production and shipment for the order. While some of the processing can proceed concurrently, there are control and data dependencies between the three paths. In particular, the shipping price is required to finalize the price calculation, and the shipping date is required for the complete fulfillment schedule. When the three concurrent paths are completed, invoice processing can proceed and the invoice is sent to the customer."

Figure 1: Purchase Order Process Outline

Figure 2: Partner links view of the Purchase Order Process


Figure 3: BPEL Process View in DevStudio BPEL Designer

The Complete BPEL Process

<bpel:process name="PurchaseOrderProcess"
         targetNamespace="http://wso2.org/bps/sample"
         suppressJoinFailure="yes"
         xmlns:tns="http://wso2.org/bps/sample"
         xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
         xmlns:ns="http://computeprice.spec.bpel.wso2.org" xmlns:ns0="http://www.example.org/InvoiceCallback/" xmlns:ns1="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://shipping.spec.bpel.wso2.org" xmlns:ns3="http://www.example.org/ShippingCallback/" xmlns:ns4="http://scheduling.spec.bpel.wso2.org">

    <!-- Import the client WSDL -->
    <bpel:import namespace="http://scheduling.spec.bpel.wso2.org" location="ProductionSchedulingService.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"></bpel:import>
    <bpel:import namespace="http://www.example.org/ShippingCallback/" location="ShippingCallback.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"></bpel:import>
    <bpel:import namespace="http://shipping.spec.bpel.wso2.org" location="ShippingService.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"></bpel:import>
    <bpel:import namespace="http://www.example.org/InvoiceCallback/" location="InvoiceCallback.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"></bpel:import>
    <bpel:import namespace="http://computeprice.spec.bpel.wso2.org" location="ComputePriceService.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"></bpel:import>
    <bpel:import location="PurchaseOrderProcess.wsdl" namespace="http://wso2.org/bps/sample" 
         importType="http://schemas.xmlsoap.org/wsdl/" />
         
    <!-- ================================================================= -->         
    <!-- PARTNERLINKS                                                      -->
    <!-- List of services participating in this BPEL process               -->
    <!-- ================================================================= -->         
    <bpel:partnerLinks>
        <!-- The 'client' role represents the requester of this service. -->
        <bpel:partnerLink name="client"
                     partnerLinkType="tns:PurchaseOrderProcess"
                     myRole="PurchaseOrderProcessProvider"
                     />
        <bpel:partnerLink name="InvoicingPL" partnerLinkType="tns:InvoicingPLT" partnerRole="computePriceRole" myRole="computePriceCallbackRole"></bpel:partnerLink>
        <bpel:partnerLink name="shippingPL" partnerLinkType="tns:shippingPL" partnerRole="shipper" myRole="shippingCallback"></bpel:partnerLink>
        <bpel:partnerLink name="schedulingPL" partnerLinkType="tns:schedulingPLT" partnerRole="producer"></bpel:partnerLink>
    </bpel:partnerLinks>
  
    <!-- ================================================================= -->         
    <!-- VARIABLES                                                         -->
    <!-- List of messages and XML documents used within this BPEL process  -->
    <!-- ================================================================= -->         
    <bpel:variables>
        <!-- Reference to the message passed as input during initiation -->
        <bpel:variable name="input"
                  messageType="tns:PurchaseOrderProcessRequestMessage"/>
                  
        <!-- 
          Reference to the message that will be returned to the requester
          -->
        <bpel:variable name="output"
                  messageType="tns:PurchaseOrderProcessResponseMessage"/>
        <bpel:variable name="InvoicingPLResponse" messageType="ns:computePriceResponse"></bpel:variable>
        <bpel:variable name="InvoicingPLRequest" messageType="ns:computePriceRequest"></bpel:variable>
        <bpel:variable name="InvoicingPLRequest1" messageType="ns0:computePriceCallbackRequest"></bpel:variable>
        <bpel:variable name="shippingPLResponse" messageType="ns2:selectShipperResponse"></bpel:variable>
        <bpel:variable name="shippingPLRequest" messageType="ns2:selectShipperRequest"></bpel:variable>
        <bpel:variable name="shippingPLRequest1" messageType="ns3:sendShippingPriceRequest"></bpel:variable>
        <bpel:variable name="schedulingPLRequest" messageType="ns4:scheduleRequest"></bpel:variable>
    </bpel:variables>

    <!-- ================================================================= -->         
    <!-- ORCHESTRATION LOGIC                                               -->
    <!-- Set of activities coordinating the flow of messages across the    -->
    <!-- services integrated within this business process                  -->
    <!-- ================================================================= -->         
    <bpel:correlationSets>
        <bpel:correlationSet name="OrderIdCorrelationSet" properties="tns:orderId"></bpel:correlationSet>
        <bpel:correlationSet name="ShipperIdCorrelationSet" properties="tns:shipperId"></bpel:correlationSet>
    </bpel:correlationSets>
    <bpel:sequence name="main">
        
        <!-- Receive input from requester. 
             Note: This maps to operation defined in PurchaseOrderProcess.wsdl 
             -->
        <bpel:receive name="receiveInput" partnerLink="client" portType="tns:PurchaseOrderProcess" operation="process" variable="input" createInstance="yes"><bpel:correlations>
                <bpel:correlation set="OrderIdCorrelationSet" initiate="yes"></bpel:correlation>
                <bpel:correlation set="ShipperIdCorrelationSet" initiate="yes"></bpel:correlation>
            </bpel:correlations>
        
        </bpel:receive>
        <bpel:flow name="Flow"><bpel:sequence name="InvoicingSequence">
                <bpel:assign validate="no" name="InitializeInvoicing"><bpel:copy>
                <bpel:from>
                    <bpel:literal>
                        <ns:computePrice xmlns:ns="http://computeprice.spec.bpel.wso2.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ns:orderId>ns:orderId</ns:orderId>

                        </ns:computePrice>
                    </bpel:literal>
                </bpel:from>
                <bpel:to variable="InvoicingPLRequest" part="parameters"></bpel:to>
            </bpel:copy>
            <bpel:copy>
                <bpel:from part="payload" variable="input">
                            <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
                                <![CDATA[tns:orderId]]>
                            </bpel:query>
                        </bpel:from>
                <bpel:to part="parameters" variable="InvoicingPLRequest">
                            <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
                                <![CDATA[ns:orderId]]>
                            </bpel:query>
                        </bpel:to>
            </bpel:copy>
        </bpel:assign>
                <bpel:invoke name="InvokeInvoicing" partnerLink="InvoicingPL" operation="computePrice" portType="ns:ComputePriceServicePortType" inputVariable="InvoicingPLRequest" outputVariable="InvoicingPLResponse">
                </bpel:invoke>
                
                <bpel:receive name="receiveInvoiceCallback" partnerLink="InvoicingPL" operation="computePriceCallback" portType="ns0:ComputePriceCallbackPortType" variable="InvoicingPLRequest1"><bpel:correlations>
                <bpel:correlation set="OrderIdCorrelationSet" initiate="no"></bpel:correlation>
            </bpel:correlations>
        
                </bpel:receive>
                
            </bpel:sequence><bpel:sequence name="ShippingSequence">
                <bpel:assign validate="no" name="InitializeShipping">
                    <bpel:copy>
                        <bpel:from>
                            <bpel:literal>
                                <ns:selectShipper xmlns:ns="http://shipping.spec.bpel.wso2.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ns:shipperId>ns:shipperId</ns:shipperId>

                                </ns:selectShipper>
                            </bpel:literal>
                        </bpel:from>
                        <bpel:to variable="shippingPLRequest" part="parameters"></bpel:to>
                    </bpel:copy>
                    <bpel:copy>
                        <bpel:from part="payload" variable="input">
                            <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[tns:shipperId]]></bpel:query>
                        </bpel:from>
                        <bpel:to part="parameters" variable="shippingPLRequest">
                            <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[ns2:shipperId]]></bpel:query>
                        </bpel:to>
                    </bpel:copy>
                </bpel:assign>
                <bpel:invoke name="InvokeShipping" partnerLink="shippingPL" operation="selectShipper" portType="ns2:ShippingServicePortType" inputVariable="shippingPLRequest" outputVariable="shippingPLResponse">
                </bpel:invoke>
                <bpel:receive name="receiveShippingCallback" partnerLink="shippingPL" operation="sendShippingPrice" portType="ns3:ShippingCallbackPortType" variable="shippingPLRequest1">
                    <bpel:correlations>
                        <bpel:correlation set="ShipperIdCorrelationSet" initiate="no"></bpel:correlation>
                    </bpel:correlations>
                </bpel:receive>
            </bpel:sequence></bpel:flow>
        <!-- Generate reply to synchronous request -->
        <bpel:sequence name="ProductionSchedulingSequence">
            <bpel:assign validate="no" name="InitializeProductionScheduling">
                <bpel:copy>
                    <bpel:from>
                        <bpel:literal>
                            <ns:schedule xmlns:ns="http://scheduling.spec.bpel.wso2.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ns:orderId>ns:orderId</ns:orderId>

                            </ns:schedule>
                        </bpel:literal>
                    </bpel:from>
                    <bpel:to variable="schedulingPLRequest" part="parameters"></bpel:to>
                </bpel:copy>
                <bpel:copy>
                    <bpel:from part="payload" variable="input">
                        <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[tns:orderId]]></bpel:query>
                    </bpel:from>
                    <bpel:to part="parameters" variable="schedulingPLRequest">
                        <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[ns4:orderId]]></bpel:query>
                    </bpel:to>
                </bpel:copy>
            </bpel:assign>
            <bpel:invoke name="InvokeProductionScheduling" partnerLink="schedulingPL" operation="schedule" portType="ns4:ProductionSchedulingServicePortType" inputVariable="schedulingPLRequest"></bpel:invoke>
        </bpel:sequence>
        <bpel:assign validate="no" name="AssignOutput"><bpel:copy>
                <bpel:from>
                    <bpel:literal>
                        <tns:PurchaseOrderProcessResponse xmlns:tns="http://wso2.org/bps/sample" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><tns:result>0</tns:result>
                        </tns:PurchaseOrderProcessResponse>
                    </bpel:literal>
                </bpel:from>
                <bpel:to variable="output" part="payload"></bpel:to>
            </bpel:copy>
            <bpel:copy>
                <bpel:from>
                    <![CDATA[number($InvoicingPLRequest1.parameters/price) + number($shippingPLRequest1.parameters/amount)]]>
                </bpel:from>
                <bpel:to part="payload" variable="output">
                    <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
                        <![CDATA[tns:result]]>
                    </bpel:query>
                </bpel:to>
            </bpel:copy>
        </bpel:assign>
        <bpel:reply name="replyOutput" 
               partnerLink="client"
               portType="tns:PurchaseOrderProcess"
               operation="process" 
               variable="output"
               />
    </bpel:sequence>
</bpel:process>




The entire project can be downloaded from here.


For details on how to use the WSO2 Developer Studio BPEL editor see Developing WS-BPEL Processes using WSO2 Carbon Studio

Post a Comment