Histórico da Página
01. Apresentação
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.
02. Responsabilidades
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.
03. Implementando um publicador de mensagens
Para que uma classe seja um publicador de mensagens, deve-se atender aos pré-requisitos listados abaixo:
Pré-requisitos
- Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].XXX.SmartLink.Service.
- Exemplo: RM.Glb.SGDP.SmartLink.Service.dll
- Adicionar referência para a dll "RM.Lib.SmartLink.dll";
Criar uma classe que receba em seu construtor instâncias para as seguintes interfaces:
"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".
"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"
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":
Propriedade Descrição Command Nome do comando a ser incluído na fila do SmartLink. Ex: SGDPUpdateTenantMetada CorrelatedId deve 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.
RouterMessage rota de envio da mensagem. Será concatenada ao endpoint do serviço do SmartLink.Server. ex: /api/v1/link/send/SGDPMaskResponse/SGDP
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 language c# firstline 1 linenumbers true 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); } } }
04. Implementando um consumidor de mensagens
Para que uma classe seja um provedor de proteção de dados, , deve-se atender aos pré-requisitos listados abaixo:
Pré-requisitos
- Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].DataProtection.Provider.
- Exemplo: RM.RHU.DataProtection.Provider.dll
- Adicionar referência para a dll "RM.Glb.DataProtection.Service.dll";
Criar uma classe herdando da ancestral "GlbDataProtectionProviderBase". O tipo genérico "Identifier" deve ser usado conforme descrito abaixo.
- 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.
- Carimbar a classe com o atributo "GlbDataProtectionRoleAttr". Nesse atributo, devem ser informados os dados abaixo:
- Identificador único do provedor (novo guid);
- Nome do papel (essa informação será mostrada para o usuário no sistema LGDP que está sendo criado pela Totvs);
- Linha do Produto (RM,TREPORTS, etc)
- Aplicação (Folha de Pagament, Educacional, Globais, etc)
- ClassName (Nome do Menu Controller do segmento) - Pode ser localizado na tabela GDICDATAPROTECTION coluna CLASSNAME.
- CodSistema (Código Sistema do segmento) -Pode ser localizado na tabela GDICDATAPROTECTION coluna CODSISTEMA.
Exemplo:
Bloco de código language c# firstline 1 linenumbers true 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() { } }
04. Diagrama de classes
- Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].DataProtection.Provider.
05. Endpoint de teste para um provedor de proteção de dados
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.