Contents


Simplify how you manage complex input data with a custom IBM BPM data handler

Create a custom data handler for processing fixed-width data with hierarchic structures

Comments

IBM® Business Process Manager (BPM) Advanced V8 and more recent versions include an internal data handler component that transforms data from a generic data format to a Java™ object to implement the commonj.sdo.DataObject interface. It can manage various data formats, for example JavaScript Object Notation (JSON), XML, SOAP, Concurrent Versions System (CVS), and fixed-width.

But your data might be more complex. For example, consider the aerospace industry, where a part of an airplane, such as the fuselage, can contain nested and repeating parts like portholes, which also have nested parts like screws and nuts. Or consider a document of an inspection process that contains a main header and many nested documents that describe every specific inspection step.

This tutorial shows how to implement a custom data handler to manage fixed-width data that represents complex objects with multiple cardinalities. It also shows how to bind the data handler to different kinds of exports, such as Java Message Service (JMS), flat file, and IBM MQ.

If you are working in a hybrid cloud environment, you can implement the custom data handler to manage, convert, and process customer data on-premises in an IBM BPM Advanced module that is integrated with an IBM BPM process on the cloud for human validation and approval.

The fixed-width custom data handler in this tutorial was built by using the IBM BPM APIs for creating custom data handlers. See the Developing data handlers topic in the IBM BPM documentation.

What you need to complete this tutorial

  • You must have hands-on experience with IBM BPM Advanced, including IBM Integration Designer.
  • You must be expert with Java, XML Schema Definition Language (XSD), and XML parsing.
  • You must have IBM BPM Advanced (including IBM Integration Designer) V8.0 or a more recent version installed.
  • To follow along with the examples in this tutorial, download a code sample of the entire project from GitHub: github.com/elmdor666/HierarchicDataHandler. Download the project interchange compressed file and import it into the Integration Designer. The source code is not intended as production ready. Use and modify it at your own risk.

XSD files, IBM BPM data objects, and the bytes input steam

The example solution in this tutorial includes the following main data structures:

  • The XSD files, which describe the data structure.
  • The IBM BPM data objects, which are created in IBM BPM and based on the XSD files.
  • The bytes input stream, which is the external data that is handled by IBM BPM.

XSD files

The object structure is defined in one or more XSD files that are imported in an IBM BPM module so that a corresponding commonj.sdo.DataObject can be handled.

Consider a data structure that describes a movie (with the field type and the size, only for simple types, in parentheses):

MOVIE
- Title (String L50)
- Year (String L4)
- Genre (String L10)
- Directors (List of MOVIE_DIRECTOR)
- MovieAwards (List of MOVIE_AWARD)
- Actors (List of MOVIE_ACTOR)

MOVIE_DIRECTOR
- Name (String L50)
- DateOfBirth (String L10)
- DirectedMovie (List of String L50)

MOVIE_AWARD
- Name (String L50)- Year (String L4)
- Category (String L20)

MOVIE_ACTOR
- Role (String L20)
- Name (String L50)
- DateOfBirth (String L10)
- WorkedOnMovie (List of String L50)
- Awards (List of MOVIE_AWARD)

