Tempo aproximado para leitura: 00 min

01. Apresentação

Este documento tem por objetivo apresentar as responsabilidades dos adapters de recebimento.

02. Responsabilidades

Os Adapters de envio de mensagens são responsáveis por preparar os dados a serem enviados, gerando uma BusinessMessage no padrão definido para esta, e processar a ResponseMessage retornada pelo sistema integrado, utilizando para isso os corretos padrões de desenvolvimento.

O diagrama abaixo apresenta de forma macro a série de eventos que ocorrem durante o processamento de uma mensagem de envio, exemplificando com a origem em DataServer mas esta pode ocorrer nos Subscribers, Process ou qualquer outro objeto de negócio.

Principais funções do adapter de envio


  1. Gerar o conteúdo de negócio da mensagem a enviar (BusinessContent).
    1. O adapter é responsável por implementar os padrões apresentados anteriormente, transformando o formato do dado original, enriquecendo ou empobrecendo o mesmo, além de realizar as validações necessárias.
    2. Após o adapter encaminhar ao EAI o dado de negócio (BusinessContent), todo o fluxo de envelopamento, salvamento na fila de mensagens e envio ao destinatário é de responsabilidade do EAI.
  2. Transformar e/ou processar as informações de negócio da resposta (ReturnContent).
    1. Em integrações para consulta de dados a mensagem de resposta deve ser transformada do formato da Mensagem Padronizada TOTVS para o modelo de retorno, esperado pelo módulo que originou a mensagem.
      1. Ex.: Mensagens de consulta de informações devem transformar o dado recebido antes de encaminhar para o módulo de consulta.
    2. Caso a mensagem trafegada demande algum processamento de responsabilidade da camada de integração, este deve ser implementado no método correspondente do adapter.
      1. Ex.: Mensagens de cadastro devem ter o De-Para armazenado na base de dados.
      2. Ex2.: Mensagens assíncronas que devam desbloquear o registro no momento do retorno de sucesso.

03. Implementação de um adapter de envio

Para que uma classe seja um adapter de envio, deve-se atender aos pré-requisitos listados abaixo e realizar as funções de integração listadas anteriormente.

Pré-requisitos

  1. Implementar a interface IAdapterSend, implementando em cada método a sua respectiva responsabilidade, internamente a um projeto cuja Dll gerada siga o padrão "RM.*.TotvsMessage.Adapter.dll".

    1. InitializeAdapter - Método responsável pela inicialização do Adapter, recebendo o contexto de execução por referência.

    2. CanExecute - Método que permite ao adapter realizar verificações e informar se a mensagem deve ser processada, ignorada ou gerar exceção.

    3. Prepare - Método responsável por retornar ao EAI o BusinessContent a ser enviado ao destinatário, juntamente com outras demandas específicas de negócio.

    4. ProcessResponseMessage - Método responsável por processar os dados retornados pelo aplicativo integrado, como atualizar algum campo de controle ou transformar o dado em caso de consultas, como esta mensagem.

  2. Decorar a classe do adapter com o atributo "AdapterAttr".

    1. O atributo deve receber as informações obrigatórias, como nome da mensagem, versão, descrição e tipo (event/request).

  3. Implementar as classes de modelo referentes ao BusinessContent e ao ReturnContent da Mensagem Padronizada TOTVS, que serão utilizadas na serialização e deserialização das mensagens.

  4. As classes de modelo devem ser decoradas com o atributo "MessageContentTypeAttr" informando os atributos, descritos abaixo.
    1. TransactionName - Nome da transação referente a este modelo.
    2. MajorVersion - Versão cheia da mensagem. 
      1. Exemplo: Versão 1.003 possui MajorVersion 1. 
      2. Exemplo 2: Versão 3.023 possui MajorVersion 3.
    3. MessageType -  Tipo da transação a ter seu conteúdo de negócio serializado/deserializado utilizando esta classe (BusinessMessage ou ResponseMessage).

Código Fonte

using RM.Eai.TotvsMessage.Intf;
using RM.Eai.TotvsMessage.IService;
using RM.Eai.TotvsMessage.Lib;
using RM.Lib;
using System.Collections.Generic;
using System.Data;

namespace RM.Eai.TotvsMessage.Adapter
{
  [AdapterAttr(typeof(Properties.Resources),nameof(Properties.Resources.sEaiCaptionWhoIs), "WHOIS", "1.000", SubTypeEnum.teRequest)]
  public class WhoIs_Send_1000 : IAdapterSend
  {
    #region Properties
    private EAIAdapterContext AdapterContext { get; set; }
    #endregion 

    /// <summary>
    /// Método de inicialização do Adapter.
    /// </summary>
    /// <param name="adapterContext">Contexto de execução do Adapter</param>
    public void InitializeAdapter(EAIAdapterContext adapterContext)
    {
      AdapterContext = adapterContext;
    }

    /// <summary>
    /// Método responsável por informar ao EAI se a mensagem deve ser processada, ignorada ou gerar exceção.
    /// </summary>
    /// <param name="parms">Parametros</param>
    /// <returns>Retorno</returns>
    public EAICanExecuteSendResult CanExecute(EAICanExecuteSendParams parms)
    {
      //Não existe condicional, sempre permitindo enviar.
      return new EAICanExecuteSendResult() { CanExecute = EAICanExecuteEnum.csEnviar };
    }

    /// <summary>
    /// Método responsável por transformar os parâmetros de entrada no BusinessContent a ser enviado
    /// </summary>
    /// <param name="parms">Parâmetros originais</param>
    /// <returns>Resultado do método de preparação, com o Objeto BusinessContent</returns>
    public EAIPrepareSendResult Prepare(EAIPrepareSendParms parms)
    {
      EAIPrepareSendResult result = new EAIPrepareSendResult();
      
      //A mensagem de WhoIs não possui dados no BusinessContent
      result.BusinessContent = new WhoIsModel_V1_BusinessContent();

      return result;
    }

    /// <summary>
    /// Processa ReturnContent recebido, transformando no objeto no formato esperado pelo método chamador.
    /// </summary>
    /// <param name="parms">Parâmetros de entrada</param>
    /// <returns>Resultado</returns>
    public EAIProcessResponseMessageSendResult ProcessResponseMessage(EAIProcessResponseMessageSendParams parms)
    {
      EAIProcessResponseMessageSendResult result = new EAIProcessResponseMessageSendResult(parms.ResponseMessageItem);

      //Obtém o ReturnContent deserializado para o tipo definido
      WhoIsModel_V1_ReturnContent returnContent = (WhoIsModel_V1_ReturnContent)parms.ResponseMessageItem.ResponseMessage.ReturnContent.ReturnContentObj;

      //Converte lista de transações no tipo de retorno.
      EAIWhoIsResult listaTransacoes = new EAIWhoIsResult(AdapterContext.ContextItem.CurrentRoute.IdApp);

      //Percorre todas as transações
      foreach (WhoIsModel_V1_EnabledTransaction enabledTransaction in returnContent.EnabledTransactions)
      {
        EAIWhoIsTransaction transacao = new EAIWhoIsTransaction()
        {
          ModoHabilitado = ConvertModoHabilitado(RMSConvert.ToString(enabledTransaction.Mode)),//DONOTLOCALIZE
          NomeMensagem = RMSConvert.ToString(enabledTransaction.Name),//DONOTLOCALIZE
          Versao = RMSConvert.ToString(enabledTransaction.Version)//DONOTLOCALIZE
        };
        listaTransacoes.Add(transacao);
      }

      //Obtém o UUID da mensagem original
      listaTransacoes.BusinessMessageUUID = this.AdapterContext.ContextItem.Message.UUID;
      //Obtém o UUID da mensagem de resposta
      listaTransacoes.ResponseMessageUUID = parms.ResponseMessageItem.MessageInformation.UUID;

      //Adiciona no objeto de retorno
      result.Data = listaTransacoes;
      
      //Retorna o dado processado, no tipo de retorno esperado.
      return result;
    }

    private EnabledModeEnum ConvertModoHabilitado(string Mode)
    {
      switch (Mode.ToUpperInvariant())
      {
        case "SEND_ENABLED"://DONOTLOCALIZE
          return EnabledModeEnum.emSend;
        case "RECEIVE_ENABLED"://DONOTLOCALIZE
          return EnabledModeEnum.emReceive;
        case "BOTH_ENABLED"://DONOTLOCALIZE
          return EnabledModeEnum.emBoth;
        default:
          RMSException.Throw(string.Format(Properties.Resources.sEaiErroWhoIsModoInvalido, Mode));
          //O método acima gera exceção, mas o compilador não compreende.
          //A linha abaixo foi inserida para permitir compilação mas nunca será executada.
          return 0;//EnabledModeEnum
      }
    }
  }
}




using RM.Eai.TotvsMessage.IService;
using RM.Eai.TotvsMessage.Lib;
using System.Collections.Generic;

namespace RM.Eai.TotvsMessage.Adapter
{
  [System.SerializableAttribute()]
  [System.ComponentModel.DesignerCategoryAttribute("code")]
  [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
  [System.Xml.Serialization.XmlRootAttribute(ElementName = "BusinessContent", IsNullable = false)]
  [MessageContentTypeAttr("WHOIS", 1, MessageTypeEnum.tmBusinessMessage)]
  public partial class WhoIsModel_V1_BusinessContent
  {
	//O BusinessContent da mensagem WhoIs não possui propriedades.
  }
}
using RM.Eai.TotvsMessage.IService;
using RM.Eai.TotvsMessage.Lib;
using System.Collections.Generic;

namespace RM.Eai.TotvsMessage.Adapter
{
  [System.SerializableAttribute()]
  [System.ComponentModel.DesignerCategoryAttribute("code")]
  [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
  [System.Xml.Serialization.XmlRootAttribute(ElementName = "ReturnContent", IsNullable = false)]
  [MessageContentTypeAttr("WHOIS", 1, MessageTypeEnum.tmResponseMessage)]
  public partial class WhoIsModel_V1_ReturnContent
  {
    [System.Xml.Serialization.XmlArrayItemAttribute("Transaction", IsNullable = false)]
    public List<WhoIsModel_V1_EnabledTransaction> EnabledTransactions { get; set; } = new List<WhoIsModel_V1_EnabledTransaction>();
  }

  /// <remarks/>
  [System.SerializableAttribute()]
  [System.ComponentModel.DesignerCategoryAttribute("code")]
  [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
  public partial class WhoIsModel_V1_EnabledTransaction
  {
    public string Mode { get; set; }
    public string Version { get; set; }
    public string Name { get; set; }
  }
}

Implementações de produto

Os times dos segmentos tiveram iniciativa de desenvolver classes base e auxiliares para executar ações comuns e assim aumentar a produtividade no desenvolvimento de adapters. Estas classes estão disponíveis no projeto "RM.EAI.TotvsMessage.Adapter", que mesmo estando na solution do EAI é de domínio e manutenção dos times de produto.

A forma de uso destas classes foi documentada pelo produto no link a seguir: Desenvolvimento - Adapter.

04. Assuntos Relacionados