Apresentação

Este SandBox tem o objetivo de auxiliar na construção de conectores que possam interagir com o Octopus. Começaremos com os conceitos relacionados a cada ação do ato de construir o Conector e, depois, um passo a passo de como construir o conector.

API

API ou Application Program Interface é a maneira pela qual um determinado software expõe as interfaces que outros softwares ou plataformas poderão interagir, enviar dados, consumir dados, et cetera. A exposição desta interface ocorre através de serviços Rest, >Restful ou SOAP; filas de integração, entre outros.

Conector

Conector é um programa ou uma parte do software construído com a finalidade de interconectar sistemas. Normalmente, ele não somente faz a interação como também a transformação dos dados brutos (RAW DATA) em um modelo de dados canônico (ou geral), de maneira que todos os agentes consigam interconectar-se.

Diagrama de Conector

Capacidades

Capacidade é o que define o tipo da operação, método ou função desenvolvido no conector, o qual será executado sobre um modelo canônico. Elas podem ser do tipo:

  • Publisher;
  • Subscriber;
  • Callback.

Publisher

Publisher ou Publicador é quem disponibilizará a informação. Ou seja, ao escrever um método ou função que disponibiliza uma determinada informação, você estará fazendo um Publisher. Este comportamento ou capacidade deverá ser descrito no manifesto do método.

Subscriber

Subscriber ou Consumidor (Subscritor) é quem consumirá a informação. Ou seja, ao escrever um método ou função que aguarda uma determinada informação, por exemplo, um método de inserção ou exclusão de dados, você estará fazendo um Subscriber. Este comportamento ou capacidade deverá ser descrito no manifesto do método.

Callback

Callback é toda e qualquer rotina, função ou método chamado encadeado ao retorno de um processo, seja através do uso de threads, seja uma chamada AJAX, por definição. No caso dos conectores, o método tipo Callback será chamado após a execução de uma determinada ação. Ele somente é indicado nos casos onde é necessário uma execução de determinada lógica de negócio após o término de outra ação.

Por exemplo, em um determinado sistema, usa-se filas para integrar dados de cliente. Dessa forma:

  1. O Publisher é invocado pelo sistema controlador, que insere uma mensagem na fila com os dados recebidos do Publisher;
  2. O Subscriber consome esse cliente da fila e insere-o ou atualizá-o no sistema de destino;
  3. O Subscriber retorna ao controlador uma resposta de sucesso ao integrar o cliente;
  4. O Controlador invoca o Callback encadeado no Subscriber executado anteriormente e remove a mensagem da fila de integração.
Diagrama de Sequência do Processamento de um Cliente com Remoção do Cliente da Fila utilizando Conector com Capacidade de Callback. Diagrama de Sequência do Processamento de um Cliente com Remoção do Cliente da Fila utilizando Conector com Capacidade de Callback

Modelo de Dados Canônico

Modelo de Dados Canônico é o modelo padrão ou gernérico definido para tráfego de dados intersistemas ou interplataformas, de maneira a traduzir corretamente a representação de dados de um sistema ou plataforma em outro.

Por exemplo, para a entidade cliente, o sistema A representa o código e nome utilizando os identificadores C1 e C2, respectivamente. Já o sistema B representa os mesmos dados utilizando os identificadores Cod e Nome. Assim, para que seja possível mapear C1 para Cod e C2 para Nome e, posteriomente para outros sistemas sem overhead, a operação tipo Publisher consultada fará a tradução dos dados do sistema A em um modelo canônico Cliente. Este modelo canômico será consumido pelo conector do sistema B através da respectiva operação Subscriber, a qual traduzirá os dados para o modelo de dados do sistema B.

Dessa forma, caso queira-se conectar um sistema C aos sistemas A e B, basta desenvolver o conector do sistema C, mapeando o seu modelo de dados para o modelo de dados canônico e adicioná-lo ao Pipeline de integração daquela informação.

Cada conector deve implementar ao menos um Modelo de Dados Canônico.

Abaixo, segue a lista de Modelos de Dados Canônicos:

  • Brand: contém as informações de Marca;
  • Category: contém as informações de Categorias do Produto;
  • Product: contém as informações de Produto;
  • ProductImage: contém as informações das imagens de Produto;
  • Price: contém a Lista de Preços do Produto;
  • Inventory: contém a informação acerca do Estoque do Produto;
  • Customer: contém os dados de Cliente;
  • Order: contém os dados de Pedido;
  • OrderStatus: contém os Estados de Pedido.

No arquivo modelocanonicocomentado20161128.xlsx está a descrição do Modelo de Dados Canônico com exemplo do JSON retornado.

Manifesto

Manifesto é o que descreve o conector, quais suas capacidades e quais modelos de dados canônicos são implementados.

Pipeline

Pipeline é um tipo de fluxo de informação onde: inicia-se um processo, dados são recebidos e transformados, finalizando o processo com uma saída.

Por exemplo, ao executar uma integração de cliente, processa-se um Pipeline, o qual publica o cliente em uma fila, consome o cliente da fila, integra o cliente no destino, remove o cliente da fila consumida anteriormente.

Pipeline de Execução das Capacidades de Conectores Pipeline de Execução das Capacidades de Conectores.

Por onde começar

Antes de começar o desenvolvimento, é necessário definir quais serão os modelos de dados canônicos manipulados pelo conector, quais serão os seus métodos, onde ele será hospedado, etc. Tendo isto definido, agora, é começar a montar a solução. Para mais detalhes acerca de quais capacidades e/ou modelos de dados canônicos deverão ser implementados, consulte a seção Capacidades Básicas a Implementar.

Este how to está baseado em um ambiente de desenvolvimento Microsoft™, utilizando Microsoft™Asp.Net MVC WebApi2, linguagem de programação C# e Microsoft™ Visual Studio™ 2013. Entretanto, o conector pode ser construído utilizando quaisquer tecnologias que exponham serviços através de HTTP e transfiram mensagens JSON.

No link conectornodejs.zip está um exemplo de implementação de um conector utilizando Javascript.

Abaixo, segue a lista de ações necessárias para desenvolver e testar o Conector:

  • Baixar a solução de exemplo: Octopus.Connector.Sample.zip. Ela contém um exemplo de implementação do Modelo de Dados Canônico Marcas, além de todas as referências necessárias (DLLS) para que o conector funcione e seja compatível com o Octopus.

  • Criar uma solução que hospede um projeto Tipo Asp.Net Web Application;

  • Extrair as referências (arquivos com extensão DLL) para uma pasta References e adicioná-las ao projeto. As referências se encontram no arquivo References.zip;
  • Criar uma Classe Controller para cada Modelo de Dados Canônico a implementar. Ele pode conter toda a implementação para descoberta dos métodos e capacidades dos modelos de dados canônicos. Todavia, recomenda-se a utilização de padrões de projeto que tornem o desenvolvimento e manutenção mais fáceis e ágeis;
  • Criar um Classe Controller para o Manifesto. Ele pode conter toda a implementação para descoberta dos métodos e capacidades dos modelos de dados canônicos. Todavia, recomenda-se a utilização de padrões de projeto que tornem o desenvolvimento e manutenção mais fáceis e ágeis;
  • Criar um Projeto de teste unitário para validar a lógica desenvolvida;
  • Depois de testado unitariamente, publicar o ASP.NET WebApi Application em uma url que possa ser acessada através da Internet;
  • Configurar o Conector no ambiente SandBox de Teste do Octopus.

Todos os exemplos de código apresentados nas seções a seguir encontram-se na solução de exemplo disponibilizada em Octopus.Connector.Sample.zip.

Nas próximas seções, entraremos em detalhe de como fazer cada um dos itens descritos acima.

Definindo o Manifesto

O Controller do Manifesto deverá expor os métodos, as capacidades e as operações (se existirem) em formato JSON.

Neste exemplo, criamos uma forma de buscar essas informações de maneira automática a cada vez que uma capacidade é adicionada ou uma operação é criada.

  • Em primeiro lugar, adicionam-se as propriedades Código Identificador do Conector (assembly: AssemblyConnectorId), Alias/Atalho/Apelido do Conector (assembly: AssemblyConnectorAlias) e Tipo do Conector (assembly: AssemblyConnectorType) ao arquivo AssemblyInfo. Segue abaixo o exemplo delas dentro do arquivo AssemblyInfo:

                                            [assembly: AssemblyConnectorId("Código GUID Identificador do Conector")]
    [assembly: AssemblyConnectorAlias("Alias do Conector")]
    [assembly: AssemblyConnectorType(Tipo de Conector)]
                                            

    Os Tipos de Conector disponíveis são:
    • Connector.System: conector de sistema (conector para validações de integrações);
    • Connector.Erp: conector do tipo ERP (este tipo exporá serviços de um ERP ou interagirá com um ERP);
    • Connector.Marketplace: conector do tipo Marketplace (este tipo exporá serviços de um Marketplace ou interagirá com um Marketplace);
    • Connector.Platform: conector do tipo Plataforma (este tipo exporá serviços de uma Plataforma ou interagirá com uma Plataforma).
  • Em segundo lugar, criar os atributos que serão usados para decorar as classes;

                                            
        [AttributeUsage(AttributeTargets.Assembly)]
        public sealed class AssemblyConnectorAliasAttribute : Attribute
        {
            /// 
            /// The default connector alias.
            /// 
            public const string DefaultConnectorAlias = "undefined";
            /// 
            /// Initializes a new instance of the  class.
            /// 
            /// 
            /// The connector alias.
            /// 
            public AssemblyConnectorAliasAttribute(string connectorAlias)
            {
                this.ConnectorAlias = (connectorAlias ?? DefaultConnectorAlias).ToLowerInvariant();
                this.ConnectorAlias = Regex.Replace(this.ConnectorAlias, "[^a-z]", "-");
                this.ConnectorAlias = this.ConnectorAlias.Trim('-');
                while (this.ConnectorAlias.Contains("--"))
                {
                    this.ConnectorAlias = this.ConnectorAlias.Replace("--", "-");
                }
            }
            /// 
            /// Gets the connector alias.
            /// 
            public string ConnectorAlias { get; private set; }
        }
                                                    /// 
        /// The assembly connector id attribute.
        /// 
        [AttributeUsage(AttributeTargets.Assembly)]
        public sealed class AssemblyConnectorIdAttribute : Attribute
        {
            /// 
            /// Initializes a new instance of the  class.
            /// 
            /// 
            /// The connector id.
            /// 
            public AssemblyConnectorIdAttribute(string connectorId)
            {
                this.ConnectorId = new Guid(connectorId);
            }
            /// 
            /// Gets the connector id.
            /// 
            public Guid ConnectorId { get; private set; }
        }
                                                                                                /// 
        /// The assembly connector type attribute.
        /// 
        [AttributeUsage(AttributeTargets.Assembly)]
        public sealed class AssemblyConnectorTypeAttribute : Attribute
        {
            /// 
            /// Initializes a new instance of the  class.
            /// 
            /// 
            /// The connector type.
            /// 
            public AssemblyConnectorTypeAttribute(ConnectorType connectorType)
            {
                this.ConnectorType = connectorType;
            }
            /// 
            /// Gets the connector type.
            /// 
            public ConnectorType ConnectorType { get; private set; }
        }
                                                /// 
        /// Attribute that indicates if it is a capability.
        [AttributeUsage(AttributeTargets.Method)]
        public sealed class ConnectorCapabilityAttribute : Attribute, ICapabilityAttribute
        {
            /// 
            /// Constructor
            /// 
            /// 
            /// 
            /// 
            /// 
            /// 
            public ConnectorCapabilityAttribute(ObjectType objectType, CapabilityType capabilityType, string action, Type settingsType = null, Type stateType = null)
            {
                ObjectType = objectType;
                CapabilityType = capabilityType;
                Action = action;
                SettingsType = settingsType;
                StateType = stateType;
            }
            /// 
            /// Get or set 
            /// 
            public ObjectType ObjectType { get; private set; }
            /// 
            /// Get or set  
            /// 
            public CapabilityType CapabilityType { get; private set; }
            /// 
            /// Get or set Action (it must be unique)
            /// 
            public string Action { get; private set; }
            /// 
            /// Get or set SettingsType
            /// 
            public Type SettingsType { get; private set; }
            /// 
            /// Get or set Capacity StateType
            /// 
            public Type StateType { get; private set; }
            /// 
            /// Get Capacity's generated name 
            /// 
            /// 
            public string Name
            {
                get { return string.Format("{0}/{1}/{2}", ObjectType, CapabilityType, Action); }
            }
            /// 
            /// Builds the URL.
            /// 
            /// The base URL.
            /// System.String.
            public string BuildUrl(string baseUrl)
            {
                var result = (baseUrl.TrimEnd('/') + '/' + ObjectType + '/' + Action).TrimStart('/').TrimEnd('/');
                return result;
            }
        }                                            
                                                        /// 
        /// Attribute that indicates if it is a Capability's operation
        /// 
        [AttributeUsage(AttributeTargets.Method)]
        public sealed class OperationCapabilityAttribute : Attribute, ICapabilityAttribute
        {
            /// 
            /// Constructor
            /// 
            /// 
            /// 
            public OperationCapabilityAttribute(string action, Type contentType = null)
            {
                Action = action;
                ContentType = contentType;
            }
            /// 
            /// Get Operation Action (it must be unique)
            /// 
            public string Action { get; private set; }
            /// 
            /// Get or set capacity configuration class
            /// 
            public Type ContentType { get; private set; }
            /// 
            /// Get Capacity generated name
            /// 
            /// 
            public string Name
            {
                get { return string.Format("{0}/{1}", "Operation", Action); }
            }
            /// 
            /// Builds the URL.
            /// 
            /// The base URL.
            /// System.String.
            public string BuildUrl(string baseUrl)
            {
                var result = (baseUrl.TrimEnd('/') + "/" + Action).TrimStart('/').TrimEnd('/');
                return result;
            }
        }
                                            
  • Em terceiro lugar, criar uma classe que fará a composição da resposta e carregará as informações acerca dos serviços implementados para o Modelo de Dados Canônico disponibilizado;

                                            
        /// 
        /// Manifest Builder.
        /// 
        public class ManifestBuilder
        {
            /// 
            /// Create a 
            /// 
            /// 
            /// 
            /// 
            /// 
            public ManifestConnector Run(Assembly assembly, string baseUrl, Type settingsType = null)
            {
                baseUrl = baseUrl.TrimEnd('/');
                var finder = new ConnectorCapabilitiesFinder(assembly);
                var connector = new ManifestConnector
                {
                    // Busca o identificador do connector
                    Id = assembly
                        .GetCustomAttributes(typeof(AssemblyConnectorIdAttribute), false)
                        .Cast()
                        .Select(connectorIdAttribute => connectorIdAttribute.ConnectorId)
                        .FirstOrDefault(),
                    // Busca o alias do connector
                    Name = assembly
                        .GetCustomAttributes(typeof(AssemblyConnectorAliasAttribute), false)
                        .Cast()
                        .Select(aliasAttribute => aliasAttribute.ConnectorAlias)
                        .FirstOrDefault(),
                    Version = assembly.GetName().Version.ToString(),
                    Url = baseUrl,
                    DefaultSettings = GenericInstancer.New(settingsType),
                    Capabilities = finder.Run()
                        .Where(detail => detail.Capability is ConnectorCapabilityAttribute)
                        .Select(detail => detail.Capability as ConnectorCapabilityAttribute)
                        .Select(objectCapability => new ManifestCapability
                        {
                            ObjectType = objectCapability.ObjectType,
                            CapabilityType = objectCapability.CapabilityType,
                            Action = objectCapability.Action,
                            Url = objectCapability.BuildUrl(baseUrl),
                            DefaultSettings = GenericInstancer.New(objectCapability.SettingsType),
                            DefaultState = GenericInstancer.New(objectCapability.StateType),
                        })
                        .OrderBy(capability => capability.ObjectType)
                        .ThenBy(capability => capability.CapabilityType)
                        .ThenBy(capability => capability.Action)
                        .ToList(),
                    Operations = finder.Run()
                        .Where(detail => detail.Capability is OperationCapabilityAttribute)
                        .Select(detail => detail.Capability as OperationCapabilityAttribute)
                        .Select(objectCapability => new ManifestOperation
                        {
                            Action = objectCapability.Action,
                            Url = objectCapability.BuildUrl(baseUrl),
                            DefaultContent = GenericInstancer.New(objectCapability.ContentType),
                        })
                        .OrderBy(capability => capability.Action)
                        .ToList(),
                };
                return connector;
            }
        }
                                            
  • Em quarto lugar, implementar o uso dessa classe no Controller do Manifesto.

                                            
        /// 
        /// Manifest Controller.
        /// 
        public class ManifestController : ApiController
        {
            /// 
            /// Get Manifest
            /// 
            /// 
            /// The Manifest describes Connector information, its capacities and supported operations.
            /// 
            /// OK
            /// Unknown Exception
            /// 
            /// A message containing what is executed, exceptions thrown and processed models.
            /// 
            public ManifestConnector[] Get()
            {
                var builder = new ManifestBuilder();
                var result = builder.Run(GetType().Assembly, Url.Content("."), typeof(ConnectorSettings));
                return new[] { result };
            }
        }
                                            

Definindo as Capacidades

Capacidade Publicadora

Uma Capacidade Publicadora nada mais é do que um método pelo qual os dados serão publicados pelo Conector. Este método recebe uma decoração que o identifica de maneira que o Manifesto possa expô-lo corretamente e o Octopus conseguir interagir com ele.

Para implementar uma Capacidade Publicadora:

  • Primeiro, criar um Controller para o Modelo ao qual a capacidade será adicionada;

                                            
    using OctopUS.Application;
    using Octopus.Connector.Sample.ENUS.Helpers;
    using Octopus.Connector.Sample.ENUS.Helpers.Extensions;
    using Octopus.Connector.Sample.ENUS.Helpers.Attributes;
    using Octopus.Connector.Sample.ENUS.Models;
    using Octopus.Domain.Catalog;
    using Octopus.Domain.Connectors;
    using Octopus.Domain.Workers;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    namespace Octopus.Connector.Sample.ENUS.Controllers
    {
        /// 
        /// Brand Controller
        /// 
        [Export(typeof(ConnectorController))]
        public class BrandController : ConnectorController
        {}
    }
    
                                            
  • Segundo, neste Controller, criar um método Publicador devidamente decorado.

                                            
            /// 
            ///  Brand Publisher
            /// 
            /// Message for capacity execution.
            /// OK
            /// Unknown exception
            /// 
            ///     Response within executed operations, errors and models returned.
            /// 
            [ConnectorCapability(ObjectType.Brand, CapabilityType.Publisher, "Publish", typeof(PublisherSettings))]
            public CapabilityResponse Publisher(CapabilityMessage message)
            {
                message.CheckIntegrity();
                var command = new PublishCommand(message, id => new BrandModel
                {
                    Id = id
                });
                var result = command.Run().Result;
                return result;
            }
                                            

    Onde:

    • ConnectorCapability: Encapsula e transforma as mensagens de entrada e saída;
    • ObjectType: Modelos Canônicos aos quais a capacidade está associada. No exemplo, o Modelo Canônico é Marca (ObjectType.Brand);
    • CapabilityType: Tipo de capacidade (Publisher - publicadora, Subscriber - consumidora/subscritora ou Callback - método de Callback). No exemplo, o Tipo de Capacidade é Publicadora (CapabilityType.Publisher);
    • "Publish": é o nome do método que será exposto;
    • typeof(PublisherSettings): é o tipo do objeto que contém as configurações da capacidade para este conector.
    A implementação da lógica de negócio é executada através do padrão de projeto Command.

    
    using Octopus.Connector.Sample.ENUS.Helpers;
    using Octopus.Connector.Sample.ENUS.Models;
    using Octopus.Domain;
    using Octopus.Domain.Messaging;
    using Octopus.Domain.Workers;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web;
    namespace Octopus.Connector.Sample.ENUS.Application
    {
        /// 
        /// Publish Command.
        /// 
        /// The type of the t model.
        internal class PublishCommand : CapabilityCommand
            where TModel : IOctopusModel
        {
            private readonly Func _getModel;
            /// 
            /// Initializes a new instance of the  class.
            /// 
            /// The message.
            /// The get model.
            public PublishCommand(CapabilityMessage message, Func getModel)
                : base(message)
            {
                _getModel = getModel;
            }
            /// 
            /// Overrided method for capacity execution.
            /// The request models.
            /// Task<ICollection<TModel>>.
            protected override async Task> Execute(IReadOnlyCollection requestModels)
            {
                var result = new List();
    
                for (var idx = 0; idx < base.CapabilitySettings.ModelsToGenerate; idx++)
                {
                    var model = _getModel(idx.ToString());
                    result.Add(model);
                }
    
                return await Task.FromResult(result);
            }
        }
    }

Capacidade Consumidora/Subscritora

Uma Capacidade Consumidora/Subscritora nada mais é do que um método pelo qual os dados serão recebidos pelo Conector. Ele fará a integração dos dados publicados pelo Publicador no Sistema de Destino. Este método recebe uma decoração que o identifica de maneira que o Manifesto possa expô-lo corretamente e o Octopus conseguir interagir com ele.

Para implementar uma Capacidade Publicadora:

  • Primeiro, criar um Controller para o Modelo ao qual a capacidade será adicionada;

                                            
    using Octopus.Connector.Sample.ENUS.Application;
    using Octopus.Connector.Sample.ENUS.Helpers;
    using Octopus.Connector.Sample.ENUS.Helpers.Extensions;
    using Octopus.Connector.Sample.ENUS.Helpers.Attributes;
    using Octopus.Connector.Sample.ENUS.Models;
    using Octopus.Domain.Catalog;
    using Octopus.Domain.Connectors;
    using Octopus.Domain.Workers;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    namespace Octopus.Connector.Sample.ENUS.Controllers
    {
        /// 
        /// Brand Controller
        /// 
        [Export(typeof(ConnectorController))]
        public class BrandController : ConnectorController
        {}
    }
    
                                            
  • Segundo, neste Controller, criar um método Consumidor devidamente decorado.

                                            
            /// 
            ///  Brand Subscriber. It integrates brand data on the destiny.
            /// 
            /// 
            /// Integrate Brand
            /// 
            /// Message for capacity execution
            /// OK
            /// Unknown Exception
            /// 
            ///     Response within executed operations, errors and models returned.
            /// 
            [ConnectorCapability(ObjectType.Brand, CapabilityType.Subscriber, "Integrate", typeof(IntegrateSettings))]
            public CapabilityResponse Integrate(CapabilityMessage message)
            {
                message.CheckIntegrity();
                var command = new IntegrateCommand(message);
                var result = command.Run().Result;
                return result;
            }
                                            

    Onde:

    • ConnectorCapability: Encapsula e transforma as mensagens de entrada e saída;
    • ObjectType: Modelos Canônicos aos quais a capacidade está associada. No exemplo, o Modelo Canônico é Marca (ObjectType.Brand);
    • CapabilityType: Tipo de capacidade (Publisher - publicadora, Subscriber - consumidora/subscritora ou Callback - método de Callback). No exemplo, o Tipo de Capacidade é Consumidora (CapabilityType.Subscriber);
    • "Integrate": é o nome do método que será exposto;
    • typeof(IntegrateSettings): é o tipo do objeto que contém as configurações da capacidade para este conector.
    A implementação da lógica de negócio é executada através do padrão de projeto Command.

    
    using Octopus.Connector.Sample.ENUS.Helpers;
    using Octopus.Connector.Sample.ENUS.Models;
    using Octopus.Domain;
    using Octopus.Domain.Messaging;
    using Octopus.Domain.Workers;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web;
    namespace Octopus.Connector.Sample.ENUS.Application
    {
        /// 
        /// Integrate Command.
        /// 
        internal class IntegrateCommand : CapabilityCommand
            where TModel : IOctopusModel
        {
            private readonly Random _randomSeed = new Random();
            /// 
            /// Initializes a new instance of the  class.
            /// 
            /// The message.
            public IntegrateCommand(CapabilityMessage message)
                : base(message)
            {
            }
            /// 
            /// Executes the specified request models.
            /// 
            /// The request models.
            /// Task<ICollection<TModel>>.
            protected override async Task> Execute(IReadOnlyCollection requestModels)
            {
                var responseModel = new List();
    
                foreach (var model in requestModels)
                {
                    using (base.Trace("Integrate", model))
                    {
                        var random = _randomSeed.NextDouble();
                        if (random < base.CapabilitySettings.CriticalOdd)
                        {
                            var failMessage = string.Format("Critical ({0:N4} < {1:N4})", random, base.CapabilitySettings.CriticalOdd);
                            await base.Log(LogKind.Critical, failMessage);
    
                            break;
                        }
    
                        random = _randomSeed.NextDouble();
                        if (random < base.CapabilitySettings.ErrorOdd)
                        {
                            var failMessage = string.Format("erro ({0:N4} < {1:N4})", random, base.CapabilitySettings.ErrorOdd);
                            await base.Log(LogKind.Error, failMessage);
    
                            continue;
                        }
    
                        responseModel.Add(model);
    
                        var format = string.Format("Success ({0:N4})", random);
                        await base.Log(LogKind.Info, format);
                    }
                }
    
                return await Task.FromResult(responseModel);
            }
        }
    }

Capacidade de Callback

Uma Capacidade de Callback nada mais é do que um método usado para processar o retorno dos dados executado pelo Subscriber. Normalmente, este tipo de método é usado para executar ações como remover um produto da fila do Sistema de Origem após a integração pelo Sistema de Destino. Este método recebe uma decoração que o identifica de maneira que o Manifesto possa expô-lo corretamente e o Octopus conseguir interagir com ele.

Em relação aos outros tipos, uma decoração exemplo para este método será descrita abaixo:

  • ConnectorCapability: Encapsula e transforma as mensagens de entrada e saída;
  • ObjectType: Modelos Canônicos aos quais a capacidade está associada. Neste caso, o Modelo Canônico é Marca (ObjectType.Brand);
  • CapabilityType: Tipo de capacidade (Publisher - publicadora, Subscriber - consumidora/subscritora ou Callback - método de Callback). Neste caso, o Tipo de Capacidade é Consumidora (CapabilityType.Callback);
  • "Dequeue": é o nome do método que será exposto.

Capacidades Básicas a Implementar

Segue abaixo uma tabela com a lista de Capacidades Básicas que necessitam ser implementadas para cada tipo de Conector e os Modelos Canônicos relacionados.

Conector ERP

Tipo de Conector Modelo de Dados Canônico Tipo de Capacidade Descrição Obrigatoriedade
ERP Brand (Marca) Publisher Deverá retornar todas as Marcas dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso já esteja sendo executado na Integração de Produtos.
ERP Category (Categoria) Publisher Deverá retornar todas as Categorias dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso já esteja sendo executado na Integração de Produtos.
ERP Product (Produto) Publisher Deverá retornar todos os produtos disponíveis para publicação no Sistema de Destino. Obrigatório
ERP ProductImage (Imagens de Produto) Publisher Deverá retornar todas as imagens dos produtos disponíveis para publicação no Sistema de Destino. Opcional
ERP Price (Preço) Publisher Deverá retornar os preços dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso esteja sendo executado na Integração de Produto.
ERP Inventory (Estoque) Publisher Deverá retornar os estoques dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso esteja sendo executado na Integração de Produto.
ERP Customer (Cliente) Subscriber Deverá integrar o Cliente no Sistema de Origem. Opcional caso já esteja sendo executado na Integração de Pedidos.
ERP Order (Pedido) Subscriber Deverá integrar o Pedido no Sistema de Origem. Obrigatório
ERP OrderStatus (Estado do Pedido) Publisher Deverá publicar o Estado do Pedido para o Sistema de Destino. Obrigatório

Conector Plataforma

Tipo de Conector Modelo de Dados Canônico Tipo de Capacidade Descrição Obrigatoriedade
Plataforma Brand (Marca) Subscriber Deverá integrar as Marcas dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso já esteja sendo executado na Integração de Produtos.
Plataforma Category (Categoria) Subscriber Deverá integrar as Categorias dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso já esteja sendo executado na Integração de Produtos.
Plataforma Product (Produto) Publisher Deverá integrar os produtos disponíveis para publicação no Sistema de Destino. Obrigatório
Plataforma ProductImage (Imagens de Produto) Publisher Deverá integrar as imagens dos produtos disponíveis para publicação no Sistema de Destino. Opcional
Plataforma Price (Preço) Subscriber Deverá integrar os preços dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso esteja sendo executado na Integração de Produto.
Plataforma Inventory (Estoque) Subscriber Deverá integrar os estoques dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso esteja sendo executado na Integração de Produto.
Plataforma Customer (Cliente) Publisher Deverá publicar o Cliente para o Sistema de Origem. Opcional caso já esteja sendo executado na Integração de Pedidos.
Plataforma Order (Pedido) Publisher Deverá publicar o Pedido para o Sistema de Origem. Obrigatório
Plataforma OrderStatus (Estado do Pedido) Subscriber Deverá integrar o Estado do Pedido no Sistema de Destino. Obrigatório

Conector Marketplace

Tipo de Conector Modelo de Dados Canônico Tipo de Capacidade Descrição Obrigatoriedade
Marketplace Product (Produto) Subscriber Deverá integrar os produtos disponíveis para publicação no Sistema de Destino. Obrigatório
Marketplace ProductImage (Imagens de Produto) Subscriber Deverá integrar as imagens dos produtos disponíveis para publicação no Sistema de Destino. Opcional
Marketplace Price (Preço) Subscriber Deverá integrar os preços dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso esteja sendo executado na Integração de Produto.
Marketplace Inventory (Estoque) Subscriber Deverá integrar o estoque dos produtos disponíveis para publicação no Sistema de Destino. Opcional caso esteja sendo executado na Integração de Produto.
Marketplace Order (Pedido) Publisher Deverá publicar o Pedido para o Sistema de Origem. Obrigatório
Marketplace OrderStatus (Estado do Pedido) Subscriber Deverá integrar o Estado do Pedido no Sistema de Destino. Obrigatório

Exemplo de um Cenário de Integração

Exemplo de um Cenário de Integração