The following four XSD files represent the data:

  • MOVIE.xsd:
    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema elementFormDefault="qualified"
      targetNamespace="http://www.ibm.com/bpm/schema/MOVIE"
      xmlns:MOVIE_DIRECTOR="http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR"
      xmlns:MOVIE_ACTOR="http://www.ibm.com/bpm/schema/MOVIE_ACTOR"
      xmlns:MOVIE_AWARD="http://www.ibm.com/bpm/schema/MOVIE_AWARD"
      xmlns:bx="http://www.ibm.com/bpm/schema"
      xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:import namespace="http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR"
        schemaLocation="MOVIE_DIRECTOR.xsd"/>
      <xs:import namespace="http://www.ibm.com/bpm/schema/MOVIE_ACTOR"
        schemaLocation="MOVIE_ACTOR.xsd"/>
      <xs:import namespace="http://www.ibm.com/bpm/schema/MOVIE_AWARD"
        schemaLocation="MOVIE_AWARD.xsd"/>
      <xs:element name="MOVIE">
        <xs:annotation>
          <xs:appinfo>
            <bx:boDefinition version="3.0.0"/>
          </xs:appinfo>
        </xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element default="" minOccurs="0" name="Title">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:attributeInfo isKey="true"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="50"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="Year">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="4"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="Genre">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="10"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element minOccurs="0" name="Directors">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:childObjectInfo version="3.0.0"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:complexType>
                <xs:sequence>
                  <xs:element maxOccurs="unbounded" ref="MOVIE_DIRECTOR:MOVIE_DIRECTOR"/>
                </xs:sequence>
                <xs:attribute default="1" name="size" type="xs:positiveInteger"/>
              </xs:complexType>
            </xs:element>
            <xs:element minOccurs="0" name="MovieAwards">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:childObjectInfo version="3.0.0"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:complexType>
                <xs:sequence>
                  <xs:element maxOccurs="unbounded" ref="MOVIE_AWARD:MOVIE_AWARD"/>
                </xs:sequence>
                <xs:attribute default="1" name="size" type="xs:positiveInteger"/>
              </xs:complexType>
            </xs:element>
            <xs:element minOccurs="0" name="Actors">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:childObjectInfo version="3.0.0"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:complexType>
                <xs:sequence>
                  <xs:element maxOccurs="unbounded" ref="MOVIE_ACTOR:MOVIE_ACTOR"/>
                </xs:sequence>
                <xs:attribute default="1" name="size" type="xs:positiveInteger"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  • MOVIE_DIRECTOR.xsd:
    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema elementFormDefault="qualified"
      targetNamespace="http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR"
      xmlns:bx="http://www.ibm.com/bpm/schema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="MOVIE_DIRECTOR">
        <xs:annotation>
          <xs:appinfo>
            <bx:boDefinition version="3.0.0"/>
          </xs:appinfo>
        </xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element default="" minOccurs="0" name="Name">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:attributeInfo isKey="true"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="50"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="DateOfBirth">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="10"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="DirectedMovie" maxOccurs="unbounded">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="50"></xs:maxLength>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element
    </xs:schema>
  • MOVIE_ACTOR.xsd:
    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema elementFormDefault="qualified"
      targetNamespace="http://www.ibm.com/bpm/schema/MOVIE_ACTOR"
      xmlns:MOVIE_AWARD="http://www.ibm.com/bpm/schema/MOVIE_AWARD"
      xmlns:bx="http://www.ibm.com/bpm/schema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:import namespace="http://www.ibm.com/bpm/schema/MOVIE_AWARD"
      schemaLocation="MOVIE_AWARD.xsd"/>
      <xs:element name="MOVIE_ACTOR">
        <xs:annotation>
          <xs:appinfo>
            <bx:boDefinition version="3.0.0"/>
          </xs:appinfo>
        </xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element default="" minOccurs="0" name="Role">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="20"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="Name">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:attributeInfo isKey="true"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="50"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="DateOfBirth">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="10"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="WorkedOnMovie" maxOccurs="unbounded">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="50"></xs:maxLength>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element minOccurs="0" name="Awards">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:childObjectInfo version="3.0.0"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:complexType>
                <xs:sequence>
                  <xs:element maxOccurs="unbounded" ref="MOVIE_AWARD:MOVIE_AWARD"/>
                </xs:sequence>
                <xs:attribute default="1" name="size" type="xs:positiveInteger"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  • MOVIE_AWARD.xsd:
    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema elementFormDefault="qualified"
      targetNamespace="http://www.ibm.com/bpm/schema/MOVIE_AWARD"
      xmlns:bx="http://www.ibm.com/bpm/schema"
      xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="MOVIE_AWARD">
        <xs:annotation>
          <xs:appinfo>
            <bx:boDefinition version="3.0.0"/>
          </xs:appinfo>
        </xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element default="" minOccurs="0" name="Name">
              <xs:annotation>
                <xs:documentation/>
                <xs:appinfo>
                  <bx:boAttribute>
                    <bx:attributeInfo isKey="true"/>
                  </bx:boAttribute>
                </xs:appinfo>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="50"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="Year">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="4"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element default="" minOccurs="0" name="Category">
              <xs:annotation>
                <xs:documentation/>
              </xs:annotation>
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="20"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>

IBM BPM data objects

You import the XSD files into Integration Designer inside an IBM BPM module (also called a mediation module) with the following steps:

  1. In the Business Integration perspective, click File > New > Module and add your information. Then, right-click the data section of the module and select Import.
  2. For the import source, select WSDL and XSD.
  3. In the next window, select Local WSDL or XSD file, or Both.
  4. On the Import window, in the \DataHandler\xsd source directory, select MOVIE.xsd.

    As shown in the following screen capture, make sure that the Import dependent resources check box is selected, and that MOVIE_DIRECTOR.xsd, MOVIE_ACTOR.xsd, and MOVIE_AWARD.xsd are displayed, so that all the dependent resources are resolved and imported.

    Screen capture of IBM BPM import wizard, Local WSDL or XSD file, or                         Both window
    Screen capture of IBM BPM import wizard, Local WSDL or XSD file, or Both window

    Now the objects are available in the Data section of the Module, as shown in the following screen capture:

    Screen capture of                     the view of the Data section

    And you can view the objects graphically, as shown in the following screen capture:

    Screen capture of                     the business object editor view
    Screen capture of the business object editor view
  5. Now it is important to promote the fields that refer to a complex type objects list to a separated XSD file to make sure that the Data Handler working. This step is crucial step because the BOFactory cannot create the "wrapper" data object, because it lacks a target name space and element definition.
    Right-click the BOFactory business object and select Make private business object public and Copy to another XSD file.
  6. Specify the file name as shown in the following screen capture: Screen capture of                     Copy Private Business Object window
    Screen capture of Copy Private Business Object window

    As shown in the following three screen captures, a new XSD file is created that specifies the same target name space of the parent object. (You must complete this action for each private business object.)

    Screen capture of                     the Directors XSD file
    Screen capture of the Directors XSD file
    Screen capture of                     the Actors XSM file
    Screen capture of the Actors XSM file
    Screen capture of                     the MovieAwards XSD file
    Screen capture of the MovieAwards XSD file

Review the following the generated XSD sources:

  • Directors:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema targetNamespace="http://www.ibm.com/bpm/schema/MOVIE"
    	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    	xmlns:bx="http://www.ibm.com/bpm/schema"
    	xmlns:xs="http://www.w3.org/2001/XMLSchema"
    	xmlns:MOVIE_DIRECTOR="http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR">
    	<xsd:import schemaLocation="MOVIE_DIRECTOR.xsd"
    		namespace="http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR">
    	</xsd:import>
    	<xs:element name="Directors">
    		<xs:annotation>
     <xs:documentation />
     <xs:appinfo>
     <bx:boAttribute>
     <bx:childObjectInfo version="3.0.0" />
     </bx:boAttribute>
     </xs:appinfo>
     </xs:annotation>
    		<xs:complexType>
    			<xs:sequence>
    				<xs:element maxOccurs="unbounded"
    					ref="MOVIE_DIRECTOR:MOVIE_DIRECTOR" />
    			</xs:sequence>
    			<xs:attribute default="1" name="size"
    				type="xs:positiveInteger" />
    		</xs:complexType>
    	</xs:element>
    </xsd:schema>
  • Actors:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema targetNamespace="http://www.ibm.com/bpm/schema/MOVIE"
    	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    	xmlns:bx="http://www.ibm.com/bpm/schema"
    	xmlns:MOVIE_ACTOR="http://www.ibm.com/bpm/schema/MOVIE_ACTOR"
    	xmlns:xs="http://www.w3.org/2001/XMLSchema">
    	<xsd:import schemaLocation="MOVIE_ACTOR.xsd"
    		namespace="http://www.ibm.com/bpm/schema/MOVIE_ACTOR">
    	</xsd:import>
    	<xs:element name="Actors">
    		<xs:annotation>
     <xs:documentation />
     <xs:appinfo>
     <bx:boAttribute>
     <bx:childObjectInfo version="3.0.0" />
     </bx:boAttribute>
     </xs:appinfo>
     </xs:annotation>
    		<xs:complexType>
    			<xs:sequence>
    				<xs:element maxOccurs="unbounded"
    					ref="MOVIE_ACTOR:MOVIE_ACTOR" />
    			</xs:sequence>
    			<xs:attribute default="1" name="size"
    				type="xs:positiveInteger" />
    		</xs:complexType>
    	</xs:element>
    </xsd:schema>
  • MovieAwards:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema targetNamespace="http://www.ibm.com/bpm/schema/MOVIE"
    	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    	xmlns:bx="http://www.ibm.com/bpm/schema"
    	xmlns:xs="http://www.w3.org/2001/XMLSchema"
    	xmlns:MOVIE_AWARD="http://www.ibm.com/bpm/schema/MOVIE_AWARD">
    	<xsd:import schemaLocation="MOVIE_AWARD.xsd"
    		namespace="http://www.ibm.com/bpm/schema/MOVIE_AWARD">
    	</xsd:import>
    	<xs:element name="MovieAwards">
    		<xs:annotation>
     <xs:documentation />
     <xs:appinfo>
     <bx:boAttribute>
     <bx:childObjectInfo version="3.0.0" />
     </bx:boAttribute>
     </xs:appinfo>
     </xs:annotation>
    		<xs:complexType>
    			<xs:sequence>
    				<xs:element maxOccurs="unbounded"
    					ref="MOVIE_AWARD:MOVIE_AWARD" />
    			</xs:sequence>
    			<xs:attribute default="1" name="size"
    				type="xs:positiveInteger" />
    		</xs:complexType>
    	</xs:element>
    </xsd:schema>

