Example 1 - Working with Variable Length Fields

In the following example a custom field mapper class is used to implement a primitive variable length field message. The variable length field is encoded by prefixing the data with a six character string containing a number which specifies the length of the data in the remainder of the string.

Note that this example only shows the implementation at the Cúram end of the queue. The remote system will also need to understand the encoding method and implement the necessary translations using the language of choice on the remote system.

The following pseudo code describes the struct being used in the operation. Fields idNumber and dateOfBirth will use the default conversion methods for their type and will be converted into ten and eight character strings respectively. The historyText field is a variable length field and will be encoded and decoded by means of a custom mapper class.

Figure 1. Pseudo code for the struct to be mapped:
struct PersonHistory {
  String<10> idNumber;
  String historyText;
  Date dateOfBirth;
}

Method addToHistory of class LegacyBPO sends a PersonHistory struct to a legacy system, the legacy system will append text to the variable length field historyText and return an updated copy of PersonHistory.

Figure 2. Pseudo code for the BPO interface
interface LegacyBPO {
  PersonHistory addToHistory(dtls PersonHistory);
}

Note that field historyText is being used in two cases - once in the parameter to operation addToPersonHistory and once in the return value from the operation. Therefore, the custom mapper class must be specified for each of these cases in QueueConnectorFieldMappers.properties (the lines are broken up for clarity).

Figure 3. The property file entries linking the fields to the mapper
LegacyBPO.addToPersonHistory.dtls.historyText=
  com.acme.mqutils.VariableStringMapper
LegacyBPO.addToPersonHistory.return.historyText=
  com.acme.mqutils.VariableStringMapper

The following listing shows the implementation of the custom mapper class.

Figure 4. Mapper class implementation for variable string
package com.acme.mqutils;
// implementation for variable length string field mapper class
public class VariableStringMapper
extends MQFieldMapper {

  /**
   * The size of a prefix at the beginning of the string
   * which specifies the length of following data.
   */
  private static final int kStringHeaderInfoLength = 6;

  /**
   * Gets the encoded version of the mapped field within
   * the given struct.
   *
   * @param object The struct class containing the
   *           mapped field.
   * @return The field encoded as a String.
   * @throws AppException if the field could not be encoded.
   *
   */
  public String encode(Object object)
  throws AppException {
    String historyText = null;
    // get the "historyText" field from the given struct:
    try {
      historyText = (String) getMappedField().get(object);
    } catch (IllegalAccessException e) {
      // use the handler in the superclass to deal with
      // this exception:
      handleEncodingException(e, object);
    }

    // construct the prefix which will hold the
    // size of the data.
    int bufferLength = historyText.length();

    String sizeSpecifierString = String.valueOf(bufferLength);
    // pad the size specifier to the right length
    sizeSpecifierString = MQUtils.padRight(
      sizeSpecifierString,
      kStringHeaderInfoLength);
    // put the prefix and the data together.
    String result = sizeSpecifierString + historyText;
    return result;
  }

  /**
   * Decodes the given string and assigns the resulting value
   * to the mapped field in the struct.
   *
   * @param object The struct class containing the field
   * @param encodedString The encoded form of the data.
   * @return the number of characters consumed from the
   *         encoded string.
   * @throws AppException if the target struct field could
   *         not be accessed.
   */
  public int decode(Object object, String encodedString)
  throws AppException {
    // the first N characters contain an expression
    // specifying the width of the encoded field.
    String sizeSpecifierString =
      encodedString.substring(0, kStringHeaderInfoLength);
    sizeSpecifierString = sizeSpecifierString.trim();
    int sizeOfString = Integer.valueOf(
      sizeSpecifierString).intValue();
    // Now that we know the size of the data, take that
    // many characters of data from the encoded string:
    String historyText = encodedString.substring(
      kStringHeaderInfoLength,
      kStringHeaderInfoLength + sizeOfString);
    // Update field "historyText" of the given struct:
    try {
      getMappedField().set(object, historyText);
    } catch (IllegalAccessException e) {
       // use the handler in the superclass to deal with
       // this exception:
      handleDecodingException(e, encodedString);
    }
    // indicate how many characters we decoded - remember
    // to include both the characters used to indicate the
    // string size AND the actual string data.
    return sizeOfString + kStringHeaderInfoLength;
  }
}

Examples of MQSeries messages transmitted and received by this connector operation are:

Where the first 10 characters are the idNumber field, the last 8 characters are the dateOfBirth field and the middle section is the variable length historyText field, of which the first six characters specify the length of the data.