Criando um Nó de Processamento de Mensagem ou de Saída em Java

Antes de começar

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.

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 executar processamento de mensagem dentro de um nó de saída, e da mesma forma é possível enviar uma mensagem para a saída para um fluxo de bits utilizando um nó de processamento de mensagem.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ó.

Não desenvolva nós Java no que você pretenda implementar em um intermediário em uma plataforma distribuída. Isso porque o nível de Java no pode não produzir código compatível com o nível de Java na plataforma distribuída.

Acessando os Dados da Mensagem

Em muitos casos, o nó definido pelo usuário necessita acessar o conteúdo da mensagem recebida em seu terminal de entrada. A mensagem é representada como uma árvore de elementos de sintaxe. Grupos de funções utilitárias são fornecidos para gerenciamento de mensagens, acesso a buffer de mensagem, navegação de elementos de sintaxe e acesso a elementos de sintaxe.

A classe MbElement fornece a interface para os elementos de sintaxe. Para detalhes adicionais sobre a API Java, consulte o Javadoc.

Por exemplo:

  1. Para navegar até o elemento de sintaxe relevante na mensagem XML:
        MbElement rootElement = assembly.getMessage().getRootElement();
        MbElement switchElement =
    			rootElement.getLastChild().getFirstChild().getFirstChild();
  2. Para selecionar o terminal indicado pelo valor desse elemento:
        String terminalName;
        String elementValue = (String)switchElement.getValue();
        if(elementValue.equals("add"))
          terminalName = "add";
        else if(elementValue.equals("change"))
          terminalName = "change";
        else if(elementValue.equals("delete"))
          terminalName = "delete";
        else if(elementValue.equals("hold"))
          terminalName = "hold";
        else
          terminalName = "failure";
        
        MbOutputTerminal out = getOutputTerminal(terminalName);

Transformando um Objeto Mensagem

A mensagem de entrada recebida é somente leitura, portanto antes que uma mensagem possa ser transformada é preciso gravá-la para uma nova mensagem de saída. É possível copiar elementos da mensagem de entrada ou criar novos elementos e anexá-los á mensagem. Os novos elementos em geral estão no domínio de um analisador.

A classe MbMessage fornece os construtores de cópia e métodos para obter o elemento raiz da mensagem. A classe MbElement fornece a interface para os elementos de sintaxe.

Por exemplo, onde houver um conjunto de mensagem de entrada com mensagens incorporadas:
  1. Criar uma nova cópia de conjunto de mensagens e suas mensagens incorporadas:
        MbMessage newMsg = new MbMessage(assembly.getMessage());
        MbMessageAssembly newAssembly = new MbMessageAssembly(assembly, newMsg);
  2. Navegar até o elemento de sintaxe relevante na mensagem XML:
        MbElement rootElement = newAssembly.getMessage().getRootElement();
        MbElement switchElement =
    			rootElement.getFirstElementByPath("/XML/data/action");
  3. Alterar o valor de um elemento existente:
      String elementValue = (String)switchElement.getValue();
        if(elementValue.equals("add"))
          switchElement.setValue("change");
        else if(elementValue.equals("change"))
          switchElement.setValue("delete");
        else if(elementValue.equals("delete"))
          switchElement.setValue("hold");
        else
          switchElement.setValue("failure");
  4. Incluir uma nova tag como um filho da tag chave:
        MbElement tag = switchElement.createElementAsLastChild(MbElement.TYPE_NAME,
                                                               "PreviousValue",
                                                               elementValue);
  5. Incluir um atributo a esta nova tag:
        tag.createElementAsFirstChild(MbElement.TYPE_NAME_VALUE,
                                      "NewValue",
                                      switchElement.getValue());
    
        MbOutputTerminal out = getOutputTerminal("out");

Acessando ESQL

Os nós podem chamar expressões ESQL utilizando sintaxe ESQL de nó Compute. É possível criar e modificar os componentes da mensagem utilizando expressões ESQL, e referir-se a elementos da mensagem de entrada e dos dados a partir de um banco de dados externo.

