Antes de empezar
Una biblioteca de implementación cargable, o una LIL, es el módulo de implementación para un nodo C (o analizador). Una LIL se implementa como una biblioteca de enlace dinámico (DLL). No tiene la extensión de archivo .dll, sino la extensión .lil.
Las funciones de implementación que debe escribir el desarrollador están enumeradas en el apartado Funciones de implementación de nodo de lenguaje C. Las funciones de programa de utilidad que proporciona WebSphere Business Integration Message Broker para facilitar este proceso están enumeradas en el apartado Funciones de programa de utilidad de nodo de lenguaje C.
WebSphere Business Integration Message Broker proporciona el origen para dos nodos de ejemplo definidos por el usuario, llamados SwitchNode y TransformNode. Puede utilizar estos nodos en su estado actual, o puede modificarlos.
Conceptualmente, un nodo de proceso de mensajes se utiliza para procesar un mensaje de una forma concreta, y un nodo de salida se utiliza para producir un mensaje como corriente de bits. No obstante, al codificar un nodo de proceso de mensajes o un nodo de salida, ambos son, esencialmente, el mismo nodo. Puede procesar mensajes en un nodo de salida y, del mismo modo, puede producir un mensaje en una corriente de bits utilizando un nodo de proceso de mensajes. Para que resulte más fácil, en este tema se identifica al nodo, principalmente, con el nodo de proceso de mensajes; no obstante, se describe la funcionalidad de ambos tipos de nodo.
En muchos casos, el nodo definido por el usuario necesita acceder al contenido del mensaje recibido en su terminal de entrada. El mensaje se representa como un árbol de elementos de sintaxis. Se proporcionan grupos de funciones de programas de utilidad para la gestión de mensajes, el acceso al almacenamiento intermedio de mensajes, la navegación por los elementos de sintaxis y el acceso a los elementos de sintaxis. Consulte el apartado Funciones de programa de utilidad de nodo de lenguaje C para obtener información detallada acerca de las funciones de los programas de utilidad.
Por ejemplo, para consultar el nombre y el tipo del primer elemento dependiente de cuerpo:
void cniEvaluate( ... ){ ... /* Navegar hasta el elemento de destino */ rootElement = cniRootElement(&rc, message); bodyElement = cniLastChild(&rc, rootElement); bodyFirstChild = cniFirstChild(&rc, bodyElement); /* Consultar el nombre y el valor del elemento de destino */ cniElementName(&rc, bodyFirstChild, (CciChar*)&elementname, sizeof(elementName)); bytes = cniElementCharacterValue( &rc, bodyfirstChild, (CciChar*)&eValue, sizeof(eValue)); ... }
El mensaje de entrada recibido es de sólo lectura, por lo tanto, antes de transformar un mensaje debe escribirlo en un nuevo mensaje de salida utilizando la función cniCreateMessage. Puede copiar elementos desde el mensaje de entrada, o puede crear nuevos elementos y adjuntarlos al mensaje. Generalmente, los nuevos elementos se encuentran en un dominio de analizador.
{ ... context = cniGetMessageContext(&rc, message)); outMsg = cniCreateMessage(&rc, context)); ... }
cniSetElementIntegerValue(&rc, targetElement, L"newValue", 8);
cniDeleteMessage(&rc, outMsg);
Los nodos pueden invocar expresiones ESQL utilizando la sintaxis ESQL del nodo Compute. Puede crear y modificar los componentes del mensaje utilizando expresiones ESQL, y puede hacer referencia a elementos del mensaje de entrada y de datos de una base de datos externa utilizando las funciones cniSqlCreateStatement, cniSqlSelect, cniSqlDeleteStatement y cniSqlExecute.
Por ejemplo, para llenar el elemento Resultado del contenido de una columna en una tabla de base de datos:
{ ... 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); ... }
Para obtener más información sobre ESQL, consulte el apartado 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)); ... }Un mensaje sólo puede serializarse una vez.
El procedimiento siguiente muestra cómo declarar el nodo al intermediario:
CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix bipGetMessageflowNodeFactory()
{ CciFactory* factoryObject; int rc = 0; CciChar factoryName[] = L"SwitchNodeFactory"; CCI_EXCEPTION_ST exception_st; /* Crear la fábrica del nodo para este nodo */ factoryObject = cniCreateNodeFactory(0, factoryName); if (factoryObject == CCI_NULL_ADDR) { if (rc == CCI_EXCEPTION) { /* Obtener detalles de la excepción */ cciGetLastExceptionData(&rc, &exception_st); /* El manejo de errores local puede incluirse aquí */ /* Volver a emitir la excepción */ cciRethrowLastException(&rc); } /* El manejo de errores local adicional puede incluirse aquí */ } else { /* Definir los nodos a los que da soporte esta fábrica */ defineSwitchNode(factoryObject); } /* Devolver dirección de este objeto de fábrica al intermediario */ return(factoryObject); }
void defineSwitchNode(void* factoryObject){ static CNI_VFT vftable = {CNI_VFT_DEFAULT}; /* Configurar tabla de funciones con punteros a las funciones */ /* de implementación de nodo */ 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; }Esta función se invoca desde la hebra de configuración.
Un nodo definido por el usuario se identifica como nodo que proporciona la capacidad de nodo de proceso de mensajes o nodo de salida mediante la implementación de la función cniEvaluate. Los nodos definidos por el usuario deben implementar una función de implementación cniEvaluate o cniRun, o ambas funciones, de lo contrario, el intermediario no carga el nodo definido por el usuario y la función de programa de utilidad cniDefineNodeClass no se ejecuta correctamente y devuelve CCI_MISSING_IMPL_FUNCTION.
Cuando un flujo de mensajes que contiene un nodo de proceso de mensajes definido por el usuario se difunde correctamente, se invoca la función cniEvaluate del nodo para cada mensaje que se pasa a través del flujo de mensajes.
Los datos de flujo de mensajes se reciben en la terminal de entrada del nodo, es decir, el mensaje, el entorno global, el entorno local y la lista de excepciones.
void cniEvaluate( CciContext* context, CciMessage* destinationList, CciMessage* exceptionList, CciMessage* message ){ ... }
El procedimiento siguiente muestra cómo crear una instancia del nodo:
CciContext* _Switch_createNodeContext( CciFactory* factoryObject, CciChar* nodeName, CciNode* nodeObject ){ static char* functionName = (char *)"_Switch_createNodeContext()"; NODE_CONTEXT_ST* p; CciChar buffer[256];
p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST)); if (p) { memset(p, 0, sizeof(NODE_CONTEXT_ST));
p->nodeObject = nodeObject;
CciCharNCpy((CciChar*)&p->nodeName, nodeName, MAX_NODE_NAME_LEN);
{ const CciChar* ucsIn = CciString("in", BIP_DEF_COMP_CCSID) ; insInputTerminalListEntry(p, (CciChar*)ucsIn); free((void *)ucsIn) ; } { const CciChar* ucsOut = CciString("out", BIP_DEF_COMP_CCSID) ; insOutputTerminalListEntry(p, (CciChar*)ucsOut); free((void *)ucsOut) ; } { const CciChar* ucsFailure = CciString("failure", BIP_DEF_COMP_CCSID) ; insOutputTerminalListEntry(p, (CciChar*)ucsFailure); free((void *)ucsFailure) ; }
Los atributos se configuran siempre que se inicia el intermediario, o al volver a difundir un flujo de mensajes con nuevos valores. Los atributos los configura el intermediario, invocando el código de usuario en la hebra de configuración. El código de usuario debe almacenar estos atributos en su área de contexto de nodo para utilizarlos al procesar mensajes posteriormente.
{ 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) ; }
Cuando el intermediario recupera un mensaje de la cola y dicho mensaje llega al terminal de entrada del nodo de proceso de mensajes o nodo de salida definido por el usuario, intermediario invoca la función de implementación cniEvaluate. Esta función se invoca en la hebra de proceso de mensajes y debe decidir qué hacer con el mensaje. Esta función puede invocarse en varias hebras, especialmente si se utilizan instancias adicionales.
Para suprimir una instancia de un nodo, debe utilizar la función cniDeleteNodeContext. Por ejemplo:
void _deleteNodeContext( CciContext* context ){ static char* functionName = (char *)"_deleteNodeContext()"; return; }
La función cniDeleteNodeContext la proporciona el usuario, y la invoca el intermediario al suprimirse un flujo de mensajes.
Conceptos relacionados
ESQL
Planificación de extensiones definidas por el usuario
Extensiones definidas por el usuario en el entorno de ejecución
Diseño de extensiones definidas por el usuario
Nodos de entrada definidos por el usuario
Tareas relacionadas
Desarrollo de extensiones definidas por el usuario
Implementación de los ejemplos proporcionados
Compilación de una extensión definida por el usuario en C
Referencia relacionada
API de nodo C definido por el usuario
Avisos |
Marcas registradas |
Descargas |
Biblioteca |
Soporte |
Información de retorno (feedback)
![]() ![]() |
as09980_ |