Connector Builder – O canivete suíço do Magic xpi – Parte II – a “UI”

Umas das grandes características da plataforma Magic xpi é a sua capacidade de moldar-se às necessidades e desafios propostos.

Multiplique e adapte você mesmo os recursos de integração da plataforma, com o Connector Builder. Conheça um pouco mais sobre ele, com este novo () artigo da série.

 

Ok. Você está ansioso, é compreensível, para ver e aprender sobre o Connector Builder. Mas antes:

São passos muito importantes para o correto entendimento e aproveitamento do que será abordado a seguir. Abordaremos aqui a criação e codificação do módulo “UI” do nosso componente customizado.

*Nota: o artigo I explica o que ele é e como faremos

 

Partindo do projeto MS.NET (StepUI.sln) que foi gerado pelo assistente, cfe. mostrado no artigo I, nós precisaremos definir e implementar 3 classes:

 

  • CUrlConfigData = classe livre (qualquer nome é válido, mas tem de respeitar o que foi definido nos metadados do componente), que não herda de ninguém (até poderia, mas não é obrigatório).
  • ui = classe (qualquer nome é válido, mas tem de respeitar o que foi definido nos metadados do componente), que precisa obrigatoriamente implementar a interface IUserComponent.
  • uiForm = classe (qualquer nome é válido) que está herdando de System.Windows.Forms.Form. Isso porque decidimos que a tela (interface) da nossa configuração, será uma janela WinForm.

 

Como precisamos implementar a interface IUserComponent, a primeira ação é referenciar o assemblyMagicSoftware.Integration.UserComponents” disponibilizado pelo Magic xpi  na pasta “Studio\Extensions\Application\“:

 

Agora, vamos entender a implementação de cada uma destas 3 classes. Não iremos explicar o “código C#” usado no projeto, até porque você terá livre acesso a ele. Mas vamos explicar o funcionamento e propósito de cada uma delas.

Classe CUrlConfigData

Esta é a classe encarregada de armazenar todas as configurações que o conector vai precisar. O Magic xpi Studio vai instanciar esta classe e utilizar este objeto, liberando-o para configuração, armazenando-o dentro do fluxo do projeto e repassando-o posteriormente ao módulo “Runtime(Magic xpi Server) para informar como o componente deve ser executado.

De forma resumida, cada configuração que o componente venha a precisar deve ser um propriedade pública desta classe. Veja:

 

Nesse recorte, vemos 3 propriedades (httpVerb, urlDynAddition, headersToSend). De fato, nossa classe tem 15 propriedades (configurações) no total: 6 de entrada, 8 de saída e 1 interna.

O segredo, está nestas anotações (atributos) delas. Vamos entender:

 

  • [Id] = Este atributo deve ser informado para todas as propriedades, e aceita qualquer número. Mas não pode se repetir entre elas. Funciona como “primary key” da propriedade.
  • [PrimitiveDataTypes] = É o tipo de dado “Magic” desta propriedade, dentro da lista aceita pelo Magic xpi: ALPHA, NUMERIC, DATE, TIME, LOGICAL ou BLOB.
  • [DisplayPropertyName] = É um texto curto e que representa o nome “amigável” desta propriedade, para o usuário ver por exemplo.
  • [In], [Out] ou [InOut] = Define se esta propriedade (configuração) é do tipo “input“, “output” ou “ambos“.
  • [AllowEmptyExpression] = Não é orbgatório usar, mas quando informado, diz ao Magic xpi que esta configuração é “opcional”: o checker do Magix xpi Studio não reclamará se ela não for informada.
  • [ExcludeFromTextSearch] = Se informado, o Magix xpi Studio não considera esta propriedade (configuração) no processo de “pesqusia de texto” (Find…).
  • [ExcludeFromRuntime] = Se informado, esta propriedade é relevante somente para o Magix xpi Studio e não será repassada para o Magix xpi Server.

 

As propriedades podem ter um total de 8 diferentes tipos possíveis:

  • PRIMITIVE: O valor dela será uma das opções dentro da lista aceita pelo Magic xpi: ALPHA, NUMERIC, DATE, TIME, LOGICAL ou BLOB. Por exemplo:
'A' é um valor válido para uma propriedade ALPHA. 123 é um valor válido para uma propriedade NUMERIC.
  • EXPRESSION: O valor dela será calculado por uma “expressão” do Magic xpi. Propriedades [In] podem ser deste tipo. Por exemplo:
'Botim' & ' Médico' & ' nr. ' & Trim( Str( C.UserCode, '6' ) ) é um valor válido para uma propriedade EXPRESSION.
Internamente, ela ainda precisa ser associado a um dos 6 tipos primitivos, cfe. atributo mostrado acima. 
  • VARIABLE: O valor dela é apenas uma referência a uma “variável” do  Magic xpi. Propriedades [Out] e [InOut] podem ser deste tipo. Por exemplo:
C.UserString é um valor válido para uma propriedade VARIABLE.
Internamente, ela ainda precisa ser associado a um dos 6 tipos primitivos, cfe. atributo mostrado acima.

 

Então, analisando esta definição:

 

Temos uma propriedade chamada keepWorkingFiles, do tipo EXPRESSION*, que internamente é um valor LOGICAL, é uma propriedade de input, com Id=6, nome amigável “Keep Working Files on Disc” e é obrigatória.

*Nota: Quando o Runtime ler o valor desta propriedade, a expressão será avaliada e calculada nesta hora, para saber qual será seu resultado (que será o valor da propriedade).

 

Nesta outra definição:

 

Temos uma propriedade chamada httpResultText, do tipo VARIABLE*, que internamente é um valor ALPHA, é uma propriedade de output, com Id=12, nome amigável “HTTP Result Text” e é opcional.

*Nota: Quando o Runtime ler o valor desta propriedade, estará lendo o valor de "variável" a ela associada. Se aytualizá-la, estará atualizando o conteúdo da "variável".

 

Como cada uma destas propriedades é também um objeto, no construtor da classe (CUrlConfigData) nós aproveitamos para instanciar todas delas, inclusive já definindo alguns valores “padrões(por conveniência):

 

 

E por fim, adicionamos um método auxiliar que gera uma coleção de características de cada uma das propriedades existentes, para utilização em outras classes do projeto.

Notamente na classe uiForm (interface real com o usuário) :

 

E assim, concluímos nossa 1a classe do projeto “UI“.

Classe uiForm

Não tem segredos aqui, é possivelmente a parte mais trivial do projeto. Esta é uma classe que está herdando de System.Windows.Forms.Form e será a nossa “tela de configuração” do componente.

Não existe obrigatoriedade de interface para estes casos, mas podendo manter um “padrão visual” com os demais componentes existentes no produto, convém fazê-lo.

Neste caso porém, estamos “criando” um estilo de interface todo novo.

O plano aqui é usar uma interface de “matriz” ou “tabela” para esta confioguração, onde cada linha da tabela representa uma das propriedades da classe (CUrlConfigData) e cada coluna uma característica específica desta propriedade: nome, tipo de dado, direção da informação, etc…

 

O usuário (desenvolvedor) não pode adicionar/excluir linhas, apenas editá-las. E só poderá fazer isso através de “assistentes” específicos.

Aqui será feito uso intensivo daquela coleção de informações retornadas pelo método CUrlConfigData.GetDetails().

Se a propriedade é obrigatória por exemplo, ela será exibida em negrito.

Se ela for do tipo “expression” será habilitado ao usuário o editor de expressões do Magic xpi Studio, para definir o seu valor.

Se for do tipo “variable” será habilitado ao usuário o seletor de variáveis do Magic xpi Studio, para definir o seu valor.

*Nota: Estes assistentes serão ativados clicando-se no botão [...] de cada propriedade, com duplo-clique na coluna "Value" ou duplo-clique na coluna mais à esquerda (row indicator).

 

Ao final, o usuário terá um interface (tela) assim para configurar este novo componente:

 

Também será feito uso de outras ferramentas, que o próprio Magic xpi Studio disponibiliza para o nosso componete, nesta fase de configuração:

 

  • ISDKStudioUtils = é um objeto que dá acesso a varíos assistentes (editor de expressões, seletor de variáveis, seletor de arquivox, diálogos de erro, confirmação ou questionamento), padrões da plataforma.
  • IReadOnlyResourceConfiguration = é um objeto que dá acesso ao recurso (se existir) associado a este componente.

 

É desta forma que, se o usuário clicar no botão de edição de uma propriedade “expression“, abriremos este assistente para ele:

 

Se clicar no botão de edição de uma propriedade “variable“, abriremos este outro assistente:

E assim, concluímos nossa 2a classe do projeto “UI“.

Classe ui

É a classe que liga os pontos. Como ela precisa implementar uma intarface (IUserComponent), alguns métodos são obrigatórios nela:

 

  • CreateDataObject = Este método tem de retornar uma instância (objeto) de nossa classe de configuração (explicada mais acima).

 

  • ValidateResource = Caso o componente dependa de um recurso (o nosso depende), e este recurso tenha um botão “Validate(o nosso tem), este metódo é chamado pelo Magic xpi Studio sempre que o usuário clicar neste botão “Validate“:

 

Para informarmos ao Magic xpi Studio que a validação está ‘OK’, retornamos true. Do contrário, devemos retornar false:

 

  • Check = Não usaremos em nosso componente, mas ele é chamado pelo checker do Magix xpi Studio para podermos fazer checagens adicionais nas configurações do conector, além das básicas (tipo de dados incompatíveis e propriedade obrigatória não definida).
  • InvokeResourceHelper = Não usaremos em nosso componente, mas caso o componente dependa de um recurso (o nosso depende), e este recurso tenha outros botões definidos além do “Validate(o nosso não tem), ele é chamado sempre que algum destes outros botões for clicado pelo usuário.
*Nota: Um recurso do tipo "database" por exemplo, possui 4 botões na sua interface de parametrização.
  • GetSchema = Aqui tem uma curiosidade. Quando o nosso componente informar ao Magic xpi Studio que sua configuração foi “confirmada“, um DataMapper será automaticamente aberto para prosseguir com a configuração dele.

Para o Magic xpi Studio, um componente customizado pelo Connector Builder tem sua configuração feita por 1 tela DataMapper ) ou 2 telas ( normal + DataMapper ).

A função deste método é retornar um objeto SchemaInfo, que é uma estrutura “Xml“, “Json” ou “FlatFile” para justamente ser aberta por este DataMapper:

 

De verdade, nossa intenção era não ter esta 2a. tela em nossa configuração. Mas para atender a esta imposição da interface, definimos um último (16o) argumento de configuração do nosso componente, a ser parametrizado no final por este DataMapper:

Mas exercitante um pouco a criatividade, veja que poderíamos ter desenhado um layout um pouco diferente: poderíamos ter definido no classe “uiForm” para tratar apenas das propriedades output, deixando todas as propriedades para serem editadas por este DataMapper interno.

De fato, vários componentes da plataforma (SalesForce, SAP R/3, Dynamics AX, etc…) usam esta interface híbrida de configuração.

 

  • Configure = Este é cara, o método que o Magic xpi Studio chama quando o usuário escolhe a opção “Configuration” do componente:

 

 

ou quando o usuário der duplo clique no nosso componente na janela “Find Result” ou “Checker Result”.

Ele recebe os seguintes argumentos:

 

    • dataObject = É uma instância da nossa classe de configuração (explicada acima), que pode estar vazia se é a primeira tentativa de configuração, ou já preenchida com as informações da última vez que este componente foi configurado. Caso nossa rotina altere algumas das configurações, este objeto deve ser alterado também (é um argumento ref).
    • ISDKStudioUtils = Um objeto padrão do Magic xpi Studio, que dá acesso a várias informações do projeto e assistentes built-in da plataforma.
    • IReadOnlyResourceConfiguration = Um objeto padrão do Magic xpi Studio, que dá acesso ao recurso (se existir) associado ao componente.
    • navigateTo = Caso seja “não nulo“, este objeto é o “Id” da propriedade que o usuário escolheu para olhar. Por exemplo, se o checker apontou falha de validação em alguma propriedade ou o usuário executou um “Find…”, e na janela do “Find Results” ou “Checker Results” ele der duplo clique no item, este objeto vem preenchido (com o referido Id do item). Se o usuário acionou o menu “Configuration”, este objeto vem “null”.
    • configurationChanged = Devemos atualizar este parâmetro (que também é ref) com true, caso tenhamos atualizado alguma configuração. Se não, temos de atualizá-lo com false.

 

Este método deve retornar true, para informar que o usuário confirmou a configuração. Ou false, para informar que o usuário desistiu.

Se retornar true, o Magic xpi Studio abre automaticamente o DataMapper para continuar a configuração:

 

Se retornat true e “configurationChanged” também for true, o Magc xpi Studio marca o componente com “alterado” e o fluxo como “pendente de salvamento“.

Neste caso, não podemos esquecer de alterar também o “dataObject“, para que seja salva (se for salvo pelo usuário – CTRL+S) a versão nova da classe de configuração.

 

O nosso código para o “Configure” é então, bem simples:

Nós criamos um objeto “cópia” de nossa classe de configuração, com base no que o Magic xpi Studio irá nos passar, e instanciamos a nossa tela (classe uiForm).

Se o usuário (desenvolvedor) mudar alguma coisa durante esta interação, a uiForm sabe nos dizer isso.

Se ele confirmou (clicou o botão OK), nós retornaremos true para o Magic xpi Studio. E neste caso, se houve alteração, nós também atualizamos “configurationChanged” e “dataObject“, antes de completar:

 

E assim, concluímos nossa 3a e última classe do projeto “UI“.

Lembrando que o módulo compilado precisa ser colocado sempre na pasta “Runtime\addon_connectors\<componente>\ui\lib“:

E é isto! Está pronta nosso projeto “UI“, de interface de configuração para o nosso conector customizado:

 

Lembra que mencionamos o checker algumas vezes? Considere por exemplo que tenhamos forçado a barra, informando uma expressão incompatível com o tipo de dados esperado:

 

Ao executarmos (CTRL+R) o checker, ele é capaz de analisar e detectar corretamente este probema:

 

E se o usuário der duplo clique nessa inconsistência, nossa interface (uiForm) está preparada para selecioná-la automaticamente e abrir seu assistente:

Mesmas funcionalidades dos componentes standard da plataforma, como prometido.

 

Mas lembre-se: só fizemos a definição e a “UI” do novo componente até aqui.

Não criamos ainda o código das regras de negócio (módulo Runtime) dele, então ele não pode ainda ser executado pelo Magic xpi Server.

 

E esta, é a etapa que deixaremos para as próximas publicações  🙂

Aguarde a parte III!

Quer dar uma sneak peak no código do componente, com o que foi visto até aqui? Baixe-o deste endereço.

Mas não se esqueça: você já pode vê-lo e tocá-lo, mas ainda não pode levá-lo a sério!

 

Manoel Frederico Silva – Gerente de Tecnologia e Evangelista MAGIC – Magic Brasil

Manoel Frederico Silva – Evangelista MAGIC – Magic Brasil

 

Para receber os artigos do Blog Magic Brasil em primeira mão no seu email, registre-se aqui

Novo Comentário