Criando um Nó de Entrada 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.

Um nó definido pelo usuário em Java é distribuído como um arquivo .jar. Este tópico descreve as etapas que devem ser executadas para criar um nó utilizando Java. Ele esboça as seguintes etapas:
  1. Criando um Novo Projeto Java
  2. Declarando a Classe do Nó de Entrada
  3. Definindo o Construtor de Nó
  4. Declarando o Nome do Nó
  5. Declarando Atributos
  6. Implementando a Funcionalidade do Nó
  7. Excluindo uma Instância do 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.

Recebendo Dados Externos em um Buffer

Um nó de entrada pode receber dados de qualquer tipo de origem externa, tal como um sistema de arquivos, uma fila ou um banco de dados, da mesma maneira que qualquer outro programa Java, desde que a saída do nó esteja no formato correto.

Você fornece um buffer de entrada (ou fluxo de bits) para conter os dados de entrada, e o associa a um objeto de mensagem. Você cria uma mensagem a partir de uma matriz de bytes utilizando o método createMessage da classe MbInputNode e, em seguida, gera uma montagem de mensagem válida a partir dessa mensagem. (Consulte o Javadoc para obter detalhes sobre esses métodos). Por exemplo, para ler a entrada de um arquivo:

  1. Crie um fluxo de entrada para ler do arquivo:
    FileInputStream inputStream = new FileInputStream("myfile.msg");
  2. Crie uma matriz de bytes do tamanho do arquivo de entrada:
    byte[] buffer = new byte[inputStream.available()];
  3. Leia do arquivo para a matriz de bytes:
    inputStream.read(buffer);
  4. Feche o fluxo de entrada:
    inputStream.close();
  5. Crie uma mensagem para colocar na fila:
    MbMessage msg = createMessage(buffer);
  6. Crie um novo conjunto de mensagem para receber esta mensagem:
    msg.finalizeMessage(MbMessage.FINALIZE_VALIDATE);
    MbMessageAssembly newAssembly =
         new MbMessageAssembly(assembly, msg);

Propagando a Mensagem

Quando tiver criado um conjunto de mensagem, você poderá propagá-lo para um dos terminais do nó.

Por exemplo, para propagar o conjunto da mensagem para o terminal "out":
MbOutputTerminal out = getOutputTerminal("out");
out.propagate(newAssembly);

Controlando Encadeamentos e Comportamento Transacional

A infra-estrutura do intermediário trata de questões de transação tais como controlar a consolidação de qualquer unidade de trabalho do ou de banco de dados quando o processamento da mensagem estiver concluído. Entretanto, se um nó definido pelo usuário for utilizado, quaisquer atualizações de recursos não podem ser automaticamente consolidadas pelo intermediário.

Cada encadeamento do fluxo de mensagens é alocado de um conjunto de encadeamentos mantido para cada fluxo de mensagens, e inicia a execução no método run.

O nó definido pelo usuário utiliza valores de retorno para indicar se uma transação obteve êxito, para controlar se as transações são consolidadas ou retornadas e para controlar quando o encadeamento é retornado ao conjunto. Quaisquer exceções não tratadas são capturadas pela infra-estrutura do intermediário e a transação é revertida.

O comportamento das transações e encadeamentos é determinado utilizando um valor de retorno apropriado entre os seguintes:

MbInputNode.SUCCESS_CONTINUE
A transação é consolidada e o intermediário chama o método run novamente utilizando o mesmo encadeamento.
MbInputNode.SUCCESS_RETURN
A transação é consolidada e o encadeamento é retornado ao conjunto de encadeamentos, supondo que ele não seja o único encadeamento para este fluxo de mensagens.
MbInputNode.FAILURE_CONTINUE
A transação é retornada e o intermediário chama o método run novamente utilizando o mesmo encadeamento.
MbInputNode.FAILURE_RETURN
A transação é retornada e o encadeamento é retornado ao conjunto de encadeamentos, supondo que ele não seja o único encadeamento para este fluxo de mensagens.
MbInputNode.TIMEOUT
O método run não deve bloquear indefinidamente enquanto aguarda que os dados de entrada cheguem. Enquanto o fluxo estiver bloqueado pelo código do usuário, você não poderá encerrar ou reconfigurar o intermediário. O método run deve conceder controle ao intermediário periodicamente, retornando do método run. Se os dados de entrada não tiverem sido recebidos após um certo período (por exemplo, 5 segundos), o método deve retornar com o código de retorno TIMEOUT. Supondo que o intermediário não necessite reconfigurar ou encerrar, o método run do nó de entrada é chamado de novo imediatamente.
Para criar fluxos de mensagens de múltiplos encadeamentos, o método dispatchThread é chamado após a criação de uma mensagem, mas antes de propagar a mensagem para um terminal de saída. Isso garante que apenas um encadeamento esteja aguardando por dados enquanto outros encadeamentos estão processando a mensagem. Novos encadeamentos são obtidos do conjunto de encadeamentos até o limite máximo especificado pelo atributo additionalInstances do fluxo de mensagens. Por exemplo:
public int run( MbMessageAssembly assembly ) throws MbException
{
  byte[] data = getDataWithTimeout();  // usuário abasteceu método
                                       // retorna nulo se for tempo limite
  if( data == null )
    return TIMEOUT;

  MbMessage msg = createMessage( data );
  msg.finalizeMessage( MbMessage.FINALIZE_VALIDATE );
  MbMessageAssembly newAssembly =
       new MbMessageAssembly( assembly, msg );

  dispatchThread();

  getOutputTerminal( "out" ).propagate( newAssembly );

  return SUCCESS_RETURN;
}

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);
  }

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 Entrada

Qualquer classe que implemente a MbInputNodeInterface e esteja contida no classpath do intermediário (ou no caminho da LIL) é registrada com o intermediário como um nó de entrada. Quando se implementa a MbInputNodeInterface, é preciso implementar também um método run para essa classe. O método run representa o início do fluxo de mensagens, contém os dados que formulam a mensagem e a propaga pelo fluxo. O intermediário chama o método run quando encadeamentos se tornam disponíveis de acordo com o modelo de encadeamento especificado.

Por exemplo, para declarar a classe de nó de entrada:

package com.ibm.jplugins;

import com.ibm.broker.plugin.*;

public class BasicInputNode extends MbInputNode implements MbInputNodeInterface
{
...
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 MbInputNode.
  5. Clique no botão Incluir próximo ao campo de texto Interface e selecione MbInputNodeInterface.
  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 entrada tem um número de terminais de saída associados a ele, mas em geral não tem nenhum terminal de entrada. Utilize o método createOutputTerminal para incluir terminais de saída a um nó quando o nó é instanciado. Por exemplo, para criar um nó com três terminais de saída:

public BasicInputNode() throws MbException
{
	createOutputTerminal ("out");
	createOutputTerminal ("failure");
	createOutputTerminal ("catch");
   setAttribute ("firstParserClassName","myParser");
   attributeVariable  = new String ("none");
}

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 "BasicInputNode";
}
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ó "ComIbmPluginsamplesBasicInputNode" é atribuído à seguinte classe:
package com.ibm.pluginsamples;
public class BasicInputNode extends MbInputNode implements MbInputNodeInterface
{
   ...

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ó

Como já foi descrito, o método run é chamado pelo intermediário para criar a mensagem de entrada. Esse método deve fornecer toda a função de processamento para o nó de entrada.

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.

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 Input definidos pelo usuário

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

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