The bytes input stream

Based on the data structure that is defined in the previous section, the following screen capture shows the format of the bytes input stream:

Screen capture of a                     bytes input stream
Screen capture of a bytes input stream

The following rules apply to the input stream:

  • Every portion of the input stream that describes a complex object starts with the object name.
  • Every field has a fixed width and is padded with a special character if the value does not fulfill its size.
  • When an attribute is a list of simple objects (like the "DirectedMovie" element of the MOVIE_DIRECTOR), specify the cardinality by using 4 bytes before the values list.
  • When an attribute is a list of complex types (like the "Awards" of the MOVIE_ACTOR), specify the cardinality by using 4 bytes, followed by the object name (in this example, MOVIE_AWARDS), before the complex object fields values.
  • If a child object is not present in the input stream, the 4 bytes representing the cardinality have the value of 0 without the object name.

Solution diagram

The following solution diagram includes all high-level components for the custom data handler:

Solution diagram                     for example custom data handler
Solution diagram for example custom data handler

Java implementation

The example custom data handler project in this tutorial is implemented as a Java EE Connector Architecture (JCA) module that consists of three main packages:

  • com.ibm.it.issw.utils.datahandler, for the implementation of the Data Handler.
  • com.ibm.it.issw.utils.xsd, for the XSD parser implementation.
  • com.ibm.it.issw.utils.logging, for the custom logger based on java.util.logging.Logger.

You can see the packages in the following screen capture:

Screen capture of the data handler project structure
Screen capture of the data handler project structure

The XSDParser class

The XSDParser class implements the parser that extracts from the XSD files all the information that the custom data handler needs to transform the data input stream into business objects.

It saves the information in the following class attributes:

  • private String objectName;
    for the name of the main element in the XSD file
  • private ParsedXSD parsedAttribues;
    for the XSD file elements
  • private Hashtable<String, XSDParser> parsedXSDs;
    for the elements that are contained in the imported XSD files

Access the attributes with the following methods:

  • public String getObjectName();
  • public ParsedXSD getParsedAttribues();
  • public Hashtable<String, XSDParser> getParsedXSDs();

The main function of the parser is in the parseXSDToProperties method that transforms an XSD file's xs:elements into properties of the ParsedXSD type.

The XSD file must have a structure like the one described for the Movie example:

  • The xs:schema tag contains only 1 xs:element, which represents the name of the data object.
  • The main xs:element contains an xs:complexType that has an xs:sequence of xs:element.
  • Each xs:element in the sequence can be one of the following elements:
  • A simple element is an xs:simpleType tag that contains an xs:restriction tag that specifies the element fixed length in the nested xs:maxLength tag (with attribute value).
  • A list of simple elements is an xs:element with the same characteristics previously described and with the maxOccurs attribute set to "unbounded".
  • A complex element is an xs:complexType tag that contains an xs:sequence of xs:element with the datatype name in the attribute reference. The name must be the same of the XSD file that contains the data type definition.

For example, the MOVIE_DIRECTOR XSD file has <xs:element maxOccurs="unbounded" ref="MOVIE_DIRECTOR:MOVIE_DIRECTOR"/> as the xs:element of the sequence, and <xs:import namespace="http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR" schemaLocation="MOVIE_DIRECTOR.xsd"/> as the import for the data type definition.

The method signature is public void parseXSDToProperties() throws XSDParserException.

It searches for the XSD file (specified when the XSDParser object is first instantiated) in the application class path and, if it is not present, on disk.

The parser then uses javax.xml.xpath.XPath (and org.w3c.dom.Document) to navigate the XSD and save its information into the attributes of the class: the name of the root element in the objectName attribute and the target namespace and child elements in the parsedAttributes attribute.

For simple elements, use the parsedAttribues's putAttributeWithInfo method to save the attribute name and fixed length.

For lists of simple elements, the method creates a ParsedXSD object and calls on it the buildStringListObject method, passing the attribute name and fixed length. Then it sets the object as the parsedAttributes of a new XSDParser object that is added to the parsedXSDs attribute of the original XSDParser object with the name of the subobject (generated by the buildStringListObject method). Finally, it saves the attribute name and the subobject name in the parsedAttributes of the original XSDParser object.

For complex elements, the method recursively starts the parseXSDToProperties method on the child element XSD file and saves the related information (contained in the child XSDParser object) into the parsedXSDs attribute of the class. Finally, it saves the attribute name and the subobject name in the parsedAttributes attribute of the class.

The XSDParser class also has a public String printParsedXSDs() method that you can use to print the parsed properties. This method recursively retrieves the object name, the target name space, attribute names, and related fixed length or the subobject name for the entire parsed XSD file and prints them on the output string.

The following example shows the output that is generated by the printParsedXSDs method for the MOVIE.xsd file:

MOVIE:
targetNamespace = http://www.ibm.com/bpm/schema/MOVIE
Title=50
Year=4
Genre=10
Directors=MOVIE_DIRECTOR
MovieAwards=MOVIE_AWARD
Actors=MOVIE_ACTOR
MOVIE\MOVIE_DIRECTOR:
targetNamespace = http://www.ibm.com/bpm/schema/MOVIE_DIRECTOR
Name=50
DateOfBirth=10
DirectedMovie=STRINGLIST_DirectedMovie
MOVIE_DIRECTOR\STRINGLIST_DirectedMovie:
targetNamespace =
STRINGLIST_DirectedMovie=50
MOVIE\MOVIE_AWARD:
targetNamespace = http://www.ibm.com/bpm/schema/MOVIE_AWARD
Name=50
Year=4
Category=20
MOVIE\MOVIE_ACTOR:
targetNamespace = http://www.ibm.com/bpm/schema/MOVIE_ACTOR
Role=20
Name=50
DateOfBirth=10
WorkedOnMovie=STRINGLIST_WorkedOnMovie
Awards=MOVIE_AWARD
MOVIE_ACTOR\STRINGLIST_WorkedOnMovie:
targetNamespace =
STRINGLIST_WorkedOnMovie=50
MOVIE_ACTOR\MOVIE_AWARD:
targetNamespace = http://www.ibm.com/bpm/schema/MOVIE_AWARD
Name=50
Year=4
Category=20

ParsedXSD class

Use the ParsedXSD class to save the information that is related to the elements of an XSD file.

The class has the following two attributes:

  • private String targetNamespace; for the target namespace of the XSD file
  • private LinkedHashMap<String, String> attributesWithInfo; for the attributes present in the XSD file and their fixed length

Use the following methods to work with the data that is contained in the class' attributes:

  • The public LinkedHashMap<String, String> getattributesWithInfo() method retrieves the ordered list of attribute names and related information as a LinkedHasMap.
  • The public String getAttributeInfo(String key) method retrieves the information that is related to the specified attribute as a String.
  • The public String getTargetNamespace() method retrieves the targetNamespace as a String.
  • The public Set<String> getAttributeNames() method retrieves the list of attribute names of the ParsedXSD object as a Set of String.
  • The public void putAttributeWithInfo(String key, String value) method adds one element to the attributeWithInfo list, placing it at the end of the ordered list.
  • The public void setTargetNamespace(String targetNamespace) method overrides the targetNamespace attribute with the value passed as the input parameter.
  • The public boolean isSimpleAttribute(String key) method checks if the attribute passed as input parameter is of a simple type (if the information associated to the attribute is a number).
  • The public boolean isStringListAttribute(String key) method checks if the attribute passed as input parameter is of a string list type (if the information associated to the attribute begins with the STRINGLIST_ prefix).
  • The public String buildStringListObject(String attributeName, String elementLenght) method sets the targetNamespace attribute for the current object to the empty string. It uses the putAttributeWithInfo method to add the attributeName (modified with the STRINGLIST_ prefix) and the elementLength as the only element of the ordered attributes' list of the ParsedXSD object.
  • The public String printToString() method retrieves target name space, attribute names, and related fixed length or subobject name for the ParsedXSD object, and prints them on the output string.

