Criando um Nó de Entrada em C

Antes de começar

Uma biblioteca de implementação carregável, ou uma LIL, é o módulo de implementação para um nó (ou analisador) em C.Uma LIL é implementada como uma DLL (Dynamic Link Library). Ela não tem a extensão de arquivo .dll, mas .lil.

As funções de implementação que precisam ser escritas pelo desenvolvedor estão relacionadas em Funções de Implementação de Nó C. As funções utilitárias fornecidas pelo WebSphere Message Broker para auxiliar esse processo estão relacionadas em Funções de Utilitários de Nó C.

O WebSphere Message Broker fornece a origem para dois nós de amostra definidos pelo usuário chamados SwitchNode e TransformNode. Você pode utilizar esses nós em seus estados atuais ou poderá modificá-los.

Inicializando o Nó

O procedimento a seguir mostra como inicializar o nó:

  1. A função de inicialização, bipGetMessageflowNodeFactory, é chamada pelo intermediário depois que a LIL tiver sido carregada e inicializada pelo sistema operacional. O intermediário chama essa função para compreender o que a LIL é capaz de fazer e como o intermediário deve chamar a LIL. Por exemplo:
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. A função bipGetMessageflowNodeFactory chama a função utilitária cniCreateNodeFactory. Essa função transmite de volta um nome de fábrica (ou nome de grupo) para todos os nós que a LIL suporta. Por exemplo:
    {
    	CciFactory* factoryObject;
    	int rc = 0;
    	CciChar factoryName[] = L"SwitchNodeFactory";
    	CCI_EXCEPTION_ST exception_st;
    
    	/* Criar a Fábrica de Nó para este nó */
    	factoryObject = cniCreateNodeFactory(0, factoryName);
    	if (factoryObject == CCI_NULL_ADDR) {
    		if (rc == CCI_EXCEPTION) {
    			/* Obter detalhes da exceção */
    			cciGetLastExceptionData(&rc, &exception_st);
    
    			/* Qualquer tratamento de erro local pode ir aqui */
    
    			/* Relançar a exceção */
    			cciRethrowLastException(&rc);
    		}
    
    			/* Qualquer tratamento de erro local adicional pode ir aqui */
    	}
    	else {
    		/* Definir os nós suportados por esta fábrica */
    		defineSwitchNode(factoryObject);
    	}
    
    	/* Retornar o endereço deste objeto de fábrica para o intermediário */
    	return(factoryObject);
    }

    Neste exemplo, se as informações de rastreio forem necessárias no UTF-16, será necessário substituir CCI_EXCEPTION_ST por CCI_EXCEPTION_WIDE_ST e cciGetLastExceptionData por cciGetLastExceptionDataW.

  3. A LIL deve chamar a função utilitária cniDefineNodeClass para transmitir o nome de cada nó e uma tabela de função virtual dos endereços das funções de implementação. Por exemplo, para definir um único nó chamado InputxNode e sua tabela de função:
    void defineInputxNode(void* factoryObject){
    	static CNI_VFT vftable = {CNI_VFT_DEFAULT};
    
    /* Configurar tabela de funções com ponteiros para funções de
    implementação do nó */
    	vftable.iFpCreateNodeContext = _createNodeContext;
    	vftable.iFpDeleteNodeContext = _deleteNodeContext;
    	vftable.iFpGetAttributeName2 = _getAttributeName2;
    	vftable.iFpSetAttribute = _setAttribute;
    	vftable.iFpGetAttribute2     = _getAttribute2;
    	vftable.iFpRun = _run;
    
    	cniDefineNodeClass(0, factoryObject, L"InputxNode", &vftable);
    
    	return;
    }

Definindo o Nó como um Nó de Entrada

