Creación de un nodo de proceso de mensajes o de salida en C

Antes de empezar

Una biblioteca de implementación cargable, o LIL, es el módulo de implementación para un nodo (o analizador) C. Una LIL se implementa como una biblioteca de enlaces dinámicos (DLL). No tiene la extensión de archivo .dll sino .lil.

Las funciones de implementación que el desarrollador debe escribir se listan en el apartado Funciones de implementación de nodo en C. Las funciones de programa de utilidad que WebSphere Message Broker proporciona para ayudar en este proceso se listan en el apartado Funciones de programa de utilidad de nodo en C.

WebSphere Message Broker proporciona el origen de dos nodos de ejemplo definidos por el usuario denominados SwitchNode y TransformNode. Puede utilizar estos nodos en su estado actual o puede modificarlos. También puede utilizar el ejemplo Extensión definida por el usuario.

Conceptualmente, un nodo de proceso de mensajes se utiliza para procesar un mensaje de algún modo y un nodo de salida se utiliza para producir un mensaje como una corriente de bits. Sin embargo, cuando se codifica un nodo de proceso de mensajes o un nodo de salida, éstos son esencialmente lo mismo. Puede realizar el proceso de 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. Aunque, para una mayor sencillez, este tema hace referencia principalmente al nodo como nodo de proceso de mensajes, describe la funcionalidad de ambos tipos de nodo.

Declaración del nodo en el intermediario

El procedimiento siguiente muestra cómo declarar el nodo en el intermediario:

  1. El intermediario invoca la función de inicialización, bipGetMessageflowNodeFactory, después de que el sistema operativo haya cargado e inicializado la biblioteca de implementación cargable (LIL). Dicha función se invoca desde la hebra de configuración de intermediario. El intermediario invoca esta función para saber qué es capaz de hacer la biblioteca de implementación cargable y cómo la debe invocar. Por ejemplo:
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. Entonces la función bipGetMessageflowNodeFactory invoca la función de utilidad cniCreateNodeFactory. Esta función devuelve un nombre de fábrica (o nombre de grupo) para todos los nodos soportados por la LIL. Por ejemplo:
    {
    	CciFactory* factoryObject;
    	int rc = 0;
    	CciChar factoryName[] = L"SwitchNodeFactory";
    	CCI_EXCEPTION_ST exception_st;
    
    	/* Crear la fábrica de nodos 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);
    
    			/* Aquí puede ir cualquier manejo de errores locales */
    
    			/* Volver a generar la excepción */
    			cciRethrowLastException(&rc);
    		}
    
    		/* Aquí puede ir cualquier manejo de errores locales adicional */
    	}
    	else {
    		/* Definir los nodos soportados por esta fábrica */
    		defineSwitchNode(factoryObject);
    	}
    
    	/* Devolver la dirección de este objeto de fábrica al intermediario */
    	return(factoryObject);
    }

    En este ejemplo, si se requiere información de rastreo en UTF-16, debe sustituir CCI_EXCEPTION_ST por CCI_EXCEPTION_WIDE_ST y cciGetLastExceptionData por cciGetLastExceptionDataW.

Definición del nodo como un nodo de proceso de mensajes

Entonces la biblioteca de implementación cargable (LIL) debe invocar la función de utilidad cniDefineNodeClass para pasar el nombre de cada nodo y una tabla de funciones virtual de las direcciones de las funciones de implementación. Por ejemplo, para definir un solo nodo denominado SwitchNode y la tabla de funciones:
void defineSwitchNode(void* factoryObject){
	static CNI_VFT vftable = {CNI_VFT_DEFAULT};

	/* Configurar tabla de funciones con punteros a funciones de implementación de nodo */
	vftable.iFpCreateNodeContext = _createNodeContext;
	vftable.iFpDeleteNodeContext = _deleteNodeContext;
	vftable.iFpGetAttributeName2 = _getAttributeName2;
	vftable.iFpSetAttribute      = _setAttribute;
	vftable.iFpGetAttribute2     = _getAttribute2;
	vftable.iFpEvaluate = _evaluate;

	cniDefineNodeClass(0, factoryObject, L"SwitchNode", &vftable);

	return;
}
Dicha función se invoca desde la hebra de configuración.