O procedimento a seguir demonstra como controlar transações no nó definido pelo usuário utilizando ESQL:
  1. Defina o nome da origem de dados ODBC a ser utilizada. Por exemplo:
    String dataSourceName = "myDataSource";
  2. Defina a instrução ESQL a ser executada:
    String statement =
       "SET OutputRoot.XML.data =
              (SELECT Field2 FROM Database.Table1 WHERE Field1 = 1);";
    Ou, se quiser executar uma instrução que não retorna nenhum resultado:
    String statement = "PASSTHRU(
                            'INSERT INTO Database.Table1 VALUES(
                                 InputRoot.XML.DataField1,
                                 InputRoot.XML.DataField2)');";
  3. Selecione o tipo de transação que deseja entre os seguintes:
    MbSQLStatement.SQL_TRANSACTION_COMMIT
    Consolide imediatamente a transação após a execução da instrução ESQL.
    MbSQLStatement.SQL_TRANSACTION_AUTO
    Consolide a transação quando o fluxo da mensagem tiver concluído. (Os retornos são executados caso necessário.)
    Por exemplo:
    int transactionType = MbSQLStatement.SQL_TRANSACTION_AUTO;
  4. Obtenha a instrução ESQL. Por exemplo:
    MbSQLStatement sql =
           createSQLStatement(dataSourceName, statement, transactionType);
    Você pode utilizar o método createSQLStatement(dataSource, statement) para definir o tipo de transação como o padrão de MbSQLStatement.SQL_TRANSACTION_AUTO).
  5. Crie o novo conjunto de mensagem a ser propagado:
    MbMessageAssembly newAssembly =
           new MbMessageAssembly(assembly, assembly.getMessage());
  6. Execute a instrução ESQL:
    sql.select(assembly, newAssembly);
    Ou, se quiser executar uma instrução ESQL que não retorna nenhum resultado:
    sql.execute(assembly);

Para obter informações adicionais sobre ESQL, consulte ESQL.

Manipulação de Exceções

Utilize a classe mbException para capturar e acessar exceções. A classe mbException retorna uma matriz de objetos de exceção que representam os filhos de uma exceção na lista de exceções do intermediário. Cada elemento retornado especifica o tipo de exceção. Uma matriz vazia será retornada se uma exceção não tiver filhos. A seguinte amostra de código mostra um exemplo do uso da classe MbException.

public void evaluate(MbMessageAssembly assembly, MbInputTerminal inTerm) throws MbException
  {
    try
      {

        // funcionalidade plug-in

      }
    catch(MbException ex)
      {
        traverse(ex, 0);

        throw ex; // se for uma reemissão, deverá ser a exceção original capturada
      }
  }

  void traverse(MbException ex, int level)
  {
    if(ex != null)
      {
        // Fazer qualquer ação aqui
        System.out.println("Level: " + level);
        System.out.println(ex.toString());
        System.out.println("traceText:  " + ex.getTraceText());

        // transpor a hierarquia
        MbException e[] = ex.getNestedExceptions();
        int size = e.length;
        for(int i = 0; i < size; i++)
          {
            traverse(e[i], level + 1);
          }
      }
  }

Consulte o javadoc para obter detalhes adicionais sobre o uso da classe mbException.

Você pode desenvolver uma mensagem definida pelo usuário processando nosso nó de saída de forma que ele possa acessar todas as exceções atuais. Por exemplo, para capturar as exceções do banco de dados você pode utilizar a classe MbSQLStatement. Essa classe define o valor do atributo 'throwExceptionOnDatabaseError', que determina o comportamento do intermediário quando ele encontra um erro no banco de dados. Quando ele for definido para true, se uma exceção for emitida, ela poderá ser capturada e manuseada pela extensão definida pelo usuário.

A seguinte amostra de código mostra um exemplo de como utilizar a classe MbSQLStatement.

