WebSphere Message Broker, Versión 8.0.0.5 Sistemas operativos: AIX, HP-Itanium, Linux, Solaris, Windows, z/OS

Consulte la información sobre la última versión del producto en IBM Integration Bus, Versión 9.0

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

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.

Antes de empezar

Cuando codifica un nodo de proceso de mensajes o un nodo de salida, los nodos proporcionan esencialmente los mismos servicios. Puede realizar el proceso de mensajes en un nodo de salida y puede enviar un mensaje a una corriente de bits utilizando un nodo de proceso de mensajes. Para una mayor facilidad, este tema hace referencia principalmente al nodo como nodo de proceso de mensajes, pero también contiene información sobre las funciones de ambos tipos de nodo.

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

Para obtener más información sobre las funciones de implementación de nodo C que escribe para el nodo, consulte Funciones de implementación de nodo en C. Puede llamar a las funciones de programa de utilidad de nodo C, implementadas en el intermediario de tiempo de ejecución, para ayudar con la operación de nodo; consulte Funciones de utilidad de nodo en C.

WebSphere Message Broker proporciona el origen de dos nodos definidos por el usuario de ejemplo denominados SwitchNode y TransformNode. Puede utilizar estos nodos en su estado actual o puede modificarlos. Además, puede ver el ejemplo siguiente que muestra el uso de nodos definidos por el usuario, incluyendo un nodo de proceso de mensajes escrito en C.

Puede ver información sobre los ejemplos sólo cuando utilice el Information Center que está integrado en WebSphere Message Broker Toolkit o el Information Center en línea. Puede ejecutar ejemplos sólo cuando utilice el Information Center que está integrado en WebSphere Message Broker Toolkit.

Declaración y definición del nodo

Para declarar y definir un nodo definido por el usuario en el intermediario, incluya una función de inicialización bipGetMessageflowNodeFactory, en su LIL. Los pasos siguientes tienen lugar en la hebra de configuración e indican cómo llama el intermediario a su función de inicialización y cómo esa función declara y define el nodo definido por el usuario:

  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). El intermediario llama a esta función para conocer qué puede hacer la LIL y cómo puede llamar a la LIL el intermediario. Por ejemplo:
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. La función bipGetMessageflowNodeFactory debe llamar a la función de programa de utilidad cniCreateNodeFactory. Esta función devuelve un nombre de fábrica (o nombre de grupo) para todos los nodos soportados por la LIL. El nombre de fábrica (o nombre de grupo) debe ser exclusivo en todas las LIL en un mismo intermediario de ejecución.
  3. LIL debe llamar a la función de programa de utilidad cniDefineNodeClass para pasar el nombre exclusivo de cada nodo y una tabla de funciones virtual de las direcciones de las funciones de implementación.
    Por ejemplo, el código siguiente declara y define un solo nodo denominado MessageProcessingxNode:
    {
    	CciFactory* factoryObject;
    	int rc = 0;
    	CciChar factoryName[] = L"MyNodeFactory";
    	CCI_EXCEPTION_ST exception_st;
    
    	/* Crear la fábrica de nodos para este nodo */
    	factoryObject = cniCreateNodeFactory(0, factoryName);
    	if (factoryObject == CCI_NULL_ADDR) {
    		/* Aquí puede ir cualquier manejo de errores locales */
    	}
    	else {
    		/* Definir los nodos soportados por esta fábrica */
    	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"MessageProcessingxNode", &vftable);
    
    	}
    
    	/* Devolver la dirección de este objeto de fábrica al intermediario */
    	return(factoryObject);
    }

    Un nodo definido por el usuario se identifica a sí mismo como un nodo de salida o de proceso de mensajes implementando la función cniEvaluate. Los nodos definidos por el usuario deben implementar una función de implementación cniEvaluate o cniRun, de lo contrario el intermediario no carga el nodo definido por el usuario y la función de programa de utilidad cniDefineNodeClass falla, devolviendo CCI_MISSING_IMPL_FUNCTION.

    Cuando se despliega satisfactoriamente un flujo de mensajes que contienen un nodo de proceso de mensajes definido por el usuario, se invoca la función cniEvaluate del nodo para cada mensaje propagado al nodo.

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

    Por ejemplo:
    void cniEvaluate(                
      CciContext* context,                
      CciMessage*      localEnvironment,        
      CciMessage* exceptionList,          
      CciMessage* message                 
    ){                                    
      ...
    }
    Para el código mínimo requerido para compilar un nodo definido por el usuario en C, consulte Código de esqueleto en C.

Creación de una instancia del nodo