HierarchicFixedWidthDHProperties class

The custom hierarchic fixed-width data handler has the following properties that you can configure:

  • The protected char padCharacter; property is the pad character that is used in the data stream to be parsed by the data handler to make the attribute values of the proper fixed length. It has the initial value of a blank.
  • The protected int dataObjectNameSize; property is the length of the portion of the input data stream that contains the business object name. It has the initial value of 40.
  • The protected int verbSize; property is the length of the portion of the input data stream that contains the verb. It has the initial value of 10. If the verb is not present (as in the Movie example), this property must be set to 0.
  • The protected String xsdFileName; property is the name of the XSD file containing the business object definition. If it is in the Integration Designer class path (true if you imported the XSD object definition before you created the data handler), you must specify only the name of the file. Otherwise, the full path is required.
  • The protected XSDParser xsdParser; property is the XSDParser object that contains the information that is retrieved from the XSD file that is specified in the xsdFileName property. This property cannot be configured and is automatically set when the xsdFileName is specified. When the xsdFileName property is added in the data handler create window, the related XSD file is parsed, and its information is saved in the xsdParsed property.

HierarchicFixedWidthDH class

The HierarchicFixedWidthDH class implements the DataHandler interface, which implements the following three methods:

  • public Object transform(Object source, Class targetClass, Object options) throws DataHandlerException
    This method reads the data that is contained in the input stream. It is passed as Object in the source parameter. It writes the data in a data object of the targetClass type to the output Object parameter.
  • public void transformInto(Object source, Object target, Object options) throws DataHandlerException
    This method transforms the data passed as the object in the source input parameter to the target object.
  • public void setBindingContext(Map context)
    This method sets the bindingContext of the data handler to the provided map value.

The HierarchicFixedWidthDH class has the same attributes of the HierarchicFixedWidthDHProperties class and the following additional attributes:

  • The private String dataObjectString; attribute is the input object stream transformed to a String.
  • The private int dataObjectStringLength; attribute is the length of the input stream transformed to a String.
  • The private Map bindingContext; attribute is the object containing the HierarchicFixedWidthDHProperties as a Map.

The transform method first transforms the input stream from the possible inputs (InputStream, Reader, byte[], String) to a String, saves it to the dataObjectString attribute, and calculates its length into the dataObjectStringLength attribute. Then it calls the protected method getDataObjectFromString to read the data object from the generated String.

The protected DataObject getDataObjectFromString(DataObject dataObject) throws HierarchicFixedWidthDHException method is one of the methods implemented in the custom data handler.

Consider the following actions of the getDataObjectFromString method:

  • It loads the configuration from the binding context and sets the relative attributes in the data handler object (setupConfig method).
  • It reads the data object name and the verb (getDataObjectName method).
  • It instantiates a new data object with the retrieved targetNamespace and objectName (createByElement method of the com.ibm.websphere.bo.BOFactory class).
  • It calls the parseAllProperties method to recursively retrieve all the information from the input stream String.

The protected void parseAllProperties(DataObject dataObject, XSDParser parsedXSD) throws HierarchicFixedWidthDHException method is one of the methods that are implemented in the custom data handler.

The parseAllProperties method iterates on the attributeWithInfo entry set of the parsedAttributes that is contained in the parsedXSD input parameter.

Consider the following behavior for each attribute:

  • If it is a simple attribute, the method reads the related number of bytes from the input stream and set the attribute value (dataObject.setString method)
  • If it is not a simple attribute, the method reads the number of subobjects from the input stream. Then, it moves on to the following behavior:
  • If the attribute is a list of strings, it creates a List<String>, and it reads the specified number of strings of the relative length and adds them to the list. Then, it adds the list to the data object (dataObject.setList method).
  • If the attribute is a complex type, it instantiates a new data object with the targetNamespace of the data object and the objectName of the child (createByElement method of the com.ibm.websphere.bo.BOFactory class), creates a List<DataObject> to contain all the child objects. Then, for each child object, it retrieves the object name (getDataObjectName method) from the input stream, creates a child object (createByElement method of the com.ibm.websphere.bo.BOFactory class), and calls the parseAllProperties method to retrieve all the information from the input stream String. Then, it adds the child object to the list and adds the list to the data object.

Test with a flat file adapter and a JMS export