Un nodo definido por el usuario se identifica a sí mismo como un nodo que proporciona las posibilidades de un nodo de proceso de mensajes o de salida implementando la función cniEvaluate. Los nodos definidos por el usuario tienen que implementar una función de implementación cniEvaluate y/o cniRun o, de lo contrario, el intermediario no cargará el nodo definido por el usuario y la función de utilidad cniDefineNodeClass fallará, devolviendo CCI_MISSING_IMPL_FUNCTION.

Cuando se despliega satisfactoriamente un flujo de mensajes que contiene un nodo de proceso de mensajes definido por el usuario, se invoca la función cniEvaluate del nodo para cada mensaje pasado a través del flujo de mensajes.

Los datos de flujo de mensajes se reciben en el terminal de entrada del nodo, es decir el mensaje, el entorno global, el entorno local y la lista de excepciones.

Por ejemplo:
void cniEvaluate(                
  CciContext* context,                
  CciMessage* destinationList,        
  CciMessage* exceptionList,          
  CciMessage* message                 
){                                    
  ...
}

Creación de una instancia del nodo

El procedimiento siguiente muestra cómo crear instancias del nodo:

  1. Cuando el intermediario ha recibido la tabla de punteros de función, invoca la función cniCreateNodeContext para cada creación de instancia del nodo definido por el usuario. Si tiene tres flujos de mensajes que están utilizando el nodo definido por el usuario, se invoca la función cniCreateNodeContext para cada uno de ellos. Esta función debe asignar memoria para esa creación de instancia del nodo definido por el usuario para que contenga los valores de los atributos configurados. Por ejemplo:
    1. Se invoca la función de usuario cniCreateNodeContext:
      CciContext* _Switch_createNodeContext(
        CciFactory* factoryObject,
        CciChar*    nodeName,
        CciNode*    nodeObject
      ){
        static char* functionName = (char *)"_Switch_createNodeContext()";
        NODE_CONTEXT_ST* p;
        CciChar          buffer[256];
      
      
    2. Asigne un puntero al contexto local y borre el área de contexto:
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
      
        if (p) {
           memset(p, 0, sizeof(NODE_CONTEXT_ST));
    3. Guarde el puntero de objeto de nodo en el contexto:
         p->nodeObject = nodeObject;
    4. Guarde el nombre de nodo:
       CciCharNCpy((CciChar*)&p->nodeName, nodeName, MAX_NODE_NAME_LEN);
  2. El intermediario invoca las funciones de programa de utilidad apropiadas para obtener información sobre los terminales de entrada y los terminales de salida del nodo. Un nodo tiene asociados varios terminales de entrada y terminales de salida. En la función de usuario cniCreateNodeContext, se deben efectuar llamadas a cniCreateInputTerminal y cniCreateOutputTerminal para definir los terminales del nodo de usuario. Estas funciones se deben invocar en la función de implementación cniCreateNodeContext. Por ejemplo, para definir un nodo con un terminal de entrada y dos terminales de salida:
        {
          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) ;
        }

Establecimiento de atributos

Se establecen atributos siempre que se inicia el intermediario o cuando se vuelve a desplegar un flujo de mensajes con valores nuevos. El intermediario establece atributos invocando el código de usuario en la hebra de configuración. El código de usuario necesita almacenar estos atributos en el área de contexto de nodo, para utilizarlos posteriormente al procesar mensajes.

Después de que se hayan creado los terminales de entrada y salida, el intermediario invoca la función cniSetAttribute para pasar los valores de los atributos configurados de esta creación de instancia del nodo definido por el usuario. Por ejemplo:
    {
      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) ;
    }

Implementación de la funcionalidad de nodo

Cuando el intermediario recupera un mensaje de la cola y dicho mensaje llega al terminal de entrada del nodo de salida o de proceso de mensajes definido por el usuario, el 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é se debe hacer con el mensaje. Es posible que esta función se invoque en varias hebras, específicamente si se utilizan instancias adicionales.

Supresión de una instancia del nodo de proceso de mensajes

Para suprimir una instancia de un nodo, utilice la función cniDeleteNodeContext. Por ejemplo:

void _deleteNodeContext(
  CciContext* context
){
  static char* functionName = (char *)"_deleteNodeContext()";

  return;
}

El usuario proporciona la función cniDeleteNodeContext y el intermediario la llama cuando se suprime un flujo de mensajes.

Avisos | Marcas registradas | Descargas | Biblioteca | Soporte | Su opinión
Copyright IBM Corporation 1999, 2005 Última actualización: 11/11/2005
as09980_