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ó em Linguagem C. As funções utilitárias fornecidas pelo para auxiliar esse processo estão relacionadas em Funções Utilitárias de Nó em Linguagem C.
oferece o código fonte de dois nós definidos pelo usuário chamados SwitchNode e TransformNode. Você pode utilizar esses nós em seus estados atuais ou poderá modificá-los.
Um nó de entrada pode receber dados de qualquer tipo de origem externa, tal como um sistema de arquivos ou conexões FTP, desde que a saída do nó esteja no formato correto. Para conexões a filas ou bancos de dados, devem-se utilizar os nós primitivos da IBM e as chamadas de API fornecidas, principalmente porque os nós primitivos já estão configurados para tratamento de erros. Não utilize os comandos mqget ou mqput para acesso direto às tabelas do banco de dados.
{ static char* functionName = (char *)"_Input_run()"; void* buffer; CciTerminal* terminalObject; int buflen = 4096; int rc = CCI_SUCCESS; int rcDispatch = CCI_SUCCESS; char xmlData[] = "<A>data</A>"; buffer = malloc(buflen); memcpy(buffer, &xmlData, sizeof(xmlData)); cniSetInputBuffer(&rc, message, buffer, buflen); } /*propagate etc*/ free(buffer);O exemplo acima ilustra uma área de memória sendo alocada (buffer = malloc(buflen);). Ao programar em C, sempre que se alocar memória é preciso liberá-la quando ela não for mais necessária. O intermediário pode tentar acessar essa memória a qualquer tempo enquanto a mensagem estiver sendo propagada através do fluxo, portanto a memória deve ser liberada somente depois de chamar cniPropagate na mesma CciMessage.
Um nó de entrada tem uma responsabilidade de executar o processamento apropriado de final de mensagem quando uma mensagem tiver sido propagada através de um fluxo de mensagens. Especificamente, o nó de entrada precisa fazer com que qualquer transação seja consolidada ou retornada e retornar os encadeamentos ao conjunto de encadeamentos.
Cada encadeamento do fluxo de mensagens é alocado de um conjunto de encadeamentos mantido para cada fluxo de mensagens, e inicia a execução na função cniRun. O comportamento de um encadeamento é determinado utilizando-se a função do utilitário cniDispatchThread juntamente com o valor de retorno apropriado.
O termo transaction é utilizado genericamente aqui, para descrever uma transação coordenada globalmente ou uma transação controlada pelo intermediário. As transações globalmente coordenadas são coordenadas pelo como um Gerenciador de Transação compatível com XA ou pelo RRS (Resource Recovery Service) no . O controla transações, consolidando (ou revertendo) os recursos do banco de dados e, em seguida, consolidando as unidades de trabalho do ; no entanto, se um nó definido pelo usuário for utilizado, as atualizações do recurso não podem ser consolidadas automaticamente pelo intermediário. O nó definido pelo usuário utiliza valores de retorno para indicar se uma transação obteve êxito, e para controlar se as transações foram consolidadas ou retornadas. Quaisquer exceções não tratadas são capturadas pela infra-estrutura do intermediário e a transação é revertida.
A tabela a seguir descreve cada um dos valores de retorno suportados, o efeito que cada um deles tem em qualquer transação e o que o intermediário faz com o encadeamento atual.
Valor de Retorno | Efeito na Transação | Ação do Intermediário no Encadeamento |
---|---|---|
CCI_SUCCESS_CONTINUE | consolidado | Chama o mesmo encadeamento novamente na função cniRun. |
CCI_SUCCESS_RETURN | consolidado | Retorna o encadeamento para o conjunto de encadeamentos. |
CCI_FAILURE_CONTINUE | retornado | Chama o mesmo encadeamento novamente na função cniRun. |
CCI_FAILURE_RETURN | retornado | Retorna o encadeamento para o conjunto de encadeamentos. |
CCI_TIMEOUT | Não aplicável. A função periodicamente atinge o tempo limite enquanto aguarda por uma mensagem de entrada. | Chama o mesmo encadeamento novamente na função cniRun. |
{ ... cniDispatchThread(&rcDispatch, ((NODE_CONTEXT_ST *)context)->nodeObject); ... if (rcDispatch == CCI_NO_THREADS_AVAILABLE) return CCI_SUCCESS_CONTINUE; else return CCI_SUCCESS_RETURN; }
Antes de propagar uma mensagem, você precisa decidir que dados do fluxo de mensagens deseja propagar, e que terminal deve receber os dados.
O terminalObject é derivado de uma lista que o próprio nó definido pelo usuário mantém.
if (terminalObject) { if (cniIsTerminalAttached(&rc, terminalObject)) { if (rc == CCI_SUCCESS) { cniPropagate(&rc, terminalObject, destinationList, exceptionList, message); } }
No exemplo acima, a função cniIsTerminalAttached é utilizada para testar se a mensagem pode ser propagada para o terminal especificado. Se você não utilizar a função cniIsTerminalAttached e o terminal não estiver conectado a outro nó por um conector, a mensagem não será propagada. Se você utilizar essa função, poderá modificar o comportamento do nó quando um terminal não estiver conectado.
O procedimento a seguir mostra como inicializar o nó:
CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix bipGetMessageflowNodeFactory()
{ 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); }
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.iFpGetAttributeName = _getAttributeName; vftable.iFpSetAttribute = _setAttribute; vftable.iFpGetAttribute = _getAttribute; vftable.iFpRun = _run; cniDefineNodeClass(0, factoryObject, L"InputxNode", &vftable); return; }
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.
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.
O procedimento a seguir mostra como instanciar o nó:
CciContext* _Switch_createNodeContext( CciFactory* factoryObject, CciChar* nodeName, CciNode* nodeObject ){ static char* functionName = (char *)"_Switch_createNodeContext()"; NODE_CONTEXT_ST* p; CciChar buffer[256];
p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST)); if (p) { memset(p, 0, sizeof(NODE_CONTEXT_ST));
p->nodeObject = nodeObject;
CciCharNCpy((CciChar*)&p->nodeName, nodeName, MAX_NODE_NAME_LEN);
{ 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) ; }
Os atributos são definidos sempre que se inicia o intermediário, ou quando se reimplementa o fluxo de mensagens com novos valores.
{ 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) ; }
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.
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;
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:
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); }
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) ; }
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; }
Conceitos relacionados
Planejando Extensões Definidas pelo Usuário
Extensões Definidas pelo Usuário no Ambiente de Tempo de Execução
Projetando Extensões Definidas pelo Usuário
Nós Input definidos pelo usuário
Tarefas relacionadas
Desenvolvendo Extensões Definidas pelo Usuário
Implementando as Amostras Fornecidas
Compilando uma Extensão Definida pelo Usuário em C
Referências relacionadas
Nó MQInput
API de Nó C Definido pelo Usuário
Avisos |
Marcas |
Downloads |
Biblioteca |
Suporte |
Feedback
![]() ![]() |
as09960_ |