Um nó definido pelo usuário se identifica como fornecendo a capacidade de um nó de entrada implementando a função de implementação cniRun. Os nós de entrada definidos pelo usuário precisam implementar uma função cniRun, caso contrário, o intermediário não carrega o nó definido pelo usuário e a função do utilitário cniDefineNodeClass falha, retornando CCI_MISSING_IMPL_FUNCTION. Quando um fluxo de mensagens contendo um nó de entrada definido pelo usuário é implementado com sucesso, o intermediário chama a função de implementação cniRun do nó em intervalos regulares.

Por exemplo:
int cniRun(
  CciContext* context,
  CciMessage* destinationList,
  CciMessage* exceptionList,
  CciMessage* message
){          
  ...
  /* Obter dados de origem externa */
  return CCI_SUCCESS_CONTINUE;
}
O valor de retorno deve ser utilizado para retornar o controle periodicamente ao intermediário.

Quando um fluxo de mensagens contendo um nó de entrada definido pelo usuário é implementado com êxito, a função cniRun do nó é chamada para cada mensagem transmitida através do fluxo de mensagens.

Os nós de entrada também podem implementar cniEvaluate, porém isso não é recomendado.

Criando uma Instância do Nó

O procedimento a seguir mostra como instanciar o nó:

  1. Quando o intermediário tiver recebido a tabela de ponteiros de função, ele chamará a função cniCreateNodeContext para cada instanciação do nó definido pelo usuário. Se houver três fluxos de mensagens que estejam utilizando o nó definido pelo usuário, a função cniCreateNodeContext será chamada para cada um deles. Essa função deve alocar memória para essa instanciação do nó definido pelo usuário para conter os valores dos atributos configurados. Por exemplo:
    1. Chamar a função cniCreateNodeContext:
      CciContext* _Switch_createNodeContext(
        CciFactory* factoryObject,
        CciChar*    nodeName,
        CciNode*    nodeObject
      ){
        static char* functionName = (char *)"_Switch_createNodeContext()";
        NODE_CONTEXT_ST* p;
        CciChar          buffer[256];
      
    2. Alocar um ponteiro para o contexto local e limpar a área do contexto:
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
      
        if (p) {
           memset(p, 0, sizeof(NODE_CONTEXT_ST));
    3. Salvar o ponteiro do objeto do nó no contexto:
         p->nodeObject = nodeObject;
    4. Salvar o nome do nó:
       CciCharNCpy((CciChar*)&p->nodeName, nodeName, MAX_NODE_NAME_LEN);
  2. Um nó de entrada tem um número de terminais de saída associados a ele, mas em geral não tem nenhum terminal de entrada. Utilize a função de utilitário cniCreateOutputTerminal para incluir terminais de saída em um nó de entrada quando o nó for instanciado. Essas funções devem ser chamadas dentro da função de implementação cniCreateNodeContext. Por exemplo, para definir um nó de entrada com três terminais de saída:
       {
          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) ;    }

Definindo Atributos

Os atributos são definidos sempre que se inicia o intermediário, ou quando se reimplementa o fluxo de mensagens com novos valores.

Em seguida à criação de terminais de saída, o intermediário chama a função cniSetAttribute para transmitir os valores dos atributos configurados do nó definido pelo usuário. Por exemplo:
    {
      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) ;
    }

Implementando a Funcionalidade do Nó

Quando o intermediário percebe que possui um nó de entrada, ele chama a função cniRun desse nó a intervalos regulares. A função cniRun deve então decidir que curso de ação tomar. Se houver dados disponíveis para processamento, a função cniRun deve chamar cniDispatchThread e processar a mensagem, ou retornar com CCI_TIMEOUT para que o intermediário possa continuar a processar outras mensagens em outros encadeamentos. Se um encadeamento não for despachado, o intermediário passará todo o tempo dentro desse encadeamento, o que o impedirá de fazer qualquer outra coisa.

Por exemplo, para configurar o nó para chamar cniDispatchThread e processar a mensagem, ou retornar com CCI_TIMEOUT:
If ( anything to do )
	CniDispatchThread;

   /* fazer o trabalho */

	If ( work done O.K.)
		Return CCI_SUCCESS_CONTINUE;
	Else
		Return CCI_FAILURE_CONTINUE;
