Most large companies have “workflow experts” whose job is to develop the workflows that the business implements. For example, an insurance agency might have experts that determine how a claim is to be handled. These workflows are under constant revision since the business' requests and needs are constantly changing. The tools the companies above provide usually provide a GUI that the expert can use to draw workflow, similar to how one might draw a flowchart. The enactment engine of the tools take these workflows as input and execute them.
BPEL4WS was created jointly by Microsoft and IBM, along with others. Both companies started with workflow tools that wrote the workflows to files using their own propietary format. One of the goals for BPEL4WS was for it to be able to express most of the constructs that could be implemented with both tools, so that one could save a workflow with one one vendor's tool and read it back with another vendor's tool (in the same way that many browsers can read the same HTML files).
<process name="purchaseOrderProcess" targetNamespace="http://acme.com/ws-bp/purchase" xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/" xmlns:lns="http://manufacturing.org/wsdl/purchase"> <partnerLinks> <partnerLink name="purchasing" partnerLinkType="lns:purchasingLT" myRole="purchaseService"/> <partnerLink name="invoicing" partnerLinkType="lns:invoicingLT" myRole="invoiceRequester" partnerRole="invoiceService"/> <partnerLink name="shipping" partnerLinkType="lns:shippingLT" myRole="shippingRequester" partnerRole="shippingService"/> <partnerLink name="scheduling" partnerLinkType="lns:schedulingLT" partnerRole="schedulingService"/> </partnerLinks> <variables> <variable name="PO" messageType="lns:POMessage"/> <variable name="Invoice" messageType="lns:InvMessage"/> <variable name="POFault" messageType="lns:orderFaultType"/> <variable name="shippingRequest" messageType="lns:shippingRequestMessage"/> <variable name="shippingInfo" messageType="lns:shippingInfoMessage"/> <variable name="shippingSchedule" messageType="lns:scheduleMessage"/> </variables> <faultHandlers> <catch faultName="lns:cannotCompleteOrder" faultVariable="POFault"> <reply partnerLink="purchasing" portType="lns:purchaseOrderPT" operation="sendPurchaseOrder" variable="POFault" faultName="cannotCompleteOrder"/> </catch> </faultHandlers> <sequence> <receive partnerLink="purchasing" portType="lns:purchaseOrderPT" operation="sendPurchaseOrder" variable="PO"> </receive> <flow> <links> <link name="ship-to-invoice"/> <link name="ship-to-scheduling"/> </links> <sequence> <assign> <copy> <from variable="PO" part="customerInfo"/> <to variable="shippingRequest" part="customerInfo"/> </copy> </assign> <invoke partnerLink="shipping" portType="lns:shippingPT" operation="requestShipping" inputVariable="shippingRequest" outputVariable="shippingInfo"> <source linkName="ship-to-invoice"/> </invoke> <receive partnerLink="shipping" portType="lns:shippingCallbackPT" operation="sendSchedule" variable="shippingSchedule"> <source linkName="ship-to-scheduling"/> </receive> </sequence> <sequence> <invoke partnerLink="invoicing" portType="lns:computePricePT" operation="initiatePriceCalculation" inputVariable="PO"> </invoke> <invoke partnerLink="invoicing" portType="lns:computePricePT" operation="sendShippingPrice" inputVariable="shippingInfo"> <target linkName="ship-to-invoice"/> </invoke> <receive partnerLink="invoicing" portType="lns:invoiceCallbackPT" operation="sendInvoice" variable="Invoice"/> </sequence> <sequence> <invoke partnerLink="scheduling" portType="lns:schedulingPT" operation="requestProductionScheduling" inputVariable="PO"> </invoke> <invoke partnerLink="scheduling" portType="lns:schedulingPT" operation="sendShippingSchedule" inputVariable="shippingSchedule"> <target linkName="ship-to-scheduling"/> </invoke> </sequence> </flow> <reply partnerLink="purchasing" portType="lns:purchaseOrderPT" operation="sendPurchaseOrder" variable="Invoice"/> </sequence> </process>
<process name="ncname" targetNamespace="uri" queryLanguage="anyURI"? expressionLanguage="anyURI"? suppressJoinFailure="yes|no"? enableInstanceCompensation="yes|no"? abstractProcess="yes|no"? xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"> <partnerLinks>? <!-- Note: At least one role must be specified. --> <partnerLink name="ncname" partnerLinkType="qname" myRole="ncname"? partnerRole="ncname"?>+ </partnerLink> </partnerLinks> <partners>? <partner name="ncname">+ <partnerLink name="ncname"/>+ </partner> </partners> <variables>? <variable name="ncname" messageType="qname"? type="qname"? element="qname"?/>+ </variables> <correlationSets>? <correlationSet name="ncname" properties="qname-list"/>+ </correlationSets> <faultHandlers>? <!-- Note: There must be at least one fault handler or default. --> <catch faultName="qname"? faultVariable="ncname"?>* activity </catch> <catchAll>? activity </catchAll> </faultHandlers> <compensationHandler>? activity </compensationHandler> <eventHandlers>? <!-- Note: There must be at least one onMessage or onAlarm handler. --> <onMessage partnerLink="ncname" portType="qname" operation="ncname" variable="ncname"?> <correlations>? <correlation set="ncname" initiate="yes|no"?>+ <correlations> activity </onMessage> <onAlarm for="duration-expr"? until="deadline-expr"?>* activity </onAlarm> </eventHandlers> activity </process>
<receive>
construct allows the
business process to do a blocking wait for a matching message
to arrive.
<receive partnerLink="ncname" portType="qname" operation="ncname" variable="ncname" createInstance="yes|no" standard-attributes> standard-elements <correlations>? <correlation set="ncname" initiate="yes|no"?>+ </correlations> </receive>
<reply partnerLink="ncname" portType="qname" operation="ncname" variable="ncname"? faultName="qname"? standard-attributes> standard-elements <correlations>? <correlation set="ncname" initiate="yes|no"?>+ </correlations> </reply>
<invoke partnerLink="ncname" portType="qname" operation="ncname" inputVariable="ncname"? outputVariable="ncname"? standard-attributes> standard-elements <correlations>? <correlation set="ncname" initiate="yes|no"? pattern="in|out|out-in"/>+ </correlations> <catch faultName="qname" faultVariable="ncname"?>* activity </catch> <catchAll>? activity </catchAll> <compensationHandler>? activity </compensationHandler> </invoke> <!--- for example --> <invoke partnerLink="Seller" portType="SP:Purchasing" operation="SyncPurchase" inputVariable="sendPO" outputVariable="getResponse"> <compensationHandler> <invoke partnerLink="Seller" portType="SP:Purchasing" operation="CancelPurchase" inputVariable="getResponse" outputVariable="getConfirmation"> </compensationHandler> </invoke>
<assign standard-attributes> standard-elements <copy>+ from-spec to-spec </copy> </assign>
<throw faultName="qname" faultVariable="ncname"? standard-attributes> standard-elements </throw>
<wait (for="duration-expr" | until="deadline-expr") standard-attributes> standard-elements </wait>
<empty standard-attributes> standard-elements </empty>
<sequence standard-attributes> standard-elementsactivity+ </sequence>
<switch standard-attributes> standard-elements <case condition="bool-expr">+ activity </case> <otherwise>? activity </otherwise> </switch> <!-- for example --> <switch xmlns:inventory="http://supply-chain.org/inventory" xmlns:FLT="http://example.com/faults"> <case condition= "bpws:getVariableProperty(stockResult,level) > 100"> <flow> <!-- perform fulfillment work --> </flow> </case> <case condition="bpws:getVariableProperty(stockResult,level) >= 0"> <throw faultName="FLT:OutOfStock" variable="RestockEstimate"/> </case> <otherwise> <throw faultName="FLT:ItemDiscontinued"/> </otherwise> </switch>
<while condition="bool-expr" standard-attributes> standard-elementsactivity </while> <!-- for example --> <variable name="orderDetails" type="xsd:integer"/> ... <while condition= "bpws:getVariableData(orderDetails) > 100"> <scope> ... </scope> </while>
<pick createInstance="yes|no"? standard-attributes> standard-elements <onMessage partnerLink="ncname" portType="qname" operation="ncname" variable="ncname"?>+ <correlations>? <correlation set="ncname" initiate="yes|no"?>+ </correlations> activity </onMessage> <onAlarm (for="duration-expr" | until="deadline-expr")>* activity </onAlarm> </pick> <!-- for example --> <pick> <onMessage partnerLink="buyer" portType="orderEntry" operation="inputLineItem" variable="lineItem"> <!-- activity to add line item to order --> </onMessage> <onMessage partnerLink="buyer" portType="orderEntry" operation="orderComplete" variable="completionDetail"> <!-- activity to perform order completion --> </onMessage> <!-- set an alarm to go after 3 days and 10 hours --> <onAlarm for="'P3DT10H'"> <!-- handle timeout for order completion --> </onAlarm> </pick>
<flow standard-attributes> standard-elements <links>? <link name="ncname">+ </links> activity+ </flow> <!-- for example --> <flow> <links> <link name="XtoY"/> <link name="CtoD"/> </links> <sequence name="X"> <source linkName="XtoY"/> <invoke name="A" .../> <invoke name="B" .../> </sequence> <sequence name"Y"> <target linkName="XtoY"/> <receive name="C" ...> <source linkName="CtoD"/> </receive> <invoke name="E" .../> </sequence> <invoke partnerLink="D" ...> <target linkName="CtoD"/> </invoke> </flow>
<scope variableAccessSerializable="yes|no" standard-attributes> standard-elements <variables>? </variables> <correlationSets>? </correlationSets> <faultHandlers>? </faultHandlers> <compensationHandler>? </compensationHandler> <eventHandlers>? ... </eventHandlers> activity </scope>
<compensate scope="ncname"? standard-attributes> standard-elements </compensate>
createInstance="yes"
.correlationset
. <terminate>
partner
s are the other businesses (web
services) the workflow accesses. <partnerLinkType name="BuyerSellerLink" xmlns="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"> <role name="Buyer"> <portType name="buy:BuyerPortType"/> </role> <role name="Seller"> <portType name="sell:SellerPortType"/> </role> </partnerLinkType>
<definitions name="properties" targetNamespace="http://example.com/properties.wsdl" xmlns:tns="http://example.com/properties.wsdl" xmlns:txtyp="http://example.com/taxTypes.xsd" xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <!-- define a correlation property --> <bpws:property name="taxpayerNumber" type="txtyp:SSN"/> ... </wsdl:definitions>
<complexType name="tAddress"> <sequence> <element name="number" type="xsd:int"/> <element name="street" type="xsd:string"/> <element name="city" type="xsd:string"/> <element name="phone"> <complexType> <sequence> <element name="areacode" type="xsd:int"/> <element name="exchange" type="xsd:int"/> <element name="number" type="xsd:int"/> </sequence> </complexType> </element> </sequence> </complexType> <element name = "address" type = "tAddress"/> <!-- this message in the the .wsdl file --> <message name="person" xmlns:x="http://tempuri.org/bpws/example"> <part name="full-name" type="xsd:string"/> <part name="address" element="x:address"/> </message> <!-- --> <variable name="c1" messageType="x:person"/> <variable name="c2" messageType="x:person"/> <variable name="c3" element="x:address"/> <assign> <copy> <from variable="c1"/> <to variable="c2"/> </copy> <copy> <from variable="c1" part = "address"/> <to variable="c3"/> </copy> </assign>
invoce
,
receive
, and reply
activities. <correlationSets xmlns:cor="http://example.com/supplyCorrelation.wsdl"> <!-- Order numbers are particular to a customer, this set is carried in application data --> <correlationSet name="PurchaseOrder" properties="cor:customerID cor:orderNumber"/> <!-- Invoice numbers are particular to a vendor, this set is carried in application data --> <correlationSet name="Invoice" properties="cor:vendorID cor:invoiceNumber"/> </correlationSets>so they can then be used
<receive partnerLink="Buyer" portType="SP:PurchasingPT" operation="AsyncPurchase" variable="PO"> <correlations> <correlation set="PurchaseOrder" initiate="yes"> </correlations> </receive> <invoke partnerLink="Buyer" portType="SP:BuyerPT" operation="AsyncPurchaseResponse" inputVariable="POResponse"> <correlations> <correlation set="PurchaseOrder" initiate="no" pattern="out"> <correlation set="Invoice" initiate="yes" pattern="out"> </correlations> </invoke>
initiate="yes"
means that the correlation
is being started (new instance). pattern
tells us if the correlation
applies to the outbound (request) message, the inbound
(response) message, or both. link
s have a name
.source
, and
target
which name particular links. <process name="loanApprovalProcess" targetNamespace="http://acme.com/loanprocessing" xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/" xmlns:lns="http://loans.org/wsdl/loan-approval" suppressJoinFailure="yes"> <partnerLinks> <partnerLink name="customer" partnerLinkType="lns:loanPartnerLinkType" myRole="loanService"/> <partnerLink name="approver" partnerLinkType="lns:loanApprovalLinkType" partnerRole="approver"/> <partnerLink name="assessor" partnerLinkType="lns:riskAssessmentLinkType" partnerRole="assessor"/> </partnerLinks> <variables> <variable name="request" messageType="lns:creditInformationMessage"/> <variable name="risk" messageType="lns:riskAssessmentMessage"/> <variable name="approval" messageType="lns:approvalMessage"/> <variable name="error" messageType="lns:errorMessage"/> </variables> <faultHandlers> <catch faultName="lns:loanProcessFault" faultVariable="error"> <reply partnerLink="customer" portType="lns:loanServicePT" operation="request" variable="error" faultName="unableToHandleRequest"/> </catch> </faultHandlers> <flow> <links> <link name="receive-to-assess"/> <link name="receive-to-approval"/> <link name="approval-to-reply"/> <link name="assess-to-setMessage"/> <link name="setMessage-to-reply"/> <link name="assess-to-approval"/> </links> <receive partnerLink="customer" portType="lns:loanServicePT" operation="request" variable="request" createInstance="yes"> <source linkName="receive-to-assess" transitionCondition= "bpws:getVariableData('request','amount')< 10000"/> <source linkName="receive-to-approval" transitionCondition= "bpws:getVariableData('request','amount')>=10000"/> </receive> <invoke partnerLink="assessor" portType="lns:riskAssessmentPT" operation="check" inputVariable="request" outputVariable="risk"> <target linkName="receive-to-assess"/> <source linkName="assess-to-setMessage" transitionCondition= "bpws:getVariableData('risk','level')='low'"/> <source linkName="assess-to-approval" transitionCondition= "bpws:getVariableData('risk','level')!='low'"/> </invoke> <assign> <target linkName="assess-to-setMessage"/> <source linkName="setMessage-to-reply"/> <copy> <from expression="'yes'"/> <to variable="approval" part="accept"/> </copy> </assign> <invoke partnerLink="approver" portType="lns:loanApprovalPT" operation="approve" inputVariable="request" outputVariable="approval"> <target linkName="receive-to-approval"/> <target linkName="assess-to-approval"/> <source linkName="approval-to-reply" /> </invoke> <reply partnerLink="customer" portType="lns:loanServicePT" operation="request" variable="approval"> <target linkName="setMessage-to-reply"/> <target linkName="approval-to-reply"/> </reply> </flow> </process>
This talk available at http://jmvidal.cse.sc.edu/talks/bpel4ws/
Copyright © 2009 José M. Vidal
.
All rights reserved.
21 April 2004, 11:34AM