Straight-Through Data Transformation
Example
Use Case
The DEF
Corporation's intranet has a Web-based online store through which
employees can purchase the company's products. The store's
XFORMS-based
Web interface registers the order by sending an XML document
containing the order details to an asynchronous message queue, which
is serviced by a workflow management system. Each incoming message
triggers a new workflow instance that retrieves additional
information about the employee (by calling a predefined procedure).
The workflow then merges the extra information into the XML document
by applying an XSL transform.
It then submits the transformed order for fulfillment by invoking
the Sales Order System's Web Service interface.
Interfaces
Input
Document schema
The input document is a string containing an XML document that conforms to the
following XML Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://www.def.com/2004/intranet/webstore">
<xsd:element name="web-order">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="header">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="userid" type="xsd:NMTOKEN"/>
<xsd:element name="datetime" type="xsd:dateTime"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="items">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="unbounded" name="item">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="sku" type="xsd:string"/>
<xsd:element name="qty" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Functions
available from scripting language
Map
createMap(IN STRING key, IN STRING value)
Procedures
lookupAccount(IN
STRING userId, OUT STRING accountNumber)
transform(IN
Document input, OUT Document output, IN STRING transformURI, IN Map
parms)
XSL
transform
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:in="http://www.def.com/2004/intranet/webstore"
xmlns="http://www.def.com/2004/pub/sales">
<xsl:output method="xml"/>
<!-- The user's account number, passed in as a parameter. -->
<xsl:param name="account-number"/>
<xsl:template match="in:order">
<xsl:element name="sales-order">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="in:userid">
<xsl:element name="account-number">
<xsl:value-of select="$account-number" disable-output-escaping="yes"/>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:transform>
Web Service Description
The Sales Order Processing system has a Web Service interface defined by the
following WSDL:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://www.def.com/2004/pub/sales"
xmlns:impl="http://www.def.com/2004/pub/sales"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema targetNamespace="http://www.def.com/2004/pub/sales"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:element
name="sales-order">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="header">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="account-number" type="xsd:string"/>
<xsd:element
name="datetime" type="xsd:dateTime"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="items">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="unbounded"
name="item">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="sku" type="xsd:string"/>
<xsd:element
name="qty" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="raiseOrderRequest">
<wsdl:part
name="order" element="impl:sales-order"/>
</wsdl:message>
<wsdl:portType name="SalesOrdersPortType">
<wsdl:operation
name="raiseOrder" parameterOrder="order">
<wsdl:input
name="raiseOrderRequest" message="impl:raiseOrderRequest"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding
name="SalesOrdersPortSoapBinding" type="impl:SalesOrdersPortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation
name="raiseOrder">
<soap:operation
soapAction="http://www.def.com/sales/raiseOrder"/>
<wsdl:input
name="raiseOrderRequest">
<soap:body
namespace="http://www.def.com/2004/pub/sales" use="literal"/>
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
<wsdl:service
name="SalesOrders">
<wsdl:port name="SalesOrdersPort"
binding="impl:SalesOrdersPortSoapBinding">
<soap:address
location="http://localhost:8080/obeexamples/services/SalesOrders"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Hints
-
Incorporate
the input schema into the XPDL as a user-defined
<xpdl:SchemaType>
.
-
Declare
a
STRING
accountNumber <
xpdl:
DataField>
to
hold the result of lookupAccount()
.
-
Assume
the XSL transform is available through the URI
web-sales-order.xsl
.
-
Create
user-defined types:
-
Document
::= java:org.w3c.dom.Document
-
Map
::= java:java.util.Map
-
Assume
that the workflow can access the WSDL document by appending
?wsdl
to the Web Service's SOAP endpoint address.
-
Declare
the Web Service as an
<
xpdl:
Application>
defined by an <xpdl:ExternalReference>
:
-
location
= WSDL URI
-
namespace
= target namespace URI
-
xref
= WSDL operation name
-
The
workflow should run 'straight through' to completion in a single
transaction and should not require any human intervention.
Solution
Process
Model Description
- The workflow is triggered by the
DEFWebOrderReceived
event (defined in
$OBE_HOME/examples/config/BasicApplicationEvent.xml
). Notice the
<xpdl:ExtendedAttribute name="obe.Event">
element attached to the <WorkflowProcess>
below:
see how it initializes the mandatory
1 order
process attribute from the event by
specifying it as an OUT parameter of the event.
- The Lookup Account activity invokes the
lookupAccount()
procedure. It extracts the User ID
from the order document with the XPath expression
string($order/defws:web-order/defws:header/defws:userid)
and
passes it to the procedure as an IN parameter. The
accountNum
process attribute is set from the procedure's result
by specifying it as an OUT parameter.
- The Transform Data activity invokes the
obe.transform
procedure, passing a reference to the XSL transform
shown above. The transform resides in the
web-sales-order.xsl
file stored in the ResourceRepository (see
$OBE_HOME/examples/config/
BasicResourceRepository.xml
and the
$OBE_HOME/examples/config/resources
directory). The
transformed document is stored in the salesOrder
process
attribute (once again, the receiving attribute is passed as an OUT
parameter).
- The Submit Order activity passes the sales
order to the
submitOrder
Web Service, which is described by
the submitOrder
tool with an <xpdl:ExternalReference>
to the Web Service endpoint URL:
http://localhost:8080/obeexamples/services/SalesOrdersPort?wsdl
XPDL Process Model
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://www.wfmc.org/2002/XPDL1.0" xmlns:xpdl="http://www.wfmc.org/2002/XPDL1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:obe="http://obe.sourceforge.net/2005/OBE1.0" xmlns:defws="http://www.def.com/2004/intranet/webstore"
Id="eai" Name="EAI Data Transformation" xsi:schemaLocation="http://www.wfmc.org/2002/XPDL1.0 xpdl-1.0.xsd">
<PackageHeader>
<XPDLVersion>1.0</XPDLVersion>
<Vendor>Open Business Engine</Vendor>
<Created>2004-08-08T21:26:45+0100</Created>
</PackageHeader>
<RedefinableHeader PublicationStatus="UNDER_TEST"/>
<ConformanceClass GraphConformance="NON_BLOCKED"/>
<Script Type="text/x-xpath"/>
<TypeDeclarations>
<TypeDeclaration Id="WebOrder" Name="Web Store Order">
<ExternalReference location="web-order.xsd" xref="order"
namespace="http://www.def.com/2004/intranet/webstore"/>
<Description>This is the order type generated by the internal Web Store portal.</Description>
</TypeDeclaration>
<TypeDeclaration Id="SalesOrder" Name="SalesOrder">
<ExternalReference
location="http://sales.def.com:8080/axis/services/OrderService?wsdl"
xref="SalesOrderType" namespace="http://www.def.com/2004/pub/sales"/>
<Description>This is the type of the Sales Order document accepted by the Sales Order Management system.</Description>
</TypeDeclaration>
<TypeDeclaration Id="Document" Name="XML Document">
<ExternalReference location="java:org.w3c.dom.Document"/>
</TypeDeclaration>
<TypeDeclaration Id="Map" Name="Java Map">
<ExternalReference location="java:java.util.Map"/>
<Description>This type represents the Java2 Map interface.</Description>
</TypeDeclaration>
</TypeDeclarations>
<WorkflowProcesses>
<WorkflowProcess Id="eai" Name="EAI Data Transformation" AccessLevel="PRIVATE">
<ProcessHeader DurationUnit="D">
<Created>2004-08-08T21:28:00+0100</Created>
<Description>
This workflow exemplifies straight-through processing, EAI (Enterprise Application Integration), and
data transformation.
</Description>
</ProcessHeader>
<RedefinableHeader PublicationStatus="UNDER_TEST"/>
<FormalParameters>
<FormalParameter Id="order" Mode="IN">
<DataType>
<DeclaredType Id="WebOrder"/>
</DataType>
</FormalParameter>
</FormalParameters>
<DataFields>
<DataField Id="accountNumber" Name="Account Number">
<DataType>
<BasicType Type="STRING"/>
</DataType>
<Description>The user's internal account number.</Description>
</DataField>
<DataField Id="salesOrder" Name="Sales Order">
<DataType>
<DeclaredType Id="Document"/>
</DataType>
</DataField>
<DataField Id="int">
<DataType>
<BasicType Type="INTEGER"/>
</DataType>
</DataField>
<DataField Id="bool">
<DataType>
<BasicType Type="BOOLEAN"/>
</DataType>
</DataField>
<DataField Id="date">
<DataType>
<BasicType Type="DATETIME"/>
</DataType>
</DataField>
</DataFields>
<Applications>
<Application Id="lookupAccount" Name="Lookup Account Number">
<Description>Finds the internal Web Store account number for the specified employee.</Description>
<FormalParameters>
<FormalParameter Id="userID" Mode="IN">
<DataType>
<BasicType Type="STRING"/>
</DataType>
<Description>The employee's user ID.</Description>
</FormalParameter>
<FormalParameter Id="accountNumber" Mode="OUT">
<DataType>
<BasicType Type="STRING"/>
</DataType>
<Description>The employee's Web Store account number.</Description>
</FormalParameter>
</FormalParameters>
</Application>
<Application Id="obe.transform" Name="Transform XML Document">
<Description>This procedure transforms an XML document using an XSL transform.</Description>
<FormalParameters>
<FormalParameter Id="in" Mode="IN">
<DataType>
<DeclaredType Id="Document"/>
</DataType>
<Description>The input XML document, represented as a W3C DOM node.</Description>
</FormalParameter>
<FormalParameter Id="transformUri" Mode="IN">
<DataType>
<BasicType Type="STRING"/>
</DataType>
<Description>This is the URI of the XSL transform to apply</Description>
</FormalParameter>
<FormalParameter Id="parameters" Mode="IN">
<DataType>
<DeclaredType Id="Map"/>
</DataType>
<Description>A map of input parameters, keyed on name.</Description>
</FormalParameter>
<FormalParameter Id="out" Mode="OUT">
<DataType>
<DeclaredType Id="Document"/>
</DataType>
<Description>The transformed XML document, represented as a W3C DOM node.</Description>
</FormalParameter>
</FormalParameters>
</Application>
<Application Id="submitOrder" Name="Submit Order">
<Description>
Submits a sales order to the Web Service entry point for the Sales Order Handling System.
</Description>
<ExternalReference location="http://localhost:8080/obeexamples/services/SalesOrdersPort?wsdl"
xref="raiseOrder" namespace="http://www.def.com/2004/pub/sales"/>
</Application>
</Applications>
<Activities>
<Activity Id="lookupAccNum" Name="Lookup Account Number">
<Implementation>
<Tool Id="lookupAccount" Type="PROCEDURE">
<ActualParameters>
<ActualParameter>string($order/defws:web-order/defws:header/defws:userid)</ActualParameter>
<ActualParameter>accountNumber</ActualParameter>
</ActualParameters>
<Description>
Extract the user ID from the inbound document and look up that user's internal account number.
</Description>
</Tool>
</Implementation>
<StartMode>
<Automatic/>
</StartMode>
<FinishMode>
<Automatic/>
</FinishMode>
<ExtendedAttributes>
<ExtendedAttribute Name="ParticipantID" Value="FreeTextExpressionParticipant"/>
<ExtendedAttribute Name="XOffset" Value="170"/>
<ExtendedAttribute Name="YOffset" Value="50"/>
<ExtendedAttribute Name="obe.Bounds">
<obe:Bounds x="41" y="48" width="140" height="50"/>
</ExtendedAttribute>
</ExtendedAttributes>
</Activity>
<Activity Id="transform" Name="Transform Data">
<Implementation>
<Tool Id="obe.transform" Type="PROCEDURE">
<ActualParameters>
<ActualParameter>$order</ActualParameter>
<ActualParameter>'web-sales-order.xsl'</ActualParameter>
<ActualParameter>def:createMap('account-number', $accountNumber)</ActualParameter>
<ActualParameter>salesOrder</ActualParameter>
</ActualParameters>
<Description>
Transforms the order document from the web store into the format required by the
Sales Order Handling System.
</Description>
</Tool>
</Implementation>
<StartMode>
<Automatic/>
</StartMode>
<FinishMode>
<Automatic/>
</FinishMode>
<ExtendedAttributes>
<ExtendedAttribute Name="ParticipantID" Value="FreeTextExpressionParticipant"/>
<ExtendedAttribute Name="XOffset" Value="310"/>
<ExtendedAttribute Name="YOffset" Value="50"/>
<ExtendedAttribute Name="obe.Bounds">
<obe:Bounds x="287" y="49" width="140" height="50"/>
</ExtendedAttribute>
</ExtendedAttributes>
</Activity>
<Activity Id="submitOrder" Name="submit Order">
<Implementation>
<Tool Id="submitOrder" Type="PROCEDURE">
<ActualParameters>
<ActualParameter>$salesOrder</ActualParameter>
</ActualParameters>
<Description>
Invokes the Sales Order Processing System's Web Service to submit the order.
</Description>
</Tool>
</Implementation>
<StartMode>
<Automatic/>
</StartMode>
<FinishMode>
<Automatic/>
</FinishMode>
<ExtendedAttributes>
<ExtendedAttribute Name="ParticipantID" Value="FreeTextExpressionParticipant"/>
<ExtendedAttribute Name="XOffset" Value="440"/>
<ExtendedAttribute Name="YOffset" Value="50"/>
<ExtendedAttribute Name="obe.Bounds">
<obe:Bounds x="544" y="50" width="140" height="50"/>
</ExtendedAttribute>
</ExtendedAttributes>
</Activity>
</Activities>
<Transitions>
<Transition Id="eai_Tra2" From="lookupAccNum" To="transform" Name="Transition">
<ExtendedAttributes>
<ExtendedAttribute Name="RoutingType" Value="NOROUTING"/>
</ExtendedAttributes>
</Transition>
<Transition Id="eai_Tra3" From="transform" To="submitOrder" Name="Transition">
<ExtendedAttributes>
<ExtendedAttribute Name="RoutingType" Value="NOROUTING"/>
</ExtendedAttributes>
</Transition>
</Transitions>
<ExtendedAttributes>
<ExtendedAttribute Name="obe.Event">
<obe:Event Id="DEFWebOrderReceived">
<xpdl:ActualParameters>
<xpdl:ActualParameter>order</xpdl:ActualParameter>
</xpdl:ActualParameters>
</obe:Event>
</ExtendedAttribute>
<ExtendedAttribute Name="StartOfWorkflow" Value="FreeTextExpressionParticipant;lookupAccNum;60;50;NOROUTING"/>
<ExtendedAttribute Name="EndOfWorkflow" Value="FreeTextExpressionParticipant;submitOrder;580;50;NOROUTING"/>
<ExtendedAttribute Name="ParticipantVisualOrder" Value="FreeTextExpressionParticipant;"/>
</ExtendedAttributes>
</WorkflowProcess>
</WorkflowProcesses>
<ExtendedAttributes>
<ExtendedAttribute Name="MadeBy" Value="JaWE"/>
<ExtendedAttribute Name="Version" Value="1.2"/>
</ExtendedAttributes>
</Package>
Solution Files
See the solution files under $OBE_HOME/examples
:
config/processes/eai.xpdl
config/
resources/web-sales-order.xsl
config/
resources/
order.xsd
config/
resources/sales-
order.xsd
config/
resources/sales-
order.wsdl
config/BasicFunctionRepository.xm
l
config/
BasicToolAgentFactory.xml
etc/DataTransformation/web-order1.xml
src/com/def/webstore/DEFFunctions.java
src/com/def/webstore/DEFProcedures.java
Deployment and Execution
The eai
workflow supports both manual and triggered start.
- Deploy the eai
.xpdl
package.
- Start a workflow instance by either:
- Instantiating an instance of the
eai
workflow from the
Worklist client.
- When prompted, uploading an XML order that conforms to the
$OBE_HOME/examples/config/resources/web-order.xsd
schema,
such as $OBE_HOME/examples/etc/DataTransformation/
web-order1.xml
.
- or
- Open a console window and navigate to the
$OBE_HOME/examples/etc/DataTransformation
directory.
- Execute the command:
send web-order1.xml
- In either case, enable
logging to observe in-flight process activity, or use a worklist
client or the
cladmin
tool to probe process instances.
1 Mandatory, because the
order
attribute appears as a <FormalParameter>
of
the <WorkflowProcess>
, meaning that it must be assigned a
value before a newly created process instance can be started.