- Activity - used to execute a specific task like manipulating a variable or calling an external service
- Parallel - defines two or more parallel branches that can be executed concurrently.
- Choose - implements control flow similar to if/otherwise type of logic
- Cycle - provides support for looping
- Endpoint - defines an external service
- Context - performs variable definition and initialization
endpoint :epAirBook => uri:airbooking
endpoint :epHotelBook => uri:hotelbooking
endpoint :epAirPay => uri:airpayment
endpoint :epHotelPay => uri:hotelpayment
endpoint :epInform => uri:companyinform
context :persons => 3
context :creditcard => 'Visa12345'
context :airline => nil
context :hotel => nil
context :from => 'Vienna'
context :to => 'Prag'
context :sum => 0
controlflow do
cycle (@persons > 0) do
% book an airline flight
activity :bookFlight, :call, epAirBook, @from, @to do |id|
@airline = id
end
% pay for the flight
activity :payFlight, :call, epAirPay, @airline, @creditcard do | amount |
@sum += amount
end
% book a hotel
activity :bookHotel, :call, epHotelBook, @to do |id|
@hotel = id
end
% pay for the hotel
activity :payHotel, :call, epHotelPay, @hotel, @creditcard do |amount|
@sum += amount
end
% decrement the number of people
activity :countdown, :manipulate do
@persons += -1
end
end
% alert if the total amount is greater than 5000
choose do
alternative (@sum > 5000) do
activity :inform, :call, epInform, @sum
end
end
end
end
endpoint :epHotelBook => uri:hotelbooking
endpoint :epAirPay => uri:airpayment
endpoint :epHotelPay => uri:hotelpayment
endpoint :epInform => uri:companyinform
context :persons => 3
context :creditcard => 'Visa12345'
context :airline => nil
context :hotel => nil
context :from => 'Vienna'
context :to => 'Prag'
context :sum => 0
controlflow do
cycle (@persons > 0) do
% book an airline flight
activity :bookFlight, :call, epAirBook, @from, @to do |id|
@airline = id
end
% pay for the flight
activity :payFlight, :call, epAirPay, @airline, @creditcard do | amount |
@sum += amount
end
% book a hotel
activity :bookHotel, :call, epHotelBook, @to do |id|
@hotel = id
end
% pay for the hotel
activity :payHotel, :call, epHotelPay, @hotel, @creditcard do |amount|
@sum += amount
end
% decrement the number of people
activity :countdown, :manipulate do
@persons += -1
end
end
% alert if the total amount is greater than 5000
choose do
alternative (@sum > 5000) do
activity :inform, :call, epInform, @sum
end
end
end
end
As an experiment, I decided to try to implement this workflow language using the Erlang programming language because of it's built-in support for concurrent processes, multi-core processors, distributed clusters, rock-solid performance, and scalability. The availability of Erlang tools to define parsers (like LEX and YACC) was also of huge assistance.
Overall, it took me about a week to develop the parser and run-time engine but part of that time was taken with dusting off my Erlang programming skills that had gotten a bit rusty. My appreciation for the simplicity and elegance of the WEE language steadily went up as I implemented each feature. Compared to developing BPEL processes using cumbersome XML, WEE processes are much simpler to develop and maintain.
While I have made no attempts at optimization yet, the Erlang-based WEE run-time engine seems to perform very well. I create a small workflow process that loops one million times and it executes in under 5 seconds on a laptop-class PC.
%
% Test performance of large loops
%
endpoint :timer => uri:display
context :counter => 1000000
controlflow do
% call the timer endpoint to display the current time
activity :starttime, :call, timer
end
% main loop
cycle (@counter > 1) do
activity :decrement, :manipulate do
@counter += -1
end
end
% call the timer endpoint to display the current time
activity :endtime, :call, timer
end
end
% Test performance of large loops
%
endpoint :timer => uri:display
context :counter => 1000000
controlflow do
% call the timer endpoint to display the current time
activity :starttime, :call, timer
end
% main loop
cycle (@counter > 1) do
activity :decrement, :manipulate do
@counter += -1
end
end
% call the timer endpoint to display the current time
activity :endtime, :call, timer
end
end
For fun, I built the equivalent process using a commercial BPEL engine and ran some timing tests on the same machine. The source code is shown below.
Number of iterations Erlang WEE BPEL
10,000 < 1 second 3 seconds
100,000 < 1 second 57 seconds
1,000,000 5 seconds Caused the server to crash after a few minutes
Having the code that I wrote being able to perform a million iterations in under 5 seconds made me very happy.
BPEL Source code:
<?xml version = "1.0" encoding = "UTF-8" ?>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Oracle JDeveloper BPEL Designer
Created: Fri Apr 06 09:15:36 CDT 2012
Type: BPEL 2.0 Process
Purpose: Asynchronous BPEL Process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<process name="LoopProcess"
targetNamespace="http://xmlns.oracle.com/Sandbox/LoopTest/LoopProcess"
xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:client="http://xmlns.oracle.com/Sandbox/LoopTest/LoopProcess"
xmlns:ora="http://schemas.oracle.com/xpath/extension"
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
xmlns:hwf="http://xmlns.oracle.com/bpel/workflow/xpath"
xmlns:ids="http://xmlns.oracle.com/bpel/services/IdentityService/xpath"
xmlns:bpm="http://xmlns.oracle.com/bpmn20/extensions"
xmlns:xdk="http://schemas.oracle.com/bpel/extension/xpath/function/xdk"
xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap">
<import namespace="http://xmlns.oracle.com/Sandbox/LoopTest/LoopProcess" location="LoopProcess.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"/>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PARTNERLINKS
List of services participating in this BPEL process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<partnerLinks>
<!--
The 'client' role represents the requester of this service. It is
used for callback. The location and correlation information associated
with the client role are automatically set using WS-Addressing.
-->
<partnerLink name="loopprocess_client" partnerLinkType="client:LoopProcess" myRole="LoopProcessProvider" partnerRole="LoopProcessRequester"/>
</partnerLinks>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VARIABLES
List of messages and XML documents used within this BPEL process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<variables>
<!-- Reference to the message passed as input during initiation -->
<variable name="inputVariable" messageType="client:LoopProcessRequestMessage"/>
<!-- Reference to the message that will be sent back to the requester during callback -->
<variable name="outputVariable" messageType="client:LoopProcessResponseMessage"/>
<variable name="VariableCounter" type="xsd:long">
<from>1000000</from>
</variable>
</variables>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ORCHESTRATION LOGIC
Set of activities coordinating the flow of messages across the
services integrated within this business process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<sequence name="main">
<!-- Receive input from requestor. (Note: This maps to operation defined in LoopProcess.wsdl) -->
<receive name="receiveInput" partnerLink="loopprocess_client" portType="client:LoopProcess" operation="process" variable="inputVariable" createInstance="yes"/>
<!--
Asynchronous callback to the requester. (Note: the callback location and correlation id is transparently handled using WS-addressing.)
-->
<repeatUntil name="RepeatUntil1">
<assign name="AssignCounter">
<copy>
<from>$VariableCounter - 1</from>
<to>$VariableCounter</to>
</copy>
</assign>
<condition>$VariableCounter < 1</condition>
</repeatUntil>
<invoke name="callbackClient" partnerLink="loopprocess_client" portType="client:LoopProcessCallback" operation="processResponse" inputVariable="outputVariable"/>
</sequence>
</process>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Oracle JDeveloper BPEL Designer
Created: Fri Apr 06 09:15:36 CDT 2012
Type: BPEL 2.0 Process
Purpose: Asynchronous BPEL Process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<process name="LoopProcess"
targetNamespace="http://xmlns.oracle.com/Sandbox/LoopTest/LoopProcess"
xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:client="http://xmlns.oracle.com/Sandbox/LoopTest/LoopProcess"
xmlns:ora="http://schemas.oracle.com/xpath/extension"
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
xmlns:hwf="http://xmlns.oracle.com/bpel/workflow/xpath"
xmlns:ids="http://xmlns.oracle.com/bpel/services/IdentityService/xpath"
xmlns:bpm="http://xmlns.oracle.com/bpmn20/extensions"
xmlns:xdk="http://schemas.oracle.com/bpel/extension/xpath/function/xdk"
xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap">
<import namespace="http://xmlns.oracle.com/Sandbox/LoopTest/LoopProcess" location="LoopProcess.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"/>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PARTNERLINKS
List of services participating in this BPEL process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<partnerLinks>
<!--
The 'client' role represents the requester of this service. It is
used for callback. The location and correlation information associated
with the client role are automatically set using WS-Addressing.
-->
<partnerLink name="loopprocess_client" partnerLinkType="client:LoopProcess" myRole="LoopProcessProvider" partnerRole="LoopProcessRequester"/>
</partnerLinks>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VARIABLES
List of messages and XML documents used within this BPEL process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<variables>
<!-- Reference to the message passed as input during initiation -->
<variable name="inputVariable" messageType="client:LoopProcessRequestMessage"/>
<!-- Reference to the message that will be sent back to the requester during callback -->
<variable name="outputVariable" messageType="client:LoopProcessResponseMessage"/>
<variable name="VariableCounter" type="xsd:long">
<from>1000000</from>
</variable>
</variables>
<!--
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ORCHESTRATION LOGIC
Set of activities coordinating the flow of messages across the
services integrated within this business process
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-->
<sequence name="main">
<!-- Receive input from requestor. (Note: This maps to operation defined in LoopProcess.wsdl) -->
<receive name="receiveInput" partnerLink="loopprocess_client" portType="client:LoopProcess" operation="process" variable="inputVariable" createInstance="yes"/>
<!--
Asynchronous callback to the requester. (Note: the callback location and correlation id is transparently handled using WS-addressing.)
-->
<repeatUntil name="RepeatUntil1">
<assign name="AssignCounter">
<copy>
<from>$VariableCounter - 1</from>
<to>$VariableCounter</to>
</copy>
</assign>
<condition>$VariableCounter < 1</condition>
</repeatUntil>
<invoke name="callbackClient" partnerLink="loopprocess_client" portType="client:LoopProcessCallback" operation="processResponse" inputVariable="outputVariable"/>
</sequence>
</process>
No comments:
Post a Comment