Páginas filhas
  • Integração RM x SmartLink Behavior Sharing - Visão desenvolvedor

Versões comparadas

Chave

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


Este documento técnico tem por objetivo auxiliar os desenvolvedores dos segmentos na criação de classes que "publicam" e "consomem" mensagens no SmartLink da plataforma TotvsApps.

O desenvolvimento e manutenção dos publicadores e consumidores de mensagens são de responsabilidade das equipes de segmentos. Os artefatos genéricos que controlam a fila de execução das mensagens são de responsabilidade da equipe de Framework.

Para que uma classe seja um publicador de mensagens,  deve-se atender aos pré-requisitos listados abaixo:

  1. Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].XXX.SmartLink.Service.
    1. Exemplo: RM.Glb.SGDP.SmartLink.Service.dll
  2. Adicionar referência para a dll "RM.Lib.SmartLink.dll";
  3. Criar uma classe que receba em seu construtor instâncias para as seguintes interfaces:

    1. "IRMSSmartLinkPublisherService": objeto responsável em incluir a mensagem na fila do RM.SmartLink.Client.

      Informações

      Foi criada na Lib uma classe de "factory" responsável em fornecer uma instância para interface "IRMSSmartLinkPublisherService". Trata-se da classe  "RMSSmartLinkPublisherFactory". Basta chamar seu método público "NewSmartLinkPublisher".

    2. "IRMSLogger": objeto usado para incluir logs relacionados à regra de negócio em questão. 

      Informações

      Esses logs serão persistidos automaticamente na tabela "GTotvsLinkLog"

    3. Para publicar uma mensagem na fila do RM.SmartLink.Client, basta chamar o método "AddMessage" da instância de interface "IRMSSmartLinkPublisherService". Os seguinte dados devem ser enviados através de uma classe de parâmetros do tipo "SmartLinkPublisherAddMessageParams":

      PropriedadeDescrição
      CommandNome do comando a ser incluído na fila do SmartLink. Ex: SGDPUpdateTenantMetada
      CorrelatedIddeve ser enviado nessa propriedade um identificador (guid) que correlacionam mensagens de request e response;
      Data

      mensagem contendo dados do negócio. Pode ser em qualquer formato (json, xml, etc)  desde que o consumidor consiga

      interpretá-la.

      RouterMessagerota de envio da mensagem. Será concatenada ao endpoint do serviço do SmartLink.Server. ex: /api/v1/link/send/SGDPMaskResponse/SGDP


  4. Código fonte de exemplo (extraído da classe "GlbSGDPPublisherMessageService" localizada na solution de Globais, projeto "RM.Glb.SGDP.SmartLink.Service"

    Bloco de código
    languagec#
    firstline1
    linenumberstrue
    using Newtonsoft.Json.Linq;
    using RM.Glb.SGDP.SmartLink.Service.Domain.Interfaces;
    using RM.Lib.Data;
    using RM.Lib.Log;
    using RM.Lib.SmartLink.Domain.DataModel;
    using RM.Lib.SmartLink.Domain.Interfaces;
    using RM.Lib.SmartLink.Domain.Publisher;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace RM.Glb.SGDP.SmartLink.Service
    {
      public class GlbSGDPPublisherMessageService : IGlbSGDPPublisherMessageService
      {
        private IGlbSGDPResolverService _SGDPResolverService;
        private IRMSSmartLinkPublisherService _SmartLinkPublisherService;
        private IRMSLogger _LogService;
    
        private const string ctSGDPMaskResponseEndPoint = "/api/v1/link/send/SGDPMaskResponse/SGDP";
        private const string ctSGDPDataResponseEndPoint = "/api/v1/link/send/SGDPDataResponse/SGDP";
        private const string ctSGDPUpdateTenantMetadataEndPoint = "/api/v1/link/send/SGDPUpdateTenantMetadata/SGDP";
    
        private const string ctSGDPUpdateTenantMetadata = "SGDPUpdateTenantMetadata";
        private const string ctSGDPDataCommand = "SGDPDataCommand";
        private const string ctSGDPMaskCommand = "SGDPMaskCommand";
        private const string ctSGDPResponseDataCommand = "SGDPResponseDataCommand";
        private const string ctSGDPResponseMaskCommand = "SGDPResponseMaskCommand";
        private const string ctSmartLinkSetupCommand = "Setup";
        private const string ctSmartLinkUnSetupCommand = "UnSetup";
    
    
        public GlbSGDPPublisherMessageService(IRMSSmartLinkPublisherService smartLinkPublisherService, 
          IGlbSGDPResolverService sgdpResolverService, 
          IRMSLogger logService)
        {
          _SmartLinkPublisherService = smartLinkPublisherService;
          _SGDPResolverService = sgdpResolverService;
          _LogService = logService;
        }
    
        /// <summary>
        /// Adiciona uma mensagem de reposta para o comando "SGDPResponseDataCommand".
        /// </summary>
        /// <param name="parms"></param>
        public void AddResponseDataCommand(AddResponseDataCommandParms parms)
        {
          SmartLinkPublisherAddMessageParams parPublisher = new SmartLinkPublisherAddMessageParams();
          parPublisher.Command = ctSGDPResponseDataCommand;
          parPublisher.CorrelatedId = parms.CorrelatedId; ;
          parPublisher.Data = parms.Message;
          parPublisher.RouterMessage = ctSGDPDataResponseEndPoint;
          _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPResponseDataCommandGravadoNaFila);
          _SmartLinkPublisherService.AddMessage(parPublisher);
        }
    
        /// <summary>
        /// Adiciona uma mensagem de reposta para o comando "SGDPResponseMaskCommand".
        /// </summary>
        /// <param name="parms"></param>
        public void AddResponseMaskCommand(AddResponseMaskCommandParms parms)
        {
          SmartLinkPublisherAddMessageParams parPublisher = new SmartLinkPublisherAddMessageParams();
          parPublisher.Command = ctSGDPResponseMaskCommand;
          parPublisher.CorrelatedId = parms.CorrelatedId;
          parPublisher.Data = parms.Message;
          parPublisher.RouterMessage = ctSGDPMaskResponseEndPoint;
          _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPResponseMaskCommandGravadoNaFila);
          _SmartLinkPublisherService.AddMessage(parPublisher);
        }
    
        /// <summary>
        /// Adiciona uma mensagem para envio de um comando de sgldpdateapplicationmetada.
        /// </summary>
        public void AddMessageUpdateTenantMetadata(AddMessageUpdateTenantMetadataParms parms)
        {
          if (CanAddTenantMetadataMessage())
          {
            try
            {
              List<string> jsons = GetUpdateTenandMetadata(parms.TenantId);
              foreach (string json in jsons)
              {
                SmartLinkPublisherAddMessageParams smartLinkParms = new SmartLinkPublisherAddMessageParams();
                smartLinkParms.Command = ctSGDPUpdateTenantMetadata;
                smartLinkParms.CorrelatedId = "";
                smartLinkParms.Data = json;
                smartLinkParms.RouterMessage = ctSGDPUpdateTenantMetadataEndPoint;
                _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPTenantMetadaGravadoNaFila);
                _SmartLinkPublisherService.AddMessage(smartLinkParms);
              }
            }
            catch (Exception ex)
            {
              _LogService.NotifyLogWarning(ex, Properties.Resources.sconTotvsAppErroAoEnviarSGDPUpdateTenantMetadata);
            }
          }
        }
    
        private bool CanAddTenantMetadataMessage()
        {
          //Se existir alguma mensagem de sgdp para ser processada, então não envia atualizaçaõ de medatdos pois esse processo é caro.
          var pendingMessages = _SmartLinkPublisherService.GetPendingMessages();
          List<SmartLinkMessageDataModel> messageUpstream = pendingMessages?.Messages?.Where(
            y => y.TypeEvent == ctSGDPUpdateTenantMetadata ||
                 y.TypeEvent == ctSGDPDataCommand ||
                 y.TypeEvent == ctSGDPMaskCommand ||
                 y.TypeEvent == ctSGDPResponseDataCommand ||
                 y.TypeEvent == ctSGDPResponseMaskCommand).ToList();
          if (messageUpstream?.Count > 0)//Se existir alguma não inclua na fila...
            return false;
          return true;
        }
    
        private List<string> GetUpdateTenandMetadata(string tenantId)
        {
          return _SGDPResolverService.GetSGDPTenantMetadata(
            new MetadataTenantParms() { TenantId = tenantId }
            )?.JsonsResult;
        }
    
        public void AddMessageUnSetup()
        {
          var pendingMessages = _SmartLinkPublisherService.GetPendingMessages();
          List<SmartLinkMessageDataModel> messagesSGDP = 
            pendingMessages?.Messages?.Where(y => y.TypeEvent.ToUpper() == ctSGDPUpdateTenantMetadata.ToUpper() &&
                                                  y.TypeEvent.ToUpper() == ctSGDPDataCommand.ToUpper() &&
                                                  y.TypeEvent.ToUpper() == ctSGDPMaskCommand.ToUpper() &&
                                                  y.TypeEvent.ToUpper() == ctSGDPResponseDataCommand.ToUpper() &&
                                                  y.TypeEvent.ToUpper() == ctSGDPResponseMaskCommand.ToUpper()).ToList();
          foreach (SmartLinkMessageDataModel model in messagesSGDP)
            _SmartLinkPublisherService.RemoveMessageById(model.Id);
    
          SmartLinkPublisherAddMessageParams parms = new SmartLinkPublisherAddMessageParams();
          parms.Command = ctSmartLinkUnSetupCommand;
          parms.CorrelatedId = "";
          parms.Data = _SGDPResolverService.GetSGDPSetup().JsonResult;
          _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppUnSetupGravadoNaFila);
          _SmartLinkPublisherService.AddMessage(parms);
        }
    
        public void AddMessageSetup()
        {
          SmartLinkPublisherAddMessageParams parms = new SmartLinkPublisherAddMessageParams();
          parms.Command = ctSmartLinkSetupCommand;
          parms.CorrelatedId = "";
          parms.Data = _SGDPResolverService.GetSGDPSetup().JsonResult;
          _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSetupGravadoNaFila);
          _SmartLinkPublisherService.AddMessage(parms);
        }
      }
    }
    
    
    


    Para que uma classe seja um provedor de proteção de dados, , deve-se atender aos pré-requisitos listados abaixo:

    1. Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].DataProtection.Provider.
      1. Exemplo: RM.RHU.DataProtection.Provider.dll
    2. Adicionar referência para a dll "RM.Glb.DataProtection.Service.dll";
    3. Criar uma classe herdando da ancestral "GlbDataProtectionProviderBase". O tipo genérico "Identifier" deve ser usado conforme descrito abaixo.

    4. A classe "GlbDataProtectionProviderBase" herda da classe RMSObject da Lib. Consequentemente, as classes de "providers" poderão chamar os métodos "CreateFacade" e "CreateModule" dentro de suas estruturas.
    5. Carimbar a classe com o atributo "GlbDataProtectionRoleAttr". Nesse atributo, devem ser informados os dados abaixo:
      1. Identificador único do provedor (novo guid);
      2. Nome do papel (essa informação será mostrada para o usuário no sistema LGDP que está sendo criado pela Totvs);
      3. Linha do Produto (RM,TREPORTS, etc)
      4. Aplicação (Folha de Pagament, Educacional, Globais, etc)
      5. ClassName (Nome do Menu Controller do segmento) - Pode ser localizado na tabela GDICDATAPROTECTION coluna CLASSNAME.
      6. CodSistema (Código Sistema do segmento) -Pode ser localizado na tabela GDICDATAPROTECTION coluna CODSISTEMA.
    6. Exemplo:

      Bloco de código
      languagec#
      firstline1
      linenumberstrue
      namespace RM.Glb.TesteUnitario
      {
        [GlbDataProtectionRoleAttr("7b886d91-86b1-4953-ad93-7da732d40515", "Funcionários", "RM", "Fop","FopFolhaActionModuleController", "P")]
        public class RHUDataProtectionProviderFuncionarios<FuncID> :
          GlbDataProtectionProviderBase<FuncionarioIDModel>
          where FuncID : FuncionarioIDModel, new()
        {
        }
      }
      
      


Foi criado o endpoint para teste (http://localhost:8051/api/framework/v1/dataprotection/person) para buscar dados de uma pessoa com base no nome do identificador específico do provedor.

Foi criado o endpoint para teste (http://localhost:8051/api/framework/v1/dataprotection/cananonimize) para recuperar se os dados de uma pessoa com base no nome do identificador específico do provedor podem ser anonimizados.

Está sendo criado o endpoint http://localhost:8051/api/framework/v1/dataprotection/anonimize para anonimizar os dados de uma pessoa (está em construção).

Ambos endpoints devem ser enviados por GET, com a seguinte estrutura no body:

{
  "role""Funcionários",
  "identifiers": [
      {
          "IdentifiedName""CPF",
          "Value""00251149641"
      }
  ]
}

Onde:

  • roles = nome do provedor dado pela implementação do produto;
  • IdentifiedName = nome do identificador do provedor de proteção de dados
  • Value = valor do identificador


  • Exemplo de resposta para a API dataprotection/person:

São retornados os dados da pessoa, de acordo com o provedor informado.

  • Exemplo de retorno para a APIdataprotection/cananonimize:

É informado se a pessoa pode ser anonimizada, de acordo com as regras do provedor.