Páginas filhas
  • 3.1 Adapters de Envio

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

Tempo aproximado para leitura: 00 min

01. Apresentação

Este documento tem por objetivo apresentar as responsabilidades dos adapters de envio , juntamente com os requisitos de software e boas práticas necessárias para o correto desenvolvimentode Mensagens Padronizadas TOTVS.

02. Responsabilidades

O adapter Os Adapters de envio de mensagens é responsável são responsáveis por preparar os dados a serem enviados e processar o retorno, 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. Abaixo temos melhor descritos os padrões mais utilizados e o fluxo de execução padrão da maioria dos adapters.

Padrões de integração (EAI Patterns)

Os padrões de desenvolvimento de integração listados abaixo são os principais para este contexto. É aconselhável o estudo dos demais padrões, sendo melhor descritos no site Enterprise Integration Patterns, SOA Patterns e outras referências bibliográficas.

  • Message Translator
    • Transformação de modelos de dados, mesmo que sem alteração de conteúdo.
    • Ex.: Converter os campos do DataSet para os nomes da Mensagem Padronizada, como a tag "NomeFantasia" para "Name", mantendo o valor original.
  • Content Enricher
    • Enriquecimento dos dados originais.
    • Ex.: A mensagem padronizada trafega somente o InternalId da ForeignKey, sendo necessário obter a coligada e código referentes a este registro.
    • Ex 2.: Caso no dado original não tenham relacionamentos necessários, como o responsável financeiro de um aluno, o adapter deve ser responsável enriquecer o dado com esta informação.
  • 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.

    draw.io Diagram
    bordertrue
    viewerToolbartrue
    fitWindowfalse
    diagramNameAdapterSend
    simpleViewerfalse
    width
    diagramWidth468
    revision1

    Content Filter
  • Padrão que descreve a situação contrária ao Content Enricher, sendo responsável por reduzir a quantidade de informações.
  • Ex.: O DataSet original de Movimentos possui inúmeras tabelas e colunas, mas para a mensagem de deleção de Pedidos de Compra somente a chave do registro deve ser trafegado.

    Principais funções do adapter de envio


    1. Realizar a transformação dos dados no formato original para o formato da Mensagem PadronizadaGerar 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).
    06

    Código Fonte

    Deck of Cards
    startHiddenfalse
    historyfalse
    idCodigoSemClasseBase
    Card
    defaulttrue
    idAdapter
    labelAdapter
    titleAdapter
    Bloco de código
    languagec#
    firstline1
    linenumberstrue
    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
          }
        }
      }
    }
    
    
    



    Card
    idBusinessContentModel
    labelBusinessContent Model
    titleBusinessContent Model
    Bloco de código
    languagec#
    firstline1
    linenumberstrue
    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.
      }
    }
    Card
    idReturnContentModel
    labelReturnContent Model
    titleReturnContent Model
    Bloco de código
    languagec#
    firstline1
    linenumberstrue
    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 - EAI 2.

    04. Assuntos Relacionados