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: