Páginas filhas
  • Intellector 9 - API - Criação de Plugin
Introdução

O objetivo desta API é auxiliar o desenvolvedor na construção de plugins externos.


Desenvolvendo um Plugin Externo

Para obter mais exemplos de como construir usando a Intellector API, favor contactar a equipe TOTVS Financial.

Nem preciso explicar que esse framework nasceu da necessidade de padronizar o desenvolvimento dos primeiros plugins de acessos e execuções de políticas, embora essa característica fosse evidente desde o princípio. Na realidade, queríamos "forçar" qualquer desenvolvedor de plugins de acesso para o TOTVS Intellector a seguir o pattern que fosse operacional na chamada da política ao plugin desenvolvido, como exceções lançadas, etc., e tivesse uma luz no fim do túnel, com algumas artifícios que ajudassem, pois quanto problemas e dúvidas melhor. Ele é um framework de abstração para operações como chamadas HTTPS com certificados, as vezes bem complexas, e, acreditem, não é tão trivial lidar com sopa de letrinhas esquisitas. Mas nada de ficar assustado, abaixo veremos cada característica desse framework.

  • Interface Plugin - Interface de plugins externos. Arremessa as exceções 'InfraException' para problemas de infraestrutura, como unknown host (conexões e suas configurações, erros de autenticação, logins e passwords, jks, etc);'LayoutException' para problemas relacionados aos layouts, registros e tipos do plugins e, 'ConfigException' se for detectado qualquer anomalia na configuração do plugin. Atualmente um único método precisa ser implementado, oexecute(). É interessante observar as HashMap de entrada/saída:
public interface PluginInterface {
	/**
	 * Executa um plugin externo; interface
	 * <p>
	 * @param hashIn
	 * @throws InfraException
	 * @throws LayoutException
	 * @throws ConfigException
	 */
	public HashMap<String, Object> execute( HashMap<String, Object> hashIn) 
		throws InfraException, LayoutException, ConfigException;
}


Exceptions throwable - O intellector-api disponibiliza algumas exceções para serem utilizadas pelos plugins de acessos, interpretados e tratados por qualquer política compilada pelo TOTVS Intellector Server, são elas:

  1. CipheringException - Classe Exception para tratamento das exceptions de ciphering (criptografia);
  2. ConfigException - Exceção gerada sempre que há um erro na configuração do plugin externo, como por exemplo, arquivos de configuração não localizados, certificados não localizados, etc.;
  3. InfraException - Exceção gerada sempre que há um erro na execução do plugin externo, como por exemplo, host não localizado, erros na conexão, autenticação, etc.;
  4. LayoutException - Exceção gerada sempre que há um erro na configuração dos layouts, como por exemplo, arquivos de configuração não localizados, layouts configurados de forma errada, etc.;
  5. PolicyException - Exceção gerada sempre que há um erro na política de controle de acessos de usuários na publicação de políticas, layouts de políticas, autenticação no site e execução de políticas.

Todas as exceções tem overload como no exemplo abaixo, permitindo lançar o throwable da causa junto.

public class CipheringException extends Exception {
	/** 
	 * Excecao relativa a problemas de criptografia
	 * <p>
	 * @param msg mensagem para ser mostrada pela excecao
	 */
	public CipheringException(String msg) {
		super(msg);
	}

	/**
	 * Constrói uma nova exceção especificando a mensagem detalhada e a causa.
	 * Note que a mensagem detalhada associada a causa não são incorporadas
	 * automaticamente na mensagem desta exceção.
	 * <p>
	 * @param message
	 *            Mensagem detalhada (que é armazenada para posterior obtenção
	 *            pelo método {@link #getMessage()})
	 * @param cause
	 *            Causa (que é guardada para posterior recuperação pelo método
	 *            {@link #getCause()}) (Um valor nulo é permitida, e indica que
	 *            a causa é inexistente ou desconhecida.)
	 */
	public CipheringException(String message, Throwable cause) {
		super(message, cause);
	}
}


Arquivos de configuração do Plugin e para a sua geração