public void evaluate(MbMessageAssembly assembly, MbInputTerminal inTerm) throws MbException
  {
    MbMessage newMsg = new MbMessage(assembly.getMessage());
    MbMessageAssembly newAssembly = new MbMessageAssembly(assembly, newMsg);

    String table =
       assembly.getMessage().getRootElement().getLastChild().getFirstChild().getName();

    MbSQLStatement state = createSQLStatement( "dbName",
       "SET OutputRoot.XML.integer[] = PASSTHRU('SELECT * FROM " + table + "');" );

    state.setThrowExceptionOnDatabaseError(false);
    state.setTreatWarningsAsErrors(true);

    state.select( assembly, newAssembly );

    int sqlCode = state.getSQLCode();
    if(sqlCode != 0)
      {
        // Fazer tratamento de erros aqui

        System.out.println("sqlCode = " + sqlCode);
        System.out.println("sqlNativeError = " + state.getSQLNativeError());
        System.out.println("sqlState = " + state.getSQLState());
        System.out.println("sqlErrorText = " + state.getSQLErrorText());
      }

    getOutputTerminal("out").propagate(assembly);
  }

Propagando a Mensagem

Antes de propagar uma mensagem, você precisa decidir que dados do fluxo de mensagens deseja propagar, e qual dos terminais do nó deve receber os dados. Você deve finalizar a mensagem antes de propagá-la. Depois de propagar uma mensagem, é preciso excluir a mensagem de saída.

Por exemplo:
  1. Para propagar a mensagem para o terminal de saída "out":
    MbOutputTerminal out = getOutputTerminal("out");
            out.propagate(newAssembly);
  2. Para excluir a mensagem de saída:
      newMsg.clearMessage();	

Gravando em um Dispositivo de Saída

Para gravar para um dispositivo de saída, a mensagem lógica (hierárquica) precisa ser convertida de volta para um fluxo de bits. Você faz isso utilizando o método getBuffer em MbMessage, da seguinte forma:

public void evaluate( MbMessageAssembly assembly, MbInputTerminal in)
                                                     throws MbException
{
  MbMessage msg = assembly.getMessage();
  byte[] bitstream = msg.getBuffer();

  // gravar o fluxo de bits para algum lugar
  writeBitstream( bitstream );   // user method

 }

Em geral, para um nó de saída a mensagem não é propagada para nenhum terminal de saída, portanto você pode somente retornar neste ponto.

Nota: É preciso utilizar o nó MQOutput fornecido ao gravar para filas do , porque o intermediário mantém internamente uma conexão ao e o identificador de filas aberto em uma base encadeamento a encadeamento, e estes são armazenados em cache para otimizar o desempenho. Além disso, o intermediário manipula cenários de recuperação quando determinados eventos ocorrem e isso seria afetado de forma adversa se chamadas fossem utilizadas em um nó de saída definido pelo usuário.

Criando um Novo Projeto Java

É possível criar nós Java de dentro do utilizando o PDE (Plug-in Development Environment) fornecido. Para fazer isso, você deve criar um novo projeto Java, da seguinte forma:
  1. Alterne para o .
  2. Clique em Arquivo > Novo > Projeto. Selecione Java no menu esquerdo e, em seguida, selecione Projeto Java no menu direito.
  3. Dê um nome ao projeto.

    O painel Definições Java é exibido.

  4. Selecione a guia Bibliotecas e clique em Incluir JARs Externos.
  5. Selecione \classes\jplugin.jar.
  6. Siga os prompts nas outras guias para definir quaisquer outras definições de construção.
  7. Clique em Concluir.
Em seguida você pode desenvolver a origem para o nó Java dentro deste projeto.

Declarando a Classe do Nó de Processamento de Mensagem

Qualquer classe que implemente a MbNodeInterface e esteja contida no classpath do intermediário (ou no caminho da LIL) é registrada com o intermediário como um nó de processamento de mensagem. Ao implementar MbNodeInterface, você também deve implementar um método evaluate para essa classe. O método evaluate é chamado pelo intermediário para cada mensagem que é transmitida através do fluxo.

Por exemplo, para declarar a classe de nó de processamento de mensagem:
package com.ibm.jplugins;

import com.ibm.broker.plugin.*;

public class BasicNode extends MbNode implements MbNodeInterface
Você pode fazer isso no da seguinte forma:
  1. Clique em Arquivo > Novo > Classe.
  2. Defina o pacote e os campos de nome de classe para valores adequados.
  3. Exclua o texto no campo de texto Superclasse e clique no botão Procurar.
  4. Selecione MbNode.
  5. Clique no botão Incluir próximo ao campo de texto Interfaces e selecione MbNodeInterface.
  6. Clique em Concluir.

