Criando um Plugin

De BIS Wiki
Ir para navegação Ir para pesquisar

Definições do Plugin

Como qualquer aplicação de computador, a primeira coisa a definir é a sua função. Levantar os requisitos do plugin. Depois do objetivo e dos requisitos definidos, é hora de começar a implementar o plugin. Para implementa-lo a melhor ideia é seguir o passo a passo abaixo:

Pacote Raiz

Para começar a organizar o código criado é importante ter os packages bem definidos e estruturados desde o começo para evitar diversos refactores.futuros. É padrão da linguagem Java utilizar o nome dos pacotes similar aos domínios da web. Por exemplo, o BISCore utiliza como pacote raiz "br.com.biserp.bis.core" e depois separa suas classes em sub-pacotes de acordo com a necessidade.

Esse pacote raiz também será utilizado em outras partes do sistema, como por exemplo, para definir o ID do plugin, variáveis de sistema, etc. É recomendado que este pacote raiz não seja igual ao de nenhum outro plugin ou aplicação, por isso uma boa estrutura sugerida é o domínio da empresa (Ex: "br.com.biserp") + nome da aplicação e plugin (Ex: "bis.core").

Prefixos

A definição de um prefixo é utilizada em diversos lugares em que os recursos dos vários plugins acabam se misturando. O prefixo não deve ser tão curto a ponto de não evitar duplicatas com outros plugins e nem tão longo que dificulte a programação e leitura dos objetos. Recomendamos um mínimo de 10 caracteres, ficando liberado apenas para plugins do próprio BIS a utilização de prefixos menores, por conhecer o prefixo de todos os outros plugins.

Lembre ao definir o prefixo que ele deve ser único, por isso escolha palavras ou abreviações/siglas que não sejam comuns de alguém escolher. Quando possível, é recomendado que se utiliza o próprio ID do plugin ou o pacote raiz da aplicação como prefixo de distinção entre os plugins.

Alguns exemplos são:

  • tabelas do banco de dados: as tabelas dos plugins são colocadas todas juntos no mesmo banco de dados, usar um prefixo é conveniente para evitar nomes duplicados, principalmente em tabelas comuns como "contacts", "users", "items", "addresses", etc., e também para agilizar a identificação do plugin dono da tabela; O BISCore, por exemplo, tem todas as suas tabelas com o prefixo "core_".
  • nomes das fachadas das camadas de negócio: as fachadas de todos os plugins estarão disponíveis no mesmo ambiente, por isso é importante que sejam todas distintas ou o servidor de aplicação não disponibilizará uma das fachadas para ser encontrada por lookup;
  • mensagens de I18N: Cada plugin registrará seu bundle com base em um prefixo no BISCore. Sempre que alguma mensagens precisar ser resolvida, o BISCore analisa o prefixo da mensagem, e de acordo com esse prefixo ele chamará o Bundle registrado. Por isso, além de ser importante que seja único o prefixo, é importante que todas as mensagens do bundle tenham o prefixo definido; o plugin de Itens utiliza "ModItem_";
  • chaves de segurança: o plugin pode ter várias chaves de segurança definidas, o que permite ou não que o usuário faça alguma tarefa, acesse alguma informação, etc.. O BISCore trata todas as chaves de segurança junto, se as chaves forem duplicadas, o acesso dado em um plugin acabará garantindo acesso no outro. Para este uso é recomendado que os plugins utilizando o pacote raiz como prefixo de distinção.

Classes de Implementação

Para implementar um novo módulo devemos começar implementando a classe de integração do Módulo com o BISCore Framework. Feita a integração cada módulo basta que cada módulo implemente suas próprias funcionalidades, usando a base do BISCore para facilitar o desenvolvimento.

Para criar um novo módulo para o BISCore, a "única" coisa que precisa ser feita é criar um Singleton, que será inicializado pelo servidor de aplicações. Essa inicialização tem apenas o propósito de notificar o BISCore que carregue o módulo. Não é recomendado realizar nenhuma outra ação neste bloco além da solicitação de carregamento do PlugIn. As inicializações dos plugins deverão ser realizadas mais tarde, quando o BISCore carregar o plugin e chamar o método initPlugin().

Esqueleto de um CorePlugin
/*
 * Classe que implementa um novo CorePlugin
 */
@Singleton
@Startup
public class <ModulePrefix>CorePlugin extends CorePluginAdapter {

  @PostConstruct
  private void startup() {
    try {
      <ModulePrefix>CorePlugin plugin = new <ModulePrefix>CorePlugin();
      getBISFacade().queuePluginToLoadList(plugin);
    } catch (BISException e) {
      BISLogger.logException(e);
    }
  }

  ...
}

O método startup será chamado assim que o servidor de aplicações tiver terminado o deploy. Neste método chamamos a fachada do BIS e colocamos nosso plugin na fila para ser carregado. Há ainda outros métodos que o Adapter força a implementação, assim como outros que têm uma implementação padrão e podem ser sobrescritos para adapta-los à necessidade do plugin. Para maiores detalhes consulte o JavaDoc de cada método.

Alguns dos métodos de implementação obrigatória são:

  • getId(): Este método deve retornar o ID do Plugin, que deve ser único em todo o sistema. Recomenda-se usar o pacote raiz do plugin como prefixo no ID para garantir sua unicidade no sistema.
  • getRequiredLicense(): Este método retorna o ID da licença que o módulo precisa para funcionar adequadamente. Pode ser usada a mesma chave do ID do módulo.
  • getVersion(): Retorna a versão atual do Plugin.
  • getDependencies(): Retorna um array com a definição dos módulos necessários para que este módulo funcione.


Centralizando as Definições
As informações de ID, versão, versão do banco de dados e algumas vezes as dependências dos módulos são as mesmas ao criar um plugin para o Core ou para alguma camada de apresentação.

É recomendável que nestes casos crie-se uma única classe (final e de construtor privado para não ser inicializada) com todos os dados em atributos static, e que seja empacotados no pacote de biblioteca do módulo (pacote client que contém todas as classes comuns a todos as camadas, como VO, MOs, classes utilitárias, etc.). Desta forma toda a definição do Plugin ficará em uma única classe ao invés de espalhada e replicada dificultando a manutenção. Para estas classes de definições damos o sufixo "PluginDefinitions".


O método initPlugin()

Este método é chamado pelo Core depois que o módulo foi iniciado com sucesso, depois de ter suas dependências carregados, licença validada, banco atualizado, etc. Neste método o plugin deve realizar as tarefas que precisa para funcionar. Com exceção de atualização do banco de dados que é feita antes do plugin ser carregado, depois validações e setups devem ser feitas neste método. Entre as funções que o Plugin deve realizar nesta etapa estão:

  • Registrar seus Bundles: Para que a aplicação funcione adequadamente, o Plugin deve registrar seus Bundles no BundleManager da aplicação. Desta forma, toda a aplicação saberá internacionalizar suas mensagens, como erros, mensagens, etc. Mesmo quando usadas por outros módulos. Leia em: Bundle i18n.)
  • Registro de Eventos: Registrar o plugin para escutar eventos de outros módulos, como o recebimento de um e-mail pelo BISCore, a manipulação de um objeto de outro módulo, etc.
  • Outros Setups: Ao inicializar, o plugin pode fazer checagens e definições no sistema para garantir que não vá falhar durante o uso. Por exemplo, verificar se determinadas tarefas agendadas continuam agendada e funcionando, redefinir variáveis que se deseja reiniciar toda vez que a aplicação sofrer um deploy, etc.