Work with data handlers, faults and registries


Work with data handlers, faults and registries

Creating your own data handlers provides a way of handling data formats unique to your own organization. The binding registry page lets you register your own data handlers with IBM Integration Designer, allowing them to be reused by yourself or others. Adding faults, lets you handle error conditions related to your application at run time.

Whereas a binding class provided as-is might be thought of as a class with hard-coded values, a binding resource configuration allows you to customize a binding yourself for your particular needs. Moreover, a binding resource configuration you create can often be reused by another type of binding. For example, you might create a binding resource configuration to work with a Flat Files adapter that might be suitable for a service with a JMS binding.

Binding resource configurations can be created for data bindings, data handlers and function selectors, each of which has a section explaining their creation and how these binding resource configurations work together to bring flexibility and reuse to your services. These sections are followed by a look at the registry where these configurations are contained.


Data handlers

Data handlers are reusable transformation logic independent of a specific transport protocol like JMS or HTTP. They can be invoked from data bindings and Java™ components.

The following sections explain the value of data handlers, the data handlers that are included with BPM and how to create your own data handlers.


Overview of data handlers

How to create a data handler, configure a data handler instance and call the data handler from a binding are discussed in this section.

In your service-oriented architecture (SOA) implementation, business data can flow between service providers and service consumers over a variety of protocols (HTTP, JMS, MQ, EIS and so on) in a variety of data formats such as comma separated value, delimited, fixed width, COBOL and so on. Different protocols have different mechanisms for carrying the business data in their protocol envelope. For example, in the case of JMS, as a message body of JMS message; in the case of HTTP, as payload of HTTP message. While the business protocol envelope is different, the business data may or may not be in same format across these protocols. The format in which business data flows on the wire between service provider and service consumer is referred to as the native format.

Business process components running on Process Server understand business data as business objects but they do not understand the native format in which the data is flowing. Therefore, an export of an Process Server module needs to de-serialize business data in native format obtained from a protocol message which was received itself in a request from a service consumer, into a business object. The export then invokes the business process component with the business object. For two-way operations (as shown in the diagram) the business object response from business process needs to be serialized into native data format, which then can be packed into the transport protocol message to be returned as a response to service requester. 1 indicates the message protocol carrying business data in native format.

Likewise, to invoke a service, the business process components running on Process Server need to serialize a business object into native data format. Therefore, an import of an Process Server module needs to serialize a business object to business data in a native format, which then is packaged into the transport protocol message used to invoke the target service. For a two-way operation, a business response in native data format obtained from the protocol response message needs to be de-serialized into a business object. 1 indicates the message protocol carrying business data in native format.

Process Server data bindings can be developed to serialize and de-serialize business data. However for scenarios where the same native data format can flow over multiple transport protocols (HTTP, JMS, MQ, EIS), the data transformation logic needs to be repeated for each of the data bindings. For these scenarios Process Server introduces the concept of data handlers.

Data handlers are reusable transformation logic in Process Server which can be invoked from data bindings, flow components and Java™ components. Data handlers can be configured on some bindings and can be used in flow components. Unlike data binding interfaces, the data handler interface is protocol neutral, which enables data handlers to be usable across the bindings. Additionally, if your scenario requires a business object to native data format transformation beyond the normal types of data transformation, you can call a data handler that can support that format from your Java components.

Data handler implementation can call other data handlers. This is referred to as data handler chaining. Data handler chaining is very useful for complex native data formats. For such formats if transformation logic is complex the data handler implementation can call other data handlers. For example if the native protocol message has multiple parts, data handlers can be developed for each part. The complex data handler for this multi-part message can call the data handlers for each of the parts.

This section illustrates how to author data handlers, how to configure them, how to call them and use them with your data bindings or in your Java components.



Prepackaged data format handlers

Several data format handlers are included with BPM.

The following data format handlers are available with BPM.

If you intend to use the standard JMS message class with a body type containing the message then use the business objects provided for these body types. To create these business objects, a predefined resource is available. To add this predefined resource, expand your module and then double-click Dependencies. The Dependencies editor opens. Expand Predefined Resources and select Native Body Schema for Native Body DataHandler. Save your work.

Prepackaged data format handlers

Data format handler Description Simple type supported?
Atom feed format This data format handler should be used when you have serialized data in a format an Atom feed format as input into an export or need to generate serialized data in an Atom feed format for an import. It can be used with JMS, MQ JMS, generic JMS, MQ and HTTP bindings. No
Delimited format This data format handler should be used when you have serialized data in a format using a delimiter as input into an export or need to generate serialized data in a format using a delimiter for an import. It can be used with JMS, MQ JMS, generic JMS, MQ and HTTP bindings. No
Fixed width format This data format handler should be used when you have serialized data in a fixed width format as input into an export or need to generate serialized data in a fixed width format for an import. It can be used with JMS, MQ JMS, generic JMS, MQ and HTTP bindings. No
JavaScript Object Notation (JSON) format This data format handler should be used when you have serialized data in a JavaScript Object Notation (JSON) format as input into an export or need to generate serialized data in a JSON format for an import. It can be used with JMS, MQ JMS, generic JMS, MQ and HTTP bindings. No
SOAP data handler The SOAP data handler parses and serializes both SOAP messages and the header, as well as the SOAP fault details. Yes
WTX Invoker Data Handler This data format handler invokes WTX to do the transformation. This data handler needs a WTX map name which is provided by the WTX MapSelectionDataHandler. No
WTX MapSelection Data Handler This data format handler should be used if you are creating a configuration that makes use of the Email, FTP and Flat Files adapters. No
XML Data Handler This data format handler should be used when you have serialized XML data as input into your export (for inbound processing at run time) or need to generate serialized XML data for an import (for outbound processing at run time). Yes



Developing data handlers

You can create your own data handlers in addition to using the data handlers that are included with BPM.

This section shows you how to create your own data handlers specific to your own needs.



Data handler authoring

Creating a data handler requires knowledge of the interfaces, types of transformations and configurations.

Creating a data handler involves knowledge of the following elements.


Data handler interface

The data handler provides the transformation function for transforming from one form (source) to another (target). The result of the transformation is mapped into either a provided target type or a new instance of a specified target. All data handlers must implement the DataHandler interface which has methods that map into a provided target type or into a new instance of a specified target.

package commonj.connector.runtime;

public interface DataHandler extends commonj.connector.runtime.BindingContext
{
    public Object transform(Object source,                             Class targetClass,
                            Object options)
        throws DataHandlerException;

    public void transformInto(Object source,                               Object target,                               Object options)
        throws DataHandlerException;}

Let us first explore the transformation that maps into a provided target type.

public Object transform(Object source, Class targetClass, Object options)
        throws DataHandlerException;

In the implementation of this method, the data handler is expected to transform data from the source object to a new instance of the targetClass. options provides additional hints for the transformation. The signature of this method is very generic. It allows both the source object to be of any type and the targetClass to be of any type. This method requires the data handler implementation to construct the target object type, which is given by targetClass. If there is any error during the transformation, the data handler implementation is expected to throw a DataHandlerException.

There are scenarios where the target object instance is available to the caller. For such scenarios, the DataHandler interface provides a transformInto method.

public void transformInto(Object, Object target, Object options)
       throws DataHandlerException;

In this method implementation the data handler is expected to transform data from the source object to the target object. options provides additional hints for the transformation. The signature of this method is very generic. It allows the source object to be of any type and the target object to be of any type. If there is any error during the transformation data handler implementation is expected to throw a DataHandlerException.


Binding context interface

The binding context contains runtime contextual information passed from the caller to the data handler. The BindingContext interface specifies the runtime context of the data handler. The DataHandler interface extends from BindingContext interface. Therefore, each data handler implementation needs to implement the setBindingContext method of the BindingContext interface.

public void setBindingContext( Map context)
 {
  this.context = context;
 }

The context is a Map. The key gives the name of the context information and the value passed gives its value. Refer to the BindingContext class for the information that bindings can provide in the context. The following table contains the list of some of the relevant information available in the context.

BindingContext keys

Key Value Description of value
BindingContext.BINDING_COMMUNICATION BindingContext.BINDING_COMMUNICATION_INBOUND BindingContext.BINDING_COMMUNICATION_OUTBOUND Indicates if the native data is coming into the module or going out of the module.
BindingContext.BINDING_CONFIGURATION Configuration properties for a JavaBean. This JavaBean provided by the data handler implementation contains the values for the properties that are set at design time. This information is set by the BindingRegistry which instantiated the data handler.

See Access configuration properties for more details.

BindingContext.BINDING_INVOCATION BindingContext.BINDING_INVOCATION_REQUEST BindingContext.BINDING_ INVOCATION_RESPONSE BindingContext.BINDING_ INVOCATION_FAULT Indicates whether the invocation to the data handler is in the context of a request, response or fault.
BindingContext.BINDING_NAME String Name of the export or import
BindingContext.EXPECTED_TYPE Qualified name (QName) of the business object. The QName of the expected type of business object for native data to business object transformation. This information is set by the caller of the data handler.

See Obtain a business object type for more details.

BindingContext .BINDING_REGISTRY Runtime implementation of the Binding registry. The Binding registry maintains all the data handler, data binding and function selectors. This information is set by the BindingRegistry which instantiated the data handler.

See Binding registry and invoking other data handlers for more details.

WPSBindingContext.FAULT_NAME String Name of the business fault in case of export response
WPSBindingContext.TRANSFORMED_DATA Object This allows context data sharing between the function selector and data handler, and fault selector and data handler. If the data is already parsed or read by the function selector or fault selector then it can be stored in the context and passed onto the data handler so the data handler does not re-read it.


Data handler transformations

As mentioned previously, data handler interface signatures are very generic. The data handler can allow transformation between source of any type and target of any type. A generic interface enables data handler implementations to support transformations between multiple types of objects. While the interface is generic, there are limited transformations that are relevant from the Process Server perspective; these are the transformations with are described in this section. . If you decide to implement a data handler, you may decide to support some or all of these transformations. Calling data handlers from bindings describes how various transformations can be used from different export and import bindings.

Business processes and mediation flows in Process Server understand business data as a DataObject type. This constrains one side of the transformation to be DataObject. The transformations relevant from Process Server can be grouped into the following categories:


Native data format to DataObject transformations

In Process Server, the binding (HTTP, MQ, JMS and EIS) receives business data in native format inside a protocol envelope. The binding then invokes the data binding to obtain the data object from the transport envelope. Depending on the transport and type of transport envelope, the business data in native transport envelope can be obtained as characters or bytes or as java.lang.Object. Calling data handlers from bindings describes how this can be done. Therefore to be usable across these bindings, it is sufficient for data handlers to support the source object as java.io.InputStream, java.io.Reader and java.lang.Object.

Source object descriptions

Source object Description
java.io.InputStream If the business data in native format is byte stream, then either it is in the form of an input stream which can be passed directly to the data handler or it is in the form of raw bytes from which an input stream can be constructed. This input stream can be used to invoke the data handler.

dataObject = (DataObject) dh.transform(inputStream, DataObject.class, options);

Java.io.Reader If the business data in native format is characters, then either it is in the form of a reader which can be passed directly to the data handler or it is in the form of raw characters from which a reader can be constructed. This reader can be used to invoke the data handler.

dataObject = (DataObject) dh.transform(reader, DataObject.class, options);

Java.lang.Object If the business data in native format is received as Java™ object, data handlers for such protocols should support Java object to DataObject transformations.

dataObject = (DataObject) dh.transform(object, DataObject.class, options);


DataObject to native data format transformations

In Process Server, the binding (HTTP, MQ, JMS and EIS) sends business data in native format inside a protocol envelope. The binding then invokes the data binding to obtain the transport envelope from the data object. Depending on the transport and type of transport envelope, the business data in the native transport envelope can be as sent as characters or bytes or as java.lang.Object. Calling data handlers from bindings describes how this can be done. To be usable across these bindings, it is sufficient for data handlers to support target objects as one or more of the following types: java.io.Writer, java.io.OutputStream, java.lang.Object and java.io.InputStream.

Target object descriptions

Target object Description
java.io.Writer If the caller wants the data handler to write native data as character type on the protocol character stream, the caller can invoke the transformInto method with a target object of type java.io.Writer. Some protocols require java.lang.String (for example, JMS TextMessage). For such protocols, the caller can invoke the data handler with java.io.StringWriter.

dh.transformInto(dataObject, writer, options);

java.io.OutputStream If the caller wants the data handler to write the native data as bytes on the protocol byte stream, the caller can invoke the transformInto method with a target object of type java.io.OutputStream. Some protocols require byte[] ( JMS ByteMessage). For such protocols, the caller can invoke the data handler with the in-memory byte output stream.

dh.transformInto(dataObject, outputStream, options);

java.io.InputStream If the caller wants the data handler to provide a byte stream from which the caller can read the transformed native data, the caller can invoke the transform method requesting a target object of type java.io.InputStream.

InputStream is = (InputStream) dh.transform(dataObject, java.io.InputStream.class, options);

java.lang.Object If the caller wants the data handler to transform the business object into an object, the caller can invoke the transform method requesting a target object of type java.lang.Object.

Object o = dh.transform(dataObject, Object.class, options);


ServiceRuntimeException to native data transformations

If you are authoring a data handler to transform a ServiceRuntimeException to native data, then there are additional transformations that you have to code in your data handler.

Additional transformations when transforming a ServiceRuntimeException to native data

Source object Target object Description
ServiceRuntimeException OutputStream If the caller wants the data handler to convert the ServiceRuntimeException object to the native data as bytes on the protocol byte stream, the caller can invoke the transformInto method with a target object of type java.io.OutputStream. Some protocols require byte[] ( JMS ByteMessage). For such protocols, the caller can invoke the data handler with the in-memory byte output stream: dh.transformInto(serviceRuntimeException, outputStream, options);
ServiceRuntimeException Writer If the caller wants the data handler to convert the ServiceRuntimeException object to the native data as string on the protocol stream, the caller can invoke the transformInto method with a target object of type java.io.Writer. Some protocols require string ( JMS TextMessage). For such protocols, the caller can invoke the data handler with the in-memory writer: dh.transformInto(serviceRuntimeException, writer, options);
ServiceRuntimeException Object.class If the caller wants the data handler to convert the ServiceRuntimeException object to the native data as serialized object on the protocol stream, the caller can invoke the transform method with a target class of type java.io.Object. For such protocols, the caller can invoke the data handler as follows: dh.transform(serviceRuntimeException, Object.class, options);


Native data to ServiceRuntimeException transformations

If you are authoring a data handler to transform native data to ServiceRuntimeException, then there are additional transformations that you have to code.

Additional transformations when transforming native data to a ServiceRuntimeException

Source object Target class Description
InputStream ServiceRuntimeException.class If the business data in native format is byte stream, then the data handler gets an input stream which is constructed from the byte stream. The data handler is expected to convert this native data to a ServiceRuntimeException object: dataObject = (DataObject) dh.transform(inputStream, ServiceRuntimeException.class, options);
Reader ServiceRuntimeException.class If the business data in native format is a string, then the data handler gets a reader which is constructed from the String. The data handler is expected to convert this native data to a ServiceRuntimeException object: dataObject = (DataObject) dh.transform(reader, ServiceRuntimeException.class, options);
Object ServiceRuntimeException.class If the business data in native format is a simple type object or a seriliazed object, then the data handler gets an object. The data handler is expected to convert this native data to a ServiceRuntimeException object: dataObject = (DataObject) dh.transform(object, ServiceRuntimeException.class, options);


Data handler configuration

Configure a data handler consists of specifying the configuration properties at authoring time and then accessing the configuration properties at run time. The following sections show you how to work with the configuration properties:


Specifying configuration properties

The data handler implementation can have configuration properties. For example, a delimited data handler can have a configuration for delimiter. Data handlers are configured at authoring time from IBM Integration Designer.

In order for this data handler to be configured from IBM Integration Designer, the following rules apply:

For example if the data handler implementation class is com.example.DelimitedDataHandler, the configuration class is com.example.DelimitedDataHandlerProperties.

1 import java.io.Serializable;
2
3 public class DelimitedDataHandlerProperties
4     implements Serializable
5 {
6     protected String delimiter = ",";
7    
8    
9     public String getDelimiter(){
10         return delimiter;
11     }
12
13     public void setDelimiter (String delimiter){
14         this.delimiter = delimiter;
15     }
 }

In this example, delimiter is a property of String type. The other types that are supported for the properties are boolean, Boolean, byte, Byte, char, Character, double, Double, float, Float, int, Integer, JavaBeans, long, Long, short, Short, String, BindingTypeBeanProperty.

BindingTypeBeanProperty is a type used when the type is a configuration namespace and name. This is used when there is a data handler calling another data handler and the called data handler is configured as a property. Arrays are also supported, but only the default user interface rendering (no configuration) is supported for simple arrays.

Before the data handler can be invoked, the data handler needs to be configured in IBM Integration Designer. There can be multiple configurations for the same data handler. Configuring data handler instances describes how resource configurations are created for data handlers in IBM Integration Designer. In Integration Designer each data handler configuration has a QName. For example, delimited data handler can have following two configurations:

http://configtns:configuration_1:
  delimiter = !
http://configtns:configuration_2:
  delimiter = *


Access configuration properties

The values for the configuration properties set at author time are accessed by the data handler implementation at run time from the binding context class. The binding context contains runtime contextual information passed from the caller to the data handler. The BindingContext interface specifies the runtime context of the data handler. The DataHandler interface extends from the BindingContext interface. Therefore each data handler implementation needs to implement the setBindingContext method of the BindingContext interface.

public void setBindingContext( Map context)
{
 this.context = context;
          // get information from context           // ... }

The context is a Map. The key gives the name of the context information and the value for the key gives its value. The properties are accessed from the binding context using BindingContext.BINDING_CONFIGURATION. The following example illustrates how the Delimited data handler can access its properties:

DelimitedDataHandlerProperties properties = null;
if(context != null)
     properties =
      (DelimitedDataHandlerProperties)context.get(BindingContext.BINDING
   _CONFIGURATION);
if(properties != null)
      delimiter = properties.getDelimiter();


Obtain a business object type

For native to business object transformations, if the caller has advanced knowledge of the type of business object in the native data, the caller can specify that type in the binding context to the data handler. The key name is BindingContext.EXPECTED_TYPE and the value is the QName of the expected type. The data handler implementation can use BindingContext.EXPECTED_TYPE to construct the business object from the native data. Some data handlers may require BindingContext.EXPECTED_TYPE be supplied to them in the binding context. However, for some formats, type information is available in the native business data. Such data handlers may not require BindingContext.EXPECTED_TYPE in the context. If the caller supplied BindingContext.EXPECTED_TYPE, the data handler implementation may obtain it from the context as follows:


Binding registry and invoking other data handlers

The binding registry provides the means of retrieving configured DataBinding, DataHandler or FunctionSelector instances. The binding registry can be obtained from the BindingRegistryFactory class. BindingRegistryFactory provides a static method to get an instance of BindingRegistry. the following code snippet illustrates how the binding registry can be used to obtain configured instances of data handler. This code snippet assumes the user has configured the data handler instance with a QName of "http://ProcessCustomerWPS, DelimitedDataHandlerConfig".

QName config = new QName("http://ProcessCustomerWPS",
   "DelimitedDataHandlerConfig");
BindingRegistry bindingRegistry = BindingRegistryFactory.getInstance();
DataHandler dataHandler =
 (DataHandler) bindingRegistry.locateBinding( config,
 bindingContext);

A data handler implementation, a data binding implementation, and a Java component implementation can use the binding registry to obtain the configured data handler instance. The required transformation method can then be called on the data handler instance.

The binding registry enables data handler reuse. There are multiple scenarios where the native data needs multiple transformations before the business object can be constructed and, similarly, the business object needs multiple transformations before the required native data can be obtained.

For such scenarios, data handler implementations can invoke other data handlers. This is called the chaining of data handlers. For example let us consider delimited, compressed data format. The compress data handler can be developed to reuse delimited data handler as follows:


Data handler implementation outline

Following code snippet provides outline for data handler implementation. It provides outline for all the transformations described in Data handler transformations.

1 public class DataHandlerOutline
2     implements DataHandler
3 {
4
5     private DataHandlerOutlineProperties config;
6     private Map context;
7
8     public void setBindingContext(Map context)
9     {
10         this.context = context;
11         config = (DataHandlerOutlineProperties) context.get(BindingContext.BINDING_CONFIGURATION);
12     }
13
14     public Object transform(Object source, 15                             Class target, 16                             Object options)
17         throws DataHandlerException 18     {
19        if ((source == null) || (target == null))
20             return null;
21
22         // native data format to DataObject transformations
23        if (target == DataObject.class) {
24            if (source instanceof InputStream) {
25                 // TODO: Transform InputStream to DataObject 26             }
27             else if (source instanceof Reader) {
28                 // TODO: Transform Reader to DataObject 29             }
30             else {
31                 // TODO: Transform Object to DataObject 32             }
33         }
34
35         // DataObject to native data format transformations
36        if (source instanceof DataObject) {
37            if (target == InputStream.class) {
38                 // TODO: Transform DataObject to InputStream
39             }
40             else {
41                 // TODO: Transform DataObject to Object 42             }
43         }
44         throw new DataHandlerException("Transformation not supported");
45     }
46
47     public void transformInto(Object source, 48                               Object target, 49                               Object options)
50         throws DataHandlerException 51     {
52        if ((source == null) || (target == null))
53             return;
54
55        if (source instanceof DataObject)
56            if (target instanceof OutputStream) {
57                 // TODO: Transform DataObject into given OutputStream
58             }
59         throw new DataHandlerException("Transformation not supported");
60     }
61 }



Service Message Object (SMO) headers

Service Message Object headers provide protocol-specific and protocol-neutral headers to author data handlers.

In order to perform the data transformation, some data handlers need access to protocol headers. These headers could be protocol neutral like DataBindingDescriptor or they can be protocol specific like JMSType. Some examples of protocol neutral headers are JMS user properties, HTTP custom headers, MQRFH2 user properties, and so on. The programming model to access these headers is a Service Message Object (SMO) in the context service which is essentially data object APIs. The protocol neutral headers are stored in the context in a protocol neutral manner such the data handler can access it with a uniform XPath expression independent of whether this information came from a JMS header, a MQ header, and so on.




Service Message Object (SMO) headers at run time

The behavior of the Service Message Object (SMO) headers at run time differ depending on whether they are used by an export or import.


Export request and import response

An export will create an SMO header and put the protocol neutral and protocol specific headers in the SMO header. It will then set the SMO header in the binding context and set the binding context on the data handler. Once the data handler returns, it will read the headers from the SMO header (since they could have been modified by the data handler) and populate them in the SCA message.


Import request and export response

An import will read the headers from the SCA message, create a Service message Object and put the headers in the SMO header. The SMO header will then be put in the binding context and set on the data handler. Once the data handler returns, it will read the headers from the Service Message Object and populate them in the outgoing protocol specific message.



Binding-specific headers in a Service Message Object (SMO)

Where data handlers can find the header information for a binding is described.

The sections below list all the header information that is in the system today for each protocol. The highlighted sections indicate the sections that are common and should be available to the data handler in a generic manner.


JMS header

The JMS user properties will be added to the properties section shown below.


MQ header

The MQ rfh2 user folder will be added to the properties section.

Folder is equal to the usr folder in the diagram.


HTTP header

The HTTP custom headers will be added to the properties section in the SMO header.


EIS headers in a Service Message Object (SMO)

The data object that will be set in the EISConnectionSpec and EISInterationSpec classes at run time for the Email, FTP and Flat File adapters is shown below.

The data structure is as follows:

EISHeader EISHeaderType
 EISConnectionSpec anyType
 EISInteractionSpec anyType


EIS Flat File header

The ConnectionSpec properties are not required. The InteractionSpec properties for inbound and outbound processing are shown.


EIS Email header

The ConnectionSpec properties are userid and password. The InteractionSpec properties for inbound and outbound processing are shown.


EIS FTP header

The ConnectionSpec properties are userid and password. The InteractionSpec properties for inbound and outbound processing are shown.



Code to access binding-specific headers

Access the binding-specific headers from a SMO header in a data handler requires only a few lines of code.


Access SMO headers in data handlers

The following programming examples show how the header information can be accessed by the data handlers.


Access the properties section of an SMO header

Consider the case where there is a property called businessObjectName in the properties section of the SMO header.

1 DataObject header = (DataObject) ContextService.INSTANCE.getHeaders();
2 List<DataObject> userPropertiesList = header.getList("properties");
3 for (DataObject userProperty : userPropertiesList) {
4     String name = userProperty.getString("name");
5     if (name.equals("businessObjectName")) {
6            String businessObjectName = userProperty.getString("value");
7      }
8  }


Access a JMS header from an SMO header

To access the JMS header from the SMO header, you would use the following code:

9 DataObject header = (DataObject) ContextService.INSTANCE.getHeaders();
10 DataObject jmsHeader = header.getDataObject("JMSHeader");
11 String jmsMessageID = jmsHeader.get("JMSMessageID");


Access an MQ header from an SMO header

To access the MQ header from the SMO header, you would use the following code:

12 DataObject header = (DataObject) ContextService.INSTANCE.getHeaders();
13 DataObject mqHeader = header.getDataObject("MQHeader");
14 DataObject mqmd = mqHeader.get("md");


Access an HTTP header from an SMO header

To access the HTTP header from the SMO header, you would use the following code:

15 DataObject header = (DataObject) ContextService.INSTANCE.getHeaders();
16 DataObject httpHeader = header.getDataObject("HTTPHeader");
17 DataObject httpControl = mqHeader.get("HTTPControl");


Access an EIS Flat File header from an SMO header

To access the EIS Flat File header from the SMO header, you would use the following code:

18 DataObject header = (DataObject) ContextService.INSTANCE.getHeaders();
19 DataObject eisHeader = header.getDataObject("EISHeader");
20 DataObject eisIneractionSpec = mqHeader.get("EISInteractionSpec");



Data handler resource configuration

Once you decide either on using a pre-packaged data handler or one that you have created, you need to create a data handler resource configuration with the a wizard in IBM Integration Designer. This section references the instructions to create the data handler resource configuration.

To create a data handler resource configuration, see Create a data format transformation resource configuration, which you will also find in the Creating resource configurations section.



Calling data handlers from bindings

As mentioned earlier, data handlers in Process Server are not callable from exports or imports directly. This section illustrates how to call data handlers from JMS, MQ and HTTP bindings. It assumes you are familiar with data bindings for JMS, MQ JMS, generic JMS, MQ, and HTTP bindings.

The following sections show how the delimited data handler created previously is invoked from these data bindings.


JMS, MQ JMS and Generic JMS data bindings

The code snippets that follow show how the delimited data handler whose configuration was created previously is invoked from the JMS data bindings. The JMS data binding implementation uses the configuration QName of the data handler to obtain and create the data handler instance from the binding registry.

Converting native data to data object

The String or bytes data is extracted from the JMS Message and a corresponding reader or inputstream is created and passed to the data handler. The data handler converts the input native data to a business object and returns it to the data binding.
1 public void read(Message jmsMessage)
2         throws JMSException
3 {
4     QName configurationName = new QName("http://ProcessCustomerWPS", "DelimitedDataHandlerConfiguration");
5     DataHandler dataHandler = (DataHandler)bindingRegistry.locateBinding(configurationName, bindingContext);
6
7    if (jmsMessage instanceof TextMessage) {
8         String textMessage = ((TextMessage) jmsMessage).getText();
9         Reader reader = new StringReader(textMessage);
10         this.dataObject = (DataObject)datahandler.transform(reader,DataObject.class, null);               
11         return;
12     }
13
14    if (jmsMessage instanceof BytesMessage) {
15         BytesMessage bytesMessage = (BytesMessage) jmsMessage;
16         byte[] sourceBytes = new byte[(int) bytesMessage.getBodyLength()];
17         bytesMessage.readBytes(sourceBytes);
18         ByteArrayInputStream InputStream = new ByteArrayInputStream(sourceBytes);
19         this.dataObject = (DataObject)datahandler.transform(inputStream, DataObject.class, null);
20         return;
21     }
22 }

Converting data object to native data

In case of TextMessage, a Writer is created and passed to the data handler transformInto method. For BytesMessage, an OutputStream is created and passed into the transformInto method.
24 public void write(Message jmsMessage)
25         throws JMSException
26 {
27     QName configurationName = new QName("http://ProcessCustomerWPS", "DelimitedDataHandlerConfiguration");
28     BindingRegistry bindingRegistry = BindingRegistryFactory.getInstance();
29     DataHandler dataHandler = (DataHandler)bindingRegistry.locateBinding(configurationName, bindingContext);

30    if((jmsMessage instanceof TextMessage){
31          Writer writer = new StringWriter();   
32      datahandler.transformInto(dataObject, Writer, null);               
33      String messageString = writer.toString();
34     ((TextMessage) message).setText(messageString);
35     return;
36 }
      if((jmsMessage instanceof BytesMessage)
37     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
38     datahandler.transformInto(dataObject, outputStream, null);               
39     byte[] messageBytes = outputStream.toByteArray();
40     ((BytesMessage) message).setBytes(messageBytes);
41     return;
42 }


MQ data binding

The following code snippet shows how the delimited data handler is invoked from the MQ data binding. The MQ data binding implementation uses the configuration QName of the data handler to obtain and create the data handler instance from the binding registry.

Converting native data to data object

If the format is null, the InputStream is directly passed to the data handler. If the format is MQSTR, then a reader is constructed from the characters and passed to the data handler. The data handler converts the input native data to a business object and returns it to the data binding.
1 public void read(MQMD md,
2                  List headers,
3                  MQDataInputStream inputStream)
4         throws IOException
5         // Create the configuration information for the child DataHandler
6         QName configurationName = new QName("http://ProcessCustomerWPS", "DelimitedDataHandlerConfiguration");
7         BindingRegistry registry = BindingRegistryFactory.getInstance();
8         DataHandler dataHandler = (DataHandler) bindingRegistry.locateBinding(configurationName, context);
9        
10        if(format != null && (format.equals("MQSTR") || format.equals(""))
11         {
12             String textMessage = inputStream.readMQChar(InputStream.available());
13             Reader reader = new StringReader(textMessage);
14             this.dataObject = (DataObject)datahandler.transform(reader,DataObject.class, null);               
15
16         }
17         else 18         {
19              this.dataObject = (DataObject)dataHandler.transform(inputStream, DataObject.class, null);
20         }
21         //deal with business exception 22    }

Converting data object to native data

If the format is MQSTR, a Writer is created and passed to the data handler transformInto method otherwise the OutputStream is directly passed into the transformInto method of data handler.
1     public void write(MQMD md,
2                       List headers,
3                       MQDataOutputStream output)
4         throws IOException
5     {
6         // Create the configuration information for the child DataHandler
7         QName configurationName = new QName("http://ProcessCustomerWPS", "DelimitedDataHandlerConfiguration");
8
9         BindingRegistry registry = BindingRegistryFactory.getInstance();
10         DataHandler dataHandler = (DataHandler) bindingRegistry.locateBinding(configurationName, context);
11
12        if(format != null && (format.equals("MQSTR") || format.equals(""))
13         {
14             Writer writer = new StringWriter();
15             datahandler.transformInto(dataObject, writer, null);               
16             String messageString = writer.toString();
17              output.writeMQChar(messageString);
18         }
19         else 20         {
21
22             dataHandler.transformInto(dataObject, output, null);
23         }
24     }


HTTP data binding

The following code snippet shows how the delimited data handler is invoked from the HTTP data binding. The HTTP data binding implementation uses the configuration QName of the data handler to obtain and create the data handler instance from the binding registry.

Converting native data to data object

The bytes are read from the HTTPInputStream and an input stream is created from those bytes. The input stream is then passed to the data handler.
25 public void convertFromNativeData(HTTPInputStream inputStream)
26         throws DataBindingException, IOException
27 {
28     // Create the configuration information for the child DataHandler
1     QName configurationName = new QName("http://ProcessCustomerWPS", "DelimitedDataHandlerConfiguration");
2     BindingRegistry registry = BindingRegistryFactory.getInstance();
3     DataHandler dataHandler = (DataHandler) registry.locateBinding(configurationName, context);
4     byte[] bytes = httpInputStream.getBytes();
5     ByteArrayInputStream InputStream = new ByteArrayInputStream(bytes);
6
7     this.dataObject = dataHandler.transform(inputStream, DataObject.class, null);
8     //...
9 }

Converting data object to native data

An OutputStream is created and passed into the transformInto method. The result of the transformation is then extracted from the outputstream and set on the HTTPOutputStream.
10 public void write(HTTPOutputStream output)
11         throws IOException
12 {
13     // Create the configuration information for the child DataHandler
14     QName configurationName = new QName("http://ProcessCustomerWPS", "DelimitedDataHandlerConfiguration");
15     BindingRegistry registry = BindingRegistryFactory.getInstance();
16     DataHandler dataHandler = (DataHandler) registry.locateBinding(configurationName, context);
17    
18     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
19     dataHandler.transformInto(dataObject, outputStream, null);
20     byte[] messageBytes = outputStream.toByteArray();
21
22     httpControl.setContentLength(bytes.length);
23     output.write(messageBytes);
24    
25     // ...
26 }


Configure a data binding to call a data handler

We have shown how to call a data handler from a data binding with example code. You can also configure a data binding to call a data handler using the binding resource configuration wizard, where the data handler is configured as a property (see Create a data format transformation resource configuration).


Use data handler instances from multiple threads

The data handler instance created as described is not thread safe so a data handler instance should not be called from more than one thread. Create a new instance each time you need to apply the data handler.



Data handler formats

The Atom feed, delimited, fixed width, JSON formats and SOAP data handler are discussed in detail.

Understanding the Atom feed, delimited, fixed width, JSON formats and SOAP data handler can be helpful to you especially if you are about to configure your own import or export with these data bindings and are unfamiliar with some of the format details about each one. In this section, we examine the file structure, corresponding business object for that structure, cardinality, and properties of each format.



Atom feed format

The Atom feed format is discussed.

The term "Atom" applies to two related standards:

Web feeds allow clients to check for updates published on a web site. To provide a web feed, a web site publishes a list of recent articles or content in a standardized, machine-readable format. This list is known as a feed. The feed can then be downloaded by web sites that syndicate content from the feed or by feed-reader programs.

The Atom feed format has a well defined schema. The feed contains multiple entries and each entry is associated with content. The content can either be inline or the content can be available at the link specified. The content has associated type information which is the mime type of the content.

There are three well-defined types called "text", ""html" and "xhtml". A user can provide his own types complying to the rules of Atom specification.


Inbound data

For inbound data, the Atom data handler converts the Atom feed into a well-defined business object. If the feed contains inline content, then, based on the configuration setup on the data handler, it will call the configured data handler to convert the inline content to a business object and set that business object in the feed. You must provide a schema for the business object corresponding to this inline content.

Consider the following example. There are two entries in the feed. The content type of the first entry is XML and the other entry is JSON. This is what the input data would look like.

287 <?xml version="1.0" encoding="utf-8"?>
288 <feed xmlns="http://www.w3.org/2005/Atom">
289 
290  <title>Example Feed</title>
291  <subtitle>A subtitle.</subtitle>
292  <link href="http://example.org/feed/" rel="self"/>
293  <link href="http://example.org/"/>
294  <updated>2003-12-13T18:30:02Z</updated>
295  <author>
296    <name>John Doe</name>
297    <email>johndoe@example.com</email>
298  </author>
299  <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
300 
301  <entry>
302    <content type="text/xml">
303        <p:Customer xmlns:p="http://www.ibm.com/crm" xmlns="http://www.ibm.com/crm">
304                <id>10</id>
305        </p:Customer>
306    </content>
307    <title>Atom-Powered Robots Run Amok</title>
308    <link href="http://example.org/2003/12/13/atom03"/>
309    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
310    <updated>2003-12-13T18:30:02Z</updated>
311    <summary>Some text.</summary>
312  </entry>
313 <entry>
314    <content>
315       <content type="text/json">
316           {"firstName"="John","lastName"="Doe","id"="10"}
317       </content>
318       <type>text/json</type>
319    </content>
320    <title>Atom-Powered Robots Run Amok</title>
321    <link href="http://example.org/2003/12/13/atom03"/>
322    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
323    <updated>2003-12-13T18:30:02Z</updated>
324    <summary>Some text.</summary>
325  </entry>
326
327 </feed>

You would need to provide an XML schema that would correspond to the Customer shown previously. This customer is an inline content entry.

You would also need to provide an XML schema corresponding to the JSON data shown previously. This JSON data is also an inline content entry.

You would then configure the data handler:


Outbound data

For outbound data, the Atom data handler converts a well-defined business object into an Atom feed. If the feed business object contains an inline content business object, then, depending on the configuration of the data handler, it will call the configured data handler to convert the business object in the content to the inline content entry in the feed. You must provide a schema for the business object corresponding to this inline content.

Consider the following example. There are two business objects corresponding to the content entry. One of the business objects is Customer and the business object is Order. The Customer business object has to be serialized into XML in the Atom feed and the Order has to be serialized as a delimited stream in the Atom feed.

The Customer business object:

The serialized XML for it:

<entry>
 <content type="text/xml">
  <p:Customer xmlns:p="http://www.ibm.com/crm"
     xmlns="http://www.ibm.com/crm">
   <id>10</id>
   <firstName>John</firstName>
   <lastName>Doe</lastName>
  </p:Customer>
 </content>
</entry>

The Order business object:

The serialized delimited stream for it:

<entry>
 <content type="text/delimited">
  10,Television

The output data would be as follows:

328 <?xml version="1.0" encoding="utf-8"?>
329 <feed xmlns="http://www.w3.org/2005/Atom">
330 
331  <title>Example Feed</title>
332  <subtitle>A subtitle.</subtitle>
333  <link href="http://example.org/feed/" rel="self"/>
334  <link href="http://example.org/"/>
335  <updated>2003-12-13T18:30:02Z</updated>
336  <author>
337    <name>John Doe</name>
338    <email>johndoe@example.com</email>
339  </author>
340  <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
341  <entry>
342    <content type="text/xml">
343        <p:Customer xmlns:p="http://www.ibm.com/crm"
344                    xmlns="http://www.ibm.com/crm">
345            <id>10</id>
346            <firstName>John</firstName>
347            <lastName>Doe</lastName>
348        </p:Customer>
349    </content>      
350    <title>Atom-Powered Robots Run Amok</title>
351    <link href="http://example.org/2003/12/13/atom03"/>
352    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
353    <updated>2003-12-13T18:30:02Z</updated>
354    <summary>Some text.</summary>
355  </entry> 
356  <entry>
357    <content type="text/delimited">
358        10,Television
359    </content>       
360    <title>Atom-Powered Robots Run Amok</title>
361    <link href="http://example.org/2003/12/13/atom03"/>
362    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
363    <updated>2003-12-13T18:30:02Z</updated>
364    <summary>Some text.</summary>
365  </entry>
366  <entry>
367    <title>Atom-Powered Robots Run Amok</title>
368    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
369    <updated>2003-12-13T18:30:02Z</updated>
370    <summary>Some text.</summary>
371  </entry>
372 </feed>



Related reference:

Delimited format

Fixed width format

JavaScript Object Notation (JSON) format

SOAP data handler


Atom feed format properties

The properties of the Atom feed format are described.

You can set properties for the Atom feed data handler on the Data Handler Properties page.

The following properties can be configured on the Atom feed data handler.

Configurable properties for the Atom feed data handler

Property name Explanation Possible values Default value
Encode This is the encoding that will be used in converting bytes to string and string to bytes wherever applicable. Enum All encodings
Mime Type This is the mime type of the incoming content. In the case of Atom, this corresponds to the field in content called "type". None None
Data handler binding This is the configuration corresponding to a data handler that will be used to transform content in the given mime type. None None


Handling nulls and absence of tags

If a certain tag is not present in the Atom feed, then we consider this as unset in the business object. Conversely, if a certain property in the business object is unset, then the corresponding element does not appear in the Atom feed.



Interface for Atom feed format

The interface and business objects to support the Atom feed format are discussed.

In order to parse and serialize Atom feeds to a business object in a module, the interface on the export or import should be defined with an Atom feed business object, which looks as follows:

This business object can be added to a module by opening the Predefined Resources in the Dependencies of the module and selecting ATOM schemas from the list. This selection will add the required Atom-specific business objects to the module under the Data folder. When creating the interface, select the feed business object that was added in the previous step. A sample interface looks as follows:



Delimited format

The delimited format used with a CSV file is discussed.

This format typically stores tabular data. It uses comma to separate the fields of data. The last field ends with a new line character. In the case where the comma is part of the field, the field is surrounded by double quotation marks. If there are double quotation marks or new line characters in the field, then the double quote is followed by another double quote and the entire property value is put in double quotation marks. This data handler follows the RFC4180 specification and Microsoft Excel CSV format. The CSV data may contain a header line.

The following rules apply when using the delimited CSV format.


CSV file with no header and one record

This is a CSV file with one record and it does not contain a header. In this case, the business object properties have to be in the order of the fields in the data.

The corresponding business object for the record is as follows. Note the business object property names are in order of the data in the file. Note the lastName and firstName fields.

Business object

CustomerBO
id
firstName lastName salary
8A7111
John
Doe
80000


CSV file with header and one record

This is a CSV file with one record and a header.

id,firstName,lastName,salary
8A7111,John,Doe,80000

The corresponding business object for the first record is as follows. The rest of the records will be similar. Note the business object property names are exactly the same as the header and their order is the same.

Business object

CustomerBO
id
firstName lastName salary
8A7111
John
Doe
80000


CSV file with multiple records and header

This is a CSV file with multiple records and also a header. This file will be read into a business object that contains a single property which is an array. This array will be populated with the records from the incoming data.

id,firstName,lastName,salary
8A7111,John,Doe,80000
8A7112,Mary,Cay,100000
8A7113,Tom,Howard,600000
8A7114,Liz,Taylor,700000

The corresponding business object for this file is as follows:

Business object

CustomerBO
customers[]
id
firstName lastName salary
8A7111
John
Doe
80000
id
firstName lastName salary
8A7112
Mary Cay
100000
id
firstName lastName salary
8A7113
Tom
Howard
600000
id
firstName lastName salary
8A7114
Liz
Taylor
700000



Related reference:

Atom feed format

Fixed width format

JavaScript Object Notation (JSON) format

SOAP data handler


Delimited format with hierarchical business objects

The hierarchical business objects in a delimited format are described.


Single cardinality

This is a CSV file that contains customer record with an address in it.

The corresponding business object for the record is as follows. Note, the business object property names are in order of the data in the file. This is a requirement if the business object is not a flat business object.

Business object

CustomerBO
id
firstName lastName
8A7111
John
Doe
address
 street 577 Airport Blvd
 city   Burlingame
 state  CA
 zip    94010

    salary

    80000


Multiple cardinality contained business object

This scenario is supported only with the caveat the maxOccurs property is not unbounded and the maxOccurs number of elements are present in the stream.


Property value is not set

If a property is unset, then there are two consecutive delimiters.


Property value contains a comma

If the property contains a comma in it, then it is put in double quotation marks.


Property value contains a double quote

If the property contains a double quote in it, then the double quote is followed by another double quote and the entire property is put in double quotation marks.



Delimited format properties

Properties of the delimited format are described.

The following properties can be configured on the Delimited data binding. The default values for the properties are setup for a CSV format.

Configurable properties for the Delimited data binding

Property name Explanation Type Possible values Default value
Header line This indicates if there is a header in the incoming data or if a header has to be created in the outgoing data. Enum True False False
Delimiter This is the delimiter between any 2 fields of data. If the field of data is not set, then there will be 2 consecutive delimiters. \t is a valid delimiter for TAB. \r, \n is not a valid delimiter since it indicates the default end of record. Unicode values are allowed. String Any string Comma is the default value
Encode This is the encoding that will be used in converting bytes to string and string to bytes wherever applicable. Enum All encodings UTF-8
Text qualifier If the delimiter appears as part of the field, then the field is enclosed in the text qualifier. Enum Double quotation marks ("), Single quote ('), None Double quotation marks (")
Escape character This is the character that will be used to escape the delimiter when the delimiter appears as part of the field. If the escape character is part of the field, then it is escaped with another escape character. The escape character is applicable only when the Text qualifier property is set to none. Unicode values are allowed. character Any character Not set
Record delimiter This indicates what the separator is between the records. Unicode values can be specified as well. For example:. \u00FF String EOL or type your own EOL (\r, \r\n, \n)
Value of null This property indicates what value should be written out for null and what value should be treated as null when reading data in. String Null or type your own Null



Fixed width format

The fixed width format is discussed.

This format has data where every field has a fixed width and for those fields where their width is less than the value, it is padded with pad characters. Every record ends with a new line character. The field width and pad character are both user configurable. This format may optionally contain a header at the top which corresponds to the properties of the business object. If the header is absent, then the order of the fields in the input data is the same as the order of properties in the business object. Typically, fixed width format contains data where every field has a different width. To enable this, the field width will be represented as a list property.

Fixedwidth format may be transmitted in several forms. Fixed width format may come in a stream through data bindings such as HTTP, JMS and MQ as well as files.


Fixed width format with no header and one record

This is a fixed width format with one record and does not contain a header. In this case, the business object properties have to be in the order of the fields in the data.

The corresponding business object for the record is as follows. Note the business object property names are in order of the data in the fixedwidth format. Note the lastName and firstName fields.

Business object

CustomerBO
id
firstName lastName salary
8A7111
John
Doe
80000


Fixed width format with header and one record

This is a fixed width format with one record and a header. The field width format id is 6, firstName and lastName are 10 and salary is 6 as well.

id~~~~firstName~lastName~~salary
8A7111John~~~~~~Doe~~~~~~~80000~

The corresponding business object is as follows. Note the business object property names are exactly the same as the header and their order is also the same.

Business object

CustomerBO
id
firstName lastName salary
8A7111
John
Doe
80000


Fixed width format with multiple records and header

This is a fixed width format with multiple records and also a header.

id~~~~firstName~lastName~~salary
8A7111John~~~~~~Doe~~~~~~~80000~
8A7112Mary~~~~~~Cay~~~~~~~100000
8A7113Tom~~~~~~~Howard~~~~600000
8A7114Liz~~~~~~~Taylor~~~~700000

The corresponding business object for this fixed width format is as follows:

Business object

CustomerWrapperBO
customers[]
id
firstName lastName salary
8A7111
John
Doe
80000
id
firstName lastName salary
8A7112
Mary Cay
100000
id
firstName lastName salary
8A7113
Tom
Howard
600000
id
firstName lastName salary
8A7114
Liz
Taylor
700000

In this case, the export interface is set up with the CustomerWrapperBO as the business object not customers[ ].



Related reference:

Atom feed format

Delimited format

JavaScript Object Notation (JSON) format

SOAP data handler


Fixed width format cardinality and properties

Cardinality and properties of the fixed width format are described.


Single cardinality

This is a fixed width format that contains a customer record with an address in it.

The corresponding business object for the record is as follows. Note the business object property names are in order of the data in the fixedwidth format. This is a requirement if the business object is not a flat business object.

Business object

CustomerBO
id
firstName lastName
8A7111
John
Doe
address
 street 577 Airport Blvd
 city   Burlingame
 state  CA
 zip    94010

    salary

    80000


Multiple cardinality contained business object

This scenario is supported only with the caveat the maxOccurs property is not unbounded and the maxOccurs property's number of elements are present in the stream.


Property value is not set

If a property is unset, pad characters equal to the field width are added.


Property value is empty

This occurs in the case of writing out fixed width data. If a property is empty (""), pad characters equal to the field width are added.


Configurable properties

The following properties can be configured on the Fixed Width data binding or fixed width data handler.

Configurable properties for the Fixed Width data binding or fixed width data handler

Property name Explanation Type Possible values Default value
Header line This indicates if there is a header in the incoming data or if a header has to be created in the outgoing data. Enum True or false False
Fixed width This is a list which contains the width of every property value in the stream in the order that it appears in the stream. List   None
Pad character for non-numeric types If the property value size is less than the field width then the pad characters are added to it so the size is equal to the field width. \u is the pad character for Unicode characters. This property is applicable for non-numeric types in the data like string, boolean, date and so on. Character An empty character such as " " or type your own An empty character such as " "
Pad character for numeric types If the property value size is less than the field width then the pad characters are added to it so the size is equals to the field width. \u is the pad character for Unicode characters. This property is applicable for numeric types like int, float, double, long and so on. Character An empty character such as " " or type your own An empty character such as " "
Alignment for non-numeric types This indicates whether the padding is left, right or both left and right. This alignment is for non-numeric types Enum LEFT_ALIGNMENT, RIGHT_ALIGNMENT, BOTH_ALIGNMENT RIGHT_ALIGNMENT
Alignment for numeric types This indicates whether the padding is left, right or both left and right. This alignment is applicable for numeric types Enum LEFT_ALIGNMENT, RIGHT_ALIGNMENT, BOTH_ALIGNMENT RIGHT_ALIGNMENT
Truncation When writing the values out, if the field width is less than the property value, then a true value indicates the value should be truncated and a false value indicates that an exception should be thrown. boolean True or False True
Encode This is the encoding that will be used in converting bytes to string and string to bytes wherever applicable. Enum All encodings UTF-8
Record delimiter type This can be based either on a delimiter or size of record. Enum By delimiter or by size By delimiter
End of line delimiter This indicates what the separator is between the records. String EOL or type your own End of line (either /n or /r/n or /r)
Value of null This property indicates what value should be written out for null and what value should be treated as null when reading data in. String NULL or type your own NULL



JavaScript Object Notation (JSON) format

The JavaScript Object Notation (JSON) format is discussed.

JavaScript Object Notation (JSON) is a lightweight data-interchange format. JSON is easy for humans to read and write. JSON is easy for machines to parse and generate. JSON is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java™, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. More details on the JSON format can be found at Introducing JSON.

The property name in the JSON data should match exactly with the property name in the business object.


Single cardinality contained business object

Given the following business object:

And given the following values for the business object properties:

Business object with properties and values

Business Object Property Value
Customer

 Address
firstName
lastName streetAddress
city
state postalCode
phoneNumbers[0]
phoneNumbers[1]
John
Smith
21 2nd Street
New York
NY
10121
212-732-1234
646-123-4567

The JSON format is the following:

1 {
2     "firstName": "John",
3     "lastName": "Smith",
4     "address": {
5         "streetAddress": "21 2nd Street",
6         "city": "New York",
7         "state": "NY",
8         "postalCode": 10021
9     },
10     "phoneNumbers": [
11         "212-732-1234",
12         "646-123-4567"
13     ]
14 }


Multiple cardinality contained business object

Given the following business object:

And given the following values for the business object properties:

Business object with properties and values

Business Object Property Value
Customer

 Address[0]



 Address[1]
firstName
lastName streetAddress
city
state postalCode
streetAddress
city
state postalCode
phoneNumbers[0]
phoneNumbers[1]
John
Smith
21 2nd Street
New York
NY
10121
577 Airport Blvd
Burlingame
CA
94010
212-732-1234
646-123-4567

The JSON format is the following:

15 {
16     "firstName": "John",
17     "lastName": "Smith",
18     "address": [{
19         "streetAddress": "21 2nd Street",
20         "city": "New York",
21         "state": "NY",
22         "postalCode": 10021
23     },{
24         "streetAddress": "577 Airport Blvd",
25         "city": "Burlingame",
26         "state": "CA",
27         "postalCode": 94010
28     }],
29     "phoneNumbers": [
30         "212-732-1234",
31         "646-123-4567"
32     ]
33 }



Related reference:

Atom feed format

Delimited format

Fixed width format

SOAP data handler


JSON format properties and data type conversions

Properties and data type conversions of the JSON format are described.


Configurable properties

The following properties can be configured.

Configurable JSON format properties

Property name Explanation Possible values Default value
Encode This is the encoding that will be used in converting bytes to string and string to bytes wherever applicable. Enum All encodings


Data type conversions

JSON type system is more constrained than the XSD type system. JSON supports a value of type String, Number and Boolean. It does not support octal and hexdecimal values. The data handler will delegate all type conversions to the business object. Hence, all conversions that are supported by the business object will be supported by the data handler. We recommend the type should match between the JSON data and the corresponding data objects but we are tolerant with certain formats as shown in the tables below.


JSON to DataObject conversions

Conversion from JSON type to DataObject type

JSON/DataObject String Long Double boolean Date, datetime
String Valid Valid if value is long Valid if value is double Valid if value is true or false Valid if the value is a date
Long Valid Valid Valid Invalid Valid if the value is a date
Double Valid Valid if value is long Valid Invalid Invalid
Boolean Valid Invalid Invalid Valid Invalid

For simple type lists, the types between the JSON data and the schema have to match.

For the base64Binary and hexBinary types, the business object will be converted to byte[], however this is not a JSON data supported type. JSONDataHandler will automatically convert the byte[] to a string based on the encoding information configured on the JSON format properties.


DataObject to JSON conversions

DataObject type to JSON type

DataObject JSON
String String
Long Long
Integer Long
Double Double
Float Double
Boolean Boolean
Date String
Datetime String



Handling JSON null and empty arrays and objects

Handling null and empty arrays and objects used in JSON data is described.

JSON data has the concept of null and empty arrays and objects. This section explains how each of these concepts is mapped to the data object concepts of null and unset.


Null values

JSON has a special value called null which can be set on any type of data including arrays, objects, number and boolean types.

34 {            Schema types 35     "id":null,    (integer)
36     "firstName": null,   (string)
37     "address": null,   (Address complex type with maxOccurs = 1)
38     "homeAddresses":null  (Address complex type with maxOccurs > 1)
39     "phoneNumbers": null  (string with maxOccurs > 1)
40 }

Considering the previous example where JSON data with a null value is parsed into a data object, the following is true:

When serializing to JSON, if a value of a property in the data object is null, then it will be serialized as a JSON null.


Unset property

Non-existence of a property from the JSON data maps to an unset attribute in the data object space. If the property in the data object is not set (unset), then the property will not appear in the JSON data.


Empty property

The JSON empty concept applies for arrays and objects as shown below.

41 {
42     "address":{}
43      "homeAddresses":[]
44       "phoneNumbers":[]
45 }

In the case of address, an empty address data object is created. Data object does not have a concept of empty lists. Hence, no action is taken on the data object for those two properties.



SOAP data handler

The SOAP data handler parses and serializes both SOAP messages and the header, as well as the SOAP fault details.


Export behavior

The SOAP data handler looks at the binding context to determine if this message is a normal response or a fault. If a normal response, it converts the data object to XML and adds it to the SOAP body. If a fault, it creates a SOAP fault, converts the data object to XML and adds it to the SOAP details. It gets the fault name from the binding context and adds a custom SOAP header as follows:

<ibmSoap:BusinessFaultName
 xmlns:ibmSoap="http://www.ibm.com/soap">CustomerAlreadyExists</ibmSoap:BusinessFaultName>
where CustomerAlreadyExists is the fault name.

If the SOAP data handler is called for a service runtime exception (SRE), then the SOAP data handler creates a custom SOAP header as follows: <ibmSoap:RuntimeFault xmlns:ibmSoap="http://www.ibm.com/soap"/>, create the SOAP fault, set the status code to "Server" and set the fault string from the message of the ServiceRuntimeException.


Import behavior

The SOAP data handler converts the InputStream or Reader to a data object in the case of a normal response and service business exception. In the case of a service runtime exception (SRE), it reads the fault string from the SOAP fault, creates a ServiceRuntimeException and sets the fault string as the message of the ServiceRuntimeException


Limitations

The following limitations apply to the SOAP data handler currently:



Related reference:

Atom feed format

Delimited format

Fixed width format

JavaScript Object Notation (JSON) format


WTX data handler

The WTX data handler invokes the Websphere Transformation Extender to perform transformations from formats like Electronic Data Interchange (EDI) and many others to data object and vice versa. WebSphere Transformation Extender is a separately licensed product and is not included as part of IBM Integration Designer, IBM Business Process Manager or WebSphere Enterprise Service Bus. The product has to be installed with the WTX installer for these servers.

The WTX data handler can be used in JMS, generic JMS, MQ-JMS, MQ and HTTP exports and imports.

The WTX map selection data handler can be used in an EIS context for FlatFile, FTP and Email imports and exports.

WTX is used in a disconnected pattern. It does not connect to the client (JMS queues, for example) directly to get the incoming message or send the outgoing message. The incoming message is sent to an export/import which then hands off the data to the WTX data handler which converts the data by calling WTX and then hands it back to the export/import.



WTX data handler concepts

Several WTX concepts should be known to you.


WTX data handler and IBM Integration Designer servers

The WTX data handler communicates with Websphere Transformation Extender over JNI since Websphere Transformation Extender is a C++ product. As a result, the WTX data handler runs in the same process space as Websphere BPM or WebSphere Enterprise Service Bus.


WTX maps

The WebSphere Transformation Extender Data Binding invokes a WebSphere Transformation Extender map in order to perform the transformation. The map provides the system with the details of conversion from one format to another. The WTX data handler determines what map to call based on the configuration properties on the data binding or the data binding descriptor which is described in the runtime documentation. When converting native data like Electronic Data Interchange (EDI), for example, to data object, the map must be built with the input card from EDI and the output card based on XML Schema. When converting data object to native data, the map must be built with the input card based on XML Schema and output card based on native data.



Designing the WTX map and related artifacts

Understanding the relationship between the complex type and its corresponding element is important.

When defining the business object, the complex type definition needs to have a corresponding element. Without an element, WTX creates an XML structure which does not contain a document root. This XML is not valid and not deserializable by the WTXDataBinding. Hence, when creating a business object, a corresponding element definition needs to be created. Create the element based on the guidelines as follows:

For the given complex type, Customer.xsd, as follows:

1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3             targetNamespace="http://www.ibm.com/crm"
4             xmlns:bons="http://www.ibm.com/crm">
5   <xsd:complexType name="Customer">
6     <xsd:sequence>
7       <xsd:element minOccurs="0" name="id" type="xsd:string"/>
8       <xsd:element minOccurs="0" name="firstName" type="xsd:string"/>
9       <xsd:element minOccurs="0" name="lastName" type="xsd:string"/>
10     </xsd:sequence>
11   </xsd:complexType>
12 </xsd:schema>

The element is CustomerElement.xsd, as follows:

13 <?xml version="1.0" encoding="UTF-8"?>
14 <schema xmlns="http://www.w3.org/2001/XMLSchema"
15         xmlns:bons="http://www.ibm.com/crm"
16         targetNamespace="http://www.ibm.com/crm/wtx"
17         elementFormDefault="qualified"
18         xmlns:p="http://www.ibm.com/crm/wtx" >
19
20   <import namespace="http://www.ibm.com/crm" schemaLocation="Customer.xsd"/>
21   <element name="Customer" type="bons:Customer"/>
22 </schema>

When creating the maps in the WTX map designer, check that you create the default extension for that platform. The WTX data binding determines the map extension based on the defaults.



Configure the WTX map selection data handler

Configure the WTX map selection data handler with the binding configuration resource wizard is shown.

To configure the WTX map selection data handler, follow these steps:

  1. Right-click the module and from the menu select New > Binding Resource Configuration. The Binding Resource Configuration window opens. Select Data transformation and click Next.

  2. In the Select data format transformation page, select Handled by WTX and click Next.

  3. Enter the content type. For example, delimited. At run time, the map names will be constructed from the BusinessObject used when calling the map and the content type you entered during this configuration. If you are only mapping a one-way interaction from XML to a native data format then you do not need to create a NativeToXML map. Click Next.

  4. In the final page optionally create your own name for the configuration and add a folder. Click Finish and a configuration for this data handler is created. Now create a configuration for the custom data binding where this data handler is being used. At a minimum the custom data binding needs to have a property to chain this data handler configuration. When specifying the data handler property for the custom data binding, select the configuration you created.
  5. In your export or import, select the custom data binding configuration.


To write your own WTX MapSelectionDataHandler, the source data type, target class and options for an import and export are as follows:

Import

Export



Configure the WTX map selection data handler properties

The properties for the WTX map selection data handler need to be set.

This table lists the properties that can be configured on the WTX map selection data handler you created previously when you made the predefined WTX Map Selection Data Handler selection. These properties are used in conjunction to determine the WTX map name invoked at run time. This allows the client and server implementation to be loosely coupled and highly reusable.

WTX map selection data handler properties

Property name Explanation Default value Explanation of default value
BusinessObject This is the data type of the incoming data such as Customer, Order and so on. The value of this property is used in the regular expression defined by XMLToNative Map Name and NativeToXML Map Name properties to derive the map name. Implicit Implicit as the default value implies the value of this property is the parameter type on the operation. For example: operation = create(Customer customerBO) then the value is Customer. This enables the user to specify the data binding at only one level on the export/import instead of on every operation.
ContentType This is the content type of the incoming data. For example, EDI, SWIFT, HL7 and so on.. The value of this property is used in the regular expression defined by properties XMLToNative Map Name and NativeToXML Map Name to derive the map name. None  
XMLToNative Map Name This property is the qualified map name for the map that converts data object to native data. The value of this property is a regular expression that is constructed with the properties BusinessObject and ContentType. The map directory is with respect to the SCA module. This value can also be hard coded to a map namealthough it is not recommended. WTX/$(BusinessObject)XMLTo$(ContentType) WTX is the default directory. If the BusinessObject = "Customer" and ContentType = "EDI", the map name would be WTX/CustomerXMLToEDI
NativeToXML Map Name This property is the qualified map name for the map that converts native data to data object. The value of this property is a regular expression that is constructed with the properties BusinessObject and ContentType. The map directory is with respect to the SCA module. This value can also be hard coded to a map namealthough it is not recommended. WTX/$(BusinessObject)$(ContentType)ToXML WTX is the default directory. If the BusinessObject = "Customer" and ContentType = "EDI", the map name would be WTX/CustomerEDIToXML

To have the choice of map to be a runtime decision, then you must instead configure the data binding descriptor as described in the runtime documentation.



Deploy the WTX map

Deploy the WTX map requires an understanding of the WTX directory in the module.

The WTX map is deployed with the application module that uses the WTX data binding. The default location to add the map is in a directory called WTX located at the top level in the module.

This location can be overridden by setting the XMLToNative Map Name and NativeToXML Map Name properties in the resource configuration of the WTX data binding.



Create a custom data handler

A custom data handler is useful when the data formats requiring transformation are unique and the prepackaged data handlers are not sufficient for your needs.

Occasionally the prepackaged data handlers will not meet your special requirements. In this case, you can develop your own data handler using custom code. This sample shows you how to implement a custom data handler.

The following list shows you what you can and cannot do with a custom data handler:

As an example of a custom data handler, the following code handles undefined elements in the input XML. The prepackaged XML data handler would not be able to convert these undefined elements from the input into a business object. The sample code snippet removes the undefined elements from the input and then invokes the prepackaged XML data handler to complete the transformation.

package com.ibm.websphere.example;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Map;
import com.ibm.wbiserver.datahandler.xml.*;

import commonj.connector.runtime.DataHandler;
import commonj.connector.runtime.DataHandlerException;

public class CustomDHExample implements DataHandler {

 XMLDataHandler xmlDH = new XMLDataHandler();
 @Override
 public Object transform(Object source, Class arg1, Object arg2)
   throws DataHandlerException {
  // TODO Auto-generated method stub
  /*
   * Set the buffer size for the input    */
  int bufferSize = 2000 * 4;
  String inputStr = null;
       if (source instanceof InputStream) {
            InputStream is = (InputStream)source;
            try {
    byte[] inputs = new byte[is.available()];
    is.read(inputs);
    inputStr = new String(inputs);
    is.reset();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
           
        } else if (source instanceof byte[]) {
            inputStr = new String((byte[])source);
        } else if (source instanceof Reader) {
        
   try {
             char[] chbf = new char[bufferSize];
             ((Reader)source).read(chbf);
             inputStr = new String(chbf);
             ((Reader)source).reset();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
           
        } else if (source instanceof String) {
            inputStr = (String)source;
        }

        /*
         * Do needed modification here for the input string. For example:
         */
       if(inputStr != null && inputStr.indexOf("<role>")!=-1)
        {
         int start = inputStr.indexOf("<role>", 0);
         int end = inputStr.indexOf("</role>",start)+7;
         inputStr = inputStr.substring(0, start) + inputStr.substring(end);

            /*
             * load XML data handler to do the transform from inputStr to DataObject              */
            return xmlDH.transform(inputStr, arg1, arg2);
        }
        else         {
        
         Object returnedObject = xmlDH.transform(source, arg1, arg2);
         return returnedObject;
        }
       
 }

 @Override
 public void transformInto(Object source, Object target, Object options)
   throws DataHandlerException {
  // TODO Auto-generated method stub
 
        xmlDH.transformInto(source, target, options);
 }

 @Override
 public void setBindingContext(Map context) {
  // TODO Auto-generated method stub
  xmlDH.setBindingContext(context);
 
 }
}



Handling faults in bindings

A fault or error that occurs at run time needs to be handled in some way by an application.

You can configure your import and export bindings to handle faults ( business exceptions) that occur during processing. You can set up a fault handler at three levels: you can associate a fault handler with a fault, with an operation, or with a binding. For import bindings, you can also set up a fault selector to determine whether a response is a fault and, if so, the name of the fault.

A fault data handler processes fault data and transforms it into the correct format to be sent by the export or import binding. For an export binding, the fault data handler transforms the exception business object sent from the component to a response message that can be used by the client application. For an import binding, the fault data handler transforms the fault data or response message sent from a service into an exception business object that can be used by the SCA component. For import bindings, the fault data handler calls the fault selector, which determines the name of the fault.

You can specify a fault data handler for a particular fault, for an operation, and for a binding. If the fault data handler is set at all three levels, the data handler associated with a particular fault is called. No further fault processing occurs. If fault data handlers are set at the operation and binding levels, the data handler associated with the operation is called. No further fault processing occurs.



Faults overview

Errors issued at run time in a Service Oriented Architecture (SOA) application can either be from a Service Component Architecture (SCA) application to another non-SCA application or from a non-SCA application to the SCA one.

The following sections provide an overview of how faults can be handled by your application, beginning with the types of faults.


Business faults

Business faults are business errors or exceptions that occur during processing. Consider the following interface which has a createCustomer operation on it. This operation has two business faults defined on it: CustomerAlreadyExists and MissingCustomerId.

In this example, if the client sends a request to create a customer to this SCA application and that customer already exists, the component throws a CustomerAlreadyExists fault to the export. The export now needs to propagate this business fault back to the calling client.

This is achieved by the fault data handler that is setup on the export binding. When a business exception is received by the export binding, the binding calls the fault data handler with the data object from the service business exception.

  1. The binding calls the appropriate data handler with the data object.
  2. The fault data handler transforms the fault data object to a response message and returns it to the export binding.
  3. The export returns the response message to the client.

If the service business exception contains the name of the fault, then the data handler setup on the fault will be called. If the service business exception does not contain the name of the fault, then the fault name will be derived by matching the fault types.


Runtime exceptions

Runtime exceptions are classified as all the exceptions that occur in the SCA application due to processing of the request and do not correspond to a business fault. Runtime exceptions are not defined on the interface as business faults are. In certain scenarios, you may want to propagate these runtime exceptions to the client application so the client application can take the appropriate action.

For example, if a client sends a request to create a customer to the SCA application and an authorization error occurs during processing of this request, the component throws a runtime exception. This runtime exception has to be propagated back to the calling client so it can take the appropriate action regarding the authorization. This is achieved by the runtime exception data handler configured on the export binding. The processing of a runtime exception is similar to the processing of a business fault.

If a runtime exception data handler was set up, the following processing occurs:

  1. The export binding calls the appropriate data handler with the service runtime exception.
  2. The data handler transforms the fault data object to a response message and returns it to the export binding.
  3. The export returns the response message to the client.


Fault handling on imports and exports

To handle both business faults and runtime exceptions, you can set up fault handling on imports and exports. Handling faults on either imports or exports is optional. You would likely create fault handlers for the most common errors that could occur at run time in your application.

You can create fault handlers on imports and exports for the following bindings: JMS, MQ JMS, generic JMS, MQ and HTTP. You can also add them to your imports and exports created with EIS bindings for services using adapters, except for those services that use CICS and IMS adapters.

In the following diagram of an import, a fault occurs on the external service the import is calling. The numbers refer to the numbers in the diagram.

  1. The fault is transformed into the data format expected by the component either as a business fault or a runtime exception.
  2. The fault originally is passed as a native response message. This fault could be passed in to any JMS-type binding (JMS, MQ JMS and generic JMS), MQ or HTTP binding, or as an exception from an EIS system.

Returning a fault in the expected format is discussed in Data format considerations.

In the following diagram of an export, a business fault or a runtime exception occurs in the SCA environment. The numbers refer to the numbers in the diagram.

  1. The fault is passed back to the client by the export in a response message. The transport can be any JMS-type binding, an MQ binding or an HTTP binding. It is transformed into the native data format expected by the client.
  2. The fault originally occurs in the SCA environment resulting in either a business fault or a runtime exception.

Returning a fault in the expected format is discussed in Data format considerations.

You can create a fault handler for your import or export on three levels. You can associate a fault handler with a binding, with an operation or with a specific fault.


Data format considerations

As with transforming data formats on bindings, so to there must be a way of transforming data formats for a fault handler since a fault in one environment must be expressed in the data format of another as the result of a request-response operation. For example, suppose a fault is issued in a non-SCA environment as the result of a call made to an application in this environment by an import. The fault in that non-SCA environment might be returned as text in a response message to the import. The import, on receiving the text in a message, must transform this text to the expected XML format in the SCA environment.

When you create a fault handler you are required to also specify how the data will be transformed between the two environments. Specifying the data format transformation for fault handlers is similar to specifying the data format transformation for bindings.


Wizard for configuring faults

Faults are initially defined in the interface editor where you add faults to the operations on the interface. For example, in the screen capture that follows the getInventory operation has two faults, one to handle a timeout condition and one to handle a system failure.

When you add a binding to and import or export, these faults are detected by the generate binding wizard.

Once you have generated a binding, you can find and modify the fault information in the properties view of the import or export. For example, in the following screen capture of a JMS binding on an import, the fault selector, fault data format and runtime exception data format are shown. Since implementing fault handling is optional, none of these elements have been implemented. If you wanted to add fault handling, you would begin by implementing the fault selector, the fault data format and, if you wanted to handle runtime exceptions, the runtime exception data format.


Fault selectors

For bindings on imports, you can configure a fault selector to determine whether a response is a fault and, if so, the name of the fault. The fault selector determines whether the import response is an actual response, a business exception, or a runtime fault. It also determines, from the response body or header, the native fault name.

The fault selector is called by a binding whenever the binding interacts with the native consumer ( a queue or an adapter) and receives a normal response or an exception (business or runtime) in the process.

The fault selector is optional. If you do not specify a fault selector, the binding calls the response data binding or data handler.


Fault data handlers

A fault data handler is nothing but a data handler. It has the same interface as a data handler.

The use of fault data handlers with respect to faults is similar to the use of data handlers with respect to bindings. Though IBM Integration Designer provides pre-packaged fault handlers, you may have a need to create your own type of fault handler for your particular application. A fault data handler transforms fault data into a data object that can be returned in a service business exception object. A fault data handler can be used by both import and export bindings.

You can specify a fault data handler for a binding, an operation or a particular fault.

You can configure a data handler to handle runtime exceptions that are received from external applications or send runtime exceptions that have occurred in your module to the external applications. If your module does not want to send or receive runtime exceptions to external applications or modules, then you should not define the data handler for runtime exceptions and leave it blank.



Prepackaged fault components

Some prepackaged fault components are provided for the bindings you work with.

The following list of bindings have a set of prepackaged fault components. Click the binding and it will open the appropriate list of fault components. This list is found in the information on each binding.

You may also create your own fault selector as a resource configuration. See Create a fault selector resource configuration.



Header-based fault selector

A header-based fault selector determines whether a response message is a business fault, a runtime exception or a normal message based on the headers in the incoming response message.

This fault selector can be used with JMS, MQ JMS, MQ, generic JMS and HTTP imports.

The section below explains the behavior of the header-based fault selector when default configuration is used.


Business faults

If an application wants to indicate the incoming message is a business fault, then there must be two headers in the incoming message for business faults, which is shown as follows:


Runtime exceptions

If an application wants to indicate the incoming response message is a runtime exception, then there must be one header in the incoming message, which is shown as follows:


Normal message

If an application wants to indicate the incoming message is a normal message, then none of these headers should be present in the incoming response message or the header value for FaultType should be something other than "Business" or "Runtime".



SOAP fault selector

The SOAP fault selector determines if the response SOAP message is a normal response, business fault or runtime exception.

Since SOAP has a first class representation of faults, the fault selector can easily determine if the response message is a normal message or a fault. There is no standard way to further classify the fault to a business fault or runtime fault hence the soap header is used to indicate whether the fault is business or runtime.

A business fault can be sent as part of the SOAP message with the following custom SOAP header. "CustomerAlreadyExists" is the name of the fault in this case.

The data will be in the details part of the SOAP fault.

If the fault name returned in the business fault case does not match to any native faults on the operation, then the binding will throw this as a service runtime exception.

A runtime fault can be sent as part of the SOAP message with the following custom SOAP header <ibmSoap:RuntimeFault xmlns:ibmSoap="http://www.ibm.com/soap"/> and the data in the details part of the SOAP fault.

If no custom business or runtime fault header is present and the fault code has a "Server" in it, then it is considered a runtime exception.

If the SOAP body is a fault and there is no business fault or runtime exception header present, then it is considered a business fault.

This fault selector can be used with JMS, MQ JMS, MQ, generic JMS and HTTP imports.



Developing a custom fault selector

To develop your own custom fault selector, you must implement the FaultSelector interface, implement a method in the BindingContext interface and understand Service Message Object (SMO) headers.


Implementing the FaultSelector interface

The custom fault selector must implement the com.ibm.websphere.dhframework.faults.FaultSelector interface.

package com.ibm.websphere.dhframework.faults;

import commonj.connector.runtime.BindingContext;


/**
* A Fault Selector that determines if the input data is a business fault,
* runtime fault or a normal response. It also determines the native fault name.
*/

public interface FaultSelector
extends BindingContext
{
public static enum ResponseType {
RESPONSE, BUSINESS_FAULT, RUNTIME_EXCEPTION };


/**
* This method looks at the source object or headers from the context service to
* determine if the response is fault or not. If the source data is read from the * input stream or reader, then this method should put this read data in the binding
* context so it can be accessed by the data handler.

* @param source
* This can be of type InputStream, Reader or Java Object like an
* Exception Object or the serialized object in case of JMS ObjectMessage.
* @return Whether the response is a normal response, business fault or
* runtime exception.
*/
ResponseType getResponseType(Object source);


/**
* Gets the native fault name from the headers from the context service or from the * source object.
*
* @param source
* This can be either InputStream, Reader or Java Object like an
* Exception Object or the serialized object in case of JMS ObjectMessage.
* @return The native fault name.
*/
String getFaultName(Object source); } 

The source data is shared between the fault selector and the data handler. If the fault selector has read the data from the input stream or reader, then the data handler will not be able to read this data again. The fault selector has to put the read data in the binding context so it can be used by the data handler.


Binding context interface

The binding context contains runtime contextual information passed from the caller to the data handler. The BindingContext interface specifies the runtime context of the data handler. The DataHandler interface extends from BindingContext interface. Therefore, each data handler implementation needs to implement the setBindingContext method of the BindingContext interface.

public void setBindingContext( Map context)
 {
  this.context = context;
 }

The context is a Map. The key gives the name of the context information and the value passed gives its value. Refer to the BindingContext class for the information that bindings can provide in the context. The following table contains the list of some of the relevant information available in the context.

BindingContext keys

Key Value Description of value
BindingContext.BINDING_COMMUNICATION BindingContext.BINDING_COMMUNICATION_INBOUND BindingContext.BINDING_COMMUNICATION_OUTBOUND Indicates if the native data is coming into the module or going out of the module.
BindingContext.BINDING_CONFIGURATION Configuration properties of the Java™ code. This Java code provided by the data handler implementation contains the values for the properties that are set at design time. This information is set by the BindingRegistry which instantiated the data handler.

See Access configuration properties for more details.

BindingContext.BINDING_INVOCATION BindingContext.BINDING_INVOCATION_REQUEST BindingContext.BINDING_ INVOCATION_RESPONSE BindingContext.BINDING_ INVOCATION_FAULT Indicates whether the invocation to the data handler is in the context of a request, response or fault.
BindingContext.BINDING_NAME String Name of the export or import
BindingContext.EXPECTED_TYPE Qualified name (QName) of the business object. The QName of the expected type of business object for native data to business object transformation. This information is set by the caller of the data handler.

See Obtain a business object type for more details.

BindingContext .BINDING_REGISTRY Runtime implementation of the Binding registry. The Binding registry maintains all the data handler, data binding and function selectors. This information is set by the BindingRegistry which instantiated the data handler.

See Binding registry and invoking other data handlers for more details.

WPSBindingContext.FAULT_NAME String Name of the business fault in case of export response
WPSBindingContext.TRANSFORMED_DATA Object This allows context data sharing between the function selector and data handler, and fault selector and data handler. If the data is already parsed or read by the function selector or fault selector then it can be stored in the context and passed onto the data handler so the data handler does not re-read it.



Example of a custom fault selector

This code sample shows how you might develop a custom fault selector.

In this incomplete code sample, a framework of code selects a fault from the payload in the body of a SOAP message. The sample finds the correct fault by examining details, which your implementation would provide (see faultName = "deduce from fault detail";).

package com.ibm.wbiserver.faults;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Map;

import javax.xml.soap.Detail;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;

import com.ibm.websphere.dhframework.faults.FaultSelector;
import com.ibm.websphere.sca.bindingcore.WPSBindingContext;

/**
 * This is only a sample. This is not IBM supported code as is.
 */
@SuppressWarnings("unchecked")
public class SOAPFaultDetailFaultSelectorSample implements FaultSelector {
 private static final long serialVersionUID = 6799865355976712457L;
 String faultName = null;
 Map context = null;

 public String getFaultName(Object source) {
  return faultName;
 }

 public ResponseType getResponseType(Object source) {
  ResponseType LocalResponseType = null;
  InputStream inputStream = null;
 if (source instanceof InputStream) {
   inputStream = (InputStream) source;
  } else {
   try {
    inputStream = convertReader((Reader) source, "UTF-8");
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  MessageFactory factory;
  try {
   factory = MessageFactory.newInstance();
   SOAPMessage msg = factory.createMessage(null, inputStream);
   context.put(WPSBindingContext.TRANSFORMED_DATA, msg);
   LocalResponseType = setResponseAndFault(msg);
  } catch (SOAPException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return LocalResponseType;
 }

 public static InputStream convertReader(Reader source, String encoding)
   throws IOException {

  Reader sourceReader = (Reader) source;
  char[] ch = new char[2];
  StringBuffer buffer = new StringBuffer();
  int len = sourceReader.read(ch);
  while (len != -1) {
   buffer.append(ch, 0, len);
   len = sourceReader.read(ch);
  }
  String sourceString = buffer.toString();
  byte[] sourceBytes = null;
 if (encoding != null) {
   sourceBytes = sourceString.getBytes(encoding);
  } else {
   sourceBytes = sourceString.getBytes();
  }
  ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
    sourceBytes);

  return byteArrayInputStream;
 }

 /**
     *
     */
 protected FaultSelector.ResponseType setResponseAndFault(SOAPMessage msg)
   throws SOAPException {

  ResponseType theResponse = null;
  SOAPBody body = msg.getSOAPBody();
  SOAPFault soapFault = body.getFault();
  String faultCode = soapFault.getFaultCode();
  Detail faultDetail = soapFault.getDetail();

  // TODO not complete - look at faultDetail and set values  if (ok) {
   faultName = "deduce from fault detail";
   theResponse = FaultSelector.ResponseType.BUSINESS_FAULT;
  } else {
   faultName = null;
   theResponse = FaultSelector.ResponseType.RUNTIME_EXCEPTION;
  }
  return theResponse;
 }

 public void setBindingContext(Map context) {
  this.context = context;
 }
}



Resource configurations for imports and exports

Resource configurations can be used with imports and exports to provide reusable configurations for your services. In this section, you are shown how to create these resource configurations with the tools in IBM Integration Designer.



Create a data format transformation resource configuration

In order to invoke a data handler from a data format transformation, create a binding resource configuration for it. This example creates a binding resource configuration for a delimited data handler.

To create the configuration, follow these steps:

  1. Right-click the module and from the menu select New > Configure Binding Resource. The Binding Resource Configuration window opens. On the Select a Configuration Type page, select Data transformation. Click Next.
  2. By default, the existing data format transformations, that is, the existing data format handlers, in the binding registry are shown. These prepackaged data handlers are described in Prepackaged data format handlers.

    You may also select a custom data format transformation from your workspace on the class path. Note that only classes on the class path with a name following this pattern <class name>Properties are selectable.

    Selecting Show the deprecated data format transformations adds previous transformations that have been deprecated.

    In this example, we chose the Delimited data format. Click Next.

    Note that if you chose another popular format, the SOAP data format, and clicked Next you would have the following selections on the next page.

    • Propagate SOAP headers: Selecting this option propagates the SOAP header information at run time
    • Construct the faultcode of SOAP Fault as QName format: Selecting this option means your faults will use the qualified name (QName) for a namespace; that is you intend to use the SOAP with Attachments API for Java (SAAJ) 1.3 standard. If you do not select this option, which is the default, then your faults will contain the unqualified name of a namespace; that is, you intend to use the SOAP with Attachments API for Java (SAAJ) 1.2 standard.

  3. Once you have selected your data format transformation, the wizard allows you to proceed to the Data Transformation Properties page where you can add or modify properties such as, in this case, the delimiter for the data.

    The delimited format property fields are discussed in Delimited format properties. Other format property fields are discussed in Data handler formats.

  4. In the New Data Transformation Configuration page, you can change or create a new module for the data format transformation, add a folder to contain the generated files and name and describe your configuration. Click Finish and the data format transformation resource configuration is completed and shown in the editor.
  5. The data format handler configuration is completed and shown in the editor along with the bindings it can be used with. It also is listed in the navigation under Binding Resources.

    If you had chosen a SOAP data format then you will see the options discussed earlier in the Properties view.




Create a function selector resource configuration

The configuration of a function selector, which determines which operation to call on an export interface, is discussed.

In this example, the module and the WebSphere Adapter for Flat Files had been previously set up. Creating a function selector resource configuration with the binding resource configuration wizard is shown.

  1. Right-click the module and from the menu select New > Binding Resource Configuration. The Binding Resource Configuration window opens. Select Function Selector and click Next.

  2. Select either an existing function selector or create your own custom function selector that is available in your workspace on the class path.

    In the second case, the Function selector class name field lets you select a class from an existing collection of custom function selectors you have created previously. Note that only classes on the class path with a name following this pattern <class name>Properties are selectable.

    Click Next.

  3. Once you have selected your function selector, the wizard allows you to proceed to the Function Selector Properties page, where you can add properties such as, in this case, the incoming text file with the customer data.

    The properties you are configuring are rules on how to map from the name of a file to an object name. The rule is a regular expression for a file name. In the following example, if a file named Customer.txt is placed in the event directory, which is used by the WebSphere Adapter for Flat Files as the point where files are read, the function selector will map the file to an operation named emit<object name>, so emitCustomer. For the object name, you would specify the name of your input type. When you construct your input operation, you would select the input type. Click Next.

  4. In the final page you specify the name of your function selector and click Finish to generate it. The function selector resource configuration is completed and shown in the editor. The function selector is listed in the navigation under Binding Resources. In the editor, you can choose to expose this function selector resource configuration to other bindings beside a binding chosen by the wizard by selecting the binding in the Select bindings table.



Create a fault selector resource configuration

The configuration of a fault selector, which can handle errors at run time, is discussed.

In this example, the module for the fault selector had been previously set up. You can alternately create the module when you launch the Binding Resource Configuration wizard.

To create a fault selector resource configuration, follow these steps:

  1. Right-click the module and from the menu select New > Configure Binding Resource. The Binding Resource Configuration window opens. Select Fault Selector and click Next.

  2. In the Select fault selector page, select an existing fault selector or choose a custom fault selector from your workspace.

    The Fault selector class name field lets you select a class from an existing list of fault selectors. The list is contextual; that is, depending on how you create your configuration, you may find a list of fault selectors that is supplied with BPM or you may not find a list at all. For example, if you had created an import with a JMS binding and then in the Faults Configuration section of the Properties view launched the Select button, you would find some existing fault selectors provided by the product because the product can determine the context for the fault selector.

    To create your own fault selectors, you would read Developing a custom fault selector. Once you had created one or more fault selectors, you would add them to the product's fault selectors by adding them through the Binding Registry section of the Preferences page as discussed in Binding registry preferences page.

    Note that only classes on the class path with a name following this pattern <class name>Properties are selectable.

    Click Next.

  3. In the Fault Selector Properties page, add the properties. Since we selected the header-based fault selector, the names for the headers were required. Click Next.

  4. In the New Binding Resource Configuration page, enter a name for your fault and, optionally, a folder. Click Finish.
  5. The fault selector resource configuration is completed and shown in the editor. The fault selector is listed in the navigation under Binding Resources. In the editor, you can choose to expose this fault selector resource configuration to other bindings besides the bindings chosen by the wizard by selecting the binding in the Select bindings table.



Editing a binding resource configuration

Binding resource configurations are listed in the Binding Resources folder of the Business Integration navigation and can be edited.

To edit a binding resource configuration, follow these steps:

  1. Expand Binding Resources in the Business Integration navigation.
  2. Double-click the configuration you want to edit.

  3. Edit the Name and Namespace fields, to edit them.

  4. Use the Browse button to select a different class name for the Class name field.

  5. In the Select bindings field, change or add different bindings by selecting them.


You can configure your binding in the Properties view by selecting a data handler, if one or more have been created, or creating a new data handler.



Limitations of binding resource configurations

A limitation of binding resource configurations is discussed.


Class does not implement correct interface message

A message the class does not implement the correct interface may be issued after you create a resource configuration for a data binding, data handler or function selector. The messages you may see are as follows:

To resolve these errors, you must place your code in one of the following locations:

If you have a JAR file containing your classes, you can create a utility project by following these steps:

  1. From the menu, select File > Import > General > File System. The Import window opens.

  2. In the From directory field, enter the JAR file location. In the Into folder field, enter the module location.

  3. Click Finish. A message asks to create a project and set it as a dependency on the module. Click Yes.
  4. A utility project is created with the correct classpath.

Alternately, if you are developing your classes in the IDE, you can either create your classes in the same module or create a Java EE utility project that specifies the same target runtime as the module. Then you should set the utility project as a dependency on the IBM Integration Designer module.


Configurations with non-configurable data bindings

In some cases, non-configurable data bindings may be used within the context of a configuration. In these cases, the normal sequence of pages in a wizard may differ.



Binding registry preferences page

The binding registry preferences page is a list of registered bindings available in IBM Integration Designer.

The following sections provide a comprehensive look at the binding registry:


Binding registry overview

When working with a resource adapter, we need to capture the information required by the adapter to marshal the EIS-neutral data objects to the native objects used to interact with the Enterprise Information System (EIS). There are several artifacts involved with the process of data conversion, formatting, and generation. The data binding generator, for example, generates a data binding implementation that is responsible for marshalling a request business object to an EIS-internal data format; it is also responsible for unmarshalling a response from an EIS-internal data format into a business object. Generic, that is, non-generated data bindings are common too. A function selector converts an inbound message to the correct function on a target service.

A data binding and function selector object can use data handlers that provide data transformation functions from one form to another.

The binding registry component provides a global point of access to the repository for data binding, data binding generator, data handler and function selector objects information. When a particular binding is selected for a service component that is being created, the registry information is accessed and the right level of the binding information is provided to the user.


Binding registry preference page overview

You can register your own binding implementations through the binding registry preference page available. To access the binding registry preference page, from the menu select Window > Preferences. In the Preferences window, expand Business Integration and click Binding Registry.

The preference page is divided into a Registry Entries view where all registry entries are shown and a Details view where properties of a selected entry are shown. You can add a new entry to the User specified entries section by using an Add button or edit an existing user specified entry by using an Edit button. These buttons launch windows that you complete. You can also remove a user specified entry by using a Delete button. The plug-in specified entries and the adapter specified entries are treated as system entries and cannot be changed.


Import and exporting user-specified entries

You may decide to remove your entries from the binding registry but do not want to lose the entries information itself. You can store selected entries from the user-specified entries section into a file by using the export function which is activated by clicking the Advanced button. Subsequently, the entries stored in the file can be added back into the binding registry by using the import function, which is also activated by the Advanced button. This feature lets you share binding registry content among workbenches.


Binding registry entry edit window

Each binding object is described by a set of properties that make it unique and thus allows it to be registered in the binding registry. The Add and Edit Binding Registry Entry window lets you contribute new or modify exiting binding object properties. The following properties describe a binding object:


Binding registry export window

The Export Binding Registry User Specified Entries window lets you copy user-defined entries to an external file so the entries can be shared among other workbenches. In the window you need to specify the name of the file including a .bindings file extension, and the location in the workspace where the file should be saved. Typically you would save the file to a folder under your Business Integration module and then export the module as an Integration module or a Project Interchange file.

Important: Only files with a .bindings file extension will be processed by the import function at the time when you retrieve the entries stored in the file back into binding registry. Therefore, DO NOT CHANGE this file extension.


Binding registry import window

The Import Binding Registry User Specified Entries window lets you load user-defined entries from an external file back into the binding registry. In the window you need to specify the location in the workspace where the file with the .bindings file extension is stored. If you do not have the file in the workspace, you can import it from the file system into workspace folder using the Import function and specifying an import from the File System.



Application Specific Information (ASI) registry preferences page

The application specific information (ASI) registry preferences page is a registered list for your ASI schemas created by IBM Integration Designer generations or by yourself.

When working with a resource adapter we need to capture the information required by the adapter to marshal the Enterprise Information Systems (EIS)-neutral data objects to the native objects used to interact with the EIS. The information that describes the data conversions is stored in XML schema files in the form of annotations. The XML schema provides an appInfo tag for providers to describe application-specific information. This schema is called the ASI schema. Application Specific Information (ASI) is metadata related to data wire formatting and schema editing that is encapsulated as annotations within a schema. This information describes a request message to an EIS or a response message from an EIS. In general, ASI schemas are provided by a resource adapter.

The Application Specific Schemas Registry (ASI registry) component provides a global point of access to the repository of XML Schema documents (ASI Schemas) that specify application-specific information used by an application to map a business object into its corresponding enterprise entity. Ultimately, all XML schemas are stored into an XML catalog component. Therefore, one of the main functions of the ASI registry is to create XML catalog entries for ASI Schemas. These entries are then used by an XML processor when resolving entity references.

To see the available ASI registry entries, from the menu select Window > Preferences. In the Preferences window, expand Business Integration and click Application Specific Schemas Registry.

The preference page is divided into a Registry Entries view where all registry entries are shown and a Details view where properties of a selected entry are shown. You can add a new entry to the User specified entries section using the Add button or edit an existing user specified entry buy using the Edit button. You can also remove a user-specified entry using the Delete button. The Plug-in specified entries and Adapter-specified entries are treated as system entries and cannot be changed.

Add application-specific entries

Each ASI schema is described by a set of properties that make it unique. This allows an ASI schema to be registered in the ASI registry. The add and edit windows allow you to contribute new ASI schema information or modify existing ASI schema information. The following properties, shown when use the add and edit buttons, describe the ASI schema.

  • Display name - Contains a short name that identifies the ASI schema that will be displayed by the IBM Integration Designer tools.
  • Description - Provides the detailed description of the ASI schema.
  • XSD file location -URL that specifies the ASI schema unique location.
  • Namespace URI - Identifies the namespace of the ASI schema.

You can browse for the ASI schema location in either the workspace or the file system using the button next to the XSD file location field. The namespace URI field will be completed automatically after the ASI schema is specified.

Import and exporting user-specified entries to and from the workbench

You may decide to remove your entries from the registry but do not want to lose the entries' information. In that case you can store selected entries from the user-specified entries tree into a file using the export function. The function is available by clicking the Advanced button. The entries stored in the file can be added back into the registry by again using the same button but using the import function. This feature means you can share user-defined content among workbenches.

Export Application Specific Schemas Registry User Specified Entries

This window lets you copy user-defined entries to an external file so the entries can be shared among other workbenches. In the window, you need to specify the name of the file with an .asi file extension. You also need to specify the location in the workspace where the file should be saved. Typically, you would save the file to a folder under your Business Integration module and then export the module as an Integration module or Project Interchange file.

Only files with .asi file extensions will be processed by the import function when you want the entries stored in the file to be added back into the ASI registry. DO NOT change this file extension.

Import Application Specific Schemas Registry User Specified Entries

This window lets you load user-defined entries from an external file back into the ASI registry. In the window, you need to specify the location in the workspace where the file with .asi file extension is stored. If you do not have the file in the workspace, you can import it from the file system into workspace folder using Import Files function.



+

Search Tips   |   Advanced Search