Skip Headers
Oracle® BPEL Process Manager Developer's Guide
10g (10.1.3.1.0)

Part Number B28981-03
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

3 Manipulating XML Data in BPEL

This chapter describes how to manipulate XML data in BPEL, including the use of XPath expressions.

This chapter contains the following topics:

3.1 Use Cases for Manipulating XML Data in BPEL

This chapter covers a variety of use cases for manipulating XML data. Topics include how to work with variables, sequences, and arrays, and how to perform tasks such as mathematical calculations. The explanations are largely by example, and provide an introduction to the supported specifications.

Most of the examples in this chapter assume that the WSDL file defining the associated message types is document-literal style rather than the RPC style. There is a difference in how XPath query strings are formed for RPC-style WSDL definitions. If you are working with a type defined in an RPC WSDL file, see "Differences Between Document-Style and RPC-Style WSDL Files".

See Also:

The sample files located at
  • SOA_Oracle_Home\bpel\samples\tutorials\103.XMLDocuments

3.2 Overview of Manipulating XML Data in BPEL Concepts

This section covers the following topics:

3.2.1 How XML Data Works in BPEL

In a BPEL process, every piece of data is in XML forms. This includes the messages passed to and from the BPEL process, the messages exchanged with external services, and local variables used by the process. You define the types for these messages and variables with the XML schema, usually in the WSDL file for the flow, the WSDL files for the services it invokes, or the XSD file referenced by those WSDL files. Therefore, all variables in BPEL are XML data, and any BPEL process uses much of its code to manipulate these XML variables. This typically includes performing data transformation between representations required for different services, and local manipulation of data (for example, to combine the results from several service invocations).

3.2.2 About Data Manipulation and XPath Standards

The starting point for data manipulation in BPEL is the assign activity, which builds on the XPath standard. XPath queries, expressions, and functions play a large part in this type of manipulation. In addition, more advanced methods are available that involve using XQuery, XSLT, or Java, usually to do more complex data transformation or manipulation.

This section provides a general overview of how to manipulate XML data in BPEL. It summarizes the key building blocks used in various combinations and provides examples. The remaining sections in this chapter discuss and illustrate how to apply these building blocks to perform specific tasks.You use the assign activity to copy data from one XML variable to another, or to calculate the value of an expression and store it in a variable. A copy element within the activity specifies the source and target of the assignment (what to copy from and to), which must be of compatible types. The formal syntax as shown in the Business Process Execution Language for Web Services Specification is as follows:

<assign standard-attributes>
   standard-elements
   <copy>+
      from-spec
      to-spec
   </copy>
</assign>

This syntax is described in detail in that specification. The from-spec and to-spec typically specify a variable or variable part, as in:

<assign>
   <copy>
      <from variable="c1" part="address"/>
      <to variable="c3"/>
   </copy>
</assign>

When you use Oracle JDeveloper, you supply assign activity details in a Copy Operation window that includes a From section and a To section. This reflects the preceding BPEL source code syntax.

Rather than repeating all syntax details, this chapter shows and describes excerpts taken primarily from sample projects provided in the SOA_Oracle_Home\bpel\samples\references directory.

XPath standards play a key role in the assign activity. Brief examples are shown here as an introduction; examples with more context and explanation are provided in the sections that follow.

  • XPath queries: An XPath query selects a field within a source or target variable part. The from or to clause can include a query attribute whose value is an XPath query string. For example:

    <from variable="input" part="payload"
          query="/p:CreditFlowRequest/p:ssn"/>
    
    

    For XPath version 1.0, the value of the query attribute must be a location path that selects exactly one node. You can find further details about the query attribute and XPath standards syntax in the Business Process Execution Language for Web Services Specification (section 14.3) and the XML Path Language (XPath) Specification, respectively.

  • XPath expressions: You use an XPath expression (specified in an expression attribute in the from clause) to indicate a value to be stored in a variable. For example:

    <from expression="100"/>
    
    

    The expression can be any general expression—that is, an XPath expression that evaluates to any XPath value type. For more information about XPath expressions, see section 9.1.4 of the XML Path Language (XPath) Specification.

Within XPath expressions, you can call the following types of functions:

  • Core XPath functions: XPath supports a large number of built-in functions, including functions for string manipulation (such as concat), numeric functions (like sum), and others.

    <from expression="concat('string one', 'string two')"/>
    
    

    For a complete list of the functions built into XPath standards, see section 4 of the XML Path Language (XPath) Specification.

  • BPEL XPath extension functions: BPEL adds several extension functions to the core XPath core functions, enabling XPath expressions to access information from a process. The extensions are defined in the standard BPEL namespace http://schemas.xmlsoap.org/ws/2003/03/business-process/ and indicated by the prefix bpws:

    <from expression= "bpws:getVariableData('input', 'payload', '/p:value') + 1"/>
    
    

    For more information, see sections 9.1 and 14.1 of the Business Process Execution Language for Web Services Specification.

  • Oracle BPEL XPath extension functions: Oracle provides some additional XPath functions that use the capabilities built into BPEL and XPath standards for adding new functions.

    These functions are defined in the namespace http://schemas.oracle.com/xpath/extension and indicated by the prefix ora:.

  • Custom functions: You can also create custom XPath functions. If you do, you must register them in the BPEL process deployment descriptor or in the following XML files:

    • SOA_Oracle_Home\bpel\system\config\xpath-functions.xml (system level)

    • SOA_Oracle_Home\bpel\domains\default\config\xpath-functions.xml (domain level)

    Then, package the source implementing them into a BPEL suitcase or Oracle BPEL Process Manager startup environment. For more information about writing custom XPath functions, refer to: http://www.oracle.com/technology/bpel

Sophisticated data manipulation can be difficult to perform with the BPEL assign activity and the core XPath functions. However, you can perform complex data manipulation and transformation by using XSLT, Java, or a bpelx operation under an assign activity (See "Manipulating XML Data with bpelx Extensions"), or as a Web service. For more information on calling Java code from within BPEL, see the tutorial under the BPEL Tutorials link at http://www.oracle.com/technology/bpel. For XSLT, Oracle BPEL Process Manager includes XPath functions that execute these transformations.

See Also:

The following XPath and XQuery transformation code examples:

The following sections show related definitions in the BPEL and WSDL files that help explain the examples.

3.3 Initializing a Variable with Expression Constants or Literal XML

It is often useful to assign literal XML to a variable in BPEL, for example, to initialize a variable before copying dynamic data into a specific field within the XML data content for the variable. This is also useful for testing purposes when you want to hard code XML data values into the process.

This example assigns a literal result element to the payload part of the output variable:

<assign>
   <!-- copy from literal xml to the variable -->
   <copy>
      <from>
         <result xmlns="http://samples.otn.com">
            <name/>
            <symbol/>
            <price>12.3</price>
            <quantity>0</quantity>
            <approved/>
            <message/>
         </result>
      </from>
      <to variable="output" part="payload"/>
   </copy>
</assign>

See Also:

The following samples:
  • SOA_Oracle_Home\bpel\samples\references\Assign

3.4 Copying Between Variables

When you copy between variables, you copy directly from one variable (or part) to another variable of a compatible type, without needing to specify a particular field within either variable. In other words, there is no need to specify an XPath query.The following example performs two assignments, first copying between two variables of the same type and then copying a variable part to another variable with the same type as that part.

<assign>
   <copy>
      <from variable="c1"/>
      <to variable="c2"/>
   </copy>
   <copy>
      <from variable="c1" part = "address"/>
      <to variable="c3"/>
   </copy>
</assign>

The BPEL file defines the variables as follows:

<variable name="c1" messageType="x:person"/>
<variable name="c2" messageType="x:person"/>
<variable name="c3" element="x:address"/>

The WSDL file defines the person message type as follows:

<message name="person" xmlns:x="http://tempuri.org/bpws/example">
   <part name="full-name" type="xsd:string"/>
   <part name="address" element="x:address"/>