Criar manualmente os arquivos com o layout do plugin externo e outras informações. Um template para a criação desse arquivo se encontra no dummyplugin para facilitar a vida do desenvolvedor e, tenha em mente, ele será validado pelo Intellector IW-Editor. 

São dois os arquivos que deverão ser criados para a configuração e geração do plugin (os arquivos de exemplo estão no projeto Eclipse com fontes que são disponibilizados mais abaixo):

  • JSON - arquivo com as definições da classe implementada pelo plugin, lista de variáveis de entrada e saída do plugin, propriedades que o usuário poderá alterar.
  • POM.XML - Além das definições de armazento do plugin em um repositório contém informações sobre a geração do plugin.

JSON

{
"class_name": "br.com.totvs.plugins.dummyplugin.DummyPlugin" ,
"plugin_name": "dummyplugin",
"description":"Descrição do Plugin",
"layout": {
"editable": true,
"in": [
{
"description": "cpf requerente",
"type": "String",
"name": "CPF",
"format": ""
},
{
"description": "Data de Nascimento",
"type": "Date",
"name": "DT_NASC",
"format": "ddMMyyyy"
},
{
"description": "Tem seguro",
"type": "Boolean",
"name": "TEM_SEGURO",
"format": ""
},
{
"description": "Valor do salario",
"type": "Double",
"name": "VAL_SALARIO",
"format": ""
},
{
"description": "Idade do requerente",
"type": "Integer",
"name": "IDADE",
"format": ""
}
],
"out": [
{
"id": "DUMMY",
"counter": 0,
"counter_max": 0,
"register": [
{
"description": "Teste de boolean",
"type": "Boolean",
"name": "BOOLEAN_VALUE",
"format": ""
},
{
"description": "Teste pra tipo Data",
"type": "Date",
"name": "DATE_VALUE",
"format": "ddMMyyyy"
},
{
"description": "Teste pra tipo Double",
"type": "Double",
"name": "DOUBLE_VALUE",
"format": ""
},
{
"description": "Teste pra tipo Integer",
"type": "Integer",
"name": "INTEGER_VALUE",
"format": ""
},
{
"description": "Teste pra tipo String",
"type": "String",
"name": "STRING_VALUE",
"format": ""
}
]
},
{
"id": "D100",
"counter": 0,
"counter_max": 0,
"register": [
{
"description": "Um Nome qualquer",
"type": "String",
"name": "D100_NOME",
"format": ""
},
{
"description": "Uma data de Nascimento",
"type": "Date",
"name": "D100_DTNASCIMENTO",
"format": "ddMMyyyy"
},
{
"description": "Mostra o diretorio",
"type": "String",
"name": "D100_MYDIR",
"format": ""
},
{
"description": "Qualquer string",
"type": "String",
"name": "D100_OUTRO",
"format": ""
}
]
},
{
"id": "D200",
"counter": 2,
"counter_max": 3,
"register": [
{
"description": "Simula String com contador",
"type": "String",
"name": "D200_TIPO_",
"format": ""
},
{
"description": "Simula Date com contador",
"type": "Date",
"name": "D200_DATA_",
"format": "yyyyddMM"
},
{
"description": "Simula String com contador",
"type": "String",
"name": "D200_HORA_",
"format": ""
},
{
"description": "Simula String com contador",
"type": "String",
"name": "D200_MOEDA_",
"format": ""
},
{
"description": "Simula Double com contador",
"type": "Double",
"name": "D200_VALOR_",
"format": ""
}
]
}
]
},
"properties": {
"database": "mango_d",
"usuario": "claudio",
"senha": "mariposa",
"audita": true
}
}

POM.XML

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>grouo-id</groupId>
	<artifactId>dummyplugin</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<description>Dummy para exemplificar plugins externos</description>

	<properties>
		<!-- nome da package e classe - FQN -->
		<main-class>br.com.totvs.plugins.dummyplugin.DummyPlugin</main-class>
		<!-- Nome do Plugin -->
		<pluginname>dummyplugin</pluginname>
		<description>Dummy para exemplificar plugins externos</description>
		<!-- chave de acesso ao dado na persistencia -->
		<primarykey>CPF</primarykey>
		<pkdescription>CPF do adquirente</pkdescription>
		<!-- Caminho para o Layout do Plugin -->
		<layoutpath>resources/dummyplugin.json</layoutpath>
		
		<!-- P - plugin /  L - lib para plugin -->
		<pluginlib>P</pluginlib>
	</properties>

	<distributionManagement>
		<repository>
			<id>releases</id>
			<url>http://repo.com:8081/nexus/content/repositories/releases</url>
		</repository>
		<snapshotRepository>
			<id>snapshots</id>
			<url>http://repo.com:8081/nexus/content/repositories/snapshots</url>
		</snapshotRepository>
	</distributionManagement>

	<build>
		<sourceDirectory>src</sourceDirectory>
		<resources>
			<resource>
				<directory>src</directory>
				<excludes>
					<exclude>**/*.java</exclude>
				</excludes>
			</resource>
			<resource>
				<directory>resources</directory>
				<includes>
					<include>**/*.*</include>
				</includes>
				<targetPath>resources</targetPath>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>3.0.2</version>
				<configuration>
					<archive>
						<manifest>
							<addClasspath>false</addClasspath>
							<mainClass>${main-class}</mainClass>
						</manifest>
						<manifestSections>
							<manifestSection>
								<name>Intellector Entries</name>
								<manifestEntries>
									<Implementation-Plugin>${pluginname}</Implementation-Plugin>
									<Implementation-Layout>${layoutpath}</Implementation-Layout>
									<Implementation-Description>${description}</Implementation-Description>
									<primarykey>${primarykey}</primarykey>
									<pkdescription>${pkdescription}</pkdescription>
									<Plugin-Lib>${pluginlib}</Plugin-Lib>
								</manifestEntries>
							</manifestSection>
						</manifestSections>
					</archive>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-source-plugin</artifactId>
				<version>2.2.1</version>
				<executions>
					<execution>
						<id>attach-sources</id>
						<phase>verify</phase>
						<goals>
							<goal>jar-no-fork</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<artifactId>maven-clean-plugin</artifactId>
				<version>3.0.0</version>
				<executions>
					<execution>
						<!-- Aqui estou forçando um clean toda vez que o maven install for 
							executado. -->
						<id>auto-clean</id>
						<phase>initialize</phase>
						<goals>
							<goal>clean</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<pluginManagement>
			<plugins>
				<!--This plugin's configuration is used to store Eclipse m2e settings 
					only. It has no influence on the Maven build itself. -->
				<plugin>
					<groupId>org.eclipse.m2e</groupId>
					<artifactId>lifecycle-mapping</artifactId>
					<version>1.0.0</version>
					<configuration>
						<lifecycleMappingMetadata>
							<pluginExecutions>
								<pluginExecution>
									<pluginExecutionFilter>
										<groupId>org.apache.maven.plugins</groupId>
										<artifactId>maven-clean-plugin</artifactId>
										<versionRange>[2.5,)</versionRange>
										<goals>
											<goal>clean</goal>
										</goals>
									</pluginExecutionFilter>
									<action>
										<ignore></ignore>
									</action>
								</pluginExecution>
							</pluginExecutions>
						</lifecycleMappingMetadata>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
	<dependencies>
		<dependency>
			<groupId>iw-server</groupId>
			<artifactId>iw-server-api</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>iw-server</groupId>
			<artifactId>iw-server-beans</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>
</project>


E o dummyaccess não é tão dummy assim...

O plugin dummy estará sempre sendo submetido a melhorias, por isso, procure sempre por uma versão atualizada, pois ele terá várias versões, que ao longo do nosso desenvolvimento são taggeds. Talvez exista uma que seja mais adequado a sua necessidade.

Desenvolvendo...

Importar o plugin dummy (dummyplugin) como um template para desenvolvimento de um plugin externo. A ideia é que ele oriente o desenvolvimento de toda a estrutura necessária para a criação de um plugin de acesso, mantendo uma padronização na construção destes, evitando que o fonte de cada plugin externo tenha uma forma de implementação completamente diferente dos outros. O objetivo é facilitar desenvolvimento de novos plugins de forma fácil e rápida. Os artefatos que comporão o projeto vazio de um plugin serão:

    • No arquivo JSON:
      • Definir as propriedades com os dados de configuração do plugin externo, caso existam. Como não se sabe inicialmente quais são esses dados, definir no arquivo JSON de exemplo as propriedades mais comuns: protocolo (HTTP, HTTPS, TCP, etc), host, porta e objeto no servidor; atualmente só http/servlet é suportado. Essas propriedades poderão ser configuradas na interface do Intellector na edição do plugin.
        • "properties": {
          "database": "mango_d",
          "usuario": "user",
          "senha": "senha",
          "audita": true
          }
      • Definir os dados de entrada para chamada do plugin de acordo com o layout pré estabelecido pelo órgão e, que receberá o layout montado pela classe anterior e fará o acesso e retornará a classe com o layout de saída;
    • As estruturas das classes Java que deverão ser programadas para cada plugin externo:
    • As classes, se for o caso, de implementação do plugin externo, para que o desenvolvedor possa programar o plugin externo propriamente dito;
    • Uma classe que fará o parser do retorno do órgão externo e montará o VO com as variáveis de resposta, que será chamada pela classe que efetuou o acesso;
    • Parametrizar no arquivo POM.XML as propriedades necessárias para correta geração do plugin. Essas confiogurações serã utilizadas para, por exemplo, a geração do META-INF/MANIFEST.MF.
      • <main-class> : classe principal do plugin, ou seja, a classe a ser instanciada pelo Intellector Server. 
      • <pluginname> : nome do plugin
      • <description> : uma descrição do plugin
      • <primarykey> : chave a ser usada para a persistência da execução do plugin. Normalmente é uma das variáveis de entrada do plugin e será usada como referência do uso de cache.
      • <pkdescription>: descrição da chave
      • <layoutpath>: caminho para o arquivo json de configuração do plugin.
      • <pluginlib> : indicação se é um plugin ou uma lib para uso por outros plugins.  P - plugin / L - lib para plugin
    • Para consultar o plugin de acesso é necessário determinar as chaves primárias para que futuramente o plugin de acesos seja armazenado em uma base de dados, portanto as variáveis primarykey e pkdescription deverão ser informados no arquivo de manifesto, i.e. META-INF/MANIFEST.MF, sendo o campo primarykey as chaves no HashMap de entrada do plugin mais importantes da consulta separados por ',' para que sejam consultados na funcionalidade Consultar Resultados de Plugin e o campo pkdescription um nome mais amigável para que seja listado na funcionalidade também separado por ',' na mesma sequência descrita no campo primarykey;
    • Criar um novo projeto no Eclipse, tendo como base/exemplo o dummyplugin no diretório base de onde os artefatos foram gerados.
    • É obrigatório informar no layout de saída nas variáveis  XXX e  YYYY a string que foi enviada no request e a string que foi retornada do request. Caso o plugin não tenha essas informações deixe-as vazias.
      • hashOut.put("LPT__PLUGIN_ENVIO", "STRING REQUEST");
      • hashOut.put("LPT__PLUGIN_RETORNO", "STRING RETORNO");

Exemplo do MANIFEST.MF : 

Manifest-Version: 1.0
Built-By: ricart.monachesi
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_202
Main-Class: br.com.totvs.plugins.dummyplugin.DummyPlugin

Name: Intellector Entries
Implementation-Description: Dummy para exemplificar plugins externos
Plugin-Lib: P
pkdescription: CPF do adquirente
Implementation-Plugin: dummyplugin
Implementation-Layout: resources/dummyplugin.json
primarykey: CPF
Downloads

Baixe dummyplugin.7z o template do dummyplugin


  • Sem rótulos