To develop a data handler, you implement the following methods of the DataHandler class:
The methods of your custom data handler go in the Java source file of the DataHandler class that you created in Extending the data handler base class.
The data-handler base class, DataHandler, provides the abstract
methods in Table 67, which you must implement in the
DataHandler class for your
custom data handler.
Table 67. Abstract methods in the DataHandler class
Data conversion | Format of serialized data | DataHandler method |
---|---|---|
String-to-business-object conversion | Converts serialized data, accessed through a Reader object, to a business object | getBO() - abstract |
Business-object-to-string conversion | Converts a business object to an InputStream object | getStreamFromBO() |
| Converts a business object to a String object | getStringFromBO() |
| Converts a business object to a byte array. | getByteArrayFromBO() |
The following sections provide implementation information for each of the abstract DataHandler methods.
The abstract getBO() method performs the string-to-business-object conversion; that is, it populates a business object with data extracted from a Java Reader object. There are two versions of the getBO() method:
Input arguments include a Reader object that contains the serialized data and a reference to the business object. The method populates the theBusObj business object with the serializedData data.
Input arguments include a Reader object that contains the serialized data. The method determines the name of the business object type (the business object definition) from the data, then creates and fills a business object instance of that type.
The getBO() method allows the caller to pass in an optional object containing configuration information (the config parameter). This information is in addition to the configuration information specified in the data-handler meta-object. As an example, the configuration object can point to a template file or to a URL that the data handler uses.
The purpose of the abstract getBO() method is to populate a business object with the serialized data that the Reader object contains. The public versions of getBO() can then receive the serialized data in one of several supported forms, convert the data to a Reader object, and then call the abstract getBO() method to perform the actual string-to-business-object conversion. For more information on the public getBO() method, see getBO() - public.
Figure 36 shows a basic implementation of the second form of the getBO() method. The example illustrates the steps in the conversion of data from a Reader object that contains fixed-width data to a business object:
Figure 36. Example getBO() method
public BusinessObjectInterface getBO(Reader serializedData, Object config) throws Exception { clear(config); BusinessObjectInterface resultObj = null; // Create a String object from the Reader, then use the string // method int conversionCheck; char[] temp = new char[2000]; StringBuffer tempStringBuffer = new StringBuffer(1000); while ( (conversionCheck = serializedData.read(temp)) != -1 ) tempStringBuffer.append(new String (temp, 0, conversionCheck)); mBOString = new String(tempStringBuffer); mBOStringLength = mBOString.length(); resultObj = getBOFromString(null); return resultObj; } // Gets business object name and verb and creates a bus obj instance private BusinessObjectInterface getBOFromString(String pvBOType) throws Exception { BusinessObjectInterface returnObj = null; String lvBOName = null; String lvVerb = null; lvBOName = this.getNextToken(mBONameSize, true); lvVerb = this.getNextToken(mBOVerbSize, true); if( (pvBOType != null) && (lvBOName.compareTo(pvBOType) != 0) ) { throw new Exception(...); } else { returnObj = JavaConnectorUtil.createBusinessObject(lvBOName); } returnObj.setVerb(lvVerb); parseAttributeList(returnObj); return returnObj; }
// Parse String to populate the attributes in the business object protected void parseAttributeList(BusinessObjectInterface pvBO) throws Exception { if ( mEndOfBOString ) throw new Exception(...); else if( pvBO == null ) throw new Exception(...); int lvAttrNum = pvBO.getAttrCount(); String lvAttrName = null; String lvAttrValue = null; int lvAttrMaxLength = 0; try { for (int lvAttrIndex = 0; lvAttrIndex < lvAttrNum; lvAttrIndex++) { CxObjectAttr lvAttrSpec = pvBO.getAttrDesc(lvAttrIndex); lvAttrName = lvAttrSpec.getName(); // Determine if the attribute is a simple attribute or a // business object container. if (lvAttrSpec.isObjectType()) { // Get the next token based on the BOCountSize lvAttrMaxLength = mBOCountSize; lvAttrValue = this.getNextToken(mBOCountSize, true); String lvBOType = lvAttrSpec.getTypeName(); Object lvAttrBOValue = null; if (lvAttrSpec.isMultipleCard()) { this.getMultipleCard(pvBO,lvAttrIndex,lvBOType, lvAttrValue); } else { this.getSingleCard(pvBO,lvAttrIndex,lvBOType, lvAttrValue); } } else { // Get the next token based on the MaxLength of the attribute lvAttrMaxLength = lvAttrSpec.getMaxLength(); if (lvAttrMaxLength > 0) lvAttrValue = this.getNextToken(lvAttrMaxLength, false); else lvAttrValue = null;
// For simple String attribute, set to null, set to // configured CxIgnore or CxBlank values, or set to the // attribute value if (lvAttrValue == null ) pvBO.setAttrValue(lvAttrIndex, null); else if (lvAttrValue.equals(mCxIgnore)|| lvAttrValue.equals("")) pvBO.setAttrValue(lvAttrIndex, null); else if (lvAttrValue.equals(mCxBlank)|| lvAttrValue.equals(" ")) pvBO.setAttrValue(lvAttrIndex, ""); else pvBO.setAttrValue(lvAttrIndex, lvAttrValue); } } } } // Populates a child container with values in the String protected void getMultipleCard(BusinessObjectInterface pvParentBO, int pvParentAttrIndex, String pvBOType, String pvObjectCountString) throws CW_BOFormatException, Exception { try { if ( pvObjectCountString.equals(mCxIgnore) ) { // trace message } else { int lvObjectCount = Integer.parseInt(pvObjectCountString); if ( lvObjectCount == 0) { // trace message with the number of objects in container } else if (lvObjectCount > 0) { // There is at least one instance of the object in the string BusinessObjectInterface lvChildBO = null; // For each instance of the child object, parse the attribute // list, and then add the object container to the parent. for (int lvObjectIndex = 0; lvObjectIndex < lvObjectCount; lvObjectIndex++) { lvChildBO = getBOFromString(pvBOType); pvParentBO.setAttrValue(pvParentAttrIndex,lvChildBO); } } } } }
// Populates a single cardinality child with values in the String protected void getSingleCard(BusinessObjectInterface pvParentBO, int pvParentAttrIndex, String pvBOType, String pvObjectCountString) throws CW_BOFormatException, Exception { try { BusinessObjectInterface lvChildBO = null; // Check the object count token // If it does not match "1", assume that the child object should // be null if (pvObjectCountString.equals("1")) { // The string contains a single instance of the child lvChildBO = getBOFromString(pvBOType); pvParentBO.setAttrValue(pvParentAttrIndex, lvChildBO); } else if ( pvObjectCountString.equals(mCxIgnore) || pvObjectCountString.equals("0")) { // Validate that the object count token is valid } else throw new CW_BOFormatException(...); } }
The abstract methods in Table 68 perform the business-object-to-string conversion; that
is, they each create serialized data in a particular format from a business
object.
Table 68. Abstract methods to implement business-object-to-string conversion
Abstract method | Description |
---|---|
getStringFromBO() | Converts the data in a business object to a String object. |
getStreamFromBO() | Converts the data in a business object to an InputStream object. |
getByteArrayFromBO() | Cconverts the data in a business object to a byte array. |
The goal of converting from a business object is to create a serialized form of all data in the business object. Sometimes, however, some business-object data should not be included in the serialized data. For example, a business object might use a child meta-object to hold dynamic configuration information for a connector.
IBM reserves all application-specific information that begins with the prefix cw_mo_label for configuration and/or dynamic meta-data. To indicate any attribute that a data handler should ignore during conversion from a business object, the business object definition for the parent business object specifies the following tag in its application-specific information:
cw_mo_label=child_meta-object_attribute_name
where label is a string you define to further identify the purpose of the cw_mo_ tag and child_meta-object_attribute_name identifies the name of the attribute to ignore. This attribute usually contains the child meta-object. Multiple cw_mo_label tags are delimited by a semicolon (;).
When you implement the getStringFromBO(), getStreamFromBO(), and getByteArrayFromBO() methods for a custom data handler, these methods need to ensure that the data handler skips over connector-specific attributes, as follows:
The following code fragment shows how to skip over attributes:
List configObjList = com.crossworlds.DataHandlers.text.namevalue.listMOAttrNames(BusObj); //this list contains attribute names, which are configuration objects for ( attributes in BusObj ) { String attrName = BusObj.getAttrDisc(i).getName(); if ( configObjList.contains(attrName) ) { //skip continue; } }
For example, suppose a business object called MyCustomer uses a child meta-object to hold connector-specific routing information. If this meta-object is represented by an attribute named CustConfig, then MyCustomer could have the following tag in its application-specific information:
cw_mo_cfg=CustConfig
During conversion from a business object, a custom data handler checks the application-specific information for the business object definition associated with MyCustomer, locates the cw_mo_cfg tag, and determines that the CustConfig attribute needs to be skipped over. The resulting serialized data from the data handler does not include the CustConfig child meta-object.
You need to develop any custom data handler to handle cw_mo_label tags only if the data handler works with connectors that use child meta-objects or other dynamic objects.
The getStringFromBO() method performs the business-object-to-string conversion; that is, it converts the data in a business object to a String object. For this method, the caller passes in the business object to be converted. Figure 37 shows the getStringFromBO() method as implemented by the FixedWidth data handler. The method creates a String of fixed-width fields.
The example illustrates the steps in the conversion of data from a business object to a Reader object:
Figure 37. Example getStringFromBO() method
public String getStringFromBO(BusinessObjectInterface theObj, Object config) throws Exception { traceWrite( "Entering getStringFromBO(BusinessObjectInterface, Object) " + " for object type " + theObj.getName(), JavaConnectorUtil.LEVEL4); clear(config); String lvBOString = null; setAttrList(theObj); lvBOString = mBOStringBuffer.toString(); traceWrite( "Exiting getStringFromBO(BusinessObjectInterface, Object) " + " for object type " + theObj.getName(), JavaConnectorUtil.LEVEL4); return lvBOString; } protected void setAttrList(BusinessObjectInterface pvBO) throws Exception { traceWrite( "Entering setAttrList(BusinessObjectInterface) for object " + pvBO.getName(), JavaConnectorUtil.LEVEL4); int lvAttrNum = pvBO.getAttrCount(); String lvAttrName = null; String lvAttrValue = null; int lvAttrMaxLength = 0; // Add the business object name and verb to the fixed width format // String this.setSimpleToken( mBONameSize, pvBO.getName()); this.setSimpleToken( mBOVerbSize, pvBO.getVerb()); try { List moAttrNames = listMOAttrNames( pvBO ); int lvAttrCount = pvBO.getAttrCount(); ATTRIBUTE_WALK: for (int lvAttrIndex = 0; lvAttrIndex < lvAttrCount; ++lvAttrIndex) { CxObjectAttr lvAttrSpec = pvBO.getAttrDesc(lvAttrIndex); lvAttrName = lvAttrSpec.getName(); // Check if the current attribute is a simple (String) type // or a contained object. if (lvAttrSpec.isObjectType()) { //skip child objects designated as meta objects if( moAttrNames.contains( lvAttrName ) ) { continue ATTRIBUTE_WALK; }
if (lvAttrSpec.isMultipleCard()) { CxObjectContainerInterface lvAttrMultiCardBOValue = (CxObjectContainerInterface) pvBO.getAttrValue(lvAttrIndex); if (lvAttrMultiCardBOValue == null) { traceWrite( "setAttrList found empty multiple cardinality container " + lvAttrSpec.getTypeName(), JavaConnectorUtil.LEVEL5); // Add the count to the fixed width String this.setSimpleToken( mBOCountSize, "0"); } else { int lvObjectCount = lvAttrMultiCardBOValue.getObjectCount(); traceWrite( "setAttrList found multiple cardinality container " + lvAttrSpec.getTypeName() + " with " + lvObjectCount + " instances", JavaConnectorUtil.LEVEL5); // Add the count to the fixed width String this.setSimpleToken( mBOCountSize, Integer.toString(lvObjectCount)); // Add each object in the container to the fixed // width String. for (int lvContObjectIndex = 0; lvContObjectIndex < lvObjectCount; ++lvContObjectIndex) setAttrList( lvAttrMultiCardBOValue.getBusinessObject( lvContObjectIndex)); } } else { BusinessObjectInterface lvAttrSingleCardBOValue = (BusinessObjectInterface) pvBO.getAttrValue(lvAttrIndex); if (lvAttrSingleCardBOValue == null) { traceWrite( "setAttrList found empty single cardinality container " + lvAttrSpec.getTypeName(), JavaConnectorUtil.LEVEL5); // Add the count to the fixed width String this.setSimpleToken( mBOCountSize, "0"); }
else { traceWrite( "setAttrList found single cardinality container " + lvAttrSpec.getTypeName(), JavaConnectorUtil.LEVEL5); // Add the count to the fixed width String this.setSimpleToken( mBOCountSize, "1"); setAttrList(lvAttrSingleCardBOValue); } } } else { lvAttrValue = (String) pvBO.getAttrValue(lvAttrIndex); lvAttrMaxLength = lvAttrSpec.getMaxLength(); if (lvAttrMaxLength > 0) this.setSimpleToken(lvAttrMaxLength, lvAttrValue); } } } catch (CxObjectNoSuchAttributeException e) { throw new Exception(e.getMessage()); } traceWrite( "Exiting setAttrList(BusinessObjectInterface) for object " + pvBO.getName(), JavaConnectorUtil.LEVEL4); } protected void setSimpleToken( int pvCellSize, String pvTokenValue) throws Exception { traceWrite( "Entering setSimpleToken(int, String)", JavaConnectorUtil.LEVEL4); StringBuffer lvNewBuffer = new StringBuffer(pvCellSize); int lvTokenLength = 0; int lvCxIgnoreLength = mCxIgnore.length(); int lvCxBlankLength = mCxBlank.length(); int lvPadNumber = 0; // Check the token value to see if it is null if (pvTokenValue == null) { // For this case, we add the configured CxIgnore value to the // fixed width String if it fits in the cell. if (!mTruncation && lvCxIgnoreLength > pvCellSize) throw new Exception( " Null attribute value encountered where cell size is " + pvCellSize + ", size of CxIgnore value is " + lvCxIgnoreLength + "and trucation is not allowed. " + "Please check your MO format configuration.");
else { lvPadNumber = pvCellSize - lvCxIgnoreLength; lvNewBuffer.append(mCxIgnore); } } else if (pvTokenValue.equals("")) { // For this case, the configured CxBlank value is added to the // fixed width String if it fits in the cell. if (! mTruncation && lvCxBlankLength > pvCellSize) throw new Exception( " Blank attribute value encountered where cell size is " + pvCellSize + ", size of CxBlank value is " + lvCxBlankLength + "and trucation is not allowed. " + "Please check your MO format configuration."); else { lvPadNumber = pvCellSize - lvCxBlankLength; lvNewBuffer.append(mCxBlank); } } else { // For this case, actually add the token value to the fixed // width String, unless the data is too long for the cell. lvTokenLength = pvTokenValue.length(); if (!mTruncation && lvTokenLength > pvCellSize ) throw new Exception( " Attribute value encountered where cell size is " + pvCellSize + ", size of token value is " + lvTokenLength + "and trucation is not allowed. " + "Please check your MO format configuration."); else { lvNewBuffer.append(pvTokenValue); lvPadNumber = pvCellSize - lvTokenLength; } } if (lvPadNumber <= 0 && mTruncation) // Token is longer than the cell and truncation is allowed, // so the characters up to pvCellSize are added lvNewBuffer.setLength(pvCellSize); else if (lvPadNumber > 0) { // Pad the cell based on the configuration option chosen if ( mAlignment.equals(fixedwidth.AlignmentLeft) || mAlignment.equals(fixedwidth.AlignmentBoth)) this.padRight(lvNewBuffer, lvPadNumber); else if (mAlignment.equals(fixedwidth.AlignmentRight)) this.padLeft(lvNewBuffer, lvPadNumber); }
String lvNewBuffString = lvNewBuffer.toString(); // Note that this may cause a performance issue when the tracing // level is low, but in most cases it should not as any one token // is *usually* not very long. traceWrite( "Adding the following token to the fixed width String: " + lvNewBuffString, JavaConnectorUtil.LEVEL5); // After the cell has been fully formatted, append to fixed width // String being built mBOStringBuffer.append(lvNewBuffString); traceWrite( "Exiting setSimpleToken(int, String)", JavaConnectorUtil.LEVEL4); }
The getStreamFromBO() method converts the data in a business object to an InputStream object. Figure 38 shows an example implementation of the getStreamFromBO() method. In this implementation, getStreamFromBO() calls getStringFromBO() to build a String object containing the business object data, and then it converts the String to an InputStream. The method returns an InputStream object representing the data in the business object.
Figure 38. Example getStreamFromBO() method
public InputStream getStreamFromBO(BusinessObjectInterface theObj, Object config) throws Exception { clear(config); String BOstring; BOstring = getStringFromBO(theObj, config); return new ByteArrayInputStream( BOstring.getBytes() ); }
In addition to the abstract DataHandler methods (which you
must implement), you might also need to override some public
methods of the DataHandler class (see Table 69) so they work optimally with your custom data
handler.
Table 69. Public methods of the DataHandler class
Public DataHandler method | Description |
---|---|
getBO() - public | Converts serialized data(in one of several formats) to a business object. |
getBOName() | Obtains the name of the business object from the serialized data. |
getBooleanOption() | Gets a value of a Boolean configuration option from the data handler. |
getOption() | Gets the value of a configuration option from the data handler. |
setOption() | Sets a configuration option in the data handler. |
traceWrite() | Calls a trace-write method for the appropriate context of the data handler: connector or the Server Access Interface (if your integration broker is InterChange Server). |