Commit 69773da32ff9a5f20fe28e49daecc2dec4cba90a

Authored by Ednara Oliveira
2 parents 455cc039 0e170313
Exists in master

Merge branch '2.4.0' of git@github.com:demoiselle/framework.git into 2.4.0

documentation/reference/pt-BR/configuracao.xml
... ... @@ -8,38 +8,50 @@
8 8 <section>
9 9 <title>Configurações em uma aplicação</title>
10 10 <para>
11   - Muitas vezes é necessário parametrizar a aplicação à partir de arquivos de configuração ou variáveis de
12   - ambiente. O <emphasis>Demoiselle Framework</emphasis> traz algumas facilidades para você utilizar este
13   - recurso na sua aplicação para os casos mais comuns:
  11 + Muitas vezes, por motivos diversos, é necessário parametrizar a aplicação à partir de algum mecanismo de
  12 + configuração. E em java é comum se utilizar as seguintes abordagens para armazenas as configurações:
14 13 <itemizedlist>
15 14 <listitem>
16   - <emphasis>arquivo de propriedades</emphasis>: tratam-se de simples arquivos de texto nomeados com a extensão
17   - <filename>.properties</filename> e que internamente são escritos com a sintaxe <literal>chave=valor</literal>,
18   - armazenando uma única chave por linha;
  15 + <para>
  16 + <emphasis>arquivo de propriedades</emphasis>: tratam-se de simples arquivos de texto nomeados com a
  17 + extensão <filename>.properties</filename>, os quais são escritos com a sintaxe <literal>chave=valor
  18 + </literal>, armazenando uma única chave por linha;
  19 + </para>
19 20 </listitem>
20 21 <listitem>
21   - <emphasis>arquivo XML</emphasis>: são arquivos de texto altamente estruturados com a sintaxe de tags e que
22   - permitem uma maior validação dos seus valores, sendo geralmente nomeados com a extensão <filename>.xml</filename>;
  22 + <para>
  23 + <emphasis>arquivo XML</emphasis>: são arquivos de texto altamente estruturados com a sintaxe de tags e
  24 + que permitem uma maior validação dos seus valores, sendo geralmente nomeados com a extensão
  25 + <filename>.xml</filename>;
  26 + </para>
23 27 </listitem>
24 28 <listitem>
25   - <emphasis>variáveis de ambiente</emphasis>: valores definidos no sistema operacional, independente de
26   - plataforma (Windows, Linux, etc) e que podem ser recuperados durante a execução da aplicação.
  29 + <para>
  30 + <emphasis>variáveis de ambiente</emphasis>: valores definidos no sistema operacional, independente de
  31 + plataforma (Windows, Linux, Mac OS, etc) e que podem ser recuperados durante a execução da aplicação.
  32 + </para>
27 33 </listitem>
28 34 </itemizedlist>
29 35 </para>
  36 + <para>
  37 + Esse capítulo mostra de que maneira o <emphasis>Demoiselle Framework</emphasis> pode facilitar a utilização dessas
  38 + formas de configuração, oferencendo vários recursos interessantes e poderosos para a sua aplicação.
  39 + </para>
  40 +
30 41 </section>
31 42 <section>
32 43 <title>As classes de configuração</title>
33 44 <para>
34   - A primeira etapa para a utilização do mecanismo de configuração em uma aplicação consiste em criar uma classe específica
35   - para armazenar os parâmetros desejados e anotá-la com <literal>@Configuration</literal>. Eis um exemplo:
  45 + O primeiro passo para a utilização do mecanismo de configuração em uma aplicação consiste em criar uma classe
  46 + específica para armazenar os parâmetros desejados e anotá-la com <literal>@Configuration</literal>. O código
  47 + abaixo mostra um exemplo de classe de configuração:
36 48 </para>
37   - <programlisting role="JAVA"><![CDATA[@Configuration(resource = "bookmark")
  49 + <programlisting role="JAVA"><![CDATA[@Configuration
38 50 public class BookmarkConfig {
39 51  
40 52 private String applicationTitle;
41 53  
42   - private boolean loadInitialData = true;
  54 + private boolean loadInitialData;
43 55  
44 56 public String getApplicationTitle() {
45 57 return applicationTitle;
... ... @@ -49,10 +61,6 @@ public class BookmarkConfig {
49 61 return loadInitialData;
50 62 }
51 63 }]]></programlisting>
52   - <para>
53   - Sugere-se criar apenas os acessores para leitura (<emphasis>getters</emphasis>). Para definir valores padrão,
54   - especifique-os na própria declaração do atributo (ex: <literal>boolean loadInitialData=true</literal>).
55   - </para>
56 64 <note>
57 65 <para>
58 66 As classes anotadas com <literal>@Configuration</literal> são instanciadas uma única vez (seguindo o padrão
... ... @@ -61,73 +69,65 @@ public class BookmarkConfig {
61 69 primeiro acesso à respectiva classe de configuração, quando os seus atributos são preenchidos automaticamente.
62 70 </para>
63 71 </note>
64   - <para>
65   - No exemplo a seguir será buscado um arquivo de propriedades com o nome <filename>bookmark.properties</filename>
66   - contendo as seguintes chaves:
67   - </para>
68   - <programlisting><![CDATA[application.title=Título da Aplicação
69   -load.initial.data=false
70   -]]></programlisting>
71 72 <note>
72 73 <para>
73   - Recomenda-se usar o sufixo <quote>Config</quote> nas classes de configuração.
  74 + Recomenda-se usar o sufixo <quote>Config</quote> nas classes de configuração, e que sejam criados
  75 + apenas os acessores para leitura (<emphasis>getters</emphasis>).
74 76 </para>
75 77 </note>
76   - <para>
77   - O nome do recurso (<literal>resource</literal>) e o tipo de configuração (<literal>type</literal>) são argumentos
78   - opcionais na anotação <literal>@Configuration</literal>. Caso não sejam especificados, será considerado o arquivo
79   - de propriedades padrão do <emphasis>Demoiselle Framework</emphasis>, o <filename>demoiselle.properties</filename>.
80   - </para>
81   - </section>
  78 +
82 79  
83   - <section>
84   - <title>Especificando os parâmetros</title>
85 80 <para>
86   - Por padrão todos os atributos existentes em uma classe anotada com <literal>@Configuration</literal> são tratados
87   - como parâmetros de configuração e serão automaticamente preenchidos durante a leitura do recurso.
  81 + Esse é um exemplo bastante simples, no qual não são especificados nem nome nem tipo do arquivo de configuração. Nessa
  82 + situação os parâmetros de nome <emphasis>applicationTitle</emphasis> e <emphasis>loadInitialData</emphasis> serão
  83 + procurados em um arquivo de propriedades de nome <emphasis>demoiselle.properties</emphasis>. Ou seja, quando não
  84 + especificados nome e tipo do arquivo, assume-se que o arquivo é do tipo <emphasis>propriedades</emphasis>
  85 + e seu nome é <emphasis>demoiselle</emphasis>. Mas como fazer para não utilizar o valor padrão e definir
  86 + nome e tipo do arquivo? Bastante simples. Basta adicionar esses parâmetros à anotação @Configuration, como mostra o
  87 + exemplo a seguir:
88 88 </para>
89   - <tip>
90   - <para>
91   - Para ignorar um determinado atributo no processo automático de carregamento, anote-o com <literal>@Ignore</literal>.
92   - Para torná-lo obrigatório, anote-o com <literal>@NotNull</literal>.
93   - </para>
94   - </tip>
95   - <para>
96   - No arquivo de recursos será buscada a chave correspondente ao nome do atributo da classe.
97   - Por exemplo, para atributo <literal>loadInitialData</literal> será buscada a chave <literal>loadInitialData</literal>
98   - no recurso de configuração.
99   - </para>
100   - <tip>
101   - <para>
102   - Para redefinir os nomes das chaves, utilize a anotação <literal>@Name</literal> no atributo.
103   - </para>
104   - </tip>
  89 + <programlisting role="JAVA"><![CDATA[@Configuration(resource="my-property-file", type=ConfigType.XML)
  90 +public class BookmarkConfig {
  91 +
  92 + private String applicationTitle;
  93 +
  94 + private boolean loadInitialData;
  95 +
  96 + public String getApplicationTitle() {
  97 + return applicationTitle;
  98 + }
  99 +
  100 + public boolean isLoadInitialData() {
  101 + return loadInitialData;
  102 + }
  103 +}]]></programlisting>
  104 +
105 105 <para>
106   - Em determinadas situações é utilizado um prefixo comum a todos as chaves de configuração.
107   - Nestes casos, especifique atributo <literal>prefix</literal> da anotação <literal>@Configuration</literal>.
  106 + Devemos atribuir o nome do arquivo de configuração ao parâmetro <emphasis>resource</emphasis>, sem a extensão.
  107 + Ao parâmetro <emphasis>type</emphasis> pode ser atribuída uma das três possibilidades:
  108 + <emphasis>ConfigType.PROPERTIES</emphasis>, que é o valor padrão e indica que as configurações daquela classe
  109 + estão em um arquivo do tipo <emphasis>properties</emphasis>; <emphasis>ConfigType.XML</emphasis>, que indica que
  110 + as configurações daquela classe estão em um arquivo do tipo <emphasis>xml</emphasis>; e <emphasis>
  111 + ConfigType.SYSTEM</emphasis>, que indica que as configurações daquela classe são valores definidos pelo Sistema
  112 + Operacional. Nesse exemplo, ao definir <emphasis>resource</emphasis> e <emphasis>type</emphasis> os parâmetros de
  113 + nome <emphasis>applicationTitle</emphasis> e <emphasis>loadInitialData</emphasis> serão procurados em um arquivo
  114 + xml de nome <emphasis>my-property-file</emphasis> (my-property-file.xml).
108 115 </para>
109 116 <para>
110   - Veja na listagem abaixo um código fonte que ilustra a utilização das anotações descritas nesta seção:
  117 + Outro parâmetro que você pode ajustar nessa anotação é o prefixo. Ao definir um valor de prefixo você informa que
  118 + o nome das propriedades definidas naquela classe devem ser concatenados com o prefixo, de forma que o nome dos
  119 + atributos procurados no arquivo seja <emphasis>prefixo.nomeatributo</emphasis>. O exemplo abaixo mostra a
  120 + utilização desse parâmetro. Nesse caso, os parâmetros de nome <emphasis>info.applicationTitle</emphasis> e
  121 + <emphasis>info.loadInitialData</emphasis> serão procurados em um arquivo de propriedade de nome
  122 + <emphasis>my-property-file</emphasis> (<emphasis>my-property-file.properties</emphasis>).
111 123 </para>
112   - <programlistingco>
113   - <areaspec>
114   - <area id="resource-prefix" coords="1"/>
115   - <area id="param-name" coords="4"/>
116   - <area id="param-notnull" coords="7"/>
117   - <area id="param-ignore" coords="10"/>
118   - </areaspec>
119   - <programlisting role="JAVA"><![CDATA[@Configuration(resource = "bookmark", prefix = "general.")
  124 + <programlisting role="JAVA"><![CDATA[@Configuration(prefix="info", resource="my-property-file")
120 125 public class BookmarkConfig {
121 126  
122   - @Name("app.title")
123 127 private String applicationTitle;
124 128  
125   - @NotNull
126 129 private boolean loadInitialData;
127 130  
128   - @Ignore
129   - private int dummy;
130   -
131 131 public String getApplicationTitle() {
132 132 return applicationTitle;
133 133 }
... ... @@ -136,141 +136,485 @@ public class BookmarkConfig {
136 136 return loadInitialData;
137 137 }
138 138 }]]></programlisting>
139   - <calloutlist>
140   - <callout arearefs="resource-prefix">
141   - <para>
142   - Na anotação <literal>@Configuration</literal> foram especificados o arquivo de recursos
143   - <filename>bookmark.properties</filename> e o prefixo <literal>general.</literal> para as
144   - chaves de configuração.
145   - </para>
146   - </callout>
147   - <callout arearefs="param-name">
148   - <para>
149   - Ao invés de adotar o padrão convencionado, a anotação <literal>@Name</literal> definirá a chave
150   - <literal>app.title</literal> após o prefixo.
151   - </para>
152   - </callout>
153   - <callout arearefs="param-notnull">
154   - <para>
155   - Como o atributo é anotado com <literal>@NotNull</literal>, presume-se que ele sempre
156   - estará presente no recurso. Caso contrário, uma exceção ocorrerá.
157   - </para>
158   - </callout>
159   - <callout arearefs="param-ignore">
160   - <para>
161   - Este atributo, por estar anotado com <literal>@Ignore</literal>, não será considerado
162   - no carregamento automático das configurações.
163   - </para>
164   - </callout>
165   - </calloutlist>
166   - </programlistingco>
167   - <para>
168   - Neste caso, será buscado um arquivo de propriedades com o nome <filename>bookmark.properties</filename>
169   - contendo as seguintes chaves:
170   - </para>
171   - <programlisting><![CDATA[general.app.title=Título da Aplicação
172   -general.loadInitialData=true
173   -]]></programlisting>
  139 + <note>
  140 + <para>
  141 + O <emphasis>Demoiselle Framework</emphasis> adiciona automaticamente o ponto entre o prefixo e o nome do
  142 + atributo, você não precisa se preocupar com isso.
  143 + </para>
  144 + </note>
174 145 <tip>
175 146 <para>
176   - Além de <literal>String</literal> e <literal>boolean</literal>, existe a possibilidade de se recuperar valores de qualquer
177   - tipo primitivo do Java (i.e., <literal>int, byte, short, char, long, float, double</literal> e <literal>boolean</literal>)
178   - e também arrays desses tipos e de alguns tipos complexos (i.e., <literal>Integer, BigDecimal, BigInteger, Calendar, Date,
179   - Color, Locale, URL</literal> e <literal>String</literal>).
  147 + No arquivo xml o prefixo corresponde a uma <emphasis>tag</emphasis> acima das tag que correspondem aos
  148 + atributos. O exemplo acima ficaria da seguinte forma em um arquivo xml:
180 149 </para>
  150 + <programlisting role="XML"><![CDATA[
  151 +<info>
  152 + <applicationTitle>Demoiselle Application<\applicationTitle>
  153 + <loadInitialData>true<\loadInitialData>
  154 +</info>
  155 +
  156 +]]></programlisting>
  157 +
181 158 </tip>
182 159 </section>
183   -
  160 +
184 161 <section>
185   - <title>Usando a configuração na aplicação</title>
  162 + <title>Especificando os parâmetros</title>
186 163 <para>
187   - A fim de utilizar o objeto de configuração previamente instanciado e preenchido pelo contêiner, basta criar uma variável numa
188   - classe qualquer da aplicação e anotá-la com <literal>@Inject</literal>. Tal variável será injetada automaticamente e pode ser
189   - usada dentro de um método. Veja na listagem a seguir um exemplo de injeção e uso de uma classe de configuração:
  164 + Atualmente são suportados nativamente pelo <emphasis>Demoiselle Framework</emphasis> parâmetros de cinco tipos
  165 + diferentes, são eles: <emphasis>primitivo</emphasis>, <emphasis>wrapped</emphasis>, <emphasis>String</emphasis>,
  166 + <emphasis>class</emphasis>, <emphasis>map</emphasis> e <emphasis>array</emphasis>, sendo que os três últimos
  167 + são suportados a partir da versão 2.4.0. A seguir vamos explicar e exemplificar como utilizar cada um desses
  168 + tipos, e alertar para as possíveis exceções que poderão ser lançadas para sua aplicação.
190 169 </para>
191   -<programlisting role="JAVA"><![CDATA[public class BookmarkBC {
  170 + <caution>
  171 + <para>
  172 + A partir da versão 2.4.0 não são mais reconhecidas as convenções. Os parâmetros serão procurados exatamente
  173 + como foram definidos na classe de configuração.
  174 + </para>
  175 + </caution>
  176 + <informaltable>
  177 + <tgroup cols="1">
  178 + <colspec colwidth="100*" />
  179 + <tbody>
  180 + <row>
  181 + <entry>
  182 + <emphasis role="bold">Primitivos</emphasis>
  183 + </entry>
  184 + </row>
  185 + <row>
  186 + <entry>
  187 + <para>
  188 + A utilização dos tipos primitivos é bastante simples. Veja no exemplo abaixo uma classe de configuração um arquivo
  189 + de configurações, que ilustram como é o procedimento para adicionar parâmetros do tipo primitivo.
  190 + </para>
  191 + <programlisting role="JAVA"><![CDATA[@Configuration
  192 + public class BookmarkConfig {
192 193  
193   - @Inject
194   - private BookmarkConfig config;
  194 + private int pageSize;
195 195  
196   - public void startup() {
197   - if (config.isLoadInitialData()) {
198   - ...
199   - }
  196 + public String getPageSize() {
  197 + return pageSize;
200 198 }
201 199 }]]></programlisting>
202   - <note>
203   - <para>
204   - O <emphasis>Demoiselle Framework</emphasis> utiliza internamente o mecanismo de configurações na leitura do arquivo
205   - <filename>demoiselle.properties</filename> para outras funcionalidades, tais como transação, segurança, persistência e paginação.
206   - </para>
207   - </note>
208   - </section>
209 200  
210   - <section>
211   - <title>Lendo arquivos XML</title>
212   - <para>
213   - Agora veja como ficaria a abordagem de configuração usando arquivos XML. Eis um arquivo de exemplo, o
214   - <filename>escola.xml</filename>, possuindo um valor numérico e um conjunto de strings:
215   - </para>
216   - <programlisting role="XML"><![CDATA[<configuration>
217   - <qtdeInicial>125</qtdeInicial>
218   - <papeis>
219   - <papel>Aluno</papel>
220   - <papel>Professor</papel>
221   - <papel>Administrador</papel>
222   - </papeis>
223   -</configuration>]]></programlisting>
224   - <para>
225   - Neste caso, na classe de configuração <literal>EscolaConfig</literal> a anotação <literal>@Configuration</literal>
226   - precisa apontar para o tipo de recursos XML e usar o respectivo arquivo <filename>escola.xml</filename>. Eis a
227   - implementação necessária para que o referido arquivo XML seja lido e os seus valores carregados automaticamente:
228   - </para>
229   - <programlisting role="JAVA"><![CDATA[@Configuration(resource = "escola", type = ConfigType.XML)
230   -public class EscolaConfig {
  201 + <para>
  202 + Para essa classe, o arquivo de propriedade correspondente (<emphasis>demoiselle.properties</emphasis>) deveria
  203 + apresentar o seguinte conteúdo:
  204 + </para>
  205 + <programlisting role="JAVA"><![CDATA[
  206 +pageSize=10
  207 +]]></programlisting>
  208 + <para>
  209 + Bastante simples, não? Mesmo assim, é bom ficarmos atentos, pois alguns cenários diferentes podem
  210 + acontecer. Vamos supor por exemplo que, por um motivo qualquer, a classe de configuração não esteja associada a um arquivo que contenha a chave de um de
  211 + seus parâmetros. Nesse caso será atribuido o valor padrão da linguagem ao atributo, que para os tipos primitivos
  212 + é 0, exceto para os tipos <emphasis>boolean</emphasis>, cujo valor padrão é <emphasis>false</emphasis>, e
  213 + <emphasis>char</emphasis>, cujo valor padrão é o caracter nulo (<emphasis>'\u0000'</emphasis>).
  214 + Outro cenário possível é a existência da chave, mas sem valor atribuído (<emphasis>pageSize=</emphasis>). Nesse
  215 + caso o valor encontrado no arquivo é equivalente a uma <emphasis>String</emphasis> vazia, e a exceção
  216 + <emphasis>ConfigurationException</emphasis>, cuja causa foi uma <emphasis>ConversionException</emphasis>, será
  217 + lançada.
  218 + </para>
  219 + </entry>
  220 + </row>
  221 + </tbody>
  222 + </tgroup>
  223 + </informaltable>
  224 +
  225 + <informaltable>
  226 + <tgroup cols="1">
  227 + <colspec colwidth="100*" />
  228 + <tbody>
  229 + <row>
  230 + <entry>
  231 + <emphasis role="bold">Wrappers</emphasis>
  232 + </entry>
  233 + </row>
  234 + <row>
  235 + <entry>
  236 + <para>
  237 + Os atributos do tipo <emphasis>wrapper</emphasis> devem ser utilizados da mesma forma que os atributos do tipo
  238 + primitivo. A única diferença entre eles é que o valor padrão atribuído a um parâmetro, no caso da classe de
  239 + configuração não estar associada a um arquivo que contenha sua chave, é nulo.
  240 + </para>
  241 + </entry>
  242 + </row>
  243 + </tbody>
  244 + </tgroup>
  245 + </informaltable>
  246 +
  247 + <informaltable>
  248 + <tgroup cols="1">
  249 + <colspec colwidth="100*" />
  250 + <tbody>
  251 + <row>
  252 + <entry>
  253 + <emphasis role="bold">Strings</emphasis>
  254 + </entry>
  255 + </row>
  256 + <row>
  257 + <entry>
  258 + <para>
  259 + Por sua vez, as configurações do tipo <emphasis>String</emphasis> tem funcionalidade bastante similar às
  260 + configurações do tipo Wrapper. A diferença fica por conta de que, ao deixar a chave sem valor atribuído, para
  261 + atributo desse tipo, não será lançada exceção, pois que não haverá o problema de conversão, e à configuração
  262 + será atribuido o valor de uma <emphasis>String</emphasis> vazia.
  263 + </para>
  264 + </entry>
  265 + </row>
  266 + </tbody>
  267 + </tgroup>
  268 + </informaltable>
  269 +
  270 + <informaltable>
  271 + <tgroup cols="1">
  272 + <colspec colwidth="100*" />
  273 + <tbody>
  274 + <row>
  275 + <entry>
  276 + <emphasis role="bold">Class</emphasis>
  277 + </entry>
  278 + </row>
  279 + <row>
  280 + <entry>
  281 + <para>
  282 + A partir da versão 2.4.0 é possível ter atributos do tipo <emphasis>Class</emphasis> como parâmetro. O atributo
  283 + pode ou não ser tipado, e no arquivo o valor atribuído à chave deve corresponder ao nome (<emphasis>
  284 + Canonical Name</emphasis>) de uma classe existente. Abaixo temos um exemplo de uma classe de configuração com
  285 + dois atributos do tipo <emphasis>Class</emphasis>, um tipado e outro não tipado:
  286 + </para>
  287 + <programlisting role="JAVA"><![CDATA[
  288 +@Configuration
  289 +public class BookmarkConfig {
231 290  
232   - private Integer qtdeInicial = 50;
  291 + private Class<MyClass> typedClass;
233 292  
234   - @Name("papeis.papel")
235   - private List<String> papeis;
  293 + private Class<?> untypedClass;
236 294  
237   - private Integer getQtdeInicial() {
238   - return qtdeInicial;
  295 + public Class<MyClass> getTypedClass() {
  296 + return typedClass;
239 297 }
240 298  
241   - public List<String> getPapeis() {
242   - return papeis;
  299 + public Class<?> getUntypedClass() {
  300 + return untypedClass;
243 301 }
244   -}]]></programlisting>
245   - </section>
  302 +}
  303 + ]]></programlisting>
  304 + <para>O arquivo de propriedades teria o seguinte conteúdo:</para>
  305 + <programlisting role="JAVA"><![CDATA[
  306 +typedClass=package.MyClass
  307 +untypedClass=package.MyOtherClass
  308 + ]]></programlisting>
  309 + <para>
  310 + Caso uma chave de uma configuração do tipo <emphasis>Class</emphasis> não tenha valor atribuído ou seja
  311 + atribuído um nome de classe que não existe (ou não possa ser encontrada pela aplicação), no momento do
  312 + seu carregamento sera lançada uma exceção do tipo <emphasis>ConfigurationException</emphasis>, cuja causa é uma
  313 + <emphasis>ClassNotFoundException</emphasis>. Caso a classe de configuração não esteja associada a um
  314 + arquivo que contenha a chave de um de seus parâmetros do tipo <emphasis>Class</emphasis>, este será carregado
  315 + com valor nulo.
  316 + </para>
  317 + </entry>
  318 + </row>
  319 + </tbody>
  320 + </tgroup>
  321 + </informaltable>
  322 +
  323 + <informaltable>
  324 + <tgroup cols="1">
  325 + <colspec colwidth="100*" />
  326 + <tbody>
  327 + <row>
  328 + <entry>
  329 + <emphasis role="bold">Map</emphasis>
  330 + </entry>
  331 + </row>
  332 + <row>
  333 + <entry>
  334 + <para>
  335 + Para utilizar parâmetros do tipo <emphasis>Map</emphasis>, o arquivo de configurações deve usar a seguinte
  336 + estrutura na formação da chave: <emphasis>prefixo+chavedomap+nomedoatributo</emphasis>. Vejamos um exemplo.
  337 + Se temos em nossa aplicação uma classe de configuração como a mostrada abaixo:
  338 + </para>
  339 + <programlisting role="JAVA"><![CDATA[
  340 +@Configuration
  341 +public class BookmarkConfig {
246 342  
  343 + private Map<String, String> url;
  344 +
  345 + private Map<String, String> driverClass;
  346 +
  347 + public Map<String, String> getUrl() {
  348 + return url;
  349 + }
  350 +
  351 + public Map<String, String> DriverClass() {
  352 + return driverClass;
  353 + }
  354 +}
  355 + ]]></programlisting>
  356 + <para>
  357 + O arquivo de configuração deverá ser preenchido no formato seguinte (se for do tipo <emphasis>properties</emphasis>):
  358 + </para>
  359 + <programlisting role="PROPERTIES"><![CDATA[
  360 +mapkey1.url=jdbc:postgresql://localhost:5432/app
  361 +mapkey2.url=jdbc:mysql://localhost:3306/app
  362 +mapkey1.driverClass=org.postgresql.Driver
  363 +mapkey2.driverClass=com.mysql.Driver
  364 + ]]></programlisting>
  365 + <para>
  366 + Dessa forma, ao fazer a chamada <emphasis>url.get("mapkey2");</emphasis>por exemplo, o valor retornado será
  367 + <emphasis>jdbc:mysql://localhost:3306/app</emphasis>.
  368 + </para>
  369 + <note>
  370 + <para>
  371 + O ponto entre a chave do <emphasis>Map</emphasis> e o nome do parâmetro é adicionado automaticamente pelo
  372 + framework.
  373 + </para>
  374 + </note>
  375 + <tip>
  376 + <para>
  377 + Você pode utilizar a chave do Map com nome "default" para indicar que, no arquivo de configuração, a chave é formada
  378 + apenas pela junção do prefixo com o atributo, sem utilizar a própria chave do Map. Por exemplo, se na sua classe
  379 + existir um comando como este:
  380 + </para>
  381 + <programlisting role="JAVA"><![CDATA[
  382 + myMap.get("default");
  383 + ]]></programlisting>
  384 + <para>o framework irá procurar no arquivo de configuração uma linha como esta:</para>
  385 + <programlisting role="JAVA"><![CDATA[
  386 + prefix.myMap=Default Value
  387 + ]]></programlisting>
  388 + </tip>
  389 + <para>
  390 + Caso a classe de configuração não esteja associada a um arquivo que contenha a chave de um de seus parâmetros
  391 + do tipo <emphasis>Map</emphasis>, este será carregado com valor nulo, e estará sujeito às exceções
  392 + informadas anteriormente, conforme o tipo de variáveis que ele contenha.
  393 + </para>
  394 + </entry>
  395 + </row>
  396 + </tbody>
  397 + </tgroup>
  398 + </informaltable>
  399 +
  400 + <informaltable>
  401 + <tgroup cols="1">
  402 + <colspec colwidth="100*" />
  403 + <tbody>
  404 + <row>
  405 + <entry>
  406 + <emphasis role="bold">Array</emphasis>
  407 + </entry>
  408 + </row>
  409 + <row>
  410 + <entry>
  411 + <para>
  412 + No caso do <emphasis>Array</emphasis>, a principal diferença em relação às demais formas de declarar
  413 + configurações é a maneira de atribuir valores aos seus respectivos elementos no arquivo de configuração.
  414 + Por exemplo, para que um <emphasis>Array</emphasis> de inteiros, de nome <emphasis>integerArray</emphasis>
  415 + tenha o conteúdo <emphasis>{-1, 0, 1}</emphasis>, você deve criar um arquivo de propriedades que contenha
  416 + as seguintes linhas:
  417 + </para>
  418 + <programlisting role="JAVA"><![CDATA[
  419 +integerArray=-1
  420 +integerArray=0
  421 +integerArray=1
  422 + ]]></programlisting>
  423 + <para>
  424 + Exceto a forma de atribuir os valores às configurações, se comporta de acordo com o tipo de variável que ele
  425 + contém, conforme o espeficifcado para cada um.
  426 + </para>
  427 + </entry>
  428 + </row>
  429 + </tbody>
  430 + </tgroup>
  431 + </informaltable>
  432 +
  433 + </section>
  434 +
247 435 <section>
248   - <title>Lendo variáveis de ambiente</title>
249   - <para>
250   - A terceira abordagem na configuração consiste em utilizar as variáveis de ambiente do sistema operacional.
251   - Estas variáveis geralmente são carregadas na inicialização do sistema ou após a criação da sessão do usuário
252   - (i.e., após o login), mas também podem ser modificadas manualmente através de comandos como <literal>set</literal>
253   - ou <literal>export</literal>.
254   - </para>
255   - <para>
256   - O mecanismo de configurações no <emphasis>Demoiselle Framework</emphasis> faz uso da classe
257   - <ulink url="http://download.oracle.com/javase/6/docs/api/java/lang/System.html">
258   - <literal>java.lang.System</literal></ulink> fornecida pela API do Java para carregar os valores nas
259   - propriedades a partir de variáveis de ambiente independente do sistema operacional.
260   - </para>
  436 + <title>Mais Recursos</title>
261 437 <para>
262   - Veja na listagem abaixo o código necessário para a leitura de uma variável de ambiente:
  438 + Além das possibilidades relacionadas acima, existem ainda algumas anotações e recursos extras que o
  439 + <emphasis>Demoiselle Framework</emphasis> oferece para o desenvolvedor na utilização das configurações. A seguir
  440 + listamos e explicamos como utilizar esses recursos em sua aplicação.
263 441 </para>
264   - <programlisting role="JAVA"><![CDATA[@Configuration(type = ConfigType.SYSTEM)
265   -public class EscolaConfig {
  442 +
  443 + <informaltable>
  444 + <tgroup cols="1">
  445 + <colspec colwidth="100*" />
  446 + <tbody>
  447 + <row>
  448 + <entry>
  449 + <emphasis role="bold">Ignore</emphasis>
  450 + </entry>
  451 + </row>
  452 + <row>
  453 + <entry>
  454 + <para>
  455 + Por padrão, todos os atributos existentes em uma classe anotada com <literal>@Configuration</literal> são tratados
  456 + como parâmetros de configuração e serão automaticamente preenchidos durante a leitura do recurso. Porém, caso você
  457 + não queira que determinado atributo seja tratado como parâmetro dentro desse tipo de classe, basta anotá-lo com
  458 + a anotação <literal>@Ignore</literal>, que o atributo será ignorado (como indica a própria anotação) pelo carregador
  459 + de configurações.
  460 + </para>
  461 + </entry>
  462 + </row>
  463 + </tbody>
  464 + </tgroup>
  465 + </informaltable>
  466 +
  467 + <informaltable>
  468 + <tgroup cols="1">
  469 + <colspec colwidth="100*" />
  470 + <tbody>
  471 + <row>
  472 + <entry>
  473 + <emphasis role="bold">Valor Padrão</emphasis>
  474 + </entry>
  475 + </row>
  476 + <row>
  477 + <entry>
  478 + <para>
  479 + Muitas vezes é interessante que especifiquemos um valor padrão para o parâmetro, para o caso dele não estar
  480 + presente no arquivo de configuração. Para isso, basta atribuir o valor desejado no momento da declaração do
  481 + atributo, como exemplificado abaixo:
  482 + </para>
  483 + <programlisting role="JAVA"><![CDATA[@Configuration
  484 +public class BookmarkConfig {
266 485  
267   - @Name("java.home")
268   - private String javaDirectory;
  486 + private String applicationTitle = "My App";
269 487  
270   - public String getJavaDirectory() {
271   - return javaDirectory;
  488 + public String getApplicationTitle() {
  489 + return applicationTitle;
272 490 }
273   -}]]></programlisting>
274   - </section>
  491 +} ]]></programlisting>
  492 + <para>
  493 + Com essa atribuição, se no arquivo de propriedades não existir uma chave com valor <literal>applicationTitle</literal>
  494 + esse parametro será carregado com o valor <literal>My App</literal>.
  495 + </para>
  496 + </entry>
  497 + </row>
  498 + </tbody>
  499 + </tgroup>
  500 + </informaltable>
  501 +
  502 + <informaltable>
  503 + <tgroup cols="1">
  504 + <colspec colwidth="100*" />
  505 + <tbody>
  506 + <row>
  507 + <entry>
  508 + <emphasis role="bold">Bean Validation</emphasis>
  509 + </entry>
  510 + </row>
  511 + <row>
  512 + <entry>
  513 + <para>
  514 + Fazer validação mantém a integridade dos dados e pode ser fator importante na lógica da aplicação. A partir da
  515 + versão 2.4.0 o <emphasis>Demoiselle</emphasis> permite que os atributos das classes de configuração sejam
  516 + anotados com todas as anotações definidas pela JSR 303 (Bean Validation). Com esse recurso você pode exigir que
  517 + determinado parâmetro não seja nulo (<emphasis>@NotNull</emphasis>), limitar um valor máximo ou mínimo para ele
  518 + (<emphasis>@Max</emphasis> e <emphasis>@Min</emphasis>, respectivamente), dentre outras restrições (que podem
  519 + ser feitas simultâneamente). A lista completa das restrições que podem ser aplicadas nos atributos das classes
  520 + de configuração pode ser conferida aqui:
  521 + <ulink url="http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html">
  522 + <literal>http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html</literal></ulink>.
  523 + </para>
  524 + <para>
  525 + Para utilizar esse recurso você deve ter como dependência de seu projeto alguma implementação da especificação
  526 + Bean Validation. A implementação de referência é o
  527 + <ulink url="http://www.hibernate.org/subprojects/validator"><emphasis>Hibernate Validator</emphasis></ulink>.
  528 + </para>
  529 + </entry>
  530 + </row>
  531 + </tbody>
  532 + </tgroup>
  533 + </informaltable>
  534 +
  535 + <informaltable>
  536 + <tgroup cols="1">
  537 + <colspec colwidth="100*" />
  538 + <tbody>
  539 + <row>
  540 + <entry>
  541 + <emphasis role="bold">Name</emphasis>
  542 + </entry>
  543 + </row>
  544 + <row>
  545 + <entry>
  546 + <para>
  547 + Em alguns casos você pode querer que um determinado parâmetro tenha nomes diferentes na classe de configuração e
  548 + no arquivo de propriedades. Para isso você pode utilizar a anotação <emphasis>@Name</emphasis>. Basta anotar
  549 + o atributo passando como parâmetro o nome pelo qual você deseja que ele seja procurado no arquivo de propriedades,
  550 + como mostra o exemplo abaixo:
  551 + </para>
  552 + <programlisting role="JAVA"><![CDATA[@Configuration(resource = "bookmark", prefix = "general.")
  553 +public class BookmarkConfig {
275 554  
  555 + @Name("app.title")
  556 + private String applicationTitle;
  557 +
  558 + public String getApplicationTitle() {
  559 + return applicationTitle;
  560 + }
  561 +} ]]></programlisting>
  562 + <para>
  563 + Com essa anotação, ao invés de procurar pela chave <emphasis>applicationTitle</emphasis>, o
  564 + <emphasis>Demoiselle</emphasis> irá buscar pela chave <emphasis>app.title</emphasis>.
  565 + </para>
  566 + </entry>
  567 + </row>
  568 + </tbody>
  569 + </tgroup>
  570 + </informaltable>
  571 +
  572 + <informaltable>
  573 + <tgroup cols="1">
  574 + <colspec colwidth="100*" />
  575 + <tbody>
  576 + <row>
  577 + <entry>
  578 + <emphasis role="bold">Escopo</emphasis>
  579 + </entry>
  580 + </row>
  581 + <row>
  582 + <entry>
  583 + <para>
  584 + A partir da versão 2.3.3 do <emphasis>Demoiselle Framework</emphasis> as classes anotadas com
  585 + <emphasis>@Configuration</emphasis> estarão por padrão no escopo estático (<emphasis>@StaticScoped</emphasis>).
  586 + </para>
  587 + </entry>
  588 + </row>
  589 + </tbody>
  590 + </tgroup>
  591 + </informaltable>
  592 +
  593 + <informaltable>
  594 + <tgroup cols="1">
  595 + <colspec colwidth="100*" />
  596 + <tbody>
  597 + <row>
  598 + <entry>
  599 + <emphasis role="bold">Extratores</emphasis>
  600 + </entry>
  601 + </row>
  602 + <row>
  603 + <entry>
  604 + <para>
  605 + Você precisa de parâmetros de um tipo que ainda não é suportado pelo <emphasis>Demoiselle</emphasis>? Você
  606 + pode implementar sua própria classe extratora. A partir da versão 2.4.0 as aplicações
  607 + podem implementar a interface <emphasis>ConfigurationValueExtractor</emphasis>, e ter um
  608 + extrator de configurações para atributos de qualquer tipo. Essa interface obriga a classe
  609 + a implementar os métodos: <emphasis>boolean isSupported(Field field)</emphasis>, que retorna <literal>true</literal>
  610 + caso a classe seja extratora daquele tipo de campo, e
  611 + <emphasis>Object getValue(String prefix, String key, Field field, Configuration configuration)
  612 + throws Exception</emphasis> que deve extrair o valor do campo da forma correta.
  613 + </para>
  614 + </entry>
  615 + </row>
  616 + </tbody>
  617 + </tgroup>
  618 + </informaltable>
  619 + </section>
276 620 </chapter>
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ManagementBootstrap.java
... ... @@ -11,12 +11,12 @@ import javax.enterprise.inject.spi.AfterDeploymentValidation;
11 11 import javax.enterprise.inject.spi.AnnotatedType;
12 12 import javax.enterprise.inject.spi.Bean;
13 13 import javax.enterprise.inject.spi.BeanManager;
  14 +import javax.enterprise.inject.spi.BeforeShutdown;
14 15 import javax.enterprise.inject.spi.Extension;
15 16 import javax.enterprise.inject.spi.ProcessAnnotatedType;
16 17  
17 18 import br.gov.frameworkdemoiselle.internal.context.ContextManager;
18 19 import br.gov.frameworkdemoiselle.internal.context.ManagedContext;
19   -import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess;
20 20 import br.gov.frameworkdemoiselle.management.annotation.Managed;
21 21 import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
22 22 import br.gov.frameworkdemoiselle.management.internal.ManagedType;
... ... @@ -60,11 +60,13 @@ public class ManagementBootstrap implements Extension {
60 60 monitoringManager.initialize(managementExtensionCache);
61 61 }
62 62  
63   - public void unregisterAvailableManagedTypes(@Observes final AfterShutdownProccess event) {
  63 + public void unregisterAvailableManagedTypes(@Observes final BeforeShutdown event) {
64 64  
65 65 MonitoringManager manager = Beans.getReference(MonitoringManager.class);
66 66 manager.shutdown(managementExtensionCache);
67   -
  67 +
  68 + managementExtensionCache.clear();
  69 + types.clear();
68 70 }
69 71  
70 72 }
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/MonitoringManager.java
... ... @@ -13,6 +13,7 @@ import javax.management.ReflectionException;
13 13 import org.slf4j.Logger;
14 14  
15 15 import br.gov.frameworkdemoiselle.DemoiselleException;
  16 +import br.gov.frameworkdemoiselle.annotation.Name;
16 17 import br.gov.frameworkdemoiselle.internal.context.ContextManager;
17 18 import br.gov.frameworkdemoiselle.internal.context.ManagedContext;
18 19 import br.gov.frameworkdemoiselle.management.annotation.Managed;
... ... @@ -38,12 +39,14 @@ public class MonitoringManager {
38 39 private Logger logger;
39 40  
40 41 @Inject
  42 + @Name("demoiselle-core-bundle")
41 43 private ResourceBundle bundle;
42 44  
43 45 private final List<ManagedType> managedTypes = new ArrayList<ManagedType>();
44 46  
45 47 public void addManagedType(ManagedType managedType) {
46 48 managedTypes.add(managedType);
  49 + logger.debug(bundle.getString("management-debug-registering-managed-type",managedType.getType().getCanonicalName()));
47 50 }
48 51  
49 52 /**
... ... @@ -189,8 +192,13 @@ public class MonitoringManager {
189 192 //Manda uma notificação de mudança de atributo
190 193 NotificationManager notificationManager = Beans.getReference(NotificationManager.class);
191 194 Class<? extends Object> attributeType = newValue!=null ? newValue.getClass() : null;
192   - AttributeChangeNotification notification = new AttributeChangeNotification(bundle.getString(""), propertyName, attributeType, oldValue, newValue);
193   - notificationManager.sendAttributeChangedMessage(notification);
  195 +
  196 + AttributeChangeNotification notification = new AttributeChangeNotification(bundle.getString("management-notification-attribute-changed",propertyName,managedType.getType().getCanonicalName())
  197 + , propertyName
  198 + , attributeType
  199 + , oldValue
  200 + , newValue);
  201 + notificationManager.sendNotification(notification);
194 202  
195 203 } catch (Exception e) {
196 204 throw new DemoiselleException(bundle.getString(
... ... @@ -233,6 +241,8 @@ public class MonitoringManager {
233 241 ManagementExtension monitoringExtension = Beans.getReference(monitoringExtensionClass);
234 242  
235 243 monitoringExtension.shutdown(this.getManagedTypes());
  244 +
  245 + logger.debug( bundle.getString("management-debug-removing-management-extension",monitoringExtension.getClass().getCanonicalName()) );
236 246  
237 247 }
238 248  
... ... @@ -246,6 +256,8 @@ public class MonitoringManager {
246 256 .getReference(monitoringExtensionClass);
247 257  
248 258 monitoringExtension.initialize(this.getManagedTypes());
  259 +
  260 + logger.debug( bundle.getString("management-debug-processing-management-extension",monitoringExtension.getClass().getCanonicalName()) );
249 261  
250 262 }
251 263  
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/notification/NotificationManager.java
... ... @@ -5,6 +5,7 @@ import java.io.Serializable;
5 5 import javax.enterprise.context.ApplicationScoped;
6 6 import javax.enterprise.event.Event;
7 7 import javax.enterprise.event.Observes;
  8 +import javax.enterprise.util.AnnotationLiteral;
8 9 import javax.inject.Inject;
9 10  
10 11 import br.gov.frameworkdemoiselle.management.internal.notification.event.NotificationEvent;
... ... @@ -48,16 +49,32 @@ public class NotificationManager implements Serializable{
48 49 * @param notification The notification to send
49 50 */
50 51 public void sendNotification(Notification notification) {
51   - genericNotificationEvent.fire(new NotificationEvent(notification));
  52 + if (! AttributeChangeNotification.class.isInstance(notification) ){
  53 + getGenericNotificationEvent().fire(new NotificationEvent(notification));
  54 + }
  55 + else{
  56 + getAttributeChangeNotificationEvent().fire(new NotificationEvent(notification));
  57 + }
  58 + }
  59 +
  60 + @SuppressWarnings("unchecked")
  61 + private Event<NotificationEvent> getGenericNotificationEvent() {
  62 + if (genericNotificationEvent==null){
  63 + genericNotificationEvent = Beans.getReference(Event.class , new AnnotationLiteral<Generic>() {});
  64 + }
  65 +
  66 + return genericNotificationEvent;
52 67 }
53 68  
54   - /**
55   - * Sends a notification comunicating about a change of value for an attribute.
56   - *
57   - * @param notification Special notification communicating a change of value in an attribute.
58   - *
59   - */
60   - public void sendAttributeChangedMessage(AttributeChangeNotification notification){
61   - attributeChangeNotificationEvent.fire(new NotificationEvent(notification));
  69 + @SuppressWarnings("unchecked")
  70 + private Event<NotificationEvent> getAttributeChangeNotificationEvent() {
  71 + if (attributeChangeNotificationEvent==null){
  72 + attributeChangeNotificationEvent = Beans.getReference(Event.class , new AnnotationLiteral<AttributeChange>() {});
  73 + }
  74 +
  75 + return attributeChangeNotificationEvent;
62 76 }
  77 +
  78 +
  79 +
63 80 }
... ...
impl/core/src/main/resources/demoiselle-core-bundle.properties
... ... @@ -98,15 +98,19 @@ user-has-role=Usu\u00E1rio {0} possui a(s) role(s)\: {1}
98 98  
99 99 authenticator-not-defined=Nenhum mecanismo de autentica\u00E7\u00E3o foi definido. Para utilizar {0} \u00E9 preciso definir a propriedade frameworkdemoiselle.security.authenticator.class como mecanismo de autentica\u00E7\u00E3o desejado no arquivo demoiselle.properties.
100 100  
101   -management-null-class-defined=A classe gerenciada informada n\u00E3o pode ser nula.
102   -management-no-annotation-found=Classe {0} precisa ser anotada com @Managed.
103   -management-invalid-property-no-getter-setter=Falha ao inicializar classe gerenciada {0}, n\u00E3o foi encontrado um m\u00E9todo get ou m\u00E9todo set para a propriedade {1}.
104   -management-invalid-property-as-operation=Falha ao inicializar classe gerenciada {0}, n\u00E3o \u00E9 poss\u00EDvel declarar uma propriedade cujo m\u00E9todo get ou set \u00E9 uma opera\u00E7\u00E3o.
105   -management-introspection-error=Erro ao ler atributos da classe gerenciada {0}.
106   -management-type-not-found=A classe gerenciada informada n\u00E3o existe: {0}.
107   -management-invoke-error=Erro ao tentar invocar a opera\u00E7\u00E3o "{0}" da classe gerenciada, a opera\u00E7\u00E3o n\u00E3o foi encontrada.
108   -management-debug-acessing-property=Acessando propriedade {0} da classe gerenciada {1}.
109   -management-debug-setting-property=Definindo novo valor para propriedade {0} da classe gerenciada {1}.
110   -management-debug-invoking-operation=Invocando opera\u00E7\u00E3o {0} da classe gerenciada {1}.
111   -management-debug-starting-custom-context=Levantando contexto {0} para executar comando na classe gerenciada {1}.
112   -management-debug-stoping-custom-context=Desligando contexto {0} para classe gerenciada {1}.
  101 +management-notification-attribute-changed=O atributo [{0}] da classe gerenciada [{1}] foi alterado
  102 +management-null-class-defined=A classe gerenciada informada n\u00E3o pode ser nula
  103 +management-no-annotation-found=Classe {0} precisa ser anotada com @Managed
  104 +management-invalid-property-no-getter-setter=Falha ao inicializar classe gerenciada {0}, n\u00E3o foi encontrado um m\u00E9todo get ou m\u00E9todo set para a propriedade {1}
  105 +management-invalid-property-as-operation=Falha ao inicializar classe gerenciada {0}, n\u00E3o \u00E9 poss\u00EDvel declarar uma propriedade cujo m\u00E9todo get ou set \u00E9 uma opera\u00E7\u00E3o
  106 +management-introspection-error=Erro ao ler atributos da classe gerenciada {0}
  107 +management-type-not-found=A classe gerenciada informada n\u00E3o existe\: {0}
  108 +management-invoke-error=Erro ao tentar invocar a opera\u00E7\u00E3o "{0}" da classe gerenciada, a opera\u00E7\u00E3o n\u00E3o foi encontrada
  109 +management-debug-acessing-property=Acessando propriedade {0} da classe gerenciada {1}
  110 +management-debug-setting-property=Definindo novo valor para propriedade {0} da classe gerenciada {1}
  111 +management-debug-invoking-operation=Invocando opera\u00E7\u00E3o {0} da classe gerenciada {1}
  112 +management-debug-starting-custom-context=Levantando contexto {0} para executar comando na classe gerenciada {1}
  113 +management-debug-stoping-custom-context=Desligando contexto {0} para classe gerenciada {1}
  114 +management-debug-registering-managed-type=Registrando classe gerenciada [{0}]
  115 +management-debug-processing-management-extension=Processando extens\u00E3o de gerenciamento [{0}]
  116 +management-debug-removing-management-extension=Desativando extens\u00E3o de gerenciamento [{0}]
113 117 \ No newline at end of file
... ...
impl/core/src/test/java/management/DummyManagedClass.java
... ... @@ -1,74 +0,0 @@
1   -package management;
2   -
3   -import java.util.UUID;
4   -
5   -import br.gov.frameworkdemoiselle.management.annotation.Managed;
6   -import br.gov.frameworkdemoiselle.management.annotation.Operation;
7   -import br.gov.frameworkdemoiselle.management.annotation.Property;
8   -import br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues;
9   -import br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues.ValueType;
10   -
11   -@Managed
12   -public class DummyManagedClass {
13   -
14   - @Property
15   - @AllowedValues(allows={"f","m","F","M"},valueType=ValueType.INTEGER)
16   - private Integer id;
17   -
18   - @Property
19   - private String uuid;
20   -
21   - @Property
22   - private String writeOnlyProperty;
23   -
24   - /**
25   - * Propriedade para testar detecção de métodos GET e SET quando propriedade tem apenas uma letra.
26   - */
27   - @Property
28   - private Integer a;
29   -
30   - /**
31   - * Propriedade para testar detecção de métodos GET e SET quando propriedade tem apenas letras maiúsculas.
32   - */
33   - @Property
34   - private Integer MAIUSCULO;
35   -
36   - public Integer getId() {
37   - return id;
38   - }
39   -
40   - public void setId(Integer id) {
41   - this.id = id;
42   - }
43   -
44   - public String getUuid() {
45   - return uuid;
46   - }
47   -
48   - public void setWriteOnlyProperty(String newValue){
49   - this.writeOnlyProperty = newValue;
50   - }
51   -
52   - public Integer getA() {
53   - return a;
54   - }
55   -
56   - public void setA(Integer a) {
57   - this.a = a;
58   - }
59   -
60   - public Integer getMAIUSCULO() {
61   - return MAIUSCULO;
62   - }
63   -
64   -
65   - public void setMAIUSCULO(Integer mAIUSCULO) {
66   - MAIUSCULO = mAIUSCULO;
67   - }
68   -
69   - @Operation(description="Generates a random UUID")
70   - public String generateUUID(){
71   - this.uuid = UUID.randomUUID().toString();
72   - return this.uuid;
73   - }
74   -}
impl/core/src/test/java/management/DummyManagementExtension.java
... ... @@ -1,29 +0,0 @@
1   -package management;
2   -
3   -import java.util.List;
4   -
5   -import javax.inject.Inject;
6   -
7   -import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
8   -import br.gov.frameworkdemoiselle.management.internal.ManagedType;
9   -
10   -public class DummyManagementExtension implements ManagementExtension {
11   -
12   - @Inject
13   - private ManagedClassStore store;
14   -
15   - @Override
16   - public void initialize(List<ManagedType> managedTypes) {
17   - // Armazena os beans managed detectados neste store,
18   - // para depois serem testados.
19   - store.setManagedTypes(managedTypes);
20   - }
21   -
22   - @Override
23   - public void shutdown(List<ManagedType> managedTypes) {
24   - // Limpa o store, depois o teste verificará se
25   - // o processo de shutdown rodou e limpou o store.
26   - store.setManagedTypes(null);
27   - }
28   -
29   -}
impl/core/src/test/java/management/ManagedClassStore.java
1 1 package management;
2 2  
  3 +import java.util.ArrayList;
  4 +import java.util.Collection;
3 5 import java.util.List;
4 6  
5 7 import javax.enterprise.context.ApplicationScoped;
... ... @@ -9,15 +11,15 @@ import br.gov.frameworkdemoiselle.management.internal.ManagedType;
9 11 @ApplicationScoped
10 12 public class ManagedClassStore {
11 13  
12   - private List<ManagedType> managedTypes = null;
  14 + private List<ManagedType> managedTypes = new ArrayList<ManagedType>();
13 15  
14 16  
15 17 public List<ManagedType> getManagedTypes() {
16 18 return managedTypes;
17 19 }
18 20  
19   - public void setManagedTypes(List<ManagedType> managedTypes) {
20   - this.managedTypes = managedTypes;
  21 + public void addManagedTypes(Collection<ManagedType> managedTypes){
  22 + this.managedTypes.addAll(managedTypes);
21 23 }
22 24  
23 25 }
... ...
impl/core/src/test/java/management/ManagementBootstrapTest.java
... ... @@ -1,68 +0,0 @@
1   -package management;
2   -
3   -import javax.inject.Inject;
4   -
5   -import org.jboss.arquillian.container.test.api.Deployment;
6   -import org.jboss.arquillian.junit.Arquillian;
7   -import org.jboss.shrinkwrap.api.spec.JavaArchive;
8   -import org.junit.Assert;
9   -import org.junit.Test;
10   -import org.junit.runner.RunWith;
11   -
12   -import test.Tests;
13   -import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess;
14   -import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
15   -import br.gov.frameworkdemoiselle.util.Beans;
16   -
17   -
18   -@RunWith(Arquillian.class)
19   -public class ManagementBootstrapTest {
20   -
21   - @Inject
22   - private ManagedClassStore store;
23   -
24   - @Deployment
25   - public static JavaArchive createDeployment() {
26   - JavaArchive deployment = Tests.createDeployment(ManagementBootstrapTest.class);
27   -
28   - /*deployment
29   - .addClass(ManagedClassStore.class)
30   - .addClass(DummyManagedClass.class)
31   - .addClass(DummyManagementExtension.class);*/
32   -
33   - return deployment;
34   - }
35   -
36   - /**
37   - * Test if a a management extension (a library that implements {@link ManagementExtension}) is correctly detected.
38   - */
39   - @Test
40   - public void testManagementExtensionRegistration(){
41   -
42   - //"store" é application scoped e é usado pelo DummyManagementExtension para
43   - //armazenar todos os beans anotados com @Managed. Se o bootstrap rodou corretamente,
44   - //ele chamou DummyManagementExtension.initialize e este store conterá o bean de teste que anotamos.
45   - Assert.assertNotNull(store.getManagedTypes());
46   - Assert.assertEquals(1, store.getManagedTypes().size());
47   -
48   - }
49   -
50   - /**
51   - * Test if a a management extension's (a library that implements {@link ManagementExtension}) shutdown
52   - * method is correctly called upon application shutdown.
53   - */
54   - @Test
55   - public void testManagementExtensionShutdown(){
56   -
57   - //"store" é application scoped e é usado pelo DummyManagementExtension para
58   - //armazenar todos os beans anotados com @Managed. Se o bootstrap rodou corretamente,
59   - //ele chamou DummyManagementExtension.initialize e este store conterá o bean de teste que anotamos.
60   - //Nós então disparamos o evento de shutdown onde ele deverá limpar o store.
61   - Assert.assertNotNull(store.getManagedTypes());
62   - Assert.assertEquals(1, store.getManagedTypes().size());
63   -
64   - Beans.getBeanManager().fireEvent(new AfterShutdownProccess() {});
65   - Assert.assertNull(store.getManagedTypes());
66   - }
67   -
68   -}
impl/core/src/test/java/management/ManagementBootstrapTestCase.java 0 → 100644
... ... @@ -0,0 +1,124 @@
  1 +package management;
  2 +
  3 +import java.io.File;
  4 +import java.util.List;
  5 +
  6 +import management.testclasses.DummyManagedClass;
  7 +import management.testclasses.DummyManagedClassPropertyError;
  8 +import management.testclasses.DummyManagementExtension;
  9 +
  10 +import org.jboss.arquillian.container.test.api.Deployer;
  11 +import org.jboss.arquillian.container.test.api.Deployment;
  12 +import org.jboss.arquillian.junit.Arquillian;
  13 +import org.jboss.arquillian.test.api.ArquillianResource;
  14 +import org.jboss.shrinkwrap.api.ShrinkWrap;
  15 +import org.jboss.shrinkwrap.api.asset.FileAsset;
  16 +import org.jboss.shrinkwrap.api.spec.JavaArchive;
  17 +import org.junit.Assert;
  18 +import org.junit.Test;
  19 +import org.junit.runner.RunWith;
  20 +
  21 +import test.LocaleProducer;
  22 +import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
  23 +import br.gov.frameworkdemoiselle.management.internal.ManagedType;
  24 +import br.gov.frameworkdemoiselle.util.Beans;
  25 +
  26 +@RunWith(Arquillian.class)
  27 +public class ManagementBootstrapTestCase {
  28 +
  29 + @ArquillianResource
  30 + private Deployer deployer;
  31 +
  32 + /**
  33 + * Deployment to test normal deployment behaviour
  34 + *
  35 + */
  36 + @Deployment(name = "default",managed=false,testable=false)
  37 + public static JavaArchive createDeployment() {
  38 + return ShrinkWrap
  39 + .create(JavaArchive.class)
  40 + .addClass(LocaleProducer.class)
  41 + .addPackages(true, "br")
  42 + .addAsResource(new FileAsset(new File("src/test/resources/test/beans.xml")), "beans.xml")
  43 + .addAsManifestResource(
  44 + new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"),
  45 + "services/javax.enterprise.inject.spi.Extension")
  46 + .addPackages(false, ManagementBootstrapTestCase.class.getPackage())
  47 + .addClasses(DummyManagementExtension.class,DummyManagedClass.class);
  48 + }
  49 +
  50 + /**
  51 + * Deployment containing a malformed managed class. Tests using this deployment will
  52 + * check if deployment fails (it has to).
  53 + *
  54 + */
  55 + @Deployment(name = "wrong_annotation",managed=false,testable=false)
  56 + public static JavaArchive createWrongAnnotationDeployment() {
  57 + return ShrinkWrap
  58 + .create(JavaArchive.class)
  59 + .addClass(LocaleProducer.class)
  60 + .addPackages(true, "br")
  61 + .addAsResource(new FileAsset(new File("src/test/resources/test/beans.xml")), "beans.xml")
  62 + .addAsManifestResource(
  63 + new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"),
  64 + "services/javax.enterprise.inject.spi.Extension")
  65 + .addPackages(false, ManagementBootstrapTestCase.class.getPackage())
  66 + .addClasses(DummyManagementExtension.class,DummyManagedClassPropertyError.class);
  67 + }
  68 +
  69 + /**
  70 + * Test if a a management extension (a library that implements {@link ManagementExtension}) is correctly detected.
  71 + */
  72 + @Test
  73 + public void testManagementExtensionRegistration() {
  74 + deployer.deploy("default");
  75 +
  76 + // "store" é application scoped e é usado pelo DummyManagementExtension para
  77 + // armazenar todos os beans anotados com @Managed. Se o bootstrap rodou corretamente,
  78 + // ele chamou DummyManagementExtension.initialize e este store conterá o bean de teste que anotamos.
  79 + ManagedClassStore store = Beans.getReference(ManagedClassStore.class);
  80 +
  81 + Assert.assertEquals(1, store.getManagedTypes().size());
  82 +
  83 + deployer.undeploy("default");
  84 + }
  85 +
  86 + /**
  87 + * Test if a a management extension's shutdown method is
  88 + * correctly called upon application shutdown.
  89 + */
  90 + @Test
  91 + public void testManagementExtensionShutdown() {
  92 + deployer.deploy("default");
  93 +
  94 + // "store" é application scoped e é usado pelo DummyManagementExtension para
  95 + // armazenar todos os beans anotados com @Managed. Se o bootstrap rodou corretamente,
  96 + // ele chamou DummyManagementExtension.initialize e este store conterá o bean de teste que anotamos.
  97 + // Nós então disparamos o evento de shutdown onde ele deverá limpar o store.
  98 + ManagedClassStore store = Beans.getReference(ManagedClassStore.class);
  99 +
  100 + //Detecta se a classe anotada foi detectada
  101 + List<ManagedType> managedTypes = store.getManagedTypes();
  102 + Assert.assertEquals(1, managedTypes.size());
  103 +
  104 + deployer.undeploy("default");
  105 +
  106 + //Após o "undeploy", o ciclo de vida precisa ter removido a classe gerenciada da lista.
  107 + Assert.assertEquals(0, managedTypes.size());
  108 + }
  109 +
  110 + @Test
  111 + public void testWrongAnnotation(){
  112 +
  113 + try{
  114 + deployer.deploy("wrong_annotation");
  115 +
  116 + //O processo de deploy precisa falhar, pois temos uma classe anotada com falhas.
  117 + Assert.fail();
  118 + }
  119 + catch(Exception e){
  120 + deployer.undeploy("wrong_annotation");
  121 + }
  122 + }
  123 +
  124 +}
... ...
impl/core/src/test/java/management/NotificationTestCase.java 0 → 100644
... ... @@ -0,0 +1,100 @@
  1 +package management;
  2 +
  3 +import java.io.File;
  4 +
  5 +import javax.inject.Inject;
  6 +
  7 +import junit.framework.Assert;
  8 +import management.testclasses.DummyManagedClass;
  9 +import management.testclasses.DummyNotificationListener;
  10 +
  11 +import org.jboss.arquillian.container.test.api.Deployment;
  12 +import org.jboss.arquillian.junit.Arquillian;
  13 +import org.jboss.shrinkwrap.api.ShrinkWrap;
  14 +import org.jboss.shrinkwrap.api.asset.FileAsset;
  15 +import org.jboss.shrinkwrap.api.spec.JavaArchive;
  16 +import org.junit.Test;
  17 +import org.junit.runner.RunWith;
  18 +
  19 +import test.LocaleProducer;
  20 +import br.gov.frameworkdemoiselle.annotation.Name;
  21 +import br.gov.frameworkdemoiselle.management.internal.ManagedType;
  22 +import br.gov.frameworkdemoiselle.management.internal.MonitoringManager;
  23 +import br.gov.frameworkdemoiselle.management.notification.AttributeChangeNotification;
  24 +import br.gov.frameworkdemoiselle.management.notification.Notification;
  25 +import br.gov.frameworkdemoiselle.management.notification.NotificationManager;
  26 +import br.gov.frameworkdemoiselle.util.Beans;
  27 +import br.gov.frameworkdemoiselle.util.ResourceBundle;
  28 +
  29 +/**
  30 + * Test the {@link NotificationManager} with a dummy extension
  31 + * to check if notifications are correctly propagated
  32 + *
  33 + * @author serpro
  34 + *
  35 + */
  36 +@RunWith(Arquillian.class)
  37 +public class NotificationTestCase {
  38 +
  39 + @Inject
  40 + private NotificationManager manager;
  41 +
  42 + @Inject
  43 + @Name("demoiselle-core-bundle")
  44 + private ResourceBundle bundle;
  45 +
  46 + @Deployment
  47 + public static JavaArchive createDeployment() {
  48 + return ShrinkWrap
  49 + .create(JavaArchive.class)
  50 + .addClass(LocaleProducer.class)
  51 + .addPackages(true, "br")
  52 + .addAsResource(new FileAsset(new File("src/test/resources/test/beans.xml")), "beans.xml")
  53 + .addAsManifestResource(
  54 + new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"),
  55 + "services/javax.enterprise.inject.spi.Extension")
  56 + .addPackages(false, ManagementBootstrapTestCase.class.getPackage())
  57 + .addClasses(DummyNotificationListener.class,DummyManagedClass.class);
  58 + }
  59 +
  60 + /**
  61 + * Test sending a normal notification
  62 + */
  63 + @Test
  64 + public void testSendGenericNotification(){
  65 + manager.sendNotification(new Notification("Test Message"));
  66 + DummyNotificationListener listener = Beans.getReference(DummyNotificationListener.class);
  67 + Assert.assertEquals("Test Message", listener.getMessage());
  68 + }
  69 +
  70 + /**
  71 + * Test sending a notification of change in attribute
  72 + */
  73 + @Test
  74 + public void testSendAttributeChangeNotification(){
  75 + manager.sendNotification(new AttributeChangeNotification("Test Message", "attribute", String.class, "old", "new"));
  76 + DummyNotificationListener listener = Beans.getReference(DummyNotificationListener.class);
  77 + Assert.assertEquals("Test Message - attribute", listener.getMessage());
  78 + }
  79 +
  80 + /**
  81 + * Test if notifications are automatically sent when an attribute from a managed
  82 + * class change values
  83 + */
  84 + @Test
  85 + public void testNotifyChangeManagedClass(){
  86 + MonitoringManager manager = Beans.getReference(MonitoringManager.class);
  87 +
  88 + for (ManagedType type : manager.getManagedTypes()){
  89 + if (type.getType().equals(DummyManagedClass.class)){
  90 + manager.setProperty(type, "id", new Integer(10));
  91 + break;
  92 + }
  93 + }
  94 +
  95 + DummyNotificationListener listener = Beans.getReference(DummyNotificationListener.class);
  96 + Assert.assertEquals( bundle.getString("management-notification-attribute-changed","id",DummyManagedClass.class.getCanonicalName()) + " - id"
  97 + , listener.getMessage());
  98 + }
  99 +
  100 +}
... ...
impl/core/src/test/java/management/testclasses/DummyManagedClass.java 0 → 100644
... ... @@ -0,0 +1,74 @@
  1 +package management.testclasses;
  2 +
  3 +import java.util.UUID;
  4 +
  5 +import br.gov.frameworkdemoiselle.management.annotation.Managed;
  6 +import br.gov.frameworkdemoiselle.management.annotation.Operation;
  7 +import br.gov.frameworkdemoiselle.management.annotation.Property;
  8 +import br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues;
  9 +import br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues.ValueType;
  10 +
  11 +@Managed
  12 +public class DummyManagedClass {
  13 +
  14 + @Property
  15 + @AllowedValues(allows={"f","m","F","M"},valueType=ValueType.INTEGER)
  16 + private Integer id;
  17 +
  18 + @Property
  19 + private String uuid;
  20 +
  21 + @Property
  22 + private String writeOnlyProperty;
  23 +
  24 + /**
  25 + * Propriedade para testar detecção de métodos GET e SET quando propriedade tem apenas uma letra.
  26 + */
  27 + @Property
  28 + private Integer a;
  29 +
  30 + /**
  31 + * Propriedade para testar detecção de métodos GET e SET quando propriedade tem apenas letras maiúsculas.
  32 + */
  33 + @Property
  34 + private Integer MAIUSCULO;
  35 +
  36 + public Integer getId() {
  37 + return id;
  38 + }
  39 +
  40 + public void setId(Integer id) {
  41 + this.id = id;
  42 + }
  43 +
  44 + public String getUuid() {
  45 + return uuid;
  46 + }
  47 +
  48 + public void setWriteOnlyProperty(String newValue){
  49 + this.writeOnlyProperty = newValue;
  50 + }
  51 +
  52 + public Integer getA() {
  53 + return a;
  54 + }
  55 +
  56 + public void setA(Integer a) {
  57 + this.a = a;
  58 + }
  59 +
  60 + public Integer getMAIUSCULO() {
  61 + return MAIUSCULO;
  62 + }
  63 +
  64 +
  65 + public void setMAIUSCULO(Integer mAIUSCULO) {
  66 + MAIUSCULO = mAIUSCULO;
  67 + }
  68 +
  69 + @Operation(description="Generates a random UUID")
  70 + public String generateUUID(){
  71 + this.uuid = UUID.randomUUID().toString();
  72 + return this.uuid;
  73 + }
  74 +}
... ...
impl/core/src/test/java/management/testclasses/DummyManagedClassPropertyError.java 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +package management.testclasses;
  2 +
  3 +import br.gov.frameworkdemoiselle.management.annotation.Managed;
  4 +import br.gov.frameworkdemoiselle.management.annotation.Property;
  5 +
  6 +
  7 +/**
  8 + *
  9 + * Used in tests to detect if the bootstrap detects wrong annotations
  10 + *
  11 + * @author serpro
  12 + *
  13 + */
  14 +@Managed
  15 +public class DummyManagedClassPropertyError {
  16 +
  17 + /**
  18 + * Property with no setter or getter
  19 + */
  20 + @Property
  21 + private Long property;
  22 +
  23 +}
... ...
impl/core/src/test/java/management/testclasses/DummyManagementExtension.java 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +package management.testclasses;
  2 +
  3 +import java.util.List;
  4 +
  5 +import javax.inject.Inject;
  6 +
  7 +import management.ManagedClassStore;
  8 +
  9 +import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
  10 +import br.gov.frameworkdemoiselle.management.internal.ManagedType;
  11 +
  12 +public class DummyManagementExtension implements ManagementExtension {
  13 +
  14 + @Inject
  15 + private ManagedClassStore store;
  16 +
  17 + @Override
  18 + public void initialize(List<ManagedType> managedTypes) {
  19 + // Armazena os beans managed detectados neste store,
  20 + // para depois serem testados.
  21 + store.addManagedTypes(managedTypes);
  22 + }
  23 +
  24 + @Override
  25 + public void shutdown(List<ManagedType> managedTypes) {
  26 + // Limpa o store, depois o teste verificará se
  27 + // o processo de shutdown rodou e limpou o store.
  28 + store.getManagedTypes().clear();
  29 + }
  30 +
  31 +}
... ...
impl/core/src/test/java/management/testclasses/DummyNotificationListener.java 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +package management.testclasses;
  2 +
  3 +import javax.enterprise.context.ApplicationScoped;
  4 +import javax.enterprise.event.Observes;
  5 +
  6 +import br.gov.frameworkdemoiselle.management.internal.notification.event.NotificationEvent;
  7 +import br.gov.frameworkdemoiselle.management.internal.notification.qualifier.AttributeChange;
  8 +import br.gov.frameworkdemoiselle.management.internal.notification.qualifier.Generic;
  9 +import br.gov.frameworkdemoiselle.management.notification.AttributeChangeNotification;
  10 +import br.gov.frameworkdemoiselle.management.notification.NotificationManager;
  11 +
  12 +/**
  13 + * Dummy class to test receiving of notifications sent by the {@link NotificationManager}
  14 + *
  15 + * @author serpro
  16 + *
  17 + */
  18 +@ApplicationScoped
  19 +public class DummyNotificationListener {
  20 +
  21 + private String message = null;
  22 +
  23 + public void listenNotification(@Observes @Generic NotificationEvent event){
  24 + message = event.getNotification().getMessage().toString();
  25 + }
  26 +
  27 + public void listenAttributeChangeNotification(@Observes @AttributeChange NotificationEvent event){
  28 + AttributeChangeNotification notification = (AttributeChangeNotification)event.getNotification();
  29 + message = notification.getMessage().toString() + " - " + notification.getAttributeName();
  30 + }
  31 +
  32 + public String getMessage() {
  33 + return message;
  34 + }
  35 +}
... ...