Commit dbc9dcc2ced859a6efd7474125db081759718a37
1 parent
0d9f1260
Exists in
master
-Alterada mensagem de erro ao ler propriedade inexistente em classe
gerenciada -Adicionado recurso para marcar propriedade com apenas leitura ou escrita ignorando presença ou ausência de métodos set e get -Iniciada escrita de documentação
Showing
7 changed files
with
151 additions
and
4 deletions
Show diff stats
| ... | ... | @@ -0,0 +1,62 @@ |
| 1 | +<?xml version='1.0' encoding="utf-8"?> | |
| 2 | +<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" | |
| 3 | + "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" []> | |
| 4 | +<chapter id="mensagem"> | |
| 5 | + | |
| 6 | + <title>Monitoração e Gerenciamento de Recursos</title> | |
| 7 | + | |
| 8 | + <section> | |
| 9 | + <title>Por que monitorar e gerenciar aplicações</title> | |
| 10 | + | |
| 11 | + <para>Ao implantar um sistema para produção, muitas vezes é necessário monitorar aspectos sobre o funcionamento desse sistema. Quanta memória | |
| 12 | + ele está utilizando? Qual o pico de MIPS utilizados? Quantas sessões estão autenticadas no momento?</para> | |
| 13 | + | |
| 14 | + <para>Além de monitorar um sistema, as vezes é necessário gerencia-lo alterando aspectos de seu comportamento. Se o sistema está implantado em um | |
| 15 | + servidor alugado, talvez seja necessário ajustar o uso de MIPS para reduzir custos ou talvez deseje-se solicitar que o sistema limpe dados de sessão | |
| 16 | + de autenticação abandonados por usuários que desligaram suas estações sem efetuar "logoff".</para> | |
| 17 | + | |
| 18 | + <para>Para esse fim existem diversas tecnologias que permitem ao desenvolvedor expor aspectos monitoráveis e gerenciáves de seu sistema | |
| 19 | + para clientes de gerenciamento. Exemplos dessas tecnologias incluem o <emphasis>Simple Network Management Protocol</emphasis> (SNMP) e o | |
| 20 | + <emphasis>Java Management Extension</emphasis> (JMX).</para> | |
| 21 | + | |
| 22 | + <para>O <emphasis>Demoiselle Framework</emphasis> dispõe de uma série de ferramentas para nivelar | |
| 23 | + o conhecimento do desenvolvedor e facilitar o uso e integraçao de várias tecnologias de gerenciamento e monitoração. Através de seu | |
| 24 | + uso o desenvolvedor pode se despreocupar com detalhes de implementação de cada tecnologia individual e facilmente integrar tais tecnologias.</para> | |
| 25 | + </section> | |
| 26 | + | |
| 27 | + <section> | |
| 28 | + <title>Introdução ao mecanismo</title> | |
| 29 | + | |
| 30 | + <para>Para expor aspectos monitoráveis da sua aplicação, o primeiro passo é criar uma interface contendo os atributos monitoráveis e as operações | |
| 31 | + de gerenciamento que serão expostas para clientes de gerenciamento. Isso é feito através de uma simples classe Java (<emphasis>ou POJO</emphasis>) | |
| 32 | + anotada com o estereótipo <code>@ManagementController</code>.</para> | |
| 33 | + | |
| 34 | + <programlisting role="JAVA"><![CDATA[ | |
| 35 | + @ManagementController | |
| 36 | + public class GerenciadorUsuarios]]></programlisting> | |
| 37 | + | |
| 38 | + <para>Essa anotação é suficiente para o mecanismo de gerenciamento descobrir sua classe e disponibiliza-la para ser monitorada e gerenciada.</para> | |
| 39 | + | |
| 40 | + <para>Contudo, a simples anotação acima não informa ao mecanismo quais aspectos da classe serão expostos. Por padrão, um <emphasis>Management Controller</emphasis> | |
| 41 | + não expõe nenhum aspecto seu. Para selecionais quais aspectos serão expostos usamos as anotações <code>@ManagedProperty</code> e <code>@ManagedOperation</code>.</para> | |
| 42 | + | |
| 43 | + <table> | |
| 44 | + <tbody> | |
| 45 | + <row> | |
| 46 | + <entry> | |
| 47 | + <emphasis role="BOLD">@ManagedProperty</emphasis> | |
| 48 | + </entry> | |
| 49 | + </row> | |
| 50 | + | |
| 51 | + <row> | |
| 52 | + <entry> | |
| 53 | + <para>Marca um atributo na classe como uma propriedade gerenciada, significando que clientes externos podem ler e/ou escrever valores nesses atributos.</para> | |
| 54 | + <para>Um</para> | |
| 55 | + </entry> | |
| 56 | + </row> | |
| 57 | + </tbody> | |
| 58 | + </table> | |
| 59 | + | |
| 60 | + </section> | |
| 61 | + | |
| 62 | +</chapter> | |
| 0 | 63 | \ No newline at end of file | ... | ... |
impl/core/src/main/java/br/gov/frameworkdemoiselle/annotation/ManagedProperty.java
| ... | ... | @@ -47,7 +47,8 @@ import javax.enterprise.util.Nonbinding; |
| 47 | 47 | /** |
| 48 | 48 | * <p>Indicates that a field must be exposed as a property to management clients.</p> |
| 49 | 49 | * <p>The property will be writable if there's a public setter method |
| 50 | - * declared for the field and readable if there's a getter method.</p> | |
| 50 | + * declared for the field and readable if there's a getter method. You can override this behaviour by passing a value | |
| 51 | + * to the {@link #accessLevel()} property.</p> | |
| 51 | 52 | * <p>It's a runtime error to annotate a field with no getter and no setter method.</p> |
| 52 | 53 | * <p>It's also a runtime error to declare a field as a property and one or both of it's getter and setter |
| 53 | 54 | * methods as an operation using the {@link ManagedOperation} annotation.</p> |
| ... | ... | @@ -65,5 +66,36 @@ public @interface ManagedProperty { |
| 65 | 66 | */ |
| 66 | 67 | @Nonbinding |
| 67 | 68 | String description() default ""; |
| 69 | + | |
| 70 | + @Nonbinding | |
| 71 | + ManagedPropertyAccess accessLevel() default ManagedPropertyAccess.DEFAULT; | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * <p>Access level of a managed property.</p> | |
| 75 | + * | |
| 76 | + * <p>These values only affect access via external management clients, the application is still able to inject and use the normal visibility of the property | |
| 77 | + * by Java standards.</p> | |
| 78 | + * | |
| 79 | + * @author serpro | |
| 80 | + * | |
| 81 | + */ | |
| 82 | + enum ManagedPropertyAccess{ | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Restricts a property to be only readable even if a setter method exists. | |
| 86 | + */ | |
| 87 | + READ_ONLY | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Restricts a property to be only writeable even if a getter method exists. | |
| 91 | + */ | |
| 92 | + ,WRITE_ONLY | |
| 93 | + | |
| 94 | + /** | |
| 95 | + * Says that the read or write access will | |
| 96 | + * be determined by the presence of a getter method <code>(getProperty())</code> or setter method <code>(setProperty(propertyValue))</code> for a property. | |
| 97 | + */ | |
| 98 | + ,DEFAULT; | |
| 99 | + } | |
| 68 | 100 | |
| 69 | 101 | } | ... | ... |
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/management/ManagedType.java
| ... | ... | @@ -47,6 +47,7 @@ import javax.inject.Qualifier; |
| 47 | 47 | import br.gov.frameworkdemoiselle.DemoiselleException; |
| 48 | 48 | import br.gov.frameworkdemoiselle.annotation.ManagedOperation; |
| 49 | 49 | import br.gov.frameworkdemoiselle.annotation.ManagedProperty; |
| 50 | +import br.gov.frameworkdemoiselle.annotation.ManagedProperty.ManagedPropertyAccess; | |
| 50 | 51 | import br.gov.frameworkdemoiselle.annotation.OperationParameter; |
| 51 | 52 | import br.gov.frameworkdemoiselle.internal.producer.ResourceBundleProducer; |
| 52 | 53 | import br.gov.frameworkdemoiselle.stereotype.ManagementController; |
| ... | ... | @@ -195,6 +196,12 @@ public class ManagedType { |
| 195 | 196 | .append("get") |
| 196 | 197 | .append(field.getName().substring(0, 1).toUpperCase()) |
| 197 | 198 | .append(field.getName().substring(1)); |
| 199 | + | |
| 200 | + //Se propriedade está anotada como WRITE-ONLY, ignora essa etapa. | |
| 201 | + ManagedProperty annotation = field.getAnnotation(ManagedProperty.class); | |
| 202 | + if (annotation.accessLevel() == ManagedPropertyAccess.WRITE_ONLY){ | |
| 203 | + return null; | |
| 204 | + } | |
| 198 | 205 | |
| 199 | 206 | Method getterMethod; |
| 200 | 207 | |
| ... | ... | @@ -227,6 +234,13 @@ public class ManagedType { |
| 227 | 234 | * Returns the public setter method for a given field, or <code>null</code> if no setter method can be found. |
| 228 | 235 | */ |
| 229 | 236 | private Method getSetterMethod(Field field) { |
| 237 | + | |
| 238 | + //Se propriedade está anotada como READ-ONLY, ignora essa etapa. | |
| 239 | + ManagedProperty annotation = field.getAnnotation(ManagedProperty.class); | |
| 240 | + if (annotation.accessLevel() == ManagedPropertyAccess.READ_ONLY){ | |
| 241 | + return null; | |
| 242 | + } | |
| 243 | + | |
| 230 | 244 | StringBuffer setterMethodName = new StringBuffer() |
| 231 | 245 | .append("set") |
| 232 | 246 | .append(field.getName().substring(0, 1).toUpperCase()) | ... | ... |
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/management/Management.java
| ... | ... | @@ -189,7 +189,7 @@ public class Management { |
| 189 | 189 | deactivateContexts(managedType.getType()); |
| 190 | 190 | } |
| 191 | 191 | } else { |
| 192 | - throw new DemoiselleException(bundle.getString("management-invoke-error", propertyName)); | |
| 192 | + throw new DemoiselleException(bundle.getString("management-read-value-error", propertyName)); | |
| 193 | 193 | } |
| 194 | 194 | } else { |
| 195 | 195 | throw new DemoiselleException(bundle.getString("management-type-not-found")); |
| ... | ... | @@ -282,7 +282,7 @@ public class Management { |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | 284 | } else { |
| 285 | - throw new DemoiselleException(bundle.getString("management-invoke-error", propertyName)); | |
| 285 | + throw new DemoiselleException(bundle.getString("management-write-value-error", propertyName)); | |
| 286 | 286 | } |
| 287 | 287 | } else { |
| 288 | 288 | throw new DemoiselleException(bundle.getString("management-type-not-found")); | ... | ... |
impl/core/src/main/resources/demoiselle-core-bundle.properties
| ... | ... | @@ -110,6 +110,8 @@ management-invalid-property-as-operation=Falha ao inicializar classe gerenciada |
| 110 | 110 | management-introspection-error=Erro ao ler atributos da classe gerenciada {0} |
| 111 | 111 | management-type-not-found=A classe gerenciada informada n\u00E3o existe\: {0} |
| 112 | 112 | management-invoke-error=Erro ao tentar invocar a opera\u00E7\u00E3o "{0}" da classe gerenciada, a opera\u00E7\u00E3o n\u00E3o foi encontrada |
| 113 | +management-write-value-error=N\u00E3o foi poss\u00EDvel definir um valor para a propriedade {0} | |
| 114 | +management-read-value-error=N\u00E3o foi poss\u00EDvel ler o valor da propriedade {0} | |
| 113 | 115 | management-debug-acessing-property=Acessando propriedade {0} da classe gerenciada {1} |
| 114 | 116 | management-debug-setting-property=Definindo novo valor para propriedade {0} da classe gerenciada {1} |
| 115 | 117 | management-debug-invoking-operation=Invocando opera\u00E7\u00E3o {0} da classe gerenciada {1} | ... | ... |
impl/core/src/test/java/management/ManagementTestCase.java
| ... | ... | @@ -169,6 +169,21 @@ public class ManagementTestCase { |
| 169 | 169 | } |
| 170 | 170 | |
| 171 | 171 | @Test |
| 172 | + public void testAccessLevelControl(){ | |
| 173 | + //tentamos escrever em uma propriedade que, apesar de ter método setter, está marcada como read-only. | |
| 174 | + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); | |
| 175 | + | |
| 176 | + try{ | |
| 177 | + store.setProperty(DummyManagedClass.class, "readOnlyPropertyWithSetMethod","A Value"); | |
| 178 | + Assert.fail(); | |
| 179 | + } | |
| 180 | + catch(DemoiselleException de){ | |
| 181 | + System.out.println(de.getMessage()); | |
| 182 | + //success | |
| 183 | + } | |
| 184 | + } | |
| 185 | + | |
| 186 | + @Test | |
| 172 | 187 | public void testRequestScopedOperation() { |
| 173 | 188 | ManagedClassStore store = Beans.getReference(ManagedClassStore.class); |
| 174 | 189 | ... | ... |
impl/core/src/test/java/management/testclasses/DummyManagedClass.java
| ... | ... | @@ -42,6 +42,7 @@ import javax.validation.constraints.NotNull; |
| 42 | 42 | |
| 43 | 43 | import br.gov.frameworkdemoiselle.annotation.ManagedOperation; |
| 44 | 44 | import br.gov.frameworkdemoiselle.annotation.ManagedProperty; |
| 45 | +import br.gov.frameworkdemoiselle.annotation.ManagedProperty.ManagedPropertyAccess; | |
| 45 | 46 | import br.gov.frameworkdemoiselle.stereotype.ManagementController; |
| 46 | 47 | import br.gov.frameworkdemoiselle.util.Beans; |
| 47 | 48 | |
| ... | ... | @@ -71,6 +72,12 @@ public class DummyManagedClass { |
| 71 | 72 | @ManagedProperty |
| 72 | 73 | private String readOnlyProperty = "Default Value"; |
| 73 | 74 | |
| 75 | + @ManagedProperty(accessLevel=ManagedPropertyAccess.READ_ONLY) | |
| 76 | + private String readOnlyPropertyWithSetMethod = "Default Value"; | |
| 77 | + | |
| 78 | + @ManagedProperty(accessLevel=ManagedPropertyAccess.WRITE_ONLY) | |
| 79 | + private String writeOnlyPropertyWithGetMethod; | |
| 80 | + | |
| 74 | 81 | /** |
| 75 | 82 | * Propriedade para testar detecção de métodos GET e SET quando propriedade tem apenas uma letra. |
| 76 | 83 | */ |
| ... | ... | @@ -192,11 +199,26 @@ public class DummyManagedClass { |
| 192 | 199 | return gender; |
| 193 | 200 | } |
| 194 | 201 | |
| 195 | - | |
| 196 | 202 | public void setGender(String gender) { |
| 197 | 203 | this.gender = gender; |
| 198 | 204 | } |
| 199 | 205 | |
| 206 | + public String getReadOnlyPropertyWithSetMethod() { | |
| 207 | + return readOnlyPropertyWithSetMethod; | |
| 208 | + } | |
| 209 | + | |
| 210 | + public void setReadOnlyPropertyWithSetMethod(String readOnlyPropertyWithSetMethod) { | |
| 211 | + this.readOnlyPropertyWithSetMethod = readOnlyPropertyWithSetMethod; | |
| 212 | + } | |
| 213 | + | |
| 214 | + public String getWriteOnlyPropertyWithGetMethod() { | |
| 215 | + return writeOnlyPropertyWithGetMethod; | |
| 216 | + } | |
| 217 | + | |
| 218 | + public void setWriteOnlyPropertyWithGetMethod(String writeOnlyPropertyWithGetMethod) { | |
| 219 | + this.writeOnlyPropertyWithGetMethod = writeOnlyPropertyWithGetMethod; | |
| 220 | + } | |
| 221 | + | |
| 200 | 222 | @ManagedOperation |
| 201 | 223 | public String requestScopedOperation(){ |
| 202 | 224 | RequestScopeBeanClient client = Beans.getReference(RequestScopeBeanClient.class); | ... | ... |