Para crear una instancia 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. Por ejemplo, si tres flujos de mensajes utilizan el nodo definido por el usuario, se llama a la función cniCreateNodeContext para cada uno de ellos. Esta función asigna memoria para dicha 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);
    5. Devuelva el contexto de nodo:
      return (CciContext*) p;
  2. El intermediario invoca las funciones 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 realizar llamadas a cniCreateInputTerminal y cniCreateOutputTerminal para definir los terminales del nodo de usuario. Estas funciones se deben iniciar 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) ;
        }

    El código anterior inicia las funciones insInputTerminalListEntry y insOutputTerminalListEntry. Puede encontrar estas funciones en el código de ejemplo Common.c; consulte Archivos de nodo de ejemplo. Estas funciones definen los terminales en el intermediario y almacenan los manejadores en los terminales. Los manejadores se almacenan en la estructura a la que hace referencia el valor devuelto en CciContext*. A continuación, el nodo puede acceder a los manejadores del terminal desde dentro de las otras funciones de implementación (por ejemplo, CciEvaluate) porque CciContext se pasa a esas funciones de implementación.

    El código siguiente muestra la definición de insInputTerminalListEntry:

    TERMINAL_LIST_ENTRY *insInputTerminalListEntry( 
      NODE_CONTEXT_ST* context, 
      CciChar*         terminalName 
    ){ 
      static char* functionName = (char *)"insInputTerminalListEntry()"; 
      TERMINAL_LIST_ENTRY* entry; 
      int             rc; 
     
      entry = (TERMINAL_LIST_ENTRY *)malloc(sizeof(TERMINAL_LIST_ENTRY)); 
      if (entry) { 
     
        /* Esta entrada es el final actual de la lista */ 
        entry->next = 0; 
     
        /* Almacenar el nombre del terminal */ 
        CciCharCpy(entry->name, terminalName); 
     
        /* Crear terminal y guardar su manejador */ 
        entry->handle = cniCreateInputTerminal(&rc, context->nodeObject, (CciChar*)terminalName); 
     
        /* Enlazar un elemento anterior existente con éste */ 
        if (context->inputTerminalListPrevious) context->inputTerminalListPrevious->next = entry; 
        else if ((context->inputTerminalListHead) == 0) context->inputTerminalListHead = entry; 
     
        /* Guardar el puntero al elemento anterior */ 
        context->inputTerminalListPrevious = entry; 
      } 
      else { 
        /* Error: No se ha podido asignar memoria */ 
      } 
     
      return(entry); 
    } 

    El siguiente ejemplo muestra el código para insOutputTerminalListEntry:

    TERMINAL_LIST_ENTRY *insOutputTerminalListEntry( 
      NODE_CONTEXT_ST* context, 
      CciChar*         terminalName 
    ){ 
      static char* functionName = (char *)"insOutputTerminalListEntry()"; 
      TERMINAL_LIST_ENTRY* entry; 
      int             rc; 
     
      entry = (TERMINAL_LIST_ENTRY *)malloc(sizeof(TERMINAL_LIST_ENTRY)); 
      if (entry) { 
     
        /* Esta entrada es el final actual de la lista */ 
        entry->next = 0; 
     
        /* Almacenar el nombre del terminal */ 
        CciCharCpy(entry->name, terminalName); 
     
        /* Crear terminal y guardar su manejador */ 
        entry->handle = cniCreateOutputTerminal(&rc, context->nodeObject, (CciChar*)terminalName); 
     
        /* Enlazar un elemento anterior existente con éste */ 
        if (context->outputTerminalListPrevious) context->outputTerminalListPrevious->next = entry; 
        else if ((context->outputTerminalListHead) == 0) context->outputTerminalListHead = entry; 
     
        /* Guardar el puntero al elemento anterior */ 
        context->outputTerminalListPrevious = entry; 
      } 
      else { 
        /* Error: No se ha podido asignar memoria */ 
      } 
     
      return(entry); 
    } 
    Para el código mínimo requerido para compilar un nodo definido por el usuario en C, consulte Código de esqueleto en C.

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. Su código 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) ;
    }
El número de atributos de configuración que puede tener un nodo es ilimitado. Sin embargo, un nodo no debe implementar un atributo que ya esté implementado como atributo de configuración base. La lista siguiente muestra atributos base:
  • label
  • userTraceLevel
  • traceLevel
  • userTraceFilter
  • traceFilter

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 llama 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

Si se suprime un nodo, el intermediario llama a la función cniDeleteNodeContext. Esta función se inicia en la misma hebra que cniCreateNodeContext. Utilice esta función para liberar los recursos utilizados por el nodo definido por el usuario. Por ejemplo:

void _deleteNodeContext(
  CciContext* context
){
  static char* functionName = (char *)"_deleteNodeContext()";
  free ((void*) context);
  return;
}
Avisos | Marcas registradas | Descargas | Biblioteca | Soporte | Comentarios

Copyright IBM Corporation 1999, 2014Copyright IBM Corporation 1999, 2014.

        
        Última actualización:
        
        Última actualización: 2015-02-28 17:00:27


Tema de tareaTema de tarea | Versión 8.0.0.5 | as09980_