</message>

See Also:

Section 9.3.2 of the Business Process Execution Language for Web Services Specification for this code example

3.5 Accessing Fields Within Element-Based and Message Type-Based Variables

Given the types of definitions present in most WSDL and XSD files, you must go down to the level of copying from or to a field within part of a variable based on the element and message type, which in turn uses XML schema complex types. To do this, you specify an XPath query in the from or to clause of the assign activity.

This example copies the ssn field from the CreditFlow process's input message into the ssn field of the credit rating service's input message.

<assign>
   <copy>
      <from variable="input" part="payload"
         query="/tns:CreditFlowRequest/tns:ssn"/>
      <to variable="crInput" part="payload" query="/tns:ssn"/>
   </copy>
</assign>

The BPEL file defines the variables involved in this assignment as follows:

<variable name="input" messageType="tns:CreditFlowRequestMessage"/>
<variable name="crInput"
          messageType="services:CreditRatingServiceRequestMessage"/>

The crInput variable is used as an input message to a credit rating service. Its message type, CreditFlowRequestMessage, is defined in CreditFlowService.wsdl as follows:

<message name="CreditFlowRequestMessage">
<part name="payload" element="tns:CreditFlowRequest"/>
</message>

CreditFlowRequest is defined with a field named ssn. The message type CreditRatingServiceRequestMessage is defined in CreditRatingService.wsdl as follows:

<message name="CreditRatingServiceRequestMessage">
   <part name="payload" element="tns:ssn"/>
</message>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\utils\CreditRatingService

3.6 Assigning Numeric Values

You can assign numeric values in XPath expressions. The following example shows how to assign an XPath expression with the integer value 100.

<assign>
   <!-- copy from integer expression to the variable -->
   <copy>
      <from expression="100"/>
      <to variable="output" part="payload" query="/p:result/p:quantity"/>
   </copy>
</assign>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\Assign

3.7 Mathematical Calculations with XPath Standards

You can use simple mathematical expressions like the one in the following example, which increments a numeric value.

In this example, the BPEL XPath function getVariableData retrieves the value being incremented. The arguments to getVariableData are equivalent to the variable, part, and query attributes of the from clause (including the last two arguments, which are optional).

<assign>
   <copy>
      <from expression="bpws:getVariableData('input', 'payload',
          '/p:value') + 1"/>
      <to variable="output" part="payload" query="/p:result"/>
   </copy>
</assign>

You can also use $variable syntax:

<assign>
  <copy>
    <from expression="$input.payload + 1"/>
    <to variable="output" part="payload" query="/p:result"/>
  </copy>
</assign>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\Assign

3.8 Assigning String Literals

This example copies an expression evaluating from the string literal 'GE' to the symbol field within the indicated variable part. (Note the use of the double and single quotes.)

<assign>
   <!-- copy from string expression to the variable -->
   <copy>
      <from expression="'GE'"/>
      <to variable="output" part="payload" query="/p:result/p:symbol"/>
   </copy>
</assign>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\Assign

3.9 Concatenating Strings

Rather than copy the value of one string variable (or variable part or field) to another, you first can perform string manipulation, such as concatenating several strings together. An example is shown in the following syntax. The concatenation is accomplished with the core XPath function named concat; in addition, the variable value involved in the concatenation is retrieved with the BPEL XPath function getVariableData.

In this example, getVariableData fetches the value of the name field from the input variable's payload part. The string literal 'Hello ' is then concatenated to the beginning of this value.

<assign>
   <!-- copy from XPath expression to the variable -->
   <copy>
      <from expression="concat('Hello ',
         bpws:getVariableData('input', 'payload', '/p:name'))"/>
      <to variable="output" part="payload" query="/p:result/p:message"/>
   </copy>
</assign>

Other string manipulation functions available in XPath are listed in section 4.2 of the XML Path Language (XPath) Specification.

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\Assign

3.10 Assigning Boolean Values

In this example of assigning Boolean values, the XPath expression in the from clause is a call to XPath's Boolean function true, and the specified approved field is set to true. The function false is also available.

<assign>
   <!-- copy from boolean expression function to the variable -->
   <copy>
      <from expression="true()"/>
      <to variable="output" part="payload" query="/result/approved"/>
   </copy>
</assign>

The XPath specification recommends that you use the "true()" and "false()" functions as a method for returning Boolean constant values.

If you instead use "boolean(true)" or "boolean(false)", the true or false inside the Boolean function is interpreted as a relative element step, and not as any true or false constant. This means it attempts to select a child node named true under the current XPath context node. In most cases, the true node does not exist. Therefore, an empty result node set is returned and the boolean() function in XPath 1.0 converts an empty node set into a false result. This result can be potentially confusing.

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\Assign

3.11 Assigning Date or Time

You can assign the current value of a date or time field by using the Oracle BPEL XPath function getCurrentDate, getCurrentTime, or getCurrentDateTime, respectively. In addition, if you have a date-time value in the standard XSD format, you can convert it to characters more suitable for output by calling the Oracle BPEL XPath function formatDate.For related information, see section 9.1.2 of the Business Process Execution Language for Web Services Specification.

<!-- execute the XPath extension function getCurrentDate() -->
<assign>
   <copy>
      <from expression="ora:getCurrentDate()"/>
      <to variable="output" part="payload"
         query="/invoice/invoiceDate"/>
   </copy>
</assign>

In the next example, the formatDate function converts the date-time value provided in XSD format to the string 'Jun 10, 2005' (and assigns it to the string field formattedDate).

<!-- execute the XPath extension function formatDate() -->
<assign>
   <copy>
      <from expression="ora:formatDate('2005-06-10T15:56:00',
         'MMM dd, yyyy')"/>
      <to variable="output" part="payload"
         query="/invoice/formattedDate"/>
   </copy>
</assign>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\XPathFunction

3.12 Manipulating Attributes

You may want to copy to or from something defined as an XML attribute. An at sign (@) in XPath query syntax refers to an attribute instead of a child element.

The following code example fetches and copies the custId attribute from this XML data:

<invalidLoanApplication xmlns="http://samples.otn.com">
      <application xmlns = "http://samples.otn.com/XPath/autoloan">
         <customer custId = "111" >
            <name>
               Mike Olive
            </name>
            ...
         </customer>
         ...
      </application>
   </invalidLoanApplication>

The following example selects the custId attribute of the customer field and assigns it to the variable custId:

<assign>
   <!-- get the custId attribute and assign to variable custId -->
   <copy>
      <from variable="input" part="payload"
         query="/tns:invalidLoanApplication/autoloan:application
                /autoloan:customer/@custId"/>
      <to variable="custId"/>
   </copy>
</assign>

The namespace prefixes in this example are not integral to the example.The WSDL file defines a customer to have a type in which custId is defined as an attribute, as follows:

<complexType name="CustomerProfileType">
   <sequence>
      <element name="name" type="string"/>
      ...
   </sequence>
   <attribute name="custId" type="string"/>
</complexType>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\XPath

3.13 Manipulating XML Data with bpelx Extensions

You may want to perform various operations on XML data in assign activities. The following bpelx extension types provide this functionality:

3.13.1 bpelx:append

The bpelx:append extension in an assign activity enables a BPEL process to append the contents of one variable, expression, or XML fragment to another variable's contents.

<bpel:assign> 
   <bpelx:append>
      <bpelx:from ... /> 
      <bpelx:to ... /> 
   </bpelx:append> 
</bpel:assign> 

The from-spec query within bpelx:append yields zero or more nodes. The node list is appended as child nodes to the target node specified by the to-spec query.

The to-spec query must yield one single L-Value element node. Otherwise, a bpel:selectionFailure fault is generated. The to-spec query cannot refer to a partner link.

The following example consolidates multiple bills of material into one single bill of material by appending multiple b:part's for one BOM to b:parts of the consolidated BOM.

<bpel:assign>
    <bpelx:append>
          <from variable="billOfMaterialVar" 
                query="/b:bom/b:parts/b:part" />
          <to variable="consolidatedBillOfMaterialVar"
                query="/b:bom/b:parts" />
    </bpelx:append> 
</bpel:assign>

3.13.2 bpelx:insertBefore

The bpelx:insertBefore extension in an assign activity enables a BPEL process to insert the contents of one variable, expression, or XML fragment before another variable's contents.

<bpel:assign> 
   <bpelx:insertBefore>
      <bpelx:from ... /> 
      <bpelx:to ... /> 
   </bpelx:insertBefore> 
</bpel:assign>

The from-spec query within bpelx:insertBefore yields zero or more nodes. The node list is appended as child nodes to the target node specified by the to-spec query.

The to-spec query of the insertBefore operation points to one or more single L-Value nodes. If more than one node is returned, the first node is used as the reference node. The reference node must be an element node. The parent of the reference node must also be an element node. Otherwise, a bpel:selectionFailure fault is generated. The node list generated by the from-spec query selection is inserted before the reference node. The to-spec query cannot refer to a partner link.

The following example shows the syntax before the execution of <insertBefore>. The value of addrVar is:

<a:usAddress>
       <a:state>CA</a:state>
       <a:zipcode>94065</a:zipcode> 
</a:usAddress> 

After the execution of the following syntax in the BPEL process file:

<bpel:assign>
    <bpelx:insertBefore>
        <bpelx:from>
             <a:city>Redwood Shore></a:city>
        </bpelx:from> 
        <bpelx:to "addrVar" query="/a:usAddress/a:state" /> 
    </bpelx:insertBefore> 
</bpel:assign> 

The value of addrVar now becomes:

<a:usAddress>
       <a:city>Redwood Shore</a:city>
       <a:state>CA</a:state>
       <a:zipcode>94065</a:zipcode> 
</a:usAddress> 

3.13.3 bpelx:insertAfter

The bpelx:insertAfter extension in an assign activity enables a BPEL process to insert the contents of one variable, expression, or XML fragment after another variable's contents.

<bpel:assign> 
    <bpelx:insertAfter>
       <bpelx:from ... /> 
       <bpelx:to ... /> 
    </bpelx:insertAfter> 
</bpel:assign>

This operation is similar to the functionality described for "bpelx:insertBefore", except for the following:

  • If multiple L-Value nodes are returned by the to-spec query, the last node is used as the reference node.

  • Instead of inserting nodes before the reference node, the source nodes are inserted after the reference node.

This operation can also be considered a macro of conditional-switch + (append or insertBefore).

The following example shows the syntax before the execution of <insertAfter>. The value of addrVar is:

<a:usAddress>
       <a:addressLine>500 Oracle Parkway</a:addressLine> 
       <a:state>CA</a:state>
       <a:zipcode>94065</a:zipcode> 
</a:usAddress>

After execution of the following syntax in the BPEL process file:

<bpel:assign>
    <bpelx:insertAfter>
        <bpelx:from>
             <a:addressLine>Mailstop 1op6</a:addressLine>
        </bpelx:from> 
        <bpelx:to "addrVar" query="/a:usAddress/a:addressLine[1]" /> 
    </bpelx:insertAfter> 
</bpel:assign> 

The value of addrVar becomes:

<a:usAddress>
       <a:addressLine>500 Oracle Parkway</a:addressLine> 
       <a:addressLine>Mailstop 1op6</a:addressLine>
       <a:state>CA</a:state>
       <a:zipcode>94065</a:zipcode> 
</a:usAddress>

The from-spec query within bpelx:insertAfter yields zero or more nodes. The node list is appended as child nodes to the target node specified by the to-spec query.

3.13.4 bpelx:remove

The bpelx:remove extension in an assign activity enables a BPEL process to remove a variable.

<bpel:assign> 
    <bpelx:remove>
       <bpelx:target variable="ncname" part="ncname"? query="xpath_str" />
    </bpelx:append> 
</bpel:assign>

Node removal specified by the XPath expression is supported. Nodes specified by the XPath expression can be multiple, but must be L-Values. Nodes being removed from this parent can be text nodes, attribute nodes, and element nodes.

The XPath expression can return one or more nodes. If the XPath expression returns zero nodes, then a bpel:selectionFailure fault is generated.

The syntax of bpelx:target is similar to and a subset of to-spec for the copy operation.

The following example shows addrVar with the following value:

<a:usAddress>
       <a:addressLine>500 Oracle Parkway</a:addressLine> 
       <a:addressLine>Mailstop 1op6</a:addressLine>
       <a:state>CA</a:state>
       <a:zipcode>94065</a:zipcode> 
</a:usAddress>

After executing the following syntax in the BPEL process file, the second address line of Mailstop is removed:

<bpel:assign>
    <bpelx:remove>
        <target variable="addrVar" 
            query="/a:usAddress/a:addressLine[2]" />
    </bpelx:remove> 
</bpel:assign> 

After executing the following syntax in the BPEL process file, both address lines are removed:

<bpel:assign>
    <bpelx:remove>
        <target variable="addrVar" 
            query="/a:usAddress/a:addressLine" />
    </bpelx:remove> 
</bpel:assign>

3.13.5 bpelx:rename and XSD Type Casting

The bpelx:rename extension in an assign activity enables a BPEL process to rename an element through use of XSD type casting.

<bpel:assign>
    <bpelx:rename elementTo="QName1"? typeCastTo="QName2"?>
       <bpelx:target variable="ncname" part="ncname"? query="xpath_str" />
    </bpelx:rename> 
</bpel:assign>

The syntax of bpelx:target is similar to and a subset of to-spec for the copy operation. The target must return a list of one more element nodes. Otherwise, a bpel:selectionFailure fault is generated. The element nodes specified in the from-spec are renamed the QName specified by the elementTo attribute. The xsi:type attribute is added to those element nodes to cast those elements to the QName type specified by the typeCastTo attribute.

Assume you have the following employee list:

<e:empList>
    <e:emp>
        <e:firstName>John</e:firstName><e:lastName>Dole</e:lastName>
    <e:emp>
    <e:emp xsi:type="e:ManagerType">
        <e:firstName>Jane</e:firstName><e:lastName>Dole</e:lastName>
        <e:approvalLimit>3000</e:approvalLimit>
        <e:managing /> 
    <e:emp>
    <e:emp>
        <e:firstName>Peter</e:firstName><e:lastName>Smith</e:lastName>
    <e:emp>
    <e:emp>
        <e:firstName>Mary</e:firstName><e:lastName>Smith</e:lastName>
    <e:emp>
</e:empList>

Promotion changes are now applied to Peter Smith in the employee list:

<bpel:assign>
    <bpelx:rename typeCastTo="e:ManagerType">
       <bpelx:target variable="empListVar" 
            query="/e:empList/e:emp[./e:firstName='Peter' and
 ./e:lastName='Smith'" />
    </bpelx:rename> 
</bpel:assign>

After executing the above casting (renaming), the data looks as follows with xsi:type info added to Peter Smith:

<e:empList>
    <e:emp>
        <e:firstName>John</e:firstName><e:lastName>Dole</e:lastName>
    <e:emp>
    <e:emp xsi:type="e:ManagerType">
        <e:firstName>Jane</e:firstName><e:lastName>Dole</e:lastName>
        <e:approvalLimit>3000</e:approvalLimit>
        <e:managing /> 
    <e:emp>
    <e:emp xsi:type="e:ManagerType">
        <e:firstName>Peter</e:firstName><e:lastName>Smith</e:lastName>
    <e:emp>
    <e:emp>
        <e:firstName>Mary</e:firstName><e:lastName>Smith</e:lastName>
    <e:emp>
</e:empList>

The employee data of Peter Smith is now invalid, because <approvalLimit> and <managing> are missing. Therefore, <append> is used to add that information.

<bpel:assign>
    <bpelx:rename typeCastTo="e:ManagerType">
       <bpelx:target variable="empListVar" 
            query="/e:empList/e:emp[./e:firstName='Peter' and
 ./e:lastName='Smith'" />
    </bpelx:rename> 
    <bpelx:append>
       <bpelx:from>
          <e:approvalLimit>2500</e:approvalLimit>
          <e:managing /> 
       </bpelx:from>
       <bpelx:to variable="empListVar" 
            query="/e:empList/e:emp[./e:firstName='Peter' and
 ./e:lastName='Smith'" />
    </bpelx:append> 
</bpel:assign>

With the execution of both rename and append, the corresponding data looks as follows:

<e:emp xsi:type="e:ManagerType">
     <e:firstName>Peter</e:firstName><e:lastName>Smith</e:lastName>
     <e:approvalLimit>2500</e:approvalLimit>
     <e:managing /> 
<e:emp>

3.13.6 bpelx:copyList

The bpelx:copyList extension in an assign activity enables a BPEL process to perform a copyList operation of the contents of one variable, expression, or XML fragment to another variable.

<bpel:assign> 
    <bpelx:copyList>
       <bpelx:from ... />
       <bpelx:to ... /> 
    </bpelx:copyList>
</bpel:assign>

The from-spec query can yield a list of either all attribute nodes or all element nodes. The to-spec query can yield a list of L-value nodes — either all attribute nodes or all element nodes.

All the element nodes returned by the to-spec query must have the same parent element. If the to-spec query returns a list of element nodes, all element nodes must be contiguous.

If the from-spec query returns attribute nodes, then the to-spec query must return attribute nodes. Likewise, if the from-spec query returns element nodes, then the to-spec query must return element nodes. Otherwise, a bpws:mismatchedAssignmentFailure fault is thrown.

The from-spec query can return zero nodes, while the to-spec query must return at least one node. If the from-spec query returns zero nodes, the effect of the copyList operation is similar to the remove operation.

The copylist operation provides the following features:

  • Removes all the nodes pointed to by the to-spec query

  • If the to-spec query returns a list of element nodes and there are leftover child nodes after removal of those nodes, the nodes returned by the from-spec query are inserted before the next sibling of the last element specified by the to-spec query. If there are no leftover child nodes, an append operation is performed.

  • If the to-spec query returns a list of attribute nodes, those attributes are removed from the parent element. Then, the attributes returned by the from-spec query are appended to the parent element.

3.14 Validating XML Data with bpelx:validate

The bpelx:validate function enables you to verify code and identify invalid XML data. Use this extension as follows:

If you want to verify the validity of XML data, set the validateXML property to true in the Manage BPEL Domain window of Oracle BPEL Control.

3.15 Manipulating XML Data Sequences That Use Arrays

Data sequences are one of the most basic data models used in XML. However, manipulating them can be nontrivial. One of the most common data sequence patterns used in BPEL processes are arrays. Based on the XML schema, the way you can identify a data sequence definition is by its attribute maxOccurs being set to a value of more than one or marked as unbounded. See the XML Schema Specification at http://www.w3.org/TR for more information.

The examples in this section illustrate several basic ways of manipulating data sequences in BPEL. However, there are other associated requirements, such as performing looping or dynamic referencing of endpoints. For additional code samples and further information regarding real-world use cases for data sequence manipulation in BPEL, see http://www.oracle.com/technology/bpel.Each of the following sections describes a particular requirement for data sequence manipulation. For a code example that describes all data sequences, see ArraySample.bpel, which takes a data sequence as input and loops through it, adding together individual line items in each data sequence element into a total value.

See Also:

The ArraySample.bpel sample file located at:
  • SOA_Oracle_Home\bpel\samples\tutorials\112.Arrays

3.15.1 Statically Indexing into an XML Data Sequence That Uses Arrays

The following two examples illustrate how to use XPath functionality to select a data sequence element when the index of the element you want is known at design time. In these cases, it is the first element.

In the following example, addresses[1] selects the first element of the addresses data sequence:

<assign>
   <!-- get the first address and assign to variable address -->
   <copy>
      <from variable="input" part="payload"
         query="/tns:invalidLoanApplication/autoloan:application
                /autoloan:customer/autoloan:addresses[1]"/>
      <to variable="address"/>
   </copy>
</assign>

In this query, addresses[1] is equivalent to addresses[position()=1], where position is one of the core XPath functions (see sections 2.4 and 4.1 of the XML Path Language (XPath) Specification). The query in the next example calls the position function explicitly to select the first element of the addresses data sequence. It then selects that address's street element (which the activity assigns to the variable street1).

<assign>
   <!-- get the first address's street and assign to street1 -->
   <copy>
      <from variable="input" part="payload"
         query="/tns:invalidLoanApplication/autoloan:application
                /autoloan:customer/autoloan:addresses[position()=1]
                /autoloan:street"/>
      <to variable="street1"/>
   </copy>
</assign>

If you review the definition of the input variable and its payload part in the WSDL file, you go several levels down before coming to the definition of the addresses field. There you see the maxOccurs="unbounded" attribute. The two XPath indexing methods are functionally identical; you can use whichever method you prefer.

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\XPath

3.15.2 Determining Sequence Size

If you need to know the run-time size of a data sequence—that is, the number of nodes or data items in the sequence—you can get it by using the combination of the XPath built-in count() function and the BPEL built-in getVariableData() function.

This example calculates the number of elements in the item sequence and assigns it to the integer variable lineItemSize:

<assign>
   <copy>
      <from expression="count(bpws:getVariableData('outpoint', 'payload',
                        '/p:invoice/p:lineItems/p:item')"/>
      <to variable="lineItemSize"/>
   </copy>
</assign>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\XPathFunction

3.15.3 Dynamically Indexing by Applying a Trailing XPath to an Expression

Often a dynamic value is needed to index into a data sequence—that is, you need to get the nth node out of a sequence, where the value of n is defined at run time. This section covers the following methods for dynamically indexing by applying a trailing XPath into expressions:

3.15.3.1 Dynamic Indexing Example

The dynamic indexing method shown here applies a trailing XPath to the result of bwps:getVariableData(), instead of using an XPath as the last argument of bpws:getVariableData(). The trailing XPath references to an integer-based index variable within the position predicate (that is, [...]):

<variable name="idx" type="xsd:integer"/>
...
<assign>
  <copy>
    <from expression="bpws:getVariableData('input','payload'
       )/p:line-item[bpws:getVariableData('idx')]/p:line-total" />
    <to variable="lineTotalVar" />
  </copy>
</assign> 

Assume at run time that the idx integer variable holds 2 as its value. The preceding expression within the from is equivalent to:

<from expression="bpws:getVariableData('input','payload'
       )/p:line-item[2]/p:line-total" />

There are some subtle XPath usage differences, when an XPath used trailing behind the bwps:getVariableData() function is compared with the one used inside the function.Using the same example (where payload is the message part of element "p:invoice"), if the XPath is used within the getVariableData() function, the root element name ("/p:invoice") must be specified at the beginning of the XPath.

For example:

bpws:getVariableData('input', 'payload','/p:invoice/p:line-item[2]/p:line-total')

If the XPath is used trailing behind the bwps:getVariableData()function, the root element name does not need to be specified in the XPath.

For example:

bpws:getVariableData('input', 'payload')/p:line-item[2]/p:line-total

This is because the node returned by the getVariableData() function is already the root element. Specifying the root element name again in the XPath is redundant and is standard XPath semantics.

3.15.3.2 Using the bpelx:append Extension to Append New Items to a Sequence

The bpelx:append extension in an assign activity enables BPEL processes to append new elements to an existing parent element:

<assign name="assign-3">
        <copy>
            <from expression="bpws:getVariableData('idx')+1" />
            <to variable="idx"/>
        </copy>
        <bpelx:append>
            <bpelx:from variable="partInfoResultVar" part="payload" />
            <bpelx:to variable="output" part="payload" />
        </bpelx:append>
        ...
    </assign>

