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 entrada en C

Cree un nodo de entrada definido por el usuario en C para recibir mensajes en un flujo de mensajes.

Antes de empezar

Una biblioteca de implementación cargable, o 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.

Las funciones de implementación que escribe para el nodo se listan en Funciones de implementación de nodo en C. Puede llamar a funciones de utilidad, implementadas en el intermediario de ejecución, como ayuda para el funcionamiento del nodo; estas funciones se listan en 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.

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 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) exclusivo para todos los nodos soportados por la LIL. Todos los nombres de fábrica (o nombres de grupo) que se devuelven, deben ser exclusivos en todas las LIL en un mismo intermediario de ejecución.
  3. La LIL debe llamar a la función de programa de utilidad cniDefineNodeClass para pasar el nombre exclusivo de cada nodo y una tabla de función virtual de las direcciones de las funciones de implementación.
    Por ejemplo, el código siguiente declara y define un solo nodo denominado InputxNode:
    {
    	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.iFpRun = _run;
    
    	cniDefineNodeClass(0, factoryObject, L"InputxNode", &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 que proporciona las características de un nodo de entrada implementando la función de implementación cniRun.

    Los nodos definidos por el usuario tienen que implementar una función de implementación cniRun o cniEvaluate. De lo contrario, el intermediario no carga el nodo definido por el usuario y la función de utilidad cniDefineNodeClass falla, devolviendo CCI_MISSING_IMPL_FUNCTION.

    Por ejemplo:
    int cniRun(                       
      CciContext* context,                
      CciMessage*      localEnvironment,        
      CciMessage* exceptionList,          
      CciMessage* message
    ){          
      ...
      /* Obtener datos del origen externo */
      return CCI_SUCCESS_CONTINUE;                                    
    }
    Utilice el valor de retorno periódicamente para devolver el control al intermediario.

    Cuando se despliega satisfactoriamente un flujo de mensajes que contiene un nodo de entrada definido por el usuario, se llama repetidamente a la función cniRun del nodo para habilitar el nodo con el objeto de recuperar y mensajes y propagarlos al resto del flujo de mensajes.

    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 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. Invoque la función cniCreateNodeContext:
      CciContext* _createNodeContext(
        CciFactory* factoryObject,
        CciChar*    nodeName,
        CciNode*    nodeObject
      ){
        static char* functionName = (char *)"_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. Un nodo de entrada tiene asociados varios terminales de salida, pero normalmente no tiene ningún terminal de entrada. Utilice la función de utilidad cniCreateOutputTerminal para añadir terminales de salida a un nodo de entrada cuando se cree una instancia del nodo. Estas funciones se deben invocar en la función de implementación cniCreateNodeContext. Por ejemplo, para definir un nodo de entrada con tres terminales de salida:
       {
          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) ;
        }    
        {
          const CciChar* ucsCatch = CciString("catch", BIP_DEF_COMP_CCSID) ;
          insOutputTerminalListEntry(p, (CciChar*)ucsCatch);
          free((void *)ucsCatch) ;    }
    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 el flujo de mensajes con valores nuevos.

Después de que se hayan creado los terminales de salida, el intermediario invoca la función cniSetAttribute para pasar los valores de los atributos configurados 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 definido por el usuario no debe implementar un atributo que ya esté implementado como atributo de configuración base. Los atributos básicos son:
  • label
  • userTraceLevel
  • traceLevel
  • userTraceFilter
  • traceFilter

Implementación de la funcionalidad de nodo

Cuando el intermediario sabe que tiene un nodo de entrada, invoca la función cniRun de este nodo a intervalos regulares. Entonces la función cniRun debe decidir qué acción debe realizar. Si hay datos disponibles para procesar, la función cniRun puede propagar el mensaje. Si no hay datos disponibles para procesar, la función cniRun debe volver con CCI_TIMEOUT de modo que el intermediario pueda continuar realizando cambios de configuración.

Por ejemplo, para configurar el nodo para llamar a cniDispatchThread y procesar el mensaje, o volver con CCI_TIMEOUT:
If ( algo para hacer )
	CniDispatchThread;

   /* realizar el trabajo */

	If ( trabajo realizado satisfactoriamente)
		Return CCI_SUCCESS_CONTINUE;
	Else
		Return CCI_FAILURE_CONTINUE;
Else
  Return CCI_TIMEOUT;

Alteración temporal de los atributos de analizador de mensajes predeterminados (opcional)

Normalmente, una implementación de nodo de entrada determina qué analizador de mensajes analiza inicialmente un mensaje de entrada. Por ejemplo, el nodo MQInput indica que se necesita un analizador MQMD para analizar la cabecera MQMD. Un nodo de entrada definido por el usuario puede seleccionar un analizador de mensajes o cabeceras apropiado y la modalidad en la que se controla el análisis, utilizando o modificando los atributos siguiente que se incluyen como valores predeterminados:

rootParserClassName
Define el nombre del analizador raíz que analiza los formatos de mensaje soportados por el nodo de entrada definido por el usuario. Toma por omisión GenericRoot, un analizador raíz proporcionado que hace que el intermediario asigne y encadene analizadores. Es improbable que un nodo necesite modificar este valor de atributo.
firstParserClassName
Define el nombre del primer analizador, de lo que puede ser una cadena de analizadores responsables de analizar la corriente de bits. Toma por omisión XML.
messageDomainProperty
Atributo opcional que define el nombre del analizador de mensajes necesario para analizar el mensaje de entrada. Los valores soportados son los mismos que los valores soportados por el nodo MQInput.(Consulte Nodo MQInput para obtener más información.)
messageSetProperty
Atributo opcional que define el identificador de conjunto de mensajes o el nombre de conjunto de mensajes, en el campo Conjunto de mensajes, sólo si el atributo messageDomainProperty especificaba el analizador MRM.
messageTypeProperty
Atributo opcional que define el identificador del mensaje en el campo Tipo de mensaje, sólo si el atributo messageDomainProperty especificaba el analizador MRM.
messageFormatProperty
Atributo opcional que define el formato del mensaje en el campo Formato del mensaje, sólo si el atributo messageDomainProperty especificaba el analizador MRM.
Si ha escrito un nodo de entrada definido por el usuario que empieza siempre con datos de una estructura conocida, puede asegurarse de que un determinado analizador se encargue del inicio de los datos. Por ejemplo, el nodo MQInput sólo lee datos de colas de WebSphere MQ, por lo que estos datos siempre tienen MQMD al principio, y el nodo MQInput establece firstParserClassName en MQHMD. Si el nodo definido por el usuario siempre maneja datos que empiezan por una estructura que puede analizarse con un analizador específico, por ejemplo, "MYPARSER", establezcas firstParserClassName en MYPARSER de este modo:
  1. Declare las funciones de implementación:
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix bipGetMessageflowNodeFactory()
    {
      ....
      CciFactory*      factoryObject;
      ....
      factoryObject = cniCreateNodeFactory(0, (unsigned short *)constPluginNodeFactory);
      ...
      vftable.iFpCreateNodeContext = _createNodeContext;
      vftable.iFpSetAttribute      = _setAttribute;
      vftable.iFpGetAttribute      = _getAttribute;
      ...  
      cniDefineNodeClass(&rc, factoryObject, (CciChar*)constSwitchNode, &vftable);
      ...
      return(factoryObject);
    }
  2. Establezca el atributo en la función de implementación cniCreateNodeContext:
    CciContext* _createNodeContext(
      CciFactory* factoryObject,
      CciChar*    nodeName,
      CciNode*    nodeObject
    ){
      NODE_CONTEXT_ST* p;
      ...
    
        /* Asignar un puntero al contexto local */
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
        /* Crear atributos y establecer valores predeterminados */
        {
          const CciChar* ucsAttrName = CciString("firstParserClassName", BIP_DEF_COMP_CCSID);
          const CciChar* ucsAttrValue = CciString("MYPARSER", BIP_DEF_COMP_CCSID) ;
          insAttrTblEntry(p, (CciChar*)ucsAttrName, CNI_TYPE_INTEGER);
          /*ver BipSampPluginNode.c de ejemplo para la implementación de insAttrTblEntry*/
    
          _setAttribute(p, (CciChar*)ucsAttrName, (CciChar*)ucsAttrValue);
          free((void *)ucsAttrName) ;
          free((void *)ucsAttrValue) ;
        }
    En el ejemplo de código anterior, se llama al método insAttrTblEntry. Este método se declara en los nodos de ejemplo definidos por el usuario SwitchNode y TransformNode.

Supresión de una instancia del nodo

Los nodos se destruyen cuando se vuelve a desplegar un flujo de mensajes o cuando se detiene el proceso de grupo de ejecución (utilizando el mandato mqsistop). Cuando un nodo se destruye, debe llamar a la función cniDeleteNodeContext para liberar toda la memoria utilizada y todos los recursos retenidos. Por ejemplo:

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

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