Criando um Nó de Processamento de Mensagem ou de Saída 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. Existe também a amostra do Extensão Definida pelo Usuário para ser utilizada.

Conceitualmente, um nó de processamento de mensagem é utilizado para processar uma mensagem de alguma forma, e um nó de saída é utilizado para enviar uma mensagem para a saída como um fluxo de bits. Entretanto, quando se codifica um nó de processamento de mensagem ou um nó de saída, eles são essencialmente a mesma coisa. É possível desempenhar o processamento de mensagens em um nó de saída e, da mesma forma, é possível enviar uma mensagem para um fluxo de bits utilizando um nó do processamento de mensagens. Para simplificar, este tópico refere-se principalmente ao nó como um nó de processamento de mensagem, no entanto, ele discute a funcionalidade dos dois tipos de nó.

Declarando o Nó ao Intermediário

O procedimento a seguir mostra como declarar o nó ao intermediário:

  1. A função de inicialização, bipGetMessageflowNodeFactory, é chamada pelo intermediário depois que a LIL tiver sido carregada e inicializada pelo sistema operacional. Ela é chamada a partir do encadeamento de configuração do intermediário. 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.

Definindo o Nó Como um Nó de Processamento de Mensagem

A LIL deve em seguida chamar a função utilitária cniDefineNodeClass para transmitir o nome de cada nó e uma tabela de funções virtuais dos endereços das funções de implementação. Por exemplo, para definir um único nó chamado SwitchNode e sua tabela de funções:
void defineSwitchNode(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.iFpEvaluate = _evaluate;

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

	return;
}
Ela é chamada a partir do encadeamento de configuração.

Um nó definido pelo usuário se identifica como fornecendo a capacidade de um nó de processamento de mensagem ou de saída implementando a função cniEvaluate. Os nós definidos pelo usuário precisam implementar uma função de implementação cniEvaluate ou a cniRun, ou ambas, caso contrário, o intermediário não carrega o nó definido pelo usuário e a função de utilitário cniDefineNodeClass falha, retornando CCI_MISSING_IMPL_FUNCTION.

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

Os dados do fluxo de mensagens são recebidos através do terminal de entrada do nó, ou seja, a mensagem, o ambiente global, o ambiente local e a lista de exceções.

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

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. A função de usuário cniCreateNodeContext é chamada:
      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. O intermediário chama as funções utilitárias apropriadas para localizar sobre os terminais de entrada e de saída do nó. Um nó tem um número de terminais de entrada e de terminais de saída associados a ele. Na função de usuário cniCreateNodeContext, as chamadas devem ser feitas a cniCreateInputTerminal e cniCreateOutputTerminal para definir os terminais do nó do usuário. Essas funções devem ser chamadas dentro da função de implementação cniCreateNodeContext. Por exemplo, para definir um nó com um terminal de entrada e dois terminais de saída:
        {
          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) ;
        }

Definindo Atributos

Os atributos são definidos sempre que se inicia o intermediário, ou quando se reimplementa um fluxo de mensagens com novos valores. Os atributos são definidos pelo intermediário, chamando o código do usuário a partir do encadeamento de configuração. O código do usuário precisa armazenar esses atributos em sua área de contexto do nó, para utilização no processamento de mensagens posterior.

Em seguida à criação de terminais de entrada e de saída, o intermediário chama a função cniSetAttribute para transmitir os valores dos atributos configurados para esta instanciação 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 recupera uma mensagem da fila e essa mensagem chega no terminal de entrada do nó de processamento de mensagem ou de saída definido pelo usuário, o intermediário chama a função de implementação cniEvaluate. Essa função é chamada a partir do encadeamento de processamento de mensagens e ela deve decidir o que fazer com a mensagem. Essa função pode ser chamada em vários encadeamentos, principalmente, se instâncias adicionais forem utilizadas.

Excluindo uma Instância do Nó de Processamento de Mensagem

Para excluir uma instância de um nó, é utilizada a função cniDeleteNodeContext. Por exemplo:

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

    return;
}

A função cniDeleteNodeContext é fornecida pelo usuário e é chamada pelo intermediário quando um fluxo de mensagens é excluído.

Referências relacionadas
API de Nó C Definido pelo Usuário
Avisos | Marcas Registradas | Downloads | Biblioteca | Suporte | Feedback
Direitos Autorais IBM Corporation 1999, 2005 Última Atualização: 04/11/2005
as09980_