Before you start
A loadable implementation library, or a LIL, is the implementation module for a C node (or parser). A LIL is implemented as a dynamic link library (DLL). It does not have the file extension .dll but .lil.
The implementation functions that have to be written by the developer are listed in C language node implementation functions. The utility functions that are provided by WebSphere Business Integration Message Broker to aid this process are listed in C language node utility functions.
WebSphere Business Integration Message Broker provides the source for two sample user-defined nodes call SwitchNode and TransformNode. You can use these nodes in their current state, or you can modify them.
Conceptually, a message processing node is used to process a message in some way, and an output node is used to output a message as a bitstream. However, when you code a message processing node or an output node, they are essentially the same thing. You can perform message processing within in output node, and likewise you can output a message to a bitstream using a message processing node. For simplicity, this topic mainly refers to the node as a message processing node, however, it discusses the functionality of both types of node.
In many cases, the user-defined node needs to access the contents of the message 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 language node utility functions for details of the utility functions.)
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)); ... }
The received input message is read-only, so 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 generally in a parser's domain.
{ ... context = cniGetMessageContext(&rc, message)); outMsg = cniCreateMessage(&rc, context)); ... }
cniSetElementIntegerValue(&rc, targetElement, L"newValue", 8);
cniDeleteMessage(&rc, outMsg);
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.XML.Result[] = (SELECT T.C1 AS Col1 FROM Database.TABLE AS T;"); ... cniSqlSelect(&rc, sqlExpr, destinationList, exceptionList, message, outMsg); cniSqlDeleteStatement(&rc, sqlExpr); ... }
For more information about ESQL, see ESQL.
cniFinalize(&rc, outMsg, CCI_FINALIZE_NONE);
if (terminalObject) { if (cniIsTerminalAttached(&rc, terminalObject)) { if (rc == CCI_SUCCESS) { cniPropagate(&rc, terminalObject, destinationList, exceptionList, outMsg); } }
cniDeleteMessage(&rc, outMsg);
{ ... cniWriteBuffer(&rc, message); writeToDevice(cniBufferPointer(&rc, message), cniBufferSize(&rc, message)); ... }A message can be serialized only once.
The following procedure shows you how to declare your node to the broker:
void defineSwitchNode(void* factoryObject){ static CNI_VFT vftable = {CNI_VFT_DEFAULT}; /* Setup function table with pointers to node implementation functions */ vftable.iFpCreateNodeContext = _createNodeContext; vftable.iFpDeleteNodeContext = _deleteNodeContext; vftable.iFpGetAttributeName = _getAttributeName; vftable.iFpSetAttribute = _setAttribute; vftable.iFpGetAttribute = _getAttribute; vftable.iFpEvaluate = _evaluate; cniDefineNodeClass(0, factoryObject, L"SwitchNode", &vftable); return; }This is called from the configuration thread.
A user-defined node identifies itself as providing the capability of a message processing or output node by implementing the cniEvaluate function. User-defined nodes have to either implement a cniEvaluate or a cniRun implementation function, or both, otherwise the broker does not load the user-defined node, and the cniDefineNodeClass utility function fails, returning CCI_MISSING_IMPL_FUNCTION.
When a message flow containing a user-defined message processing node is deployed successfully, the node's cniEvaluate function is called for each message passed through the message flow.
Message flow data is received at the input terminal of the node, that is, the message, global environment, local environment, and exception list.
void cniEvaluate( CciContext* context, CciMessage* destinationList, CciMessage* exceptionList, CciMessage* message ){ ... }
Attributes are set whenever you start the broker, or when you redeploy a message flow with new values. Attributes are set by the broker calling user code on the configuration thread. The user code needs to store these attributes in its node context area, for use when processing messages later.
{ const CciChar* ucsAttr = CciString("nodeTraceSetting", BIP_DEF_COMP_CCSID) ; insAttrTblEntry(p, (CciChar*)ucsAttr, CNI_TYPE_INTEGER); _setAttribute(p, (CciChar*)ucsAttr, (CciChar*)constZero); free((void *)ucsAttr) ; } { const CciChar* ucsAttr = CciString("nodeTraceOutfile", BIP_DEF_COMP_CCSID) ; insAttrTblEntry(p, (CciChar*)ucsAttr, CNI_TYPE_STRING); _setAttribute(p, (CciChar*)ucsAttr, (CciChar*)constSwitchTraceLocation); free((void *)ucsAttr) ; }
When the broker retrieves a message from the queue and that message arrives at the input terminal of your user-defined message processing or output node, the broker calls the implementation function cniEvaluate. This function is called on the message processing thread and it should decide what to do with the message. This function might be called on multiple threads, especially if additional instances are used.
To delete an instance of a node, you use the cniDeleteNodeContext function. For example:
void _deleteNodeContext( CciContext* context ){ static char* functionName = (char *)"_deleteNodeContext()"; return; }
The cniDeleteNodeContext function is provided by the user, and is called by the broker when a message flow is deleted.
Notices |
Trademarks |
Downloads |
Library |
Support |
Feedback
![]() ![]() |
as09980_ |