Commit 69773da32ff9a5f20fe28e49daecc2dec4cba90a
Exists in
master
Merge branch '2.4.0' of git@github.com:demoiselle/framework.git into 2.4.0
Showing
15 changed files
with
975 additions
and
378 deletions
Show diff stats
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 | +} | ... | ... |