Configuração No presente capítulo serão abordados os seguintes assuntos: importância do uso de configurações em uma aplicação; mecanismo de configuração provido pelo Demoiselle Framework; estereótipo @Configuration, anotação @Key e classe ConfigurationLoader; leitura de arquivos XML, arquivos de propriedades e variáveis de sistema.
Configurações em uma aplicação Em aplicações no modelo Java EE, as quais são executadas hospedadas em um servidor de aplicações ou contêiner Web, existem diversos papéis além do desenvolvedor, tais como assembler e deployer. É comum nestas aplicações que informações de configuração de ambiente, especialmente por questões de segurança, sejam de conhecimento restrito. Por exemplo, o usuário e senha de um banco de dados ou o nome de uma fila de mensagens são informações que o desenvolvedor não deve possuir, pelo menos para o ambiente de produção. Além disso, o profissional responsável pelo deploy (i.e., a implantação) da aplicação geralmente não pode ser encarregado de recompilar os códigos fontes para efetivar a alteração desses dados. Para resolver essas questões, faz-se necessário um mecanismo de configuração para as aplicações. O desenvolvedor e o assembler constroem inteiramente uma aplicação e entregam o respectivo arquivo para o deployer colocá-la em produção. Paralelamente a isso, o deployer configura arquivos externos e variáveis de sistema com as informações sigilosas e protegidas que serão posteriormente lidas pela aplicação. A aplicação não precisará ser reconstruída caso um dado de configuração precise ser modificado. Frequentemente em Java utilizamos as seguintes abordagens para armazenar as configurações: arquivo de propriedades: tratam-se de simples arquivos de texto nomeados com a extensão .properties e que internamente são escritos com a sintaxe "chave = valor", armazenando uma única chave por linha; arquivo XML: são arquivos de texto altamente estruturados com a sintaxe de tags e que permitem uma maior validação de seus valores, sendo geralmente nomeados com a extensão .xml; variáveis de ambiente: valores definidos a nível de sistema operacional, independente de plataforma (Windows, Linux, etc) e que podem ser recuperados durante a execução da aplicação. Na seção a seguir veremos como o Demoiselle Framework apoia o desenvolvimento de aplicações nas tarefas de carregamento de configurações. Tal mecanismo é comumente utilizado internamente em diversos componentes do framework.
Códigos de suporte Em diversos módulos e componentes do Demoiselle Framework existe a necessidade de se carregar, em tempo de execução, as mais variadas configurações. E para estas situações foi desenvolvido um mecanismo para o carregamento das configurações. Eis alguns exemplos utilizados: regra para a fábrica padrão de DAOs, nome da unidade de persistência padrão, inicializadores a serem carregados automaticamente e estilo CSS default para a camada de apresentação. Esse mesmo mecanismo de configurações do Demoiselle Framework também é fornecido ao desenvolvedor de aplicações na forma de uma biblioteca Java. Nesta biblioteca, fazem parte do código de suporte de configurações: o estereótipo @Configuration: destinado a identificar as classes customizadas com o papel de efetuar o carregamento e armazenamento das configurações de um determinado grupo; a anotação @Key: usada para sinalizar uma única configuração seguindo um mecanismo automático de carregamento; a classe ConfigurationLoader: classe utilitária responsável por efetuar a leitura de um arquivo especificado e armazenar os valores em uma classe anotada com @Configuration. Nesse código interno é utilizada a especificação CDI (Common Dependency Injection), a qual visa o gerenciamento do ciclo de vida das classes de configuração e por isso possui grande importância na questão de desempenho da aplicação. O ciclo de vida de uma classe estereotipada com @Configuration é gerenciado automaticamente através de uma implementação da especificação CDI, tal como o Weld. Tal ciclo segue o padrão de projeto singleton. O Demoiselle Framework utiliza internamente seu próprio mecanismo de configurações. Veremos na próxima seção como implementar o mecanismo de configuração em uma aplicação qualquer.
Implementação da configuração A primeira etapa para utilizar o mecanismo de configuração em uma aplicação consiste na criação de uma classe estereotipada com a anotação @Configuration. Nela devem ser especificados como parâmetros o tipo e o nome do arquivo de recursos a ser utilizado para esta configuração. Veja no trecho de código abaixo um exemplo: Recomenda-se agrupar as configurações carregadas de um determinado arquivo de recursos (ex: XML) em uma mesma classe anotada com @Configuration. A fim de fazer uso desta classe na aplicação, basta declarar uma variável e anotá-la com @Inject, tal como ilustrado:
Arquivo de propriedades Eis um exemplo de conteúdo para um arquivo de propriedades, chamado escola.properties: Nesta abordagem, para que o valor da chave escola.dao.factory seja recuperado, é preciso incluir os trechos de código indicados a seguir na classe EscolaConfig: Desta forma, quando houver necessidade de recuperar o valor configurado no arquivo de propriedades, basta executar o código Java abaixo (supondo que o campo EscolaConfig config esteja previamente declarado e anotado com @Inject): Além de String, note que existe a possibilidade de se recuperar valores de qualquer tipo primitivo do Java (int, byte, short, char, long, float, double e boolean) e também arrays desses tipos. É possível recuperar valores de configurações para variáveis individuais ou arrays.
Arquivo XML Agora veja como ficaria a abordagem usando arquivos XML. Eis um arquivo de exemplo, o escola.xml, possuindo um valor numérico e um conjunto de strings: 125 Aluno Professor Administrador ]]> Neste caso, na classe EscolaConfig a anotação @Configuration precisa apontar para o tipo de recursos XML e usar o respectivo arquivo escola.xml. Eis a implementação necessária para que o referido arquivo XML seja lido e as suas configurações carregadas: papeis; private Integer getQtdeInicial() { return qtdeInicial; } public List getPapeis() { return papeis; } }]]> De maneira similar, quando necessário na aplicação, o trecho de código a seguir será suficiente para carregar as configurações do arquivo XML: papeis = cfg.getPapeis();]]> Note que a propriedade qtdeInicial foi inicializada com o valor default 50. É possível fazer isso com qualquer outro campo com o objetivo de, no caso de a chave não ser encontrada no arquivo, este valor padrão ser atribuído.
Variáveis de ambiente A terceira e última abordagem na configuração consiste em utilizar as variáveis de ambiente do sistema operacional. Estas variáveis geralmente são carregadas na inicialização do sistema ou após a criação da sessão do usuário (após o login), mas também podem ser modificadas manualmente através de comandos como set ou export. Como a linguagem Java é multi-plataforma, as variáveis de ambiente podem ser carregadas independente do sistema operacional. Para esta tarefa, na API do Java é fornecida a classe java.lang.System, a qual possui métodos como getenv() para recuperar os valores das variáveis. O código abaixo varre a lista de variáveis exportadas no sistema e exibe o resultado na console: vars = System.getenv(); for (String chave : vars.keySet()) { String valor = vars.get(chave); System.out.println(chave + " = " + valor); }]]> O mecanismo de configurações no Demoiselle Framework faz uso desta classe System para carregar automaticamente os valores nas propriedades. Veja na listagem abaixo o código necessário para a leitura de uma variável de ambiente:
Opções avançadas É possível ainda fazer com que diversas abordagens de leitura de configuração coexistam em uma classe anotada com @Configuration ou mesmo utilizar múltiplos arquivos de recursos. Para isso, é preciso indicar individualmente nos campos usando parâmetros da anotação @Key, tal como exemplificado: