Apache NiFi is a powerful open source integration product. A challenge you might encounter when integrating systems is that one system can produce JSON messages and the other has a SOAP API available. In this blog post I'll show how you can use NiFi to convert JSON input to a SOAP service call. This involves abstracting an AVRO schema for the JSON, converting it to XML and transforming the XML to a SOAP message.
In this example I'm using several publicly available websites. You should of course be careful. Do not copy/paste sensitive XML or JSON on these sites!Articles containing tips, tricks and nice to knows related to IT stuff I find interesting. Also serves as online memory.
Showing posts with label xslt. Show all posts
Showing posts with label xslt. Show all posts
Monday, April 25, 2022
Thursday, June 9, 2016
Seamless source "migration" from SOA Suite 12.1.3 to 12.2.1 using WLST and XSLT
When you migrate sources from SOA Suite 12.1.3 to SOA Suite 12.2.1, the only change I've seen JDeveloper do to the (SCA and Service Bus) code is updating versions in the pom.xml files from 12.1.3 to 12.2.1 (and some changes to jws and jpr files). Service Bus 12.2.1 has some build difficulties when using Maven. See Oracle Support: "OSB 12.2.1 Maven plugin error, 'Could not find artifact com.oracle.servicebus:sbar-project-common:pom' (Doc ID 2100799.1)". Oracle suggests updating the pom.xml of the project, changing the packaging type from sbar to jar and removing the reference to the parent project. This however will not help you because the created jar file does not have the structure required of Service Bus resources to be imported. To deploy Service Bus with Maven I've used the 12.1.3 plugin to create the sbar and a custom WLST file to do the actual deployment of this sbar to a 12.2.1 environment. A similar solution is described here.
Updates to the pom files can easily be automated as part of a build pipeline. This allows you to develop 12.1.3 code and automate the migration to 12.2.1. This can be useful if you want to avoid keeping separate 12.1.3 and 12.2.1 versions of your sources during a gradual migration. You can do bug fixes on the 12.1.3 sources and compile/deploy to production (usually production is the last environment to be upgraded) and use the same pipeline to compile and deploy the same sources (using altered pom files) to a 12.2.1 environment.
Updates to the pom files can easily be automated as part of a build pipeline. This allows you to develop 12.1.3 code and automate the migration to 12.2.1. This can be useful if you want to avoid keeping separate 12.1.3 and 12.2.1 versions of your sources during a gradual migration. You can do bug fixes on the 12.1.3 sources and compile/deploy to production (usually production is the last environment to be upgraded) and use the same pipeline to compile and deploy the same sources (using altered pom files) to a 12.2.1 environment.
Friday, July 13, 2012
Webinterface REST/JSON vs Middleware SOAP/XML
Introduction
JavaScript
Webdevelopers use a lot of JavaScript on the clientside. There are things which JavaScript is good at and there are things you're better of not doing in JavaScript. JSON and REST are often used by JavaScript developers and XML and SOAP are shunned.
JSON
JSON (see http://www.json.org/), the JavaScript Object Notation, is an easy lightweight notation which can be used to transfer JavaScript objects; objects can be transported as strings. JSON is a lot easier for JavaScript then for example XML. JSON has some query languages (such as XQuery / XPATH for XML) which are still work in progress but seem to work to some extend; http://stackoverflow.com/questions/777455/is-there-a-query-language-for-json. For Java there are libraries available to make working with JSON more easy (such as JSON-lib and Jackson JSON).
REST
Since webinterfaces nowadays often require asynchronous interaction with the server to for example validate values in forms without requiring a submit of the entire form, services on the server are often deployed.
For service interaction, JavaScript can easily do HTTP POST and GET requests but it is harder to create entire SOAP messages. An example on how asynchronous HTTP requests can be done from JavaScript; http://rest.elkstein.org/2008/02/using-rest-in-javascript.html
REST services (http://en.wikipedia.org/wiki/Representational_state_transfer) are an alternative to SOAP services. REST services often do not have an interface defined (WSDL and WADL are disputable for REST services); there is often less strict message exchange (if you want to validate messages or throw exceptions, you have to do it yourself, they are application specific and not inherent to the protocol). For the sake of quick (webinterface) development, less strict standards can be a choice.
Oracle SOA and webinterfaces
This is an Oracle SOA / Java blog, so where do those fit in? Well, Middleware often has to link in some way to the Frontend or Frontend oriented backend systems. The Oracle SOA Middleware is heavily XML/SOAP based and the Frontend likes JSON and REST services a lot better. This is a gap which needs to be bridged.
SOAP and REST services
Oracle supplies an HTTP binding adapter which can be used to send and receive HTTP requests. See http://docs.oracle.com/cd/E25054_01/dev.1111/e10224/sca_bindingcomps.htm#autoId3 for more information. This adapter allows sending/receiving HTTP GET and POST requests and is capable of receiving XML from REST services. The Spring component can also be used for REST service interaction and since it is custom Java code which is used, it can more easily be expanded with additional functionality; http://technology.amis.nl/2009/12/16/soa-suite-11g-using-spring-component-to-mimic-http-binding-and-integrate-restful-services/
JSON and XML
Java
When examining the differences between JSON and XML, one major problem arises; there can be no strict fixed conversion between the two. See for example the below article on a user forum of one of the better known/performing JSON libraries (Jackson JSON); http://jackson-users.ning.com/forum/topics/xml-to-json-conversion-using; JSON and XML information models are fundamentally incompatible. Jackson JSON is good at converting JSON to Java objects and the other way around. Converting to XML however will most likely not be implemented because of the difference in information models.
JSON-lib (http://json-lib.sourceforge.net/) however does allow a conversion of JSON to XML and the other way around (although not reversible) with relatively little code. Of course certain assumptions need to be made to allow the conversion to work. If you're interested, you can read more about this on; http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html
XSLT
Going from XML to JSON is specific and can be modeled using XSLT to be able to support different conversion patterns. See http://controlfreak.net/xml-to-json-in-xslt-a-toolkit/ for some useful examples.
Conversion JSON to XML and XML to JSON webservice
I wanted to be able to easily convert JSON from the webinterface and REST services (Java code) to XML in order to be more flexible in BPEL with for example XPATH and XSLT. When I have XML, I can use XPATH to create the relevant JSON again if the default transformation is insufficient. I created a webservice based on JSON-lib to do the conversion. I used JAX WS to make developing/exposing the methods as a webservice easy. The code required is the following;
package ms.testapp.jsonxml;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.xml.XMLSerializer;
import org.apache.commons.lang.StringEscapeUtils;
@WebService
public class JsonXml {
@WebMethod
@WebResult(name = "xml")
public String JsonToXml(@WebParam(name = "namespace")String namespace, @WebParam(name = "rootelement")String rootelement,@WebParam(name = "jsonstring")String jsonStr) {
XMLSerializer serializer = new XMLSerializer();
serializer.setRootName(rootelement);
serializer.addNamespace("", namespace);
JSON json = JSONSerializer.toJSON(jsonStr);
String xml = serializer.write(json);
return xml;
}
@WebMethod
@WebResult(name = "json")
public String EscapedXmlToJson(@WebParam(name = "xmlstring")String xmlStr) {
XMLSerializer xmlSerializer = new XMLSerializer();
JSON json = xmlSerializer.read(StringEscapeUtils.unescapeXml(xmlStr));
return( json.toString() );
}
@WebMethod(exclude=true)
public String XmlToJson(@WebParam(name = "xmlstring")String xmlStr) {
XMLSerializer xmlSerializer = new XMLSerializer();
JSON json = xmlSerializer.read( xmlStr );
return( json.toString() );
}
/*
public static void main(String[] args) {
String Json = "{'foo':'bar',\n" +
" 'coolness':2.0,\n" +
" 'altitude':39000,\n" +
" 'pilot':{'firstName':'Buzz',\n" +
" 'lastName':'Aldrin'},\n" +
" 'mission':'apollo 11'}";
String Xml = new JsonXml().JsonToXml("http://www.google.com","root",Json);
System.out.println(Json);
System.out.println(Xml);
Json = new JsonXml().XmlToJson(Xml);
System.out.println(Json);
String escapedXml = StringEscapeUtils.escapeXml(Xml);
System.out.println(escapedXml);
Json = new JsonXml().EscapedXmlToJson(escapedXml);
System.out.println(Json);
}
*/
}
The full code is available here; https://dl.dropbox.com/u/6693935/blog/JsonXmlApp.zip. There is also a JAR deployment profile (in addition to the WAR deployment profile) in the package and the dependencies are included. For Java developers, it is recommended (for performance reasons to avoid webservice overhead) to use the Jar deployment profile. From BPEL (in a service oriented landscape) it is more easy to have the functionality available as a webservice. The main method has been used as a sort of unittest.
Please mind, the conversion is not reversible and specific.I personally think the JSON to XML conversion is more useful then the XML to JSON conversion since that can be achieved more specifically with XSLT. I have not exposed the XmlToJson method since it's hard to call the method as a webservice with an XML parameter containing a non-escaped XML fragment.
The method of converting JSON to XML, has the benefit of not requiring an XSD schema describing the XML for the conversion and not requiring a Java object representation of the data. This has the benefit that one service/class is enough to do the conversions different messages (at least JSON to XML).
Further suggestions; JSON and BPEL
When you want to use the XML created by converting JSON in BPEL, you need to do the following;
- create a schema for the created XML message and include it in a used WSDL file
- create a variable using this schema
- use ora:parseEscapedXML to assign the output of the JsonToXml to the variable
- use the variable however you like
Because this can be cumbersome (creating the schema from the XML message, JDeveloper has a wizard but still...), it's advisable to create another webservice with two input variables; JSON string and JSON path expression returning the result of the JSON path expression on the JSON string. This can easily be accomplished by using for example http://code.google.com/p/json-path/. This way if you want to use a single variable from the JSON string, you can query for it directly and you don't need to create an XSD schema for the result of the JSON to XML conversion since it is a simple string. Use can use something like; String result = JsonPath.read(jsonstring, jsonpathstring).toString(). This is however not recommended if you need a lot of variables from the JSON string since calling a webservice is also overhead and might cost performance.
Packaging the above JSON samples in an XPATH library (see for example http://docs.oracle.com/cd/E23943_01/dev.1111/e10224/bp_appx_functs.htm) might be a better solution then wrapping them in webservices since it further increases their ease of use and performance in BPEL. If the services need to be re-used outside of BPEL by for example other middleware products, webservices might be the better solution.
JavaScript
Webdevelopers use a lot of JavaScript on the clientside. There are things which JavaScript is good at and there are things you're better of not doing in JavaScript. JSON and REST are often used by JavaScript developers and XML and SOAP are shunned.
JSON
JSON (see http://www.json.org/), the JavaScript Object Notation, is an easy lightweight notation which can be used to transfer JavaScript objects; objects can be transported as strings. JSON is a lot easier for JavaScript then for example XML. JSON has some query languages (such as XQuery / XPATH for XML) which are still work in progress but seem to work to some extend; http://stackoverflow.com/questions/777455/is-there-a-query-language-for-json. For Java there are libraries available to make working with JSON more easy (such as JSON-lib and Jackson JSON).
REST
Since webinterfaces nowadays often require asynchronous interaction with the server to for example validate values in forms without requiring a submit of the entire form, services on the server are often deployed.
For service interaction, JavaScript can easily do HTTP POST and GET requests but it is harder to create entire SOAP messages. An example on how asynchronous HTTP requests can be done from JavaScript; http://rest.elkstein.org/2008/02/using-rest-in-javascript.html
REST services (http://en.wikipedia.org/wiki/Representational_state_transfer) are an alternative to SOAP services. REST services often do not have an interface defined (WSDL and WADL are disputable for REST services); there is often less strict message exchange (if you want to validate messages or throw exceptions, you have to do it yourself, they are application specific and not inherent to the protocol). For the sake of quick (webinterface) development, less strict standards can be a choice.
Oracle SOA and webinterfaces
This is an Oracle SOA / Java blog, so where do those fit in? Well, Middleware often has to link in some way to the Frontend or Frontend oriented backend systems. The Oracle SOA Middleware is heavily XML/SOAP based and the Frontend likes JSON and REST services a lot better. This is a gap which needs to be bridged.
SOAP and REST services
Oracle supplies an HTTP binding adapter which can be used to send and receive HTTP requests. See http://docs.oracle.com/cd/E25054_01/dev.1111/e10224/sca_bindingcomps.htm#autoId3 for more information. This adapter allows sending/receiving HTTP GET and POST requests and is capable of receiving XML from REST services. The Spring component can also be used for REST service interaction and since it is custom Java code which is used, it can more easily be expanded with additional functionality; http://technology.amis.nl/2009/12/16/soa-suite-11g-using-spring-component-to-mimic-http-binding-and-integrate-restful-services/
JSON and XML
Java
When examining the differences between JSON and XML, one major problem arises; there can be no strict fixed conversion between the two. See for example the below article on a user forum of one of the better known/performing JSON libraries (Jackson JSON); http://jackson-users.ning.com/forum/topics/xml-to-json-conversion-using; JSON and XML information models are fundamentally incompatible. Jackson JSON is good at converting JSON to Java objects and the other way around. Converting to XML however will most likely not be implemented because of the difference in information models.
JSON-lib (http://json-lib.sourceforge.net/) however does allow a conversion of JSON to XML and the other way around (although not reversible) with relatively little code. Of course certain assumptions need to be made to allow the conversion to work. If you're interested, you can read more about this on; http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html
XSLT
Going from XML to JSON is specific and can be modeled using XSLT to be able to support different conversion patterns. See http://controlfreak.net/xml-to-json-in-xslt-a-toolkit/ for some useful examples.
Conversion JSON to XML and XML to JSON webservice
I wanted to be able to easily convert JSON from the webinterface and REST services (Java code) to XML in order to be more flexible in BPEL with for example XPATH and XSLT. When I have XML, I can use XPATH to create the relevant JSON again if the default transformation is insufficient. I created a webservice based on JSON-lib to do the conversion. I used JAX WS to make developing/exposing the methods as a webservice easy. The code required is the following;
package ms.testapp.jsonxml;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.xml.XMLSerializer;
import org.apache.commons.lang.StringEscapeUtils;
@WebService
public class JsonXml {
@WebMethod
@WebResult(name = "xml")
public String JsonToXml(@WebParam(name = "namespace")String namespace, @WebParam(name = "rootelement")String rootelement,@WebParam(name = "jsonstring")String jsonStr) {
XMLSerializer serializer = new XMLSerializer();
serializer.setRootName(rootelement);
serializer.addNamespace("", namespace);
JSON json = JSONSerializer.toJSON(jsonStr);
String xml = serializer.write(json);
return xml;
}
@WebMethod
@WebResult(name = "json")
public String EscapedXmlToJson(@WebParam(name = "xmlstring")String xmlStr) {
XMLSerializer xmlSerializer = new XMLSerializer();
JSON json = xmlSerializer.read(StringEscapeUtils.unescapeXml(xmlStr));
return( json.toString() );
}
@WebMethod(exclude=true)
public String XmlToJson(@WebParam(name = "xmlstring")String xmlStr) {
XMLSerializer xmlSerializer = new XMLSerializer();
JSON json = xmlSerializer.read( xmlStr );
return( json.toString() );
}
/*
public static void main(String[] args) {
String Json = "{'foo':'bar',\n" +
" 'coolness':2.0,\n" +
" 'altitude':39000,\n" +
" 'pilot':{'firstName':'Buzz',\n" +
" 'lastName':'Aldrin'},\n" +
" 'mission':'apollo 11'}";
String Xml = new JsonXml().JsonToXml("http://www.google.com","root",Json);
System.out.println(Json);
System.out.println(Xml);
Json = new JsonXml().XmlToJson(Xml);
System.out.println(Json);
String escapedXml = StringEscapeUtils.escapeXml(Xml);
System.out.println(escapedXml);
Json = new JsonXml().EscapedXmlToJson(escapedXml);
System.out.println(Json);
}
*/
}
The full code is available here; https://dl.dropbox.com/u/6693935/blog/JsonXmlApp.zip. There is also a JAR deployment profile (in addition to the WAR deployment profile) in the package and the dependencies are included. For Java developers, it is recommended (for performance reasons to avoid webservice overhead) to use the Jar deployment profile. From BPEL (in a service oriented landscape) it is more easy to have the functionality available as a webservice. The main method has been used as a sort of unittest.
Please mind, the conversion is not reversible and specific.I personally think the JSON to XML conversion is more useful then the XML to JSON conversion since that can be achieved more specifically with XSLT. I have not exposed the XmlToJson method since it's hard to call the method as a webservice with an XML parameter containing a non-escaped XML fragment.
The method of converting JSON to XML, has the benefit of not requiring an XSD schema describing the XML for the conversion and not requiring a Java object representation of the data. This has the benefit that one service/class is enough to do the conversions different messages (at least JSON to XML).
Further suggestions; JSON and BPEL
When you want to use the XML created by converting JSON in BPEL, you need to do the following;
- create a schema for the created XML message and include it in a used WSDL file
- create a variable using this schema
- use ora:parseEscapedXML to assign the output of the JsonToXml to the variable
- use the variable however you like
Because this can be cumbersome (creating the schema from the XML message, JDeveloper has a wizard but still...), it's advisable to create another webservice with two input variables; JSON string and JSON path expression returning the result of the JSON path expression on the JSON string. This can easily be accomplished by using for example http://code.google.com/p/json-path/. This way if you want to use a single variable from the JSON string, you can query for it directly and you don't need to create an XSD schema for the result of the JSON to XML conversion since it is a simple string. Use can use something like; String result = JsonPath.read(jsonstring, jsonpathstring).toString(). This is however not recommended if you need a lot of variables from the JSON string since calling a webservice is also overhead and might cost performance.
Packaging the above JSON samples in an XPATH library (see for example http://docs.oracle.com/cd/E23943_01/dev.1111/e10224/bp_appx_functs.htm) might be a better solution then wrapping them in webservices since it further increases their ease of use and performance in BPEL. If the services need to be re-used outside of BPEL by for example other middleware products, webservices might be the better solution.
Labels:
conversion,
escape,
javascript,
json,
rest,
soap,
xml,
xslt
Saturday, March 3, 2012
Loops in BPEL 1.1 and 2.0
Introduction
When programming in BPEL, an often used construction is the following;
- the input of a process contains a collection of elements
- the elements need to be processed one at a time
There are several solutions to implement this. A couple of these solutions will be discussed here.
SOA Suite 10g and SOA Suite 11g have some differences in usage of extension functions such as the one used for transformations. SOA Suite 11g (of course) provides several improvements over 10g. Also BPEL 1.1 and BPEL 2.0 standards provide different activities for handling loops.
An alternative for using loop constructions in BPEL when XML needs to be send to the database is by using XML object types. See http://javaoraclesoa.blogspot.nl/2013/03/using-plsql-object-types-to-get-nested.html for more information.
Example processes
The complete BPEL 1.1 and BPEL 2.0 example (including XSD and XSLT) can be downloaded here; http://dl.dropbox.com/u/6693935/blog/TestXSLT.zip
The example used will use the following input and output schema definitions;
<?xml version="1.0" encoding="UTF-8"?>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="http://test.ms/itemcollections"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:me="http://test.ms/itemcollections">
<element name="item" type="me:itemType"/>
<complexType name="itemType">
<sequence>
<element name="name" type="string"/>
<element name="value" type="string"/>
</sequence>
</complexType>
<element name="itemsCollection" type="me:itemsCollectionType"/>
<complexType name="itemsCollectionType">
<sequence>
<element ref="me:item" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="itemCollectionArray" type="me:itemCollectionArrayType"/>
<complexType name="itemCollectionArrayType">
<sequence>
<element ref="me:itemsCollection" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="simpleString" type="me:simpleStringType"/>
<complexType name="simpleStringType">
<sequence>
<element name="value" type="string"/>
</sequence>
</complexType>
<element name="simpleNumber" type="me:simpleNumberType"/>
<complexType name="simpleNumberType">
<sequence>
<element name="value" type="decimal"/>
</sequence>
</complexType>
</schema>
This schema has been created to illustrate how collections can be handled.
It is advisable to define your element and type definitions inside a separate XSD. This promotes re-use and maintainability. The XSD can for example be put in the MDS (as described in http://javaoraclesoa.blogspot.com/2012/02/using-mds.html). It is also very useful to define separate types for every element used. This makes defining variables containing only a part of the message easier.
The workspace contains a BPEL 1.1 and a BPEL 2.0 process which are both exposed as webservices. The BPEL 1.1 process uses a While activity together with Assign activities to process a collection. The BPEL 2.0 process uses the For Each activity and a transformation to achieve the same.
BPEL 1.1 (SOA Suite 10g + 11g)
BPEL 1.1 contains the While activity and the FlowN activity which can both be used to process collections. The While activity allows to loop over a set of activities until a certain condition is met. The FlowN activity provides the option for parallel execution and an index variable to indicate the branche which is processed. FlowN has been described in; http://javaoraclesoa.blogspot.com/2012/02/parallel-execution-and-variable-scoping.html. This part will focus on the While activity. The part describing how to get a parameter inside an XSLT transformation or use it inside an assign activity, can of course also be applied for FlowN.
The below picture shows my BPEL 1.1 sample process. It transforms the input collection on a per item basis to a local variable (which would allow processing of the individual item). Then it adds the result to the output variable.
The While condition
You can create a variable inside the scope of the while activity and increase this. The condition can be set to check whether the counter is smaller then or equal to the count of elements in the message that need processing.
Getting to your element; The element is an XSLT element
There are several ways to obtain the element you want to process. Depending on the circumstances, some options might not be available.
The easiest option is creating a variable of the type of one of the items of the collection. Then use the assign activity to assign the element.
The empty activity in the process symbolizes actions on the l_item variable. This can for example be a transformation followed by a call to a DbAdapter. The result can be transformed to a different format which can then be used to generate the output. The example is meant as a bare-bones illustration of the functionality.
Things to mind;
- it is advisable to create a scope inside the While activity and use local variables inside this scope
- in the Assign activity where you assign the item to be processed, cast the local counter variable to a number like in the following example (else the condition which selects which item to be processed, doesn't work correctly);
bpws:getVariableData('inputVariable','payload','/ns1:itemsCollection/ns1:item')[number(bpws:getVariableData('l_counter'))]
- Use the Assign append rule type and append an item to the collection for creating output.
<assign name="AssignOutputItemProcessToOutputProcess">
<bpelx:append>
<bpelx:from expression="bpws:getVariableData('l_item')"/>
<bpelx:to variable="outputVariable" part="payload"
query="/ns1:itemsCollection"/>
</bpelx:append>
</assign>
- use >= and not => in the While activity condition!
Getting to your element; The element is not an XSLT element type. BPEL 1.1 SOA Suite 10g.
BPEL 1.1 in 10g uses a different transformation function as BPEL 1.1 in 11g. The transformation activity is an Oracle extension and not part of the BPEL specification (actually it's implemented as an Assign which is part of the specification and made easier to use with a wizard). The below part is for using the BPEL 10g version.
Sometimes the element of the collection is not available as a type. This makes processing less straightforward, since a variable of the item can not readily be created in BPEL. A solution for this is using an XSLT transformation with a parameter. It is important to think about to what type you are going to transform to, since the type of the element is not available. You can create a custom element type for this., for example the name/value pair items (as specified in the introduction), can be used for that.
Using a parameter inside an XSLT transformation can for example be found on; http://rigterink.blogspot.com/2009/09/passing-xml-as-parameter-to-xslt.html
The parameter can be assigned the counter value of the While loop and be passed to the XSLT transformation. This XSLT parameter can then be used to select the correct element of the source XML to be used.
Selecting the correct element from the source XML inside an XSLT transformation, will be illustrated in the BPEL 2.0 part.
BPEL 2.0
BPEL 2.0 is only available in SOA Suite 11g and not in 10g. It has several new features which make it more easy to deal with loops. Also the bpws:getVariableData does not need to be used anymore; the syntax for accessing variables has been simplified. A dot notation can be used, for example an assign activity;
<assign name="AssignCounter">
<copy>
<from>$ForEach1Counter</from>
<to>$l_counter/ns1:value</to>
</copy>
</assign>
For Each activity
The For Each activity can be compared with the While activity, however it is more specific.
- It provides a scope for a loop (in a While activity you have to create the scope yourself)
- It provides a start and endpoint for the counter variable and the counter variable can be created in the For Each activity wizard.
- It provides an option for an additional completion expression
- It provides the option of parallel execution of the individual branches (similar to the FlowN activity in BPEL 1.1)
- it provides a variable which can be used in Assign activities, however not in XSLT transformations without some additions!
The below picture shows the BPEL 2.0 process using the For Each activity. Noticable is that I have to use less activities to achieve the same as with a While activity in BPEL 1.1.
XSLT transformations allow more input variables
The function which is used in the transformation for SOA Suite 10g BPEL 1.1 is different from the transformation function used in SOA Suite 11g BPEL 1.1 and BPEL 2.0. In SOA Suite 11g it is easier to add multiple input parameters to a single transformation in the wizard and the input parameters do not need to confer to a specific schema.
The source types for the transformation all need to be simple or complex types. it is thus easiest to use a complex type. A complex types can be selected when using the wizard to define the type of BPEL variable and by choosing one from the 'Element' or 'Message type' category. you can see examples in the schema shown at the start of this post; simpleNumberType and simpleStringType. These types are complex type wrappers for the simple types string and decimal. They allow the simple types to be used as complex types inside transformations.
Using the counter variable of a For Each activity inside an XSLT transformation, can be done as followed;
- assign the For Each counter variable to a complextype (for example the simpleNumberType)
- use the variable inside a for-each XSLT construction with a selection on the passed simpleNumberType by using the position() function.
The transformation without namespaces used, is the following (see the example ZIP for the complete XSLT);
<xsl:param name="l_counter"/>
<xsl:template match="/">
<xsl:for-each select="/ns1:itemsCollection/ns1:item[position()=$l_counter/ns1:simpleNumber/ns1:value]">
<ns1:item>
<ns1:name>
<xsl:value-of select="ns1:name"/>
</ns1:name>
<ns1:value>
<xsl:value-of select="ns1:value"/>
</ns1:value>
</ns1:item>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note on Assigns
Changing the rule type for the assign is in SOA Suite 11g in BPEL 1.1 different then in BPEL 2.0.
BPEL 1.1
Select the rule type from the drop-down box
BPEL 2.0
Right click the From / To rule, Change rule type
When programming in BPEL, an often used construction is the following;
- the input of a process contains a collection of elements
- the elements need to be processed one at a time
There are several solutions to implement this. A couple of these solutions will be discussed here.
SOA Suite 10g and SOA Suite 11g have some differences in usage of extension functions such as the one used for transformations. SOA Suite 11g (of course) provides several improvements over 10g. Also BPEL 1.1 and BPEL 2.0 standards provide different activities for handling loops.
An alternative for using loop constructions in BPEL when XML needs to be send to the database is by using XML object types. See http://javaoraclesoa.blogspot.nl/2013/03/using-plsql-object-types-to-get-nested.html for more information.
Example processes
The complete BPEL 1.1 and BPEL 2.0 example (including XSD and XSLT) can be downloaded here; http://dl.dropbox.com/u/6693935/blog/TestXSLT.zip
The example used will use the following input and output schema definitions;
<?xml version="1.0" encoding="UTF-8"?>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="http://test.ms/itemcollections"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:me="http://test.ms/itemcollections">
<element name="item" type="me:itemType"/>
<complexType name="itemType">
<sequence>
<element name="name" type="string"/>
<element name="value" type="string"/>
</sequence>
</complexType>
<element name="itemsCollection" type="me:itemsCollectionType"/>
<complexType name="itemsCollectionType">
<sequence>
<element ref="me:item" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="itemCollectionArray" type="me:itemCollectionArrayType"/>
<complexType name="itemCollectionArrayType">
<sequence>
<element ref="me:itemsCollection" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="simpleString" type="me:simpleStringType"/>
<complexType name="simpleStringType">
<sequence>
<element name="value" type="string"/>
</sequence>
</complexType>
<element name="simpleNumber" type="me:simpleNumberType"/>
<complexType name="simpleNumberType">
<sequence>
<element name="value" type="decimal"/>
</sequence>
</complexType>
</schema>
This schema has been created to illustrate how collections can be handled.
It is advisable to define your element and type definitions inside a separate XSD. This promotes re-use and maintainability. The XSD can for example be put in the MDS (as described in http://javaoraclesoa.blogspot.com/2012/02/using-mds.html). It is also very useful to define separate types for every element used. This makes defining variables containing only a part of the message easier.
The workspace contains a BPEL 1.1 and a BPEL 2.0 process which are both exposed as webservices. The BPEL 1.1 process uses a While activity together with Assign activities to process a collection. The BPEL 2.0 process uses the For Each activity and a transformation to achieve the same.
BPEL 1.1 (SOA Suite 10g + 11g)
BPEL 1.1 contains the While activity and the FlowN activity which can both be used to process collections. The While activity allows to loop over a set of activities until a certain condition is met. The FlowN activity provides the option for parallel execution and an index variable to indicate the branche which is processed. FlowN has been described in; http://javaoraclesoa.blogspot.com/2012/02/parallel-execution-and-variable-scoping.html. This part will focus on the While activity. The part describing how to get a parameter inside an XSLT transformation or use it inside an assign activity, can of course also be applied for FlowN.
The below picture shows my BPEL 1.1 sample process. It transforms the input collection on a per item basis to a local variable (which would allow processing of the individual item). Then it adds the result to the output variable.
The While condition
You can create a variable inside the scope of the while activity and increase this. The condition can be set to check whether the counter is smaller then or equal to the count of elements in the message that need processing.
Getting to your element; The element is an XSLT element
There are several ways to obtain the element you want to process. Depending on the circumstances, some options might not be available.
The easiest option is creating a variable of the type of one of the items of the collection. Then use the assign activity to assign the element.
The empty activity in the process symbolizes actions on the l_item variable. This can for example be a transformation followed by a call to a DbAdapter. The result can be transformed to a different format which can then be used to generate the output. The example is meant as a bare-bones illustration of the functionality.
Things to mind;
- it is advisable to create a scope inside the While activity and use local variables inside this scope
- in the Assign activity where you assign the item to be processed, cast the local counter variable to a number like in the following example (else the condition which selects which item to be processed, doesn't work correctly);
bpws:getVariableData('inputVariable','payload','/ns1:itemsCollection/ns1:item')[number(bpws:getVariableData('l_counter'))]
- Use the Assign append rule type and append an item to the collection for creating output.
<assign name="AssignOutputItemProcessToOutputProcess">
<bpelx:append>
<bpelx:from expression="bpws:getVariableData('l_item')"/>
<bpelx:to variable="outputVariable" part="payload"
query="/ns1:itemsCollection"/>
</bpelx:append>
</assign>
- use >= and not => in the While activity condition!
Getting to your element; The element is not an XSLT element type. BPEL 1.1 SOA Suite 10g.
BPEL 1.1 in 10g uses a different transformation function as BPEL 1.1 in 11g. The transformation activity is an Oracle extension and not part of the BPEL specification (actually it's implemented as an Assign which is part of the specification and made easier to use with a wizard). The below part is for using the BPEL 10g version.
Sometimes the element of the collection is not available as a type. This makes processing less straightforward, since a variable of the item can not readily be created in BPEL. A solution for this is using an XSLT transformation with a parameter. It is important to think about to what type you are going to transform to, since the type of the element is not available. You can create a custom element type for this., for example the name/value pair items (as specified in the introduction), can be used for that.
Using a parameter inside an XSLT transformation can for example be found on; http://rigterink.blogspot.com/2009/09/passing-xml-as-parameter-to-xslt.html
The parameter can be assigned the counter value of the While loop and be passed to the XSLT transformation. This XSLT parameter can then be used to select the correct element of the source XML to be used.
Selecting the correct element from the source XML inside an XSLT transformation, will be illustrated in the BPEL 2.0 part.
BPEL 2.0
BPEL 2.0 is only available in SOA Suite 11g and not in 10g. It has several new features which make it more easy to deal with loops. Also the bpws:getVariableData does not need to be used anymore; the syntax for accessing variables has been simplified. A dot notation can be used, for example an assign activity;
<assign name="AssignCounter">
<copy>
<from>$ForEach1Counter</from>
<to>$l_counter/ns1:value</to>
</copy>
</assign>
For Each activity
The For Each activity can be compared with the While activity, however it is more specific.
- It provides a scope for a loop (in a While activity you have to create the scope yourself)
- It provides a start and endpoint for the counter variable and the counter variable can be created in the For Each activity wizard.
- It provides an option for an additional completion expression
- It provides the option of parallel execution of the individual branches (similar to the FlowN activity in BPEL 1.1)
- it provides a variable which can be used in Assign activities, however not in XSLT transformations without some additions!
The below picture shows the BPEL 2.0 process using the For Each activity. Noticable is that I have to use less activities to achieve the same as with a While activity in BPEL 1.1.
XSLT transformations allow more input variables
The function which is used in the transformation for SOA Suite 10g BPEL 1.1 is different from the transformation function used in SOA Suite 11g BPEL 1.1 and BPEL 2.0. In SOA Suite 11g it is easier to add multiple input parameters to a single transformation in the wizard and the input parameters do not need to confer to a specific schema.
The source types for the transformation all need to be simple or complex types. it is thus easiest to use a complex type. A complex types can be selected when using the wizard to define the type of BPEL variable and by choosing one from the 'Element' or 'Message type' category. you can see examples in the schema shown at the start of this post; simpleNumberType and simpleStringType. These types are complex type wrappers for the simple types string and decimal. They allow the simple types to be used as complex types inside transformations.
Using the counter variable of a For Each activity inside an XSLT transformation, can be done as followed;
- assign the For Each counter variable to a complextype (for example the simpleNumberType)
- use the variable inside a for-each XSLT construction with a selection on the passed simpleNumberType by using the position() function.
The transformation without namespaces used, is the following (see the example ZIP for the complete XSLT);
<xsl:param name="l_counter"/>
<xsl:template match="/">
<xsl:for-each select="/ns1:itemsCollection/ns1:item[position()=$l_counter/ns1:simpleNumber/ns1:value]">
<ns1:item>
<ns1:name>
<xsl:value-of select="ns1:name"/>
</ns1:name>
<ns1:value>
<xsl:value-of select="ns1:value"/>
</ns1:value>
</ns1:item>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note on Assigns
Changing the rule type for the assign is in SOA Suite 11g in BPEL 1.1 different then in BPEL 2.0.
BPEL 1.1
Select the rule type from the drop-down box
BPEL 2.0
Right click the From / To rule, Change rule type
Labels:
assign,
bpel,
collections,
flown,
for-each,
loop,
soa suite,
transformation,
while,
xslt
Subscribe to:
Posts (Atom)




