Extending the capability of a C message processing or output node

When you have created a user-defined message processing or output node in C, you can extend its capability.

Before you begin

Read the topic Creating a message processing or output node in C.

About this task

After you have created a user-defined node, the following options are available:
  1. Accessing message data
  2. Transforming a message object
  3. Accessing ESQL
  4. Propagating a message
  5. Writing to an output device

Accessing message data

About this task

In many cases, the user-defined node must access the contents of the message that is received on its input terminal. The message is represented as a tree of syntax elements. Groups of utility functions are provided for message management, message buffer access, syntax element navigation, and syntax element access. (See C node utility functions for details of the utility functions.)

The types of query that you are likely to want to perform include:
  • Obtaining the root element of the required message object
  • Accessing the bit stream representation of an element tree
  • Navigating or querying the tree by asking for child or sibling elements by name
  • Getting the type of the element
  • Getting the value of the element

For example, to query the name and type of the first child of body:

void cniEvaluate( ...               
){                                    
  ...
/* Navigate to the target element */ 
  rootElement = cniRootElement(&rc, message);
  bodyElement = cniLastChild(&rc, rootElement);
  bodyFirstChild = cniFirstChild(&rc, bodyElement);

/* Query the name and value of the target element */
  cniElementName(&rc, bodyFirstChild, (CciChar*)&elementname, sizeof(elementName)); 
  bytes = cniElementCharacterValue(
		&rc, bodyfirstChild, (CciChar*)&eValue, sizeof(eValue));
  ...    
}

To access the bit stream representation of an element tree you can use the cniElementAsBitstream function. Using this function, you can obtain the bit stream representation of any element in a message. See cniElementAsBitstream for details of how to use this function, and sample code.

Transforming a message object

About this task

The received input message is read-only, therefore before a message can be transformed, you must write it to a new output message using the cniCreateMessage function. You can copy elements from the input message, or you can create new elements and attach them to the message. New elements are typically in a parser's domain.

For example:
  1. To write the incoming message to a new message:
    {
      ...
      context = cniGetMessageContext(&rc, message)); 
      outMsg = cniCreateMessage(&rc, context)); 
      ...
    }
  2. To make a copy of the new message:
    cniCopyElementTree(&rc, sourceElement, targetElement);
  3. To modify the value of a target element:
      cniSetElementIntegerValue(&rc, targetElement, L"newValue", 8); 
  4. After finalizing and propagating the message, you must delete the output message using the cniDeleteMessage function:
     cniDeleteMessage(&rc, outMsg);
As part of the transformation, you might want to create a new message body. To create a new message body, use one of the following functions, which assign a parser to a message tree folder:
cniCreateElementAsFirstChildUsingParser
cniCreateElementAsLastChildUsingParser
cniCreateElementAfterUsingParser
cniCreateElementBeforeUsingParser
When creating a message body, do not use the following functions because they do not associate an owning parser with the folder:
cniCreateElementAsFirstChild
cniCreateElementAsLastChild
cniCreateElementAfter
cniCreateElementBefore

Accessing ESQL

About this task

Nodes can invoke ESQL expressions using Compute node ESQL syntax. You can create and modify the components of the message using ESQL expressions, and you can refer to elements of both the input message and data from an external database using the cniSqlCreateStatement, cniSqlSelect, cniSqlDeleteStatement, and cniSqlExecute functions.

For example, to populate the Result element from the contents of a column in a database table:

{
  ...
  sqlExpr = cniSqlCreateStatement(&rc, 
   (NODE_CONTEXT_ST *)context->nodeObject,
   L"DB", CCI_SQL_TRANSACTION_AUTO,
   L"SET OutputRoot.XMLNS.Result[] = (SELECT T.C1 AS Col1 FROM Database.TABLE AS T;");
  ...
  cniSqlSelect(&rc, sqlExpr, localEnvironment, exceptionList, message, outMsg);
  cniSqlDeleteStatement(&rc, sqlExpr);
  ...                                                               
}

For more information about ESQL, see ESQL overview.

If your user-defined node primarily uses ESQL, consider using a Compute node.

Propagating a message

About this task

Before you propagate a message, decide what message flow data you want to propagate, and which terminal is to receive the data.
  1. If the message has changed, finalize the message before you propagate it using the cniFinalize function. For example:
          cniFinalize(&rc, outMsg, CCI_FINALIZE_NONE);
    
  2. The terminalObject is derived from a list that the user-defined node maintains itself. To propagate the message to the output terminal, use the cniPropagate function:
      if (terminalObject) {
        if (cniIsTerminalAttached(&rc, terminalObject)) {
          if (rc == CCI_SUCCESS) {
            cniPropagate(&rc, terminalObject, localEnvironment, exceptionList, outMsg);
          }
        }

    In the above example, the cniIsTerminalAttached function is used to test whether the message can be propagated to the specified terminal. If you do not use the cniIsTerminalAttached function and the terminal is not attached to another node by a connector, the message is not propagated and no warning message is returned. Use the cniIsTerminalAttached function to prevent this error occurring.

  3. If you created a new output message using cniCreateMessage, after propagating the message, delete the output message using the cniDeleteMessage function:
     cniDeleteMessage(&rc, outMsg);

Writing to an output device

About this task

A transformed message must be serialized to a bit stream; a message can be serialized only once.

The bit stream can then be accessed and written to an output device. Write the message to a bit stream using the cniWriteBuffer function. For example:
{
  ...
  cniWriteBuffer(&rc, message);
  writeToDevice(cniBufferPointer(&rc, message), cniBufferSize(&rc, message));
  ...                                                               
}
In this example, the method writeToDevice is a user-written method which writes a bit stream to an output device.

Do not write a user-defined output node to write messages to WebSphere® MQ queues; use the supplied MQOutput node in this scenario. The integration node internally maintains a WebSphere MQ connection and open queue handles on a thread-by-thread basis, and these are cached to optimize performance. In addition, the integration node handles recovery scenarios when certain WebSphere MQ events occur; this recovery would be adversely affected if WebSphere MQ MQI calls are used in a user-defined output node.