Definindo o Construtor de Nó

Quando o nó é instanciado, o construtor da classe de nó do usuário é chamado. É aqui que são criados os terminais do nó e inicializados quaisquer valores padrão para os atributos.

Um nó de processamento de mensagem tem um número de terminais de entrada e de terminais de saída associados a ele. Os métodos createInputTerminal e createOutputTerminal são utilizados para incluir terminais em um nó quando ele é instanciado. Por exemplo, para criar um nó com um terminal de entrada e dois terminais de saída:

public MyNode() throws MbException
{
		// criar os terminais aqui
		createInputTerminal ("in");
		createOutputTerminal ("out");
		createOutputTerminal ("failure");
}

Declarando o Nome do Nó

É necessário declarar o nome do nó como ele será identificado pelo . Todos os nomes de nós devem terminar com "Node". O nome é declarado utilizando o seguinte método:

public static String getNodeName()
{
   return "BasicNode";
}
Se esse método não é declarado, a estrutura de API Java cria um nome de nó padrão utilizando as seguintes regras:
  • O nome da classe é anexado ao nome do pacote.
  • Os pontos são removidos e a primeira letra de cada parte do pacote e do nome da classe é transformada em maiúsculas.
Por exemplo, por padrão o nome de nó "ComIbmPluginsamplesBasicNode" é atribuído à seguinte classe:
package com.ibm.pluginsamples;
public class BasicNode extends MbNode implements MbNodeInterface
{
   ...

Declarando Atributos

Os atributos do nó são declarados da mesma forma que propriedades de Java Bean. Você é responsável por escrever métodos getter e setter para os atributos e a estrutura da API infere os nomes dos atributos utilizando as regras de introspecção do Java Bean. Por exemplo, se você declarar os dois métodos seguintes:

private String attributeVariable;

public String getFirstAttribute()
{
  return attributeVariable;
}

publc void setFirstAttribute(String value)
{
  attributeVariable = value;
}

O intermediário inferirá que esse nó tem um atributo chamado firstAttribute. Esse nome é derivado dos nomes dos métodos get ou set, não de nenhum nome de variável de membro de classe interna. Os atributos somente podem ser expostos como cadeias, portanto é preciso converter qualquer tipo numérico para e de cadeias nos métodos get ou set. Por exemplo, o método a seguir define um atributo chamado timeInSeconds:

int seconds;

public String getTimeInSeconds()
{
  return Integer.toString(seconds);
}

public void setTimeInSeconds(String value)
{
  seconds = Integer.parseInt(value);
}

Implementando a Funcionalidade do Nó

Conforme descrito anteriormente, para nós de processamento de mensagem ou saída, você deve implementar o método evaluate definido em MbNodeInterface. Ele é chamado pelo intermediário para processar a mensagem. Esse método deve fornecer toda a função de processamento para o nó.

O método evaluate tem dois parâmetros que são transmitidos pelo intermediário:
  1. O MbMessageAssembly, que contém os seguintes objetos que são acessados utilizando os métodos apropriados:
    • A mensagem de entrada
    • O ambiente local
    • O ambiente global
    • A lista de exceção
  2. O terminal de entrada no qual a mensagem chegou.

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

Excluindo uma Instância do Nó

Uma instância do nó é excluída quando:
  • Você encerra o intermediário.
  • Você remove o nó ou o fluxo de mensagens contendo o nó e reimplementa a configuração.
Durante a exclusão do nó, o nó pode querer ser informado para que ele possa executar operações de limpeza, como fechar soquetes. Se o nó implementar o método opcional onDelete, este será chamado pelo intermediário imediatamente antes da exclusão do nó.

O método onDelete é implementado da seguinte maneira:

public void onDelete()
{
  // executar limpeza do nó se necessário
}

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 de Processamento de Mensagem Definidos pelo Usuário
Nós de Saída Definidos pelo Usuário
ESQL

Tarefas relacionadas
Desenvolvendo Extensões Definidas pelo Usuário
Implementando as Amostras Fornecidas
Compilando um Nó Java Definido pelo Usuário

Referências relacionadas
API de Nó Java Definido Pelo Usuário
Estrutura da Lista de Exceções