The bpelx:append logic in this example appends the payload element of the partInfoResultVar variable as a child to the payload element of the output variable. In others words, the payload element of output variable is used as the parent element.

See Also:

The following samples:
  • "Assign Activity" for details about using multiple copies of this extension in a single assign activity

  • SOA_Oracle_Home\bpel\samples\tutorials\126.DataAggregator\AggregationTutorial

3.15.3.3 Merging Data Sequences

You can merge two sequences into a single data sequence. This pattern is common when the data sequences are in an array (that is, the sequence of data items of compatible types).The following two append operations under assign demonstrate how to merge data sequences:

<assign>
    <!-- initialize "mergedLineItems" variable
         to an empty element -->
    <copy>
        <from> <p:lineItems /> </from>
        <to variable="mergedLineItems" />
    </copy>
    <bpelx:append>
          <bpelx:from variable="input" part="payload"
                query="/p:invoice/p:lineItems/p:lineitem" />
          <bpelx:to variable="mergedLineItems" />
    </bpelx:append>
    <bpelx:append>
          <bpelx:from variable="literalLineItems"
                query="/p:lineItems/p:lineitem" />
          <bpelx:to variable="mergedLineItems" />
    </bpelx:append>
</assign> 

See Also:

The ArraySample.bpel sample file located at:
  • SOA_Oracle_Home\bpel\samples\tutorials\112.Arrays

3.15.3.4 Dynamically Indexing with the BPEL getElement Function

If you do not want to use the two-step process of creating an XPath query to dynamically index into a sequence, you can use the XPath function getElement instead. This function takes a sequence and an index (which can be a dynamic value, such as a variable) and returns the appropriate sequence element.

<variable name="lineItemIndex" type="xsd:int"/>
...
<!-- execute the XPath extension function getElement(arrayOfElements[],
index) to fetch one element from an array of elements
-->
<assign>
   <copy>
      <from expression="ora:getElement('output', 'payload',
         '/invoice/lineItems/item',
         bpws:getVariableData('lineItemIndex'))"/>
      <to variable="myLineItem"/>   </copy>
</assign>

Note:

The XPath function getElement is being deprecated in a future release.

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\XPathFunction

3.15.3.5 Generating Functionality Equivalent to an Array of an Empty Element

The genEmptyElem function generates functionality equivalent to an array of an empty element to an XML structure. This function takes the following arguments:

genEmptyElem('ElemQName',int?, 'TypeQName'?, boolean?)

Note the following issues:

  • The first argument specifies the QName of the empty elements.

  • The optional second integer argument specifies the number of empty elements. If missing, the default size is 1.

  • The third optional argument specifies the QName, which is the xsi:type of the generated empty name. This xsi:type pattern matches the SOAPENC:Array. If it is missing or is an empty string, the xsi:type attribute is not generated.

  • The fourth optional Boolean argument specifies whether the generated empty elements are XSI - nil, provided the element is XSD-nillable. The default value is false. If missing or false, xsi:nil is not generated.

The following example shows an append statement initializing a purchase order (PO) document with 10 empty <lineItem> elements under po:

<bpelx:assign> 
    <bpelx:append>
        <bpelx:from expression="ora:genEmptyElem('p:lineItem',10)" />
        <bpelx:to variable="poVar" query="/p:po" /> 
    </bpelx:append>
</bpelx:assign>

The genEmptyElem function in this example can be replaced with an embedded XQuery expression:

ora:genEmptyElem('p:lineItem',10) 
== for $i in (1 to 10) return <p:lineItem />

The empty elements generated by this function are typically invalid XML data. You perform further data initialization after the empty elements are created. Using the same example above, you can perform the following:

  • Add attribute and child elements to those empty lineItem elements.

  • Perform copy operations to replace the empty elements. For example, copy from a Web service result to an individual entry in this equivalent array under a flowN activity.

See Also:

"genEmptyElem"

3.15.4 SOAP-Encoded Arrays Not Supported

Oracle BPEL Process Manager does not support SOAP-encoded arrays (soapenc:arrayType).

Use one of the following workarounds:

  • Apache Axis supports document-literal style services. This means you can change the service to not use soapenc:arrayType.

  • A wrapper can be placed around the service (also using Apache Axis) so that the BPEL process talks to the document literal wrapper service, which in turn calls the underlying service with soapenc:arrayType.

  • Call a service with soapenc:arrayType from BPEL, but construct the XML message more manually in the BPEL code. This enables you to avoid changing or wrapping the service. However, each time you want to call that service from BPEL, you must take extra steps.

3.16 Converting from a String to an XML Element

Sometimes a service is defined to return a string, but the content of the string is actually XML data. The problem is that, although BPEL provides support for manipulating XML data (using XPath queries, expressions, and so on), this functionality is not available if the variable or field is of type string. With Java, you use document object model (DOM) functions to convert the string to a structured XML object type. You can use the BPEL XPath function parseEscapedXML to do the same thing. This function takes XML data, parses it through DOM, and returns structured XML data that can be assigned to a typed BPEL variable. For example:

<!-- execute the XPath extension function
parseEscapedXML('&lt;item&gt;') and assign to a variable
-->
<assign>
   <copy>
      <from expression="ora:parseEscapedXML(
         '&lt;item xmlns=&quot;http://samples.otn.com&quot;
                   sku=&quot;006&quot;&gt;
          &lt;description&gt;sun ultra sparc VI server
          &lt;/description&gt;
          &lt;price&gt;1000
          &lt;/price&gt;
          &lt;quantity&gt;2
          &lt;/quantity&gt;
          &lt;lineTotal&gt;2000
          &lt;/lineTotal&gt;
          &lt;/item&gt;')"/>
      <to variable="escapedLineItem"/>
   </copy>
</assign>

See Also:

The following sample:
  • SOA_Oracle_Home\bpel\samples\references\XPathFunction

3.17 Differences Between Document-Style and RPC-Style WSDL Files

The examples shown up to this point have been for document-style WSDL files, in which a message is defined with an XML schema element, as in the following example:

<message name="LoanFlowRequestMessage">
<part name="payload" element="s1:loanApplication"/>
</message>

This is in contrast to RPC-style WSDL files, in which the message is defined with an XML schema type, as in:

<message name="LoanFlowRequestMessage">
<part name="payload" type="s1:LoanApplicationType"/>
</message>

This affects the material in this chapter because there is a difference in how XPath queries are constructed for the two WSDL message styles. For an RPC-style message, the top-level element (and therefore the first node in an XPath query string) is the part name (payload in the previous example). In document-style, the top-level node is the element name (for example, loanApplication).The following example shows what an XPath query string looks like if the LoanServices used in BPEL demo applications (such as LoanFlow) were RPC style.

RPC-Style WSDL File

<message name="LoanServiceResultMessage">
   <part name="payload" type="s1:LoanOfferType"/>
</message>

<complexType name="LoanOfferType">
   <sequence>
      <element name="providerName" type="string"/>
      <element name="selected" type="boolean"/>
      <element name="approved" type="boolean"/>
      <element name="APR" type="double"/>
   </sequence>
</complexType>

RPC-Style BPEL File

<variable name="output"
          messageType="tns:LoanServiceResultMessage"/>
...
<assign>
   <copy>
      <from expression="9.9"/>
      <to variable="output" part="payload" query="/payload/APR"/>
   </copy>
</assign>

See Also:

The following samples:
  • SOA_Oracle_Home\bpel\samples\utils\AsyncLoanService (LoanServices)

  • SOA_Oracle_Home\bpel\samples\demos\LoanDemo\LoanFlow (BPEL demo application)

3.18 Adding a Custom WSIF Provider

You can add a custom WSIF provider to Oracle BPEL Process Manager by performing the following tasks:

3.18.1 Task 1: Register the WSDL Extension to the WSDL Reader

  1. Create your WSDL extension object model by following the Java WSDL extension included in the Apache WSIF package. An extensionRegistry class, such as JavaExtensionRegistry.java in the WSIF Java package, is needed to register the WSDL extension.

  2. Create a SOA_Oracle_Home\bpel\system\classes\WSDLExtensions file if it does not currently exist.

  3. Add the name of the class on its own line in the file.

    My.package.MyWSDLExtensionRegistry
    
    

    This file is picked up by the WSDL reader and enables your custom WSDL extension to be recognized when the WSDL is parsed.

3.18.2 Task 2: Register the WSIF Provider

  1. Develop your custom WSIF provider by following the example of any providers included with the Apache WSIF package.

  2. Modify the wsif-providers entry in the SOA_Oracle_Home\bpel\system\config\collaxa-config.xml file as follows:

    <property id="wsif-providers">
            <name>Custom WSIF providers for Oacle BPEL server</name>
            <value>provider-class-name</value>
            <comment>
            <![CDATA[The value should be a comma separated list of WSIF provider
     class names.]]>
            </comment>
        </property>
    
    
  3. Start Oracle BPEL Server.

  4. Go to Oracle BPEL Admin Console:

    http://localhost:port/BPELAdmin/server.jsp
    
    
  5. Log in as oc4jadmin/password when prompted.

  6. Click the WSIF tab.

    The loaded WSIF providers display in a table.

3.19 Input and Output Message Header Handling

Oracle BPEL Process Manager uses WSIF to call Web services. The WSIF API is simple to invoke. When you invoke a Web service operation, you perform operation.invoke(input, output).

However, input and output messages sometimes do not contain all the information that is transferred over the transport layer. In this case, the WSIF API appears oversimplified. However, WSIF provides a MessageContext that you can set to the operation to perform. You can bind extra information (that is, SOAP headers and HTTP headers) to the context; the WSIF provider can send this information to the service.

3.19.1 Header Handlers

The following header handlers in the Web services invocation layer of Oracle BPEL Process Manager are provided.

  • An inputHeaderHandler is invoked before calling the WSIF provider.

  • An outputHeaderHandler is invoked after calling the WSIF provider.

Figure 3-1 shows this functionality.

Figure 3-1 Message Header Handler

Description of bpmdg054.gif follows
Description of the illustration bpmdg054.gif

The input and output handlers must implement the following interface.

public interface HeaderHandler {
        invoke(CXPartnerLink partnerLink,
               String operationName,
               Map payload, 
               Map headers,
               Map callProps);
}

The payload is the input or output message. The header is a map that contains messages that are used as SOAP headers.

The partnerLink is the object model. The input header handler can get information from the partnerLink and set it to the context. The output header handler can extract information from the context and bind it to the partnerLink.

The following example shows the use of a RequestHeaderHandler:

public class MyTestRequestHeaderHandler {
 public void invoke(CXPartnerLink partnerLink, String operationName,
            Map payload, Map header, Map callProps)
 {
  System.out.println("in MyTestRequestHeaderHandler ...");
  Map httpHeaders = (Map) callProps.get("http-request-headers");
  if (httpHeaders == null)
  {
   httpHeaders = new HashMap();
   callProps.put("httpRequestHeaders", httpHeaders);
  }
  httpHeaders.put("myHeader1", partnerLink.getProperty("myHeader1"));
  httpHeaders.put("myHeader2", partnerLink.getProperty("myHeader2"));
 }
}

The header information bound to the context is still abstract in that it is transport agnostic. The underlying WSIF provider must recognize this information from the context and set and get it correctly in the transport layer.

3.19.2 Registering of Header Handlers

The registration of the header handlers is performed in the bpel.xml deployment descriptor file:

<BPELSuitcase>
  <BPELProcess src="QuoteConsumer.bpel" id="QuoteConsumer">
    <partnerLinkBindings>
      <partnerLinkBinding name="client">
        <property name="wsdlLocation">QuoteConsumer.wsdl</property>
      </partnerLinkBinding>
      <partnerLinkBinding name="StockQuoteService">
        <property name="wsdlLocation">
            http://glennmi:9700/orabpel/default/StockQuoteService/StockQuoteServ
               ice?wsdl
        </property>
        <property name="requestHeaderHandlers">
            my.custom.MyRquestHeaderHandler
        </property>
        <property name="responseHeaderHandlers">
            my.custom.MyResponseHeaderHandler
        </property>
      </partnerLinkBinding>
    </partnerLinkBindings>
    <configurations>
      <!-- Optional property used to customize the BPEL console test form. -->
      <property name="testIntroduction">
        This sample shows how to use the BPEL invoke activity to invoke
        a synchronous stock quote service.
        </property>
    </configurations>
  </BPELProcess>
</BPELSuitcase>

3.19.3 Manipulation of partnerLink Properties

The headers are bound to the partnerLink. Some use cases require partnerLink properties to be retrieved and set in the BPEL process. The partnerLink properties are not described in the Business Process Execution Language for Web Services Specification, but an extension can perform this task:

<process …>
  <assign>
    <copy>
      <from partnerLink="p1" bpelx:property="sessionId"/>
      <to partnerLink="p2" bpelx:property="sessionId"/>
    </copy>
    <copy>
      <from variable="var"/>
      <to partnerLink="p2" bpelx:property="sessionId"/>
    </copy>
  </BPELProcess>
</process>

3.20 Manipulating SOAP Headers in BPEL

BPEL's communication activities (invoke, receive, reply, and onMessage) receive and send messages through specified message variables. These default activities permit one variable to operate in each direction. For example, the invoke activity has inputVariable and outputVariable attributes. You can specify one variable for each of the two attributes. This is enough if the particular operation involved uses only one payload message in each direction.

However, WSDL supports more than one message in an operation. In the case of SOAP, multiple messages can be sent along the main payload message as SOAP headers. However, BPEL's default communication activities cannot accommodate the additional header messages.

Oracle BPEL Process Manager solves this problem by extending the default BPEL communication activities with the bpelx:headerVariable extension. The extension syntax is as follows:

<invoke bpelx:inputHeaderVariable="inHeader1 inHeader2 ..."
  bpelx:outputHeaderVariable="outHeader1 outHeader2 ..."
  .../>

<receive bpelx:headerVariable="inHeader1 inHeader2 ..." .../>
<onMessage bpelx:headerVariable="inHeader1 inHeader2 ..." .../>
<reply bpelx:headerVariable="inHeader1 inHeader2 ..." .../>

3.20.1 Receiving SOAP Headers in BPEL

This section provides an example of how to create BPEL and WSDL files to receive SOAP headers.

  1. Create a WSDL file that declares header messages and the SOAP binding that binds them to the SOAP request.

    <message name="MessageIDHeader">
        <part name="MessageID" element="wsa:MessageID"/>
      </message>
      <message name="ReplyToHeader">
        <part name="ReplyTo" element="wsa:ReplyTo"/>
      </message>
    
      <!-- custom header -->
      <message name="CustomHeaderMessage">
        <part name="header1" element="tns:header1"/>
        <part name="header2" element="tns:header2"/>
      </message>
    
      <binding name="HeaderServiceBinding" type="tns:HeaderService">
        <soap:binding style="document"
          transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="initiate">
          <soap:operation style="document" soapAction="initiate"/>
            <input>
              <soap:header message="tns:ReplyToHeader" part="ReplyTo"
                use="literal"/>
              <soap:header message="tns:MessageIDHeader" part="MessageID"
                use="literal"/>
              <soap:header message="tns:CustomHeaderMessage"
                part="header1" use="literal"/>
              <soap:header message="tns:CustomHeaderMessage"
                part="header2" use="literal"/>
              <soap:body use="literal"/>
            </input>
        </operation>
      </binding>
    
    
  2. Create a BPEL source file that declares the header message variables and uses bpelx:headerVariable to receive the headers.

    <variables>  <variable name="input"
                 messageType="tns:HeaderServiceRequestMessage"/>
      <variable name="event"
                 messageType="tns:HeaderServiceEventMessage"/>
      <variable name="output"
                 messageType="tns:HeaderServiceResultMessage"/>
      <variable name="customHeader"
                 messageType="tns:CustomHeaderMessage"/>
      <variable name="messageID"
                 messageType="tns:MessageIDHeader"/>
      <variable name="replyTo"
                 messageType="tns:ReplyToHeader"/>
    </variables>
    
    <sequence>
      <!-- receive input from requestor -->
      <receive name="receiveInput" partnerLink="client" 
        portType="tns:HeaderService" operation="initiate" 
        variable="input"
        bpelx:headerVariable="customHeader messageID replyTo"
     createInstance="yes"/>
    

3.20.2 Sending SOAP Headers in BPEL

This section provides an example of how to send SOAP headers.

  1. Define the partnerLinkBinding definition in bpel.xml to refer to the HeaderService WSDL.

  2. Define the custom header variable, manipulate it, and send it using bpelx:inputHeaderVariable.

    <variables>
      <variable name="input" messageType="tns:HeaderTestRequestMessage"/>
      <variable name="output" messageType="tns:HeaderTestResultMessage"/>
      <variable name="request" messageType="services:HeaderServiceRequestMessage"/>
      <variable name="response" messageType="services:HeaderServiceResultMessage"/>
      <variable name="customHeader"messageType="services:CustomHeaderMessage"/>
        </variables>
    ...
    <!-- initiate the remote process -->
      <invoke name="invokeAsyncService"
        partnerLink="HeaderService"
        portType="services:HeaderService" 
        bpelx:inputHeaderVariable="customHeader"
        operation="initiate"
        inputVariable="request"/>
    

3.21 Using Binary Attachments in SOAP Messages

There are two supported methods for transferring opaque data in a SOAP call:

3.21.1 Use Case: SOAP Message with Binary Attachment Using MIME

This section provides a use case and describes design implementation issues. You cannot currently model a SOAP message with an attachment through Oracle JDeveloper. You must manually edit the necessary BPEL and WSDL files.

In this use case:

  • The BPEL process acts as a service to receive and reply to a SOAP message with an attachment.

  • The BPEL process acts as a client to send and receive a response to a SOAP message with an attachment.

  • Binary data is assigned to another variable.

  • Binary data is read from a URL.

  • Binary data is saved to a local file.

Two BPEL processes are constructed:

  • MIMEService is essentially an echo service of a SOAP message with an attachment. This process does the following:

    • Receives a SOAP message with an attachment and saves the opaque data to a local file.

    • Assigns the opaque data to an output variable.

    • Uses the output variable to reply to a SOAP message with an attachment to the invoker.

  • MIMERequester is the client of the first service. This process does the following:

    • Reads the binary data from a URL and assigns it to a variable.

    • Uses the variable as input to perform an invoke on the first process.

    • Receives a SOAP message with an attachment.

3.21.1.1 WSDL File Contents

The following WSDL file defines MIMEService. This file uses the WSDL binding MIME extension to define the SOAP message with an attachment.

<?xml version="1.0" encoding="UTF-8"?>
<definitions
. . .
. . .
   <types>
   . . .
   . . .
      <schema xmlns="http://www.w3.org/2001/XMLSchema">
          <import namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing"
          schemaLocation="http://gmi-pc:9700/orabpel/xmllib/ws-addressing.xsd" /> 
      </schema>
   </types>

   <message name="ReplyToHeader">
      <part name="ReplyTo" element="wsa:ReplyTo" /> 
   </message>
   <message name="MessageIDHeader">
      <part name="MessageID" element="wsa:MessageID" /> 
   </message>
   <message name="RelatesToHeader">
      <part name="RelatesTo" element="wsa:RelatesTo" /> 
   </message>
   <message name="MIMEServiceRequestMessage">
      <part name="payload" type="xsd:int"/>
      <part name="bin" type="xsd:anyType"/>
   </message>   
<message name="MIMEServiceResponseMessage">
      <part name="payload" type="xsd:int"/>
      <part name="bin" type="xsd:anyType"/>
   </message>

    <portType name="MIMEService">
        <operation name="initiate">
           <input message="tns:MIMEServiceRequestMessage"/>
        </operation>
        <operation name="process">
           <input message="tns:MIMEServiceRequestMessage"/>
           <output message="tns:MIMEServiceResponseMessage"/>
        </operation>
    </portType>
    <portType name="MIMEServiceCallback">
        <operation name="onResult">
           <input message="tns:MIMEServiceResponseMessage"/>
        </operation>
    </portType>

    <binding name="MIMEServiceBinding" type="tns:MIMEService">
        <soap:binding style="rpc"
 transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="initiate">
            <soap:operation style="rpc" soapAction="initiate"/>
            <input>
                <mime:multipartRelated>
                    <mime:part>
                       <soap:header message="tns:MessageIDHeader"
                          part="MessageID" use="literal"/> 
                       <soap:header message="tns:ReplyToHeader"
                          part="ReplyTo" use="literal"/> 
                       <soap:body parts="payload" use="literal"/>
                    </mime:part>
                    <mime:part>
                       <mime:content part="bin" type="binary"/>
                    </mime:part>
                </mime:multipartRelated>
            </input>
        </operation>
        <operation name="process">
            <soap:operation style="rpc" soapAction="process"/>
            <input>
                <mime:multipartRelated>
                    <mime:part>
                       <soap:header message="tns:RelatesToHeader"
                          part="RelatesTo" use="literal"/> 
                       <soap:body parts="payload" use="literal"/>
                    </mime:part>
                    <mime:part>
                       <mime:content part="bin" type="binary"/>
                    </mime:part>
                </mime:multipartRelated>
            </input>
            <output>
                <mime:multipartRelated>
                    <mime:part>
                        <soap:body parts="payload" use="literal"/>
                    </mime:part>
                    <mime:part>
                        <mime:content part="bin" type="binary"/>
                    </mime:part>
                </mime:multipartRelated>
            </output>
        </operation>
     </binding>
     <binding name="MIMEServiceCallbackBinding" type="tns:MIMEServiceCallback">
        <soap:binding style="rpc"
 transport="http://schemas.xmlsoap.org/soap/http"/> 
           <operation name="onResult">
        <soap:operation style="rpc" soapAction="onResult"/>
           <input>
           <mime:multipartRelated>
              <mime:part>
                 <soap:header message="tns:RelatesToHeader"
              part="RelatesTo" use="literal"/> 
                 <soap:body use="literal" /> 
              </mime:part>
              <mime:part>
                <mime:content part="bin" type="binary"/>
              </mime:part>
           </mime:multipartRelated>
          </input>
        </operation>
    </binding>

  <plnk:partnerLinkType name="MIMEService">
     <plnk:role name="MIMEServiceProvider">
       <plnk:portType name="tns:MIMEService"/>
     </plnk:role>
     <plnk:role name="MIMEServiceRequester">
       <plnk:portType name="tns:MIMEServiceCallback"/>
     </plnk:role>
  </plnk:partnerLinkType>
</definitions>

In this WSDL, the schema type of the binary data is xsd:anyType. This ensures that payload validation is successful when using xsd:anyType with either MIME or DIME data.

3.21.1.2 BPEL File Contents

The MIMERequester.bpel file shows how to use binary data in BPEL:

<process . . .
. . .
. . .
 <sequence>
    <!-- receive input from requestor -->
    <receive name="receiveInput" partnerLink="client"
             portType="tns:MIMERequester"
             operation="initiate" variable="input"
             createInstance="yes"/>
             
    <!-- initialize the input of MIMEService -->
    <assign>
      <copy>
        <from variable="input" part="payload" query="/tns:value"/>
        <to variable="request" part="payload" query="/payload"/>
      </copy>
      <copy>
        <from expression="ora:readBinaryFromFile('request.bin')"/>
        <to variable="request" part="bin"/>
      </copy>
 </assign>
 <invoke name="invoke" partnerLink="MIMEService"
            portType="services:MIMEService"
            operation="initiate" inputVariable="request"/>
            
    <receive name="receive" partnerLink="MIMEService"
            portType="services:MIMEServiceCallback"
            operation="onResult" variable="response"/>
    <assign>
      <copy>
        <from variable="response" part="payload" query="/payload"/>
        <to variable="request" part="payload" query="/payload"/>
      </copy>
      <copy>
        <from expression="ora:writeBinaryToFile('response', 'bin',
 'C:/Temp/response.bin')"/>
        <to variable="response" part="bin"/>
      </copy>
      <copy>
          <from expression="ora:readBinaryFromFile('request2.bin')"/>
        <to variable="request" part="bin"/>
      </copy>
    </assign>     <invoke name="invoke" partnerLink="MIMEService"
            portType="services:MIMEService"
            operation="process" inputVariable="request"
            outputVariable="response"/>  
 <assign>
      <copy>
        <from variable="response" part="payload" query="/payload"/>
        <to variable="output" part="payload" query="/tns:result"/>
      </copy>
      <copy>
        <from expression="ora:writeBinaryToFile('response', 'bin',
 'C:/Temp/response2.bin')"/>
        <to variable="response" part="bin"/>
      </copy>
    </assign>        <!-- respond output to requestor -->
    <invoke name="replyOutput" partnerLink="client"
            portType="tns:MIMERequesterCallback"
            operation="onResult" inputVariable="output"/>        
  </sequence>
</process>

In this example, XPath extension function ora:readBinaryFromFile( ) reads the binary file and ora:writeBinaryToFile( ) writes the binary content to a file.

The binary data can be assigned to another variable like a normal XML document by using the standard BPEL assign activity. The BPEL assign activity is extended here to accommodate the binary data.

3.21.1.3 Java Client Using SAAJ

MIMEService can be accessed from a Java client. There are two access options:

  • Java API for XML-Based RPC (JAX-RPC)

  • SOAP with Attachments API Java (SAAJ)

Example 3-1 uses Axis' implementation of SAAJ to invoke MIMEService. This example is used to unit test the interoperability of the created service. The sample request sent by this example is shown in Example 3-2.

Example 3-1 SAAJ Example

public boolean initiateUsingSAAJ(String filename) throws Exception {
 String endPointURLString =  "http://localhost:" +opts.getPort() +
 "/orabpel/default/MIMEService/1.0";

   SOAPConnectionFactory soapConnectionFactory =
        javax.xml.soap.SOAPConnectionFactory.newInstance();
   SOAPConnection soapConnection =
        soapConnectionFactory.createConnection();
        
   MessageFactory messageFactory =
        MessageFactory.newInstance();
   SOAPMessage soapMessage =
        messageFactory.createMessage();
   MimeHeaders hd = soapMessage.getMimeHeaders();
   hd.addHeader("SOAPAction", "initiate");

   SOAPPart soapPart = soapMessage.getSOAPPart();
   SOAPEnvelope requestEnvelope =
        soapPart.getEnvelope();
   SOAPBody body = requestEnvelope.getBody();
   SOAPBodyElement operation = body.addBodyElement
        (requestEnvelope.createName("initiate"));

   Vector dataHandlersToAdd = new Vector();
   dataHandlersToAdd.add(new DataHandler(new FileDataSource(new
         File(filename))));

   javax.xml.soap.SOAPElement element1 =
         operation.addChildElement(requestEnvelope.createName("payload"));
         element1.addTextNode("1");
        
   if (dataHandlersToAdd != null) {
       ListIterator dataHandlerIterator =
             dataHandlersToAdd.listIterator();

       while (dataHandlerIterator.hasNext()) {
              DataHandler dataHandler = (DataHandler)
                    dataHandlerIterator.next();
              javax.xml.soap.SOAPElement element =
                    operation.addChildElement(requestEnvelope.createName("bin"));
              javax.xml.soap.AttachmentPart attachment =
                    soapMessage.createAttachmentPart(dataHandler);
              soapMessage.addAttachmentPart(attachment);
              element.addAttribute(requestEnvelope.createName
                       ("href"), "cid:" + attachment.getContentId());
                       }
             }
   javax.xml.soap.SOAPMessage returnedSOAPMessage =
       soapConnection.call(soapMessage, endPointURLString);
   if (returnedSOAPMessage == null)
      return true;
   Iterator iterator = returnedSOAPMessage.getAttachments();
   if (!iterator.hasNext()) {
      //The wrong type of object that what was expected.
      System.out.println("Received problem response from server");
      throw new AxisFault("", "Received problem response from server", null,
        null);

     }
     //Still here, so far so good.
     //Now lets brute force compare the source attachment
     // to the one we received.

     DataHandler rdh = (DataHandler)
        ((AttachmentPart)iterator.next()).getDataHandler();

     //From here we'll just treat the data resource as file.
     String receivedfileName = rdh.getName();//Get the filename. 

     if (receivedfileName == null) {
        System.err.println("Could not get the file name.");
        throw new AxisFault("", "Could not get the file name.", null, null);
     }

     System.out.println("Going to compare the files..");
     boolean retv = compareFiles(filename, receivedfileName);

     java.io.File receivedFile = new java.io.File(receivedfileName);
     receivedFile.delete();

     return retv;
   }
}

Example 3-2 shows the sample request sent by the SAAJ program:

Example 3-2 Sample Request

POST /orabpel/default/MIMEService/1.0 HTTP/1.0Content-Type: multipart/related;
 type="text/xml"; start="<F090DFD56421FD84AAF98C386AD50A44>"; boundary="----=_
Part_0_27211574.1133404205718"Accept: application/soap+xml, application/dime,
 multipart/related, text/*User-Agent: Axis/1.2.1Host: gmi-pc:1234Cache-Control:
 no-cachePragma: no-cacheSOAPAction: "initiate"Content-Length: 9307------=_Part_0_
27211574.1133404205718Content-Type: text/xml;
 charset=UTF-8Content-Transfer-Encoding: binaryContent-Id:
 <F090DFD56421FD84AAF98C386AD50A44><?xml version="1.0"
 encoding="UTF-8"?><soapenv:Envelope
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><initiate
 xmlns=""><payload xmlns="">1</payload><bin
 href="cid:1A744998BA8527BD121CAE96C022109F"
 xmlns=""/></initiate></soapenv:Body></soapenv:Envelope>------=_Part_0_
27211574.1133404205718Content-Type:
 application/octet-streamContent-Transfer-Encoding: binaryContent-Id:
 <1A744998BA8527BD121CAE96C022109F>
.....................

See Also:

The following documentation:

3.21.2 Displaying the Attachment Key for Binary Attachments Using the DIME Protocol in Oracle BPEL Control

The optSoapShortcut parameter value defaults to true in Oracle BPEL Control. This setting causes BPEL processes with SOAP message binary attachments that use the Direct Internet Message Encapsulation (DIME) protocol to not display their attachment key in the Oracle BPEL Control audit trail for the process instance. This is because the binary attachment file is not saved to the dehydration database. Instead, an HTML file displays in the audit trail. For example:

<PutCompanyInfo>
. . .
. . .
<report href="C:\orabpel\domains\default\tmp\.bpel_DIMERequester_
1.0.jar\report.html"/> </PutCompanyInfo> 

As a workaround, set optSoapShortcut to false in Oracle BPEL Control. This enables the file to be saved to the dehydration store and the attachment key to display in the audit trail for the instance (instead of the HTML file). Copy and paste the attachment key into the Attachment Key field at the bottom of the audit trail window and click download to save it as a file for viewing. If you do this, note that the File Download message initially prompts you to save the attachment key as a JSP file type. Instead, save the file as an HTML file type.

3.22 Summary

This chapter provides an overview of the role of XML data in BPEL processes, including describing the large role that XPath expressions play in manipulating XML data.