Now learn how to implement a module for testing the solution in this tutorial. The module contains two different export components in IBM BPM:

  • A flat file adapter export
  • A JMS export
  1. First, create a module called TestMovieSource.
  2. Import every XSD file that defines the MOVIE structure (by following the steps in the previous section).

    The new module looks like the following screen capture:

    Screen capture of the imported TestMovieSource                                     module
  3. In the same workspace, import the HierarchicFixedWidthDH project and add it to the TestMovieSource Java EE Dependencies. As shown in the following screen capture, make sure that the Deploy With Module check box is selected: Screen capture of                     module dependencies
    Screen capture of module dependencies
  4. To create the first export, open the module assembly diagram and drag the Flat File Inbound Adapter from the palette.
  5. Select the simple option as shown in the following screen capture and click Next: Screen capture of the New External Service window
    Screen capture of the New External Service window
  6. Rename the FlatFileExport name to MovieExport, as shown in the following screen capture, and click Next.Screen capture of New Inbound Flat File Service                                     window
    Screen capture of New Inbound Flat File Service window
  7. For the business object, click Browse and select the MOVIE object as the main object to manage.
  8. Specify a polling directory, for example C:\tmp\MOVIE, and click Next.
  9. Select Other for the data type and click Select to specify the custom data handler.
  10. Select Select your custom data format transformation from the workspace and then click Select.
  11. Select the HierarchicFixedWidthDH Java class, as shown in the following screen capture: Screen capture of                     Select a Data Handler window
    Screen capture of Select a Data Handler window

    Now The HierarchicFixedWidthDH configuration window opens, as shown in the following screen capture:

    Screen capture of                     Data Handler Configuration window
    Screen capture of Data Handler Configuration window

    You can edit the following information:

    • The data object name size in the input stream (in bytes).
    • The pad character (one character, the default is blank).
    • The verb size (in bytes). Some streams might define the verb, such as create.
    • The root .xsd file name. This file is searched in the module data and parsed. If not found, an error message is displayed at the top of the properties pane.
  12. Give a name to the Data Handler configuration and click Finish.

    You see that a new interface is created to manage the MOVIE object, as shown in the following screen capture:

    Screen capture of                     the MovieExport interface
    Screen capture of the MovieExport interface
  13. Now create a JMS inbound export and select the same interface of the flat file export. In the JMS export binding configuration, specify JNDI names for the activation specification and destination, as shown in the following screen capture, and click Finish. Screen capture of New JMS Export                     Service window
    Screen capture of New JMS Export Service window

    These resources are created in the IBM BPM application server runtime environment, where the module is deployed.

    The JMS export must define the same custom data handler of the flat file export, as shown in the following two screen captures:

    Screen capture of                     the JMS inbound export data handler binding
    Screen capture of the JMS inbound export data handler binding
    Screen capture of                     the JMS inbound export data handler binding for MovieDTConfiguration
    Screen capture of the JMS inbound export data handler binding for MovieDTConfiguration
  14. Create a mediation flow component from the palette to handle the MOVIE object when it is received from both the flat file adapter or the JMS export. This mediation flow component implements the same interface of the two exports.

The assembly diagram now looks like the following screen capture:

Screen capture of                     assembly diagram
Screen capture of assembly diagram

The following screen capture shows the mediation implementation. The mediation implementation contains just a custom transformation to log the MOVIE service message object.

Screen capture of                     mediation flow
Screen capture of mediation flow

The following screen capture shows the log component of the mediation flow:

Screen capture of                     the mediation flow log component
Screen capture of the mediation flow log component

This scenario is triggered in either of the following two situations:

  • A text file (containing the stream that is described in the previous section) is moved to the polling directory that is specified in the flat file export properties (C:\tmp\MOVIE in this example).
  • The same data is sent in the destination queue called jms/MovieQueue.

Conclusion

The custom data handler sample in this tutorial is fundamental to managing data structures that are not standard (such as XML) or when you can't use the IBM BPM standard fixed-width data handler because the input byte stream has a hierarchic data structure.

In this tutorial, you learned how to implement a custom data handler for IBM BPM to manage fixed-width data with complex and recursive structures.

Now you can use the data handler interfaces in IBM BPM to implement your own custom data handler. With your new custom data handler, you can manage various non-standard data structures that go beyond the default IBM BPM data handler capabilities.

Acknowledgements

The authors would like to thank Antonio Dell'Olio for his review and comments on this article.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Middleware
ArticleID=1047469
ArticleTitle=Simplify how you manage complex input data with a custom IBM BPM data handler
publish-date=07132017