Else
  Return CCI_TIMEOUT;

Substituindo os Atributos Padrão do Analisador de Mensagem (Opcional)

Uma implementação de nó de entrada em geral determina que analisador de mensagem analisa inicialmente uma mensagem de entrada. Por exemplo, o nó MQInput primitivo dita que um analisador de MQMD é necessário para analisar o cabeçalho MQMD. Um nó de entrada definido pelo usuário pode selecionar um analisador de cabeçalho ou de mensagem apropriado, e o modo no qual a análise é controlada, pela utilização dos seguintes atributos que são incluídos como padrão e que podem ser substituídos:

rootParserClassName
Define o nome do analisador raiz que analisa os formatos de mensagem suportados pelo nó de entrada definido pelo usuário. Seu padrão é GenericRoot, um analisador raiz fornecido que faz com que o intermediário aloque e encadeie analisadores juntos. É improvável que um nó precise modificar esse valor de atributo.
firstParserClassName
Define o nome do primeiro analisador, naquilo que pode ser uma cadeia de analisadores responsáveis pela análise do fluxo de bits. Seu padrão é XML.
messageDomainProperty
Um atributo opcional que define o nome do analisador de mensagem necessário para analisar a mensagem de entrada. Os valores suportados são os mesmos suportados pelo nó MQInput. (Consulte Nó MQInput para obter informações adicionais sobre o nó MQInput.)
messageSetProperty
Um atributo opcional que define o identificador do conjunto de mensagem, ou o nome do conjunto de mensagem, no campo Message Set, somente se o analisador MRM tiver sido especificado pelo atributo messageDomainProperty.
messageTypeProperty
Um atributo opcional que define o identificador da mensagem no campo MessageType, somente se o analisador MRM tiver sido especificado pelo atributo messageDomainProperty.
messageFormatProperty
Um atributo opcional que define o formato da mensagem no campo Message Format, somente se o analisador MRM tiver sido especificado pelo atributo messageDomainProperty.
Se você tiver criado um nó de entrada definido pelo usuário que sempre começa com dados de uma estrutura conhecida, poderá assegurar que um determinado analisador lide com o início dos dados. Por exemplo, o MQInputNode somente lê dados das filas do WebSphere MQ, portanto esses dados sempre têm um MQMD no início, e o MQInputNode define firstParserClassName como MQHMD. Se seu nó definido pelo usuário sempre lidar com dados que começam com uma estrutura que pode ser analisada por um determinado analisador, digamos "MYPARSER", você define firstParserClassName como MYPARSER da seguinte maneira:
  1. Declare as funções de implementação:
    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. Defina o atributo na função de implementação cniCreateNodeContext:
    CciContext* _createNodeContext(
      CciFactory* factoryObject,
      CciChar*    nodeName,
      CciNode*    nodeObject
    ){
      NODE_CONTEXT_ST* p;
      ...
    
        /* Alocar um ponteiro para o contexto local */
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
        /* Criar atributos e definir valores padrão */
        {
          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);
          /*consulte a amostra BipSampPluginNode.c para a implementação
    de insAttrTblEntry*/
    
          _setAttribute(p, (CciChar*)ucsAttrName, (CciChar*)ucsAttrValue);
          free((void *)ucsAttrName) ;
          free((void *)ucsAttrValue) ;
        }

Excluindo uma Instância do Nó

Os nós são destruídos quando um fluxo de mensagens é reimplementado ou quando o processo do grupo de execução é parado (utilizando o comando mqsistop). Quando um nó é destruído, ele deve liberar qualquer memória utilizada e quaisquer recursos retidos. Isso é feito utilizando a função cniDeleteNodeContext. Por exemplo:

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

  return;
}
Avisos | Marcas Registradas | Downloads | Biblioteca | Suporte | Feedback
Direitos Autorais IBM Corporation 1999, 2005 Última Atualização: 04/11/2005
as09960_