Wednesday, May 26, 2010

Serializing and Deserializing Business Objects From and To XML Documents in WebSphere Integration Developer

Summary:
Use BOXMLSerializer and BOXMLDocument interfaces to convert a Business Object to an XML string and vice versa in WebSphere Integration Developer.


Often times you will see a need to convert a given Business Object into an XML string and vice versa. You can serialize and deserialize a Business Object to and from a given XML string by using com.ibm.websphere.bo.BOXMLSerializer and com.ibm.websphere.bo.BOXMLDocument interfaces.

BOXMLSerializer serializer = (BOXMLSerializer)new ServiceManager().locateService(“com/ibm/websphere/bo/BOXMLSerializer”);

Sample Java code to convert a Business Object to an XML String:

Let’s say you have your Business Object stored in a variable ‘inputDataObject’ (of type commonj.sdo.DataObject)

ByteArrayOutputStream outputStream = newByteArrayOutputStream();
serializer.writeDataObject(inputDataObject,inputDataObject.getType().getURI(),inputDataObject.getType().getName(),outputStream);
String myXMLString = outputStream.toString(“UTF-8”);

“myXMLString” will hold the XML string corresponding to the Data Object “inputDataObject”.

Sample Java code to convert a given XML String to a Business Object:

Let’s say you have the XML string stored in a variable named ‘inputXMLString’ (of type java.lang.String)

BOXMLDocument document = serializer.readXMLDocument(new ByteArrayInputStream(inputXMLString.getBytes(“UTF-8”)));
commonj.sdo.DataObject myDataObject =document.getDataObject();

“myDataObject” will hold the Business Object corresponding to the XML string “inputXMLString”.

Note: The schema definition (xsd) corresponding to the Business Object that you are trying to convert the XML string into, should be available during runtime.

Wednesday, May 19, 2010

Fetching WSDL Properties From WebSphere Service Registry and Repository (WSRR) In WebSphere Integration Developer (WID) Using REST Calls

Summary:
Learn how to Query WSRR using REST calls to fetch content and parse this content. In particular, the scenario of fetching a property value on a particular WSDL without using the IBM WSRR (Java (EJB) or SOAP) API is discussed. We will use a regular Java class to make REST calls to WSRR and parse thorough the retrieved content.


WebSphere Integration Developer (WID) 6.2 offers Endpoint Lookup mediation primitive to be used in mediation modules to lookup the endpoint of a particular service from WebSphere Service Registry and Repository (WSRR), but for scenarios where you have the endpoint or any other service related information stored as a property on the WSDL in WSRR, fetching a property without using the IBM WSRR (Java (EJB) or SOAP) API is discussed. We will use a regular Java class to make REST calls to WSRR and parse thorough the retrieved content.

Querying WSRR for Content:

You could use XPath expressions to query content in WSRR. Two types of Queries

Graph Query
The URL format for a REST call using Graph Query is:

http://<host>:<port>/WSRR/6.1/Metadata/
XML/GraphQuery?query=<XPath expression>

Example:

http://<host>:<port>/WSRR/6.1/Metadata/
XML/GraphQuery?query=/WSRR/WSDLDocument
[@name=’MyWebService.wsdl’ and @version=’1.0’]

The above URL will fetch the metadata associated with a 1.0 version of the WSDL named “MyWebService.wsdl”.

Property Query
The URL format for a REST call using Graph Query is:

http://<host>:<port>/WSRR/6.1/Metadata/
XML/PropertyQuery?query=
<XPath expression>&p<#>=<property name>

# denotes a number starting from 1 and incremented by 1 for each additional property that you want to fetch.

You can use “&p<#>=<property name>” once for each property that you want to retrieve.The order of the #s can change.

Example:

http://<host>:<port>/WSRR/6.1/Metadata/
XML/PropertyQuery?query=/WSRR/WSDLDocument
[@name=’MyWebService.wsdl’ and @version=’1.0’]
&p1=name&p2=endpoint

Note: Make sure you use %27 for ‘, when you are using the URL from the browser to view the content.

Let us consider the scenario where I have a WSDL stored in WSRR with a property named ‘endpoint’. The value of the property will hold the endpoint URI for that service.

In-order to invoke a service from WID, we can create a utility class that hold the methods to fetch the information from WSRR and we can use this utility from any mediation. Once the endpoint is retrieved, you can save that information on the SMO to invoke your service dynamically with the fetched endpoint value.

The path on the SMO to store the endpoint for dynamic invocation is “smo/headers/SMOHeader/Target/address”.

Make sure you also select the “Use dynamic endpoint if set in the message header” option under “Details” section in the “Properties” view of either the “Callout” node or the “Service Invoke” primitive.

Fetching the property value involves two steps:

1. Fetch the content using REST call with a property query.
String resturl = "http://<host>:<port>/
WSRR/6.1/Metadata/XML/PropertyQuery?
query=/WSRR/WSDLDocument[@name=%27
MyWebService.wsdl%27%20and%20
@version=%271.0%27]&p2=name&p1=endpoint";
URL url = new URL(resturl);
URLConnection urlConnection = url.openConnection();
BufferedReader reader = new BufferedReader
(new InputStreamReader(urlConnection.getInputStream()));
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while(null != (line = reader.readLine()))
            stringBuffer.append(line);
reader.close();

2. Parse the fetched content using an xml parser to read the value of the property.

String searchPath = "//*[local-name()='property'
 and @*[local-name()='name'='endpoint']]
/@*[local-name()='value']";
DocumentBuilder documentBuilder =
DocumentBuilderFactory.
newInstance().newDocumentBuilder();
Document contentDocument = documentBuilder.
parse(new InputSource(new StringReader
(stringBuffer.toString())));
XPath xPath = XPathFactory.
newInstance().newXPath();
XPathExpression xPathExpression = xPath.
compile(searchPath);
String  endpoint = (String)xPathExpression.
evaluate(contentDocument,XPathConstants.STRING);

The string endpoint will hold the value against the property named “endpoint” on the WSDL “MyService.wsdl” and version 1.0 that is in WSRR.

You could basically use the same method to fetch the value of any property on the WSDL. You can also fetch any other content from WSRR by creating appropriate queries using REST calls.

If you would like to use SOAP or Java (EJB) API for WSRR, you will need to use two jar files named
  • sdo-int.jar
  • ServiceRegistryClient.jar
You can find these jars in the installation directory of WSRR.

For more information on using the IBM API for WSRR use references below.

References:
  1. Using DataPower SOA Appliances to query WebSphere Service Registry and Repository.
  2. WebSphere Service Registry and Repository Handbook.
  3. Query Content in WSRR – (WSRR Information Center).
  4. SOAP API Guide – (WSRR Information Center)

Tuesday, May 11, 2010

Dynamic Invocation Using IBM Service Component Architecture (SCA) Addressing API

Summary:
This article highlights the steps involved in invoking imports with dynamic endpoints in WebSphere Integration Developer using Service Component Architecture (SCA) API. The static endpoints defined on the imports will be overridden by the dynamically selected endpoint value.


You have defined your imports with different bindings. You have defined your component which invokes these imports. Everything looks good….

What happens when you deploy the module in different environments? Will you change the endpoints on your imports with each deployment (e.g. for SOAP/HTTP web services)? How do you dynamically select endpoints for invoking the imports?

You can use the SCA Addressing API to dynamically invoke components using imports in WebSphere Integration Developer.

All wired/un-wired imports with any type of binding can be invoked with dynamic endpoints using SCA Addressing API. Shown below are some samples for some commonly used bindings.
  • Obtain the endpoint (for overriding the defaults on the import) based on a condition.
The endpoint can either be stored in a properties file or as a namespace binding on the WebSphere process server.

If you would like to store it in a properties file, you could use resource bundles to look-up the value.

You can define namespace binding using admin console @ Environment>Naming>Name space bindings. After defining the endpoint URL as a string, you can look it up by doing a JNDI look-up.

SCA endpoint URI format:

sca://<module_name>/<export_name>

Sample:

sca://DynamicInvocationModule/SCATestExport1

Web services (SOAP/HTTP) URI format:

http://<host:port>/<module_name>/<service_name>

Sample:

http://localhost:9080/DynamicInvocationModule/
WSTestExport1

If you have changed the context root and the URL mapping, then use the format that you have defined.

(SOAP/JMS) URI format: same as JMS URI format shown below.

Unless the binding type attribute on the EndpointReference object is set (sample shown below), the address is interpreted as a SOAP/JMS endpoint.

JMS endpoint URI format:

jms:jndi:<QueueName>?jndiConnectionFactoryName=
<ConnectionFactoryName>

Sample:

Jms:jndi:MyQueue?jndiConnectionFactoryName=
MyConnectionFactory

MQ endpoint URI format:

wmq://hostname:port/msq/queue/<queueName>
@<queueManager>? connectQueueManager=<qmgr>

Samples:

wmq:/msg/queue/MyQueue  
wmq:/msg/queue/MyQueue@MyQueueManager
  • Create new EndpointReference and set required attributes.
    // import com.ibm.websphere.sca.
    addressing.EndpointReference;
    // import com.ibm.websphere.sca.
    addressing.EndpointReferenceFactory;
    EndpointReference eRef = EndpointReferenceFactory.
    INSTANCE.createEndpointReference();
    eRef.setAddress(<Obtained String Endpoint Value(URI)>);
  • Selectively add attribute values to EndpointReference
If you are trying to use imports that are not wired to the component where you have this code, also add

eRef.setImport(<ImportName>);

If you are trying to invoke an import with JMS binding, you need to explicitly set the binding type by adding the following line of code.

eRef.setBindingType(<bindingType>);

For <bindingType>, you can use one of the following
    EndpointReference.BINDING_TYPE_NOT_SET
    EndpointReference.BINDING_TYPE_JMS
    EndpointReference.BINDING_TYPE_MQJMS
    EndpointReference.BINDING_TYPE_GENERIC_JMS
    EndpointReference.BINDING_TYPE_MQ
    EndpointReference.BINDING_TYPEWEB_SERVICE
    EndpointReference.BINDING_TYPE_HTTP
    EndpointReference.BINDING_TYPE_SCA
    EndpointReference.BINDING_TYPE_EIS
  • Lookup the Service with the new endpoint reference and invoke the service
Service service = (com.ibm.websphere.sca.Service)
ServiceManager.INSTANCE.
getService(<Reference Partner String Name>, eRef);
param_output = service.invoke(<method name>, param);

To find the <ReferencePartnerStringName>, select the component that you have wired to the imports and in the properties view and select the “Details” tab.

Please Refer to my previous post "Must-Have bookmarks for IBM WebSphere Integration Developers" for reference material.

Please use the references below for information on how to use dynamic endpoints with other bindings not mentioned above or for additional information on what is discussed here.

References:
  1. IBM WebSphere Business Process Management Version 7.0 Information Center
  2. IBM WebSphere Application Server, Release 6 API Specification

Monday, May 3, 2010

Updating XML Maps in WebSphere Integration Developer When Service Message Object (SMO) Context Changes

Summary:
Update XML maps when service context on Service Message Object (SMO) changes with out having to redo the existing mappings.


Consider the scenario in which you have created a mediation module where you used XSL Transformation primitive to transform messages and have chosen the Message Root for this primitive to be the root of the Service Message Object (SMO).

If you now try to set up the correlation, transient or shared context on the input node of the flow and want to do the mappings for the same in the XML maps that you originally created, the new object that was added to the context will not show up and you will see a warning message that the context type does not match as shown below.

Warning Message

How do I now update the XML map with out having to redo my mappings?

Right click on the XML map and select “Open With>XML Editor”. You will see all the mappings in an XML format. What you are looking for are the tags <mapping></mapping>.

XML Mappings
Now rename the current XML map to <name>_old and create a new one select the Message Root to be “/” and having the same input and output as the original map.

Once the map is created, right click and select “Open With>XML Editor”, and copy the mappings (all the <mapping> tags) from the old map to the new one.

Close the new XML map and reopen it using the Mapping Editor and you should see all your old mappings. You will also see the context of the SMO updated with your changes.

New Request Map With Correlation Context

When you have submaps in the original mappings, you can basically use them as-is. Any updates to the Business Objects will be reflected automatically on the XML maps.