Commit 108457d14101cb10519f1a5835cc624e2f24f537

Authored by Dancovich
1 parent c5261017
Exists in master

-Movido projeto "demoiselle-management" para o demoiselle-core

-Escrita de testes para management
-Refatoramento do componente de gerenciamento de contextos e escopos
-Limpeza geral de código
Showing 34 changed files with 1573 additions and 69 deletions   Show diff stats
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/ManagementBootstrap.java 0 → 100644
... ... @@ -0,0 +1,70 @@
  1 +package br.gov.frameworkdemoiselle.internal.bootstrap;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.Collections;
  5 +import java.util.List;
  6 +import java.util.Set;
  7 +
  8 +import javax.enterprise.event.Observes;
  9 +import javax.enterprise.inject.spi.AfterBeanDiscovery;
  10 +import javax.enterprise.inject.spi.AfterDeploymentValidation;
  11 +import javax.enterprise.inject.spi.AnnotatedType;
  12 +import javax.enterprise.inject.spi.Bean;
  13 +import javax.enterprise.inject.spi.BeanManager;
  14 +import javax.enterprise.inject.spi.Extension;
  15 +import javax.enterprise.inject.spi.ProcessAnnotatedType;
  16 +
  17 +import br.gov.frameworkdemoiselle.internal.context.ContextManager;
  18 +import br.gov.frameworkdemoiselle.internal.context.ManagedContext;
  19 +import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess;
  20 +import br.gov.frameworkdemoiselle.management.annotation.Managed;
  21 +import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
  22 +import br.gov.frameworkdemoiselle.management.internal.ManagedType;
  23 +import br.gov.frameworkdemoiselle.management.internal.MonitoringManager;
  24 +import br.gov.frameworkdemoiselle.util.Beans;
  25 +
  26 +public class ManagementBootstrap implements Extension {
  27 +
  28 + protected static List<AnnotatedType<?>> types = Collections.synchronizedList(new ArrayList<AnnotatedType<?>>());
  29 +
  30 + private List<Class<? extends ManagementExtension>> managementExtensionCache = Collections.synchronizedList(new ArrayList<Class<? extends ManagementExtension>>());
  31 +
  32 +
  33 + public <T> void detectAnnotation(@Observes final ProcessAnnotatedType<T> event, final BeanManager beanManager) {
  34 + if (event.getAnnotatedType().isAnnotationPresent(Managed.class)) {
  35 + types.add(event.getAnnotatedType());
  36 + }
  37 + }
  38 +
  39 + public void activateContexts(@Observes final AfterBeanDiscovery event) {
  40 + ContextManager.initialize(event);
  41 + ContextManager.add(new ManagedContext(), event);
  42 + }
  43 +
  44 + @SuppressWarnings("unchecked")
  45 + public void registerAvailableManagedTypes(@Observes final AfterDeploymentValidation event,BeanManager beanManager) {
  46 + MonitoringManager monitoringManager = Beans.getReference(MonitoringManager.class);
  47 + for (AnnotatedType<?> type : types) {
  48 + ManagedType managedType = new ManagedType(type.getJavaClass());
  49 + monitoringManager.addManagedType(managedType);
  50 + }
  51 +
  52 + Set<Bean<?>> extensionBeans = beanManager.getBeans(ManagementExtension.class);
  53 + if (extensionBeans!=null){
  54 + for (Bean<?> bean : extensionBeans){
  55 + Class<?> extensionConcreteClass = bean.getBeanClass();
  56 + managementExtensionCache.add((Class<? extends ManagementExtension>) extensionConcreteClass);
  57 + }
  58 + }
  59 +
  60 + monitoringManager.initialize(managementExtensionCache);
  61 + }
  62 +
  63 + public void unregisterAvailableManagedTypes(@Observes final AfterShutdownProccess event) {
  64 +
  65 + MonitoringManager manager = Beans.getReference(MonitoringManager.class);
  66 + manager.shutdown(managementExtensionCache);
  67 +
  68 + }
  69 +
  70 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractCustomContext.java
... ... @@ -52,9 +52,9 @@ public abstract class AbstractCustomContext implements CustomContext {
52 52  
53 53 private final Class<? extends Annotation> scope;
54 54  
55   - public AbstractCustomContext(final Class<? extends Annotation> scope, boolean active) {
  55 + public AbstractCustomContext(final Class<? extends Annotation> scope) {
56 56 this.scope = scope;
57   - this.active = active;
  57 + this.active = false;
58 58 }
59 59  
60 60 protected abstract Store getStore();
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextManager.java
... ... @@ -4,6 +4,7 @@ import java.lang.annotation.Annotation;
4 4 import java.util.ArrayList;
5 5 import java.util.Collections;
6 6 import java.util.List;
  7 +import java.util.Locale;
7 8  
8 9 import javax.enterprise.context.ContextNotActiveException;
9 10 import javax.enterprise.context.spi.Context;
... ... @@ -36,15 +37,13 @@ import br.gov.frameworkdemoiselle.util.ResourceBundle;
36 37 */
37 38 public class ContextManager {
38 39  
39   - private static List<CustomContext> contexts = Collections.synchronizedList(new ArrayList<CustomContext>());
40   -
41   - private static List<CustomContext> activatedCustomContexts = Collections.synchronizedList(new ArrayList<CustomContext>());
  40 + private static List<CustomContextCounter> contexts = Collections.synchronizedList(new ArrayList<CustomContextCounter>());
42 41  
43 42 private static boolean initialized = false;
44 43  
45   - private static ResourceBundle bundle = ResourceBundleProducer.create("demoiselle-core-bundle");
  44 + private static ResourceBundle bundle;
46 45  
47   - private static Logger logger = LoggerProducer.create(ContextManager.class);
  46 + private static Logger logger;
48 47  
49 48 /**
50 49 * <p>Initializes this manager and adds the {@link StaticContext} context to the list of managed contexts. Other
... ... @@ -75,8 +74,15 @@ public class ContextManager {
75 74 * @param event The CDI event indicating all beans have been discovered.
76 75 */
77 76 public static void add(CustomContext context,AfterBeanDiscovery event){
78   - context.setActive(true);
  77 + for (CustomContextCounter contextCounter : contexts){
  78 + if (contextCounter.isSame(context.getClass(), context.getScope())){
  79 + return;
  80 + }
  81 + }
  82 +
  83 + context.setActive(false);
79 84 event.addContext(context);
  85 + contexts.add(new CustomContextCounter(context));
80 86 }
81 87  
82 88 /**
... ... @@ -98,17 +104,15 @@ public class ContextManager {
98 104 *
99 105 * @throws DemoiselleException if there is no managed context of the provided type and scope.
100 106 */
101   - public static boolean activate(Class<? extends CustomContext> customContextClass , Class<? extends Annotation> scope){
  107 + public static synchronized void activate(Class<? extends CustomContext> customContextClass , Class<? extends Annotation> scope){
102 108 if (!initialized){
103 109 throw new DemoiselleException(getBundle().getString("custom-context-manager-not-initialized"));
104 110 }
105 111  
106   - for (CustomContext context : contexts){
107   - if (context.getClass().getCanonicalName().equals( customContextClass.getCanonicalName() )
108   - && context.getScope().equals(scope)){
109   - if (!context.isActive()){
110   - return activate(context);
111   - }
  112 + for (CustomContextCounter context : contexts){
  113 + if ( context.isSame(customContextClass, scope) ){
  114 + context.activate();
  115 + return;
112 116 }
113 117 }
114 118  
... ... @@ -135,66 +139,99 @@ public class ContextManager {
135 139 *
136 140 * @throws DemoiselleException if there is no managed context of the provided type and scope.
137 141 */
138   - public static boolean deactivate(Class<? extends CustomContext> customContextClass,Class<? extends Annotation> scope){
  142 + public static synchronized void deactivate(Class<? extends CustomContext> customContextClass,Class<? extends Annotation> scope){
139 143 if (!initialized){
140 144 throw new DemoiselleException(getBundle().getString("custom-context-manager-not-initialized"));
141 145 }
142 146  
143   - for (CustomContext context : activatedCustomContexts){
144   - if (context.getClass().getCanonicalName().equals( customContextClass.getCanonicalName() )
145   - && context.getScope().equals(scope)){
146   -
147   - if (context.isActive()){
148   - return deactivate(context);
149   - }
  147 + for (CustomContextCounter context : contexts){
  148 + if (context.isSame(customContextClass, scope)){
  149 + context.deactivate();
  150 + return;
150 151 }
151 152 }
152 153  
153 154 throw new DemoiselleException(getBundle().getString("custom-context-not-found",customContextClass.getCanonicalName(),scope.getSimpleName()));
154 155 }
155   -
156   - private static boolean activate(CustomContext context){
157   - try{
158   - Beans.getBeanManager().getContext(context.getScope());
159   - return false;
160   - }
161   - catch(ContextNotActiveException ce){
162   - context.setActive(true);
163   - activatedCustomContexts.add(context);
164   - getLogger().trace(getBundle().getString("custom-context-was-activated", context.getClass().getCanonicalName(),context.getScope().getCanonicalName()));
165   - return true;
  156 +
  157 + static Logger getLogger(){
  158 + if (logger==null){
  159 + logger = LoggerProducer.create(ContextManager.class);
166 160 }
  161 +
  162 + return logger;
167 163 }
168 164  
169   - private static boolean deactivate(CustomContext context){
170   - try{
171   - Context activeContext = Beans.getBeanManager().getContext(context.getScope());
172   - if (activeContext.equals(context)){
173   - context.setActive(false);
174   - activatedCustomContexts.remove(context);
175   - return true;
176   - }
  165 + static ResourceBundle getBundle(){
  166 + if (bundle==null){
  167 + bundle = ResourceBundleProducer.create("demoiselle-core-bundle",Locale.getDefault());
177 168 }
178   - catch(ContextNotActiveException e){
  169 +
  170 + return bundle;
  171 + }
  172 +}
  173 +/**
  174 + * Class that counts how many attemps to activate and deactivate this context received, avoiding cases
  175 + * where one client activates given context and another one deactivates it, leaving the first client
  176 + * with no active context before completion.
  177 + *
  178 + * @author serpro
  179 + *
  180 + */
  181 +class CustomContextCounter{
  182 + private CustomContext context;
  183 + private int activationCounter = 0;
  184 +
  185 + public CustomContextCounter(CustomContext customContext) {
  186 + this.context = customContext;
  187 + }
  188 +
  189 + public boolean isSame(Class<? extends CustomContext> customContextClass,Class<? extends Annotation> scope){
  190 + if (context.getClass().getCanonicalName().equals( customContextClass.getCanonicalName() )
  191 + && context.getScope().equals(scope)){
  192 + return true;
179 193 }
180 194  
181 195 return false;
182 196 }
183 197  
184   - private static Logger getLogger(){
185   - if (logger==null){
186   - logger = LoggerProducer.create(ContextManager.class);
  198 + public CustomContext getInternalContext(){
  199 + return this.context;
  200 + }
  201 +
  202 + public synchronized void activate(){
  203 + try{
  204 + Context c = Beans.getBeanManager().getContext(context.getScope());
  205 + if (c==context){
  206 + activationCounter++;
  207 + }
  208 + }
  209 + catch(ContextNotActiveException ce){
  210 + context.setActive(true);
  211 + activationCounter++;
  212 + ContextManager.getLogger().trace(
  213 + ContextManager.getBundle().getString("custom-context-was-activated"
  214 + , context.getClass().getCanonicalName()
  215 + ,context.getScope().getCanonicalName()
  216 + ));
187 217 }
188   -
189   - return logger;
190 218 }
191 219  
192   - private static ResourceBundle getBundle(){
193   - if (bundle==null){
194   - bundle = ResourceBundleProducer.create("demoiselle-core-bundle");
  220 + public synchronized void deactivate(){
  221 + try{
  222 + Context c = Beans.getBeanManager().getContext(context.getScope());
  223 + if (c==context){
  224 + activationCounter--;
  225 + if (activationCounter==0){
  226 + context.setActive(false);
  227 + ContextManager.getLogger().trace(
  228 + ContextManager.getBundle().getString("custom-context-was-deactivated"
  229 + , context.getClass().getCanonicalName()
  230 + ,context.getScope().getCanonicalName()
  231 + ));
  232 + }
  233 + }
195 234 }
196   -
197   - return bundle;
  235 + catch(ContextNotActiveException ce){}
198 236 }
199   -
200 237 }
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ManagedContext.java 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +package br.gov.frameworkdemoiselle.internal.context;
  2 +
  3 +import javax.enterprise.context.RequestScoped;
  4 +
  5 +import br.gov.frameworkdemoiselle.management.annotation.Managed;
  6 +
  7 +/**
  8 + * Context that stores {@link RequestScoped} beans during client calls to {@link Managed} classes.
  9 + * This context is only activated when no other context is active for {@link RequestScoped}.
  10 + *
  11 + * @author serpro
  12 + *
  13 + */
  14 +public class ManagedContext extends ThreadLocalContext {
  15 +
  16 + /**
  17 + * Constructs a new context.
  18 + */
  19 + public ManagedContext() {
  20 + super(RequestScoped.class);
  21 + }
  22 +
  23 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/StaticContext.java
... ... @@ -43,7 +43,7 @@ public class StaticContext extends AbstractCustomContext {
43 43 private final static Store store = createStore();
44 44  
45 45 public StaticContext() {
46   - super(StaticScoped.class, true);
  46 + super(StaticScoped.class);
47 47 }
48 48  
49 49 @Override
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ThreadLocalContext.java
... ... @@ -50,16 +50,18 @@ package br.gov.frameworkdemoiselle.internal.context;
50 50  
51 51 import java.lang.annotation.Annotation;
52 52  
  53 +/**
  54 + * Base context that has a separated store for each thread
  55 + *
  56 + * @author serpro
  57 + *
  58 + */
53 59 public class ThreadLocalContext extends AbstractCustomContext {
54 60  
55 61 private final ThreadLocal<Store> threadLocal = new ThreadLocal<Store>();
56 62  
57 63 public ThreadLocalContext(final Class<? extends Annotation> scope) {
58   - super(scope, true);
59   - }
60   -
61   - public ThreadLocalContext(final Class<? extends Annotation> scope, boolean active) {
62   - super(scope, active);
  64 + super(scope);
63 65 }
64 66  
65 67 @Override
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConfigurationMapValueExtractor.java
... ... @@ -49,7 +49,6 @@ import org.apache.commons.configuration.Configuration;
49 49  
50 50 import br.gov.frameworkdemoiselle.annotation.Priority;
51 51 import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor;
52   -import br.gov.frameworkdemoiselle.util.Strings;
53 52  
54 53 @Priority(EXTENSIONS_L1_PRIORITY)
55 54 public class ConfigurationMapValueExtractor implements ConfigurationValueExtractor {
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConfigurationPrimitiveOrWrapperValueExtractor.java
... ... @@ -49,7 +49,6 @@ import org.apache.commons.lang.ClassUtils;
49 49  
50 50 import br.gov.frameworkdemoiselle.annotation.Priority;
51 51 import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor;
52   -import br.gov.frameworkdemoiselle.util.Strings;
53 52  
54 53 @Priority(EXTENSIONS_L1_PRIORITY)
55 54 public class ConfigurationPrimitiveOrWrapperValueExtractor implements ConfigurationValueExtractor {
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConfigurationStringValueExtractor.java
... ... @@ -44,7 +44,6 @@ import org.apache.commons.configuration.Configuration;
44 44  
45 45 import br.gov.frameworkdemoiselle.annotation.Priority;
46 46 import br.gov.frameworkdemoiselle.configuration.ConfigurationValueExtractor;
47   -import br.gov.frameworkdemoiselle.util.Strings;
48 47  
49 48 @Priority(EXTENSIONS_L1_PRIORITY)
50 49 public class ConfigurationStringValueExtractor implements ConfigurationValueExtractor {
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/annotation/Managed.java 0 → 100644
... ... @@ -0,0 +1,80 @@
  1 +/*
  2 + * Demoiselle Framework
  3 + * Copyright (C) 2011 SERPRO
  4 + * ----------------------------------------------------------------------------
  5 + * This file is part of Demoiselle Framework.
  6 + *
  7 + * Demoiselle Framework is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU Lesser General Public License version 3
  9 + * as published by the Free Software Foundation.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public License version 3
  17 + * along with this program; if not, see <http://www.gnu.org/licenses/>
  18 + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
  19 + * Fifth Floor, Boston, MA 02110-1301, USA.
  20 + * ----------------------------------------------------------------------------
  21 + * Este arquivo é parte do Framework Demoiselle.
  22 + *
  23 + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou
  24 + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação
  25 + * do Software Livre (FSF).
  26 + *
  27 + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA
  28 + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou
  29 + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português
  30 + * para maiores detalhes.
  31 + *
  32 + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título
  33 + * "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/>
  34 + * ou escreva para a Fundação do Software Livre (FSF) Inc.,
  35 + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
  36 + */
  37 +package br.gov.frameworkdemoiselle.management.annotation;
  38 +
  39 +import static java.lang.annotation.ElementType.TYPE;
  40 +import static java.lang.annotation.RetentionPolicy.RUNTIME;
  41 +
  42 +import java.lang.annotation.Documented;
  43 +import java.lang.annotation.Inherited;
  44 +import java.lang.annotation.Retention;
  45 +import java.lang.annotation.Target;
  46 +
  47 +import javax.enterprise.context.ApplicationScoped;
  48 +import javax.enterprise.inject.Stereotype;
  49 +import javax.enterprise.util.Nonbinding;
  50 +import javax.interceptor.InterceptorBinding;
  51 +
  52 +/**
  53 + * Stereotype to indicate a given class is managed. What it means is that an external client can manage the application
  54 + * this class is in by reading or writing it's attributes and calling it's operations.
  55 + * <p>
  56 + * Only fields annotated with {@link br.gov.frameworkdemoiselle.management.annotation.Property} or
  57 + * methods annotated with {@link br.gov.frameworkdemoiselle.management.annotation.Operation} will be exposed
  58 + * to clients.</p>
  59 + * <p>This stereotype only defines a class as managed, you need to choose an extension that will expose this managed class
  60 + * to external clients using any technology available. One example is the Demoiselle JMX extension, that will expose
  61 + * managed classes as MBeans.</p>
  62 + *
  63 + * @author SERPRO
  64 + */
  65 +@Documented
  66 +@Stereotype
  67 +@InterceptorBinding
  68 +@Inherited
  69 +@Retention(RUNTIME)
  70 +@Target({ TYPE })
  71 +@ApplicationScoped
  72 +public @interface Managed {
  73 +
  74 + /**
  75 + * @return Human readable description of this managed class.
  76 + */
  77 + @Nonbinding
  78 + String description() default "";
  79 +
  80 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/annotation/Operation.java 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +package br.gov.frameworkdemoiselle.management.annotation;
  2 +
  3 +import java.lang.annotation.Documented;
  4 +import java.lang.annotation.ElementType;
  5 +import java.lang.annotation.Retention;
  6 +import java.lang.annotation.RetentionPolicy;
  7 +import java.lang.annotation.Target;
  8 +
  9 +import javax.enterprise.util.Nonbinding;
  10 +import javax.management.MBeanException;
  11 +
  12 +/**
  13 + * <p>Indicates that a method is an operation, meaning you can manage some aspect of the application by calling it.</p>
  14 + * <p>This annotation can't be used together with {@link Property}, doing so will throw a {@link MBeanException}.</p>
  15 + *
  16 + * @author SERPRO
  17 + *
  18 + */
  19 +@Documented
  20 +@Target({ElementType.METHOD})
  21 +@Retention(RetentionPolicy.RUNTIME)
  22 +public @interface Operation {
  23 +
  24 + /**
  25 + * Description that will be used to publish the operation to clients.
  26 + * Defaults to an empty description.
  27 + */
  28 + @Nonbinding
  29 + String description() default "";
  30 +
  31 + /**
  32 + * Type of operation. Defaults to {@link OperationType#UNKNOWN}.
  33 + */
  34 + @Nonbinding
  35 + OperationType type() default OperationType.UNKNOWN;
  36 +
  37 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/annotation/OperationParameter.java 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +package br.gov.frameworkdemoiselle.management.annotation;
  2 +
  3 +import java.lang.annotation.Documented;
  4 +import java.lang.annotation.ElementType;
  5 +import java.lang.annotation.Retention;
  6 +import java.lang.annotation.RetentionPolicy;
  7 +import java.lang.annotation.Target;
  8 +
  9 +import javax.enterprise.util.Nonbinding;
  10 +
  11 +/**
  12 + * <p>Optional annotation to write additional detail about an operation's parameter.</p>
  13 + * <p>This annotation is ignored for non-operation methods.</p>
  14 + *
  15 + * @author SERPRO
  16 + *
  17 + */
  18 +@Documented
  19 +@Target({ElementType.PARAMETER})
  20 +@Retention(RetentionPolicy.RUNTIME)
  21 +public @interface OperationParameter {
  22 +
  23 + /**
  24 + * Name that will be used to publish this operation's parameter to clients.
  25 + */
  26 + @Nonbinding
  27 + String name();
  28 +
  29 + /**
  30 + * Optional description that will be used to publish this operation's parameter to clients.
  31 + * Defaults to an empty description.
  32 + */
  33 + @Nonbinding
  34 + String description() default "";
  35 +
  36 +
  37 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/annotation/OperationType.java 0 → 100644
... ... @@ -0,0 +1,45 @@
  1 +package br.gov.frameworkdemoiselle.management.annotation;
  2 +
  3 +import javax.management.MBeanOperationInfo;
  4 +
  5 +
  6 +/**
  7 + * Define the operation type for an operation inside a Managed class.
  8 + *
  9 + *
  10 + * @author SERPRO
  11 + *
  12 + */
  13 +public enum OperationType {
  14 +
  15 + /**
  16 + * Operation is write-only
  17 + */
  18 + ACTION(MBeanOperationInfo.ACTION)
  19 + ,
  20 + /**
  21 + * Operation is read-only
  22 + */
  23 + INFO(MBeanOperationInfo.INFO)
  24 + ,
  25 + /**
  26 + * Operation is read-write
  27 + */
  28 + ACTION_INFO(MBeanOperationInfo.ACTION_INFO)
  29 + ,
  30 + /**
  31 + * Operation is unkown
  32 + */
  33 + UNKNOWN(MBeanOperationInfo.UNKNOWN);
  34 +
  35 + private int operationTypeValue;
  36 +
  37 + private OperationType(int type){
  38 + this.operationTypeValue = type;
  39 + }
  40 +
  41 + public int getValue(){
  42 + return operationTypeValue;
  43 + }
  44 +
  45 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/annotation/Property.java 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +package br.gov.frameworkdemoiselle.management.annotation;
  2 +
  3 +import java.lang.annotation.Documented;
  4 +import java.lang.annotation.ElementType;
  5 +import java.lang.annotation.Retention;
  6 +import java.lang.annotation.RetentionPolicy;
  7 +import java.lang.annotation.Target;
  8 +
  9 +import javax.enterprise.util.Nonbinding;
  10 +
  11 +/**
  12 + * <p>Indicates that a field must be exposed as a property to management clients.</p>
  13 + * <p>The property will be writable if there's a public setter method
  14 + * declared for the field and readable if there's a getter method.</p>
  15 + * <p>It's a runtime error to annotate a field with no getter and no setter method.</p>
  16 + * <p>It's also a runtime error to declare a field as a property and one or both of it's getter and setter
  17 + * methods as an operation using the {@link Operation} annotation.</p>
  18 + *
  19 + * @author SERPRO
  20 + *
  21 + */
  22 +@Documented
  23 +@Target({ElementType.FIELD})
  24 +@Retention(RetentionPolicy.RUNTIME)
  25 +public @interface Property {
  26 +
  27 + /**
  28 + * @return The description of this property exposed to management clients.
  29 + */
  30 + @Nonbinding
  31 + String description() default "";
  32 +
  33 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/annotation/validation/AllowedValues.java 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +package br.gov.frameworkdemoiselle.management.annotation.validation;
  2 +
  3 +import static java.lang.annotation.ElementType.FIELD;
  4 +import static java.lang.annotation.RetentionPolicy.RUNTIME;
  5 +
  6 +import java.lang.annotation.Documented;
  7 +import java.lang.annotation.Retention;
  8 +import java.lang.annotation.Target;
  9 +
  10 +import javax.validation.Constraint;
  11 +
  12 +import br.gov.frameworkdemoiselle.management.internal.validators.AllowedValuesValidator;
  13 +
  14 +@Documented
  15 +@Target({ FIELD})
  16 +@Retention(RUNTIME)
  17 +@Constraint(validatedBy = AllowedValuesValidator.class)
  18 +/**
  19 + * Validate a value against a list of allowed values.
  20 + *
  21 + * @author serpro
  22 + *
  23 + */
  24 +public @interface AllowedValues {
  25 +
  26 + /**
  27 + * List of accepted values
  28 + */
  29 + String[] allows();
  30 +
  31 + /**
  32 + * Type of allowed values. Defaults to {@link ValueType#STRING}.
  33 + */
  34 + ValueType valueType() default ValueType.STRING;
  35 +
  36 + enum ValueType {
  37 + STRING,INTEGER,DECIMAL;
  38 + }
  39 +
  40 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/extension/ManagementExtension.java 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +package br.gov.frameworkdemoiselle.management.extension;
  2 +
  3 +import java.util.List;
  4 +
  5 +import br.gov.frameworkdemoiselle.management.internal.ManagedType;
  6 +
  7 +/**
  8 + *
  9 + * Define an entry point for monitoring extension.
  10 + *
  11 + * @author serpro
  12 + *
  13 + */
  14 +public interface ManagementExtension {
  15 +
  16 + void initialize(List<ManagedType> managedTypes);
  17 +
  18 + void shutdown(List<ManagedType> managedTypes);
  19 +
  20 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/ManagedType.java 0 → 100644
... ... @@ -0,0 +1,295 @@
  1 +package br.gov.frameworkdemoiselle.management.internal;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +import java.lang.reflect.Field;
  5 +import java.lang.reflect.Method;
  6 +import java.util.TreeMap;
  7 +
  8 +import br.gov.frameworkdemoiselle.DemoiselleException;
  9 +import br.gov.frameworkdemoiselle.internal.producer.ResourceBundleProducer;
  10 +import br.gov.frameworkdemoiselle.management.annotation.Managed;
  11 +import br.gov.frameworkdemoiselle.management.annotation.Operation;
  12 +import br.gov.frameworkdemoiselle.management.annotation.OperationParameter;
  13 +import br.gov.frameworkdemoiselle.management.annotation.Property;
  14 +import br.gov.frameworkdemoiselle.util.ResourceBundle;
  15 +
  16 +/**
  17 + * Represents a detected managed type, a Java class annotated with {@link Managed}.
  18 + *
  19 + * @author serpro
  20 + */
  21 +public class ManagedType {
  22 +
  23 + private Class<?> type;
  24 +
  25 + private TreeMap<String, FieldDetail> fields;
  26 +
  27 + private TreeMap<String, MethodDetail> operationMethods;
  28 +
  29 + private ResourceBundle bundle;
  30 +
  31 + private String description;
  32 +
  33 + public ManagedType(Class<?> type) {
  34 + bundle = ResourceBundleProducer.create("demoiselle-core-bundle");
  35 +
  36 + if (type == null) {
  37 + throw new DemoiselleException(bundle.getString("management-null-class-defined"));
  38 + }
  39 + if (!type.isAnnotationPresent(Managed.class)) {
  40 + throw new DemoiselleException(bundle.getString("management-no-annotation-found", type.getCanonicalName()));
  41 + }
  42 +
  43 + this.type = type;
  44 + fields = new TreeMap<String, FieldDetail>();
  45 + operationMethods = new TreeMap<String, MethodDetail>();
  46 + this.description = type.getAnnotation(Managed.class).description();
  47 +
  48 + initialize();
  49 + }
  50 +
  51 + public Class<?> getType() {
  52 + return type;
  53 + }
  54 +
  55 + public String getDescription() {
  56 + return description;
  57 + }
  58 +
  59 + public TreeMap<String, FieldDetail> getFields() {
  60 + return fields;
  61 + }
  62 +
  63 + public TreeMap<String, MethodDetail> getOperationMethods() {
  64 + return operationMethods;
  65 + }
  66 +
  67 + private void initialize() {
  68 + // Para cada atributo verifica se ele está anotado com Property e extrai as informações dele (método get, set e
  69 + // descrição do atributo).
  70 + Field[] fields = type.getDeclaredFields();
  71 + if (fields != null) {
  72 + for (Field field : fields) {
  73 + if (field.isAnnotationPresent(Property.class)) {
  74 + // Obtém os métodos GET e SET para esta propriedade
  75 + Method getterMethod = getGetterMethod(field);
  76 + Method setterMethod = getSetterMethod(field);
  77 + if (getterMethod == null && setterMethod == null) {
  78 + throw new DemoiselleException(bundle.getString("management-invalid-property-no-getter-setter",
  79 + type.getSimpleName(), field.getName()));
  80 + } else if ((getterMethod != null && getterMethod.isAnnotationPresent(Operation.class))
  81 + || (setterMethod != null && setterMethod.isAnnotationPresent(Operation.class))) {
  82 + throw new DemoiselleException(bundle.getString("management-invalid-property-as-operation",
  83 + type.getSimpleName()));
  84 + }
  85 +
  86 + String propertyDescription = field.getAnnotation(Property.class).description();
  87 +
  88 + this.fields.put(field.getName(), new FieldDetail(field, propertyDescription, getterMethod,
  89 + setterMethod));
  90 + }
  91 + }
  92 + }
  93 +
  94 + // Para cada metodo verifica se ele está anotado com Operation e cria um MBeanOperationInfo para ele.
  95 + Method[] methodList = type.getMethods();
  96 + if (methodList != null) {
  97 + for (Method method : methodList) {
  98 + Operation opAnnotation = method.getAnnotation(Operation.class);
  99 +
  100 + if (opAnnotation != null) {
  101 + // Lemos as informações sobre o método e criamos uma instância
  102 + // de MethodDetail para representar este método como uma
  103 + // operação.
  104 +
  105 + Class<?>[] parameterTypes = method.getParameterTypes();
  106 + Annotation[][] parameterAnnotations = method.getParameterAnnotations();
  107 + ParameterDetail[] parameterDetails = new ParameterDetail[parameterTypes.length];
  108 +
  109 + for (int i = 0; i < parameterTypes.length; i++) {
  110 + OperationParameter paramAnnotation = null;
  111 + for (Annotation annotation : parameterAnnotations[i]) {
  112 + if (annotation.annotationType() == OperationParameter.class) {
  113 + paramAnnotation = (OperationParameter) annotation;
  114 + break;
  115 + }
  116 + }
  117 +
  118 + String name = paramAnnotation != null ? paramAnnotation.name() : ("arg" + i);
  119 + String description = paramAnnotation != null ? paramAnnotation.description() : null;
  120 +
  121 + parameterDetails[i] = new ParameterDetail(parameterTypes[i], name, description);
  122 + }
  123 +
  124 + // Com todas as informações, criamos nossa instância de MethodDetail e
  125 + // acrescentamos na lista de todas as operações.
  126 + MethodDetail detail = new MethodDetail(method, opAnnotation.description(), parameterDetails);
  127 + operationMethods.put(method.getName(), detail);
  128 + }
  129 + }
  130 + }
  131 + }
  132 +
  133 + /**
  134 + * Returns the public getter method for a given field, or <code>null</code> if no getter method can be found.
  135 + */
  136 + private Method getGetterMethod(Field field) {
  137 + StringBuffer getterMethodName = new StringBuffer()
  138 + .append("get")
  139 + .append(field.getName().substring(0, 1).toUpperCase())
  140 + .append(field.getName().substring(1));
  141 +
  142 + Method getterMethod;
  143 +
  144 + try {
  145 + getterMethod = type.getMethod(getterMethodName.toString());
  146 + } catch (Exception e) {
  147 + getterMethod = null;
  148 + }
  149 +
  150 + // Se atributo for boolean, procura método getter no formato "isAttribute".
  151 + if (getterMethod == null
  152 + && (Boolean.TYPE.isAssignableFrom(field.getType()) || Boolean.class.isAssignableFrom(field.getType()))) {
  153 + // Boolean.TYPE representa o tipo primitivo "boolean", Boolean.class é a classe wrapper.
  154 + getterMethodName = new StringBuffer()
  155 + .append("is")
  156 + .append(field.getName().substring(0, 1).toUpperCase())
  157 + .append(field.getName().substring(1).toUpperCase());
  158 +
  159 + try {
  160 + getterMethod = type.getMethod(getterMethodName.toString());
  161 + } catch (Exception e) {
  162 + getterMethod = null;
  163 + }
  164 + }
  165 +
  166 + return getterMethod;
  167 + }
  168 +
  169 + /**
  170 + * Returns the public setter method for a given field, or <code>null</code> if no setter method can be found.
  171 + */
  172 + private Method getSetterMethod(Field field) {
  173 + StringBuffer setterMethodName = new StringBuffer()
  174 + .append("set")
  175 + .append(field.getName().substring(0, 1).toUpperCase())
  176 + .append(field.getName().substring(1));
  177 +
  178 + Method setterMethod;
  179 +
  180 + try {
  181 + setterMethod = type.getMethod(setterMethodName.toString() , field.getType());
  182 + } catch (Exception e) {
  183 + setterMethod = null;
  184 + }
  185 +
  186 + return setterMethod;
  187 + }
  188 +
  189 + public final class FieldDetail {
  190 +
  191 + private final Field field;
  192 +
  193 + private final String description;
  194 +
  195 + private Method getterMethod;
  196 +
  197 + private Method setterMethod;
  198 +
  199 + public FieldDetail(Field field, String description, Method getterMethod, Method setterMethod) {
  200 + super();
  201 + this.field = field;
  202 + this.description = description;
  203 + this.getterMethod = getterMethod;
  204 + this.setterMethod = setterMethod;
  205 + }
  206 +
  207 + public Field getField() {
  208 + return field;
  209 + }
  210 +
  211 + public String getDescription() {
  212 + return description;
  213 + }
  214 +
  215 + public Method getGetterMethod() {
  216 + return getterMethod;
  217 + }
  218 +
  219 + public Method getSetterMethod() {
  220 + return setterMethod;
  221 + }
  222 +
  223 + }
  224 +
  225 + public final class MethodDetail {
  226 +
  227 + private final Method method;
  228 +
  229 + private final ParameterDetail[] parameterTypers;
  230 +
  231 + private String description;
  232 +
  233 + public MethodDetail(Method method, String description, ParameterDetail[] parameterTypers) {
  234 + super();
  235 + this.method = method;
  236 + this.description = description;
  237 + this.parameterTypers = parameterTypers;
  238 + }
  239 +
  240 + public Method getMethod() {
  241 + return method;
  242 + }
  243 +
  244 + public ParameterDetail[] getParameterTypers() {
  245 + return parameterTypers;
  246 + }
  247 +
  248 + public String getDescription() {
  249 + return description;
  250 + }
  251 +
  252 + }
  253 +
  254 + public final class ParameterDetail {
  255 +
  256 + private final Class<?> parameterType;
  257 +
  258 + private final String parameterName;
  259 +
  260 + private final String parameterDescription;
  261 +
  262 + public ParameterDetail(Class<?> parameterType, String parameterName, String parameterDescription) {
  263 + super();
  264 + this.parameterType = parameterType;
  265 + this.parameterName = parameterName;
  266 + this.parameterDescription = parameterDescription;
  267 + }
  268 +
  269 + public Class<?> getParameterType() {
  270 + return parameterType;
  271 + }
  272 +
  273 + public String getParameterName() {
  274 + return parameterName;
  275 + }
  276 +
  277 + public String getParameterDescription() {
  278 + return parameterDescription;
  279 + }
  280 + }
  281 +
  282 + /**
  283 + * Indicates another {@link ManagedType} represents the same {@link Class} as this one. This method also supports a
  284 + * {@link Class} as a parameter, in this case it will return <code>true</code> if the passed class is exactly the
  285 + * same Java class represented by this {@link ManagedType}.
  286 + */
  287 + @Override
  288 + public boolean equals(Object other) {
  289 + if (other == null) {
  290 + return false;
  291 + }
  292 +
  293 + return ((ManagedType) other).getType().getCanonicalName().equals(this.getType().getCanonicalName());
  294 + }
  295 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/MonitoringManager.java 0 → 100644
... ... @@ -0,0 +1,254 @@
  1 +package br.gov.frameworkdemoiselle.management.internal;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import java.util.ArrayList;
  5 +import java.util.Collection;
  6 +import java.util.List;
  7 +
  8 +import javax.enterprise.context.ApplicationScoped;
  9 +import javax.enterprise.context.RequestScoped;
  10 +import javax.inject.Inject;
  11 +import javax.management.ReflectionException;
  12 +
  13 +import org.slf4j.Logger;
  14 +
  15 +import br.gov.frameworkdemoiselle.DemoiselleException;
  16 +import br.gov.frameworkdemoiselle.internal.context.ContextManager;
  17 +import br.gov.frameworkdemoiselle.internal.context.ManagedContext;
  18 +import br.gov.frameworkdemoiselle.management.annotation.Managed;
  19 +import br.gov.frameworkdemoiselle.management.annotation.Property;
  20 +import br.gov.frameworkdemoiselle.management.extension.ManagementExtension;
  21 +import br.gov.frameworkdemoiselle.management.internal.ManagedType.MethodDetail;
  22 +import br.gov.frameworkdemoiselle.management.notification.AttributeChangeNotification;
  23 +import br.gov.frameworkdemoiselle.management.notification.NotificationManager;
  24 +import br.gov.frameworkdemoiselle.util.Beans;
  25 +import br.gov.frameworkdemoiselle.util.ResourceBundle;
  26 +
  27 +/**
  28 + * A manager that helps implementators of the management framework to obtain a
  29 + * list of managed classes, set or obtain values from them or invoke operations
  30 + * over them.
  31 + *
  32 + * @author serpro
  33 + */
  34 +@ApplicationScoped
  35 +public class MonitoringManager {
  36 +
  37 + @Inject
  38 + private Logger logger;
  39 +
  40 + @Inject
  41 + private ResourceBundle bundle;
  42 +
  43 + private final List<ManagedType> managedTypes = new ArrayList<ManagedType>();
  44 +
  45 + public void addManagedType(ManagedType managedType) {
  46 + managedTypes.add(managedType);
  47 + }
  48 +
  49 + /**
  50 + * @return A list all managed types, classes annotated with {@link Managed}.
  51 + * The returned list is a shallow copy of the internal list, so you
  52 + * are free to modify it.
  53 + *
  54 + * TODO precisamos desse clone na lista?
  55 + */
  56 + public List<ManagedType> getManagedTypes() {
  57 + ArrayList<ManagedType> cloneList = new ArrayList<ManagedType>();
  58 + cloneList.addAll(managedTypes);
  59 + return cloneList;
  60 + }
  61 +
  62 + /**
  63 + * Invoke an operation over a managed type.
  64 + *
  65 + * @param managedType
  66 + * A type annotated with {@link Managed}. This method will create
  67 + * an (or obtain an already created) instance of this type and
  68 + * invoke the operation over it.
  69 + * @param actionName
  70 + * Name of method to be invoked, the type must have this
  71 + * operation on it's list
  72 + * @param params
  73 + * List of values for the operation parameters. Can be
  74 + * <code>null</code> if the operation require no parameters.
  75 + * @return The return value of the original invoked operation. Methods of
  76 + * return type <code>void</code> will return the {@link Void} type.
  77 + * @throws ReflectionException
  78 + * In case the operation doesn't exist or have a different
  79 + * signature
  80 + */
  81 + public synchronized Object invoke(ManagedType managedType, String actionName,
  82 + Object[] params) {
  83 + if ( managedTypes.contains(managedType) ) {
  84 + activateContexts(managedType.getType());
  85 +
  86 + Object delegate = Beans.getReference(managedType.getType());
  87 +
  88 + MethodDetail method = managedType.getOperationMethods().get(actionName);
  89 +
  90 + if (method != null) {
  91 + try {
  92 + logger.debug(bundle
  93 + .getString("management-debug-invoking-operation",actionName,managedType.getType().getCanonicalName()));
  94 + return method.getMethod().invoke(delegate, params);
  95 + } catch (Exception e) {
  96 + throw new DemoiselleException(bundle.getString(
  97 + "management-invoke-error", actionName), e);
  98 + } finally {
  99 + deactivateContexts(managedType.getType());
  100 + }
  101 + } else {
  102 + throw new DemoiselleException(bundle.getString(
  103 + "management-invoke-error", actionName));
  104 + }
  105 + } else {
  106 + throw new DemoiselleException(
  107 + bundle.getString("management-type-not-found"));
  108 + }
  109 + }
  110 +
  111 + /**
  112 + * Retrieve the current value of a property from a managed type. Properties
  113 + * are attributes annotated with {@link Property}.
  114 + *
  115 + * @param managedType The type that has the property the client wants to know the value of.
  116 + * @param propertyName The name of the property
  117 + * @return The current value of the property
  118 + */
  119 + public synchronized Object getProperty(ManagedType managedType, String propertyName) {
  120 +
  121 + if ( managedTypes.contains(managedType) ) {
  122 + Method getterMethod = managedType.getFields().get(propertyName).getGetterMethod();
  123 +
  124 + if (getterMethod != null) {
  125 + logger.debug(bundle.getString(
  126 + "management-debug-acessing-property", getterMethod
  127 + .getName(), managedType.getType().getCanonicalName()));
  128 +
  129 + activateContexts(managedType.getType());
  130 +
  131 + try {
  132 + Object delegate = Beans.getReference(managedType.getType());
  133 +
  134 + return getterMethod.invoke(delegate, (Object[]) null);
  135 + } catch (Exception e) {
  136 + throw new DemoiselleException(bundle.getString(
  137 + "management-invoke-error", getterMethod.getName()),
  138 + e);
  139 + } finally {
  140 + deactivateContexts(managedType.getType());
  141 + }
  142 + } else {
  143 + throw new DemoiselleException(bundle.getString(
  144 + "management-invoke-error", propertyName));
  145 + }
  146 + } else {
  147 + throw new DemoiselleException(
  148 + bundle.getString("management-type-not-found"));
  149 + }
  150 + }
  151 +
  152 + /**
  153 + * Sets a new value for a property contained inside a managed type. A property
  154 + * is an attribute annotated with {@link Property}.
  155 + *
  156 + * @param managedType The type that has access to the property
  157 + * @param propertyName The name of the property
  158 + * @param newValue The new value of the property
  159 + */
  160 + public synchronized void setProperty(ManagedType managedType, String propertyName,
  161 + Object newValue) {
  162 +
  163 + if ( managedTypes.contains(managedType) ) {
  164 + // Procura o método set do atributo em questão
  165 + Method method = managedType.getFields().get(propertyName).getSetterMethod();
  166 + if (method != null) {
  167 + logger.debug(bundle.getString(
  168 + "management-debug-setting-property", method.getName(),
  169 + managedType.getType().getCanonicalName()));
  170 +
  171 + // Obtém uma instância da classe gerenciada, lembrando que
  172 + // classes
  173 + // anotadas com @Managed são sempre singletons.
  174 + activateContexts(managedType.getType());
  175 + try {
  176 + Object delegate = Beans.getReference(managedType.getType());
  177 +
  178 + Method getterMethod = managedType.getFields().get(propertyName).getGetterMethod();
  179 + Object oldValue;
  180 + try{
  181 + oldValue = getterMethod.invoke(delegate, (Object[])null);
  182 + }
  183 + catch(Exception e){
  184 + oldValue = null;
  185 + }
  186 +
  187 + method.invoke(delegate, new Object[] { newValue });
  188 +
  189 + //Manda uma notificação de mudança de atributo
  190 + NotificationManager notificationManager = Beans.getReference(NotificationManager.class);
  191 + Class<? extends Object> attributeType = newValue!=null ? newValue.getClass() : null;
  192 + AttributeChangeNotification notification = new AttributeChangeNotification(bundle.getString(""), propertyName, attributeType, oldValue, newValue);
  193 + notificationManager.sendAttributeChangedMessage(notification);
  194 +
  195 + } catch (Exception e) {
  196 + throw new DemoiselleException(bundle.getString(
  197 + "management-invoke-error", method.getName()), e);
  198 + } finally {
  199 + deactivateContexts(managedType.getType());
  200 + }
  201 +
  202 + } else {
  203 + throw new DemoiselleException(bundle.getString(
  204 + "management-invoke-error", propertyName));
  205 + }
  206 + } else {
  207 + throw new DemoiselleException(
  208 + bundle.getString("management-type-not-found"));
  209 + }
  210 +
  211 + }
  212 +
  213 + private void activateContexts(Class<?> managedType) {
  214 + logger.debug(bundle.getString("management-debug-starting-custom-context",
  215 + ManagedContext.class.getCanonicalName(),
  216 + managedType.getCanonicalName()));
  217 +
  218 + ContextManager.activate(ManagedContext.class,RequestScoped.class);
  219 + }
  220 +
  221 + private void deactivateContexts(Class<?> managedType) {
  222 + logger.debug(bundle.getString("management-debug-stoping-custom-context",
  223 + ManagedContext.class.getCanonicalName(),
  224 + managedType.getCanonicalName()));
  225 +
  226 + ContextManager.deactivate(ManagedContext.class,RequestScoped.class);
  227 + }
  228 +
  229 + public void shutdown(Collection<Class<? extends ManagementExtension>> monitoringExtensions) {
  230 +
  231 + for (Class<? extends ManagementExtension> monitoringExtensionClass : monitoringExtensions) {
  232 +
  233 + ManagementExtension monitoringExtension = Beans.getReference(monitoringExtensionClass);
  234 +
  235 + monitoringExtension.shutdown(this.getManagedTypes());
  236 +
  237 + }
  238 +
  239 + }
  240 +
  241 + public void initialize(Collection<Class<? extends ManagementExtension>> monitoringExtensions) {
  242 +
  243 + for (Class<? extends ManagementExtension> monitoringExtensionClass : monitoringExtensions) {
  244 +
  245 + ManagementExtension monitoringExtension = Beans
  246 + .getReference(monitoringExtensionClass);
  247 +
  248 + monitoringExtension.initialize(this.getManagedTypes());
  249 +
  250 + }
  251 +
  252 + }
  253 +
  254 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/notification/event/NotificationEvent.java 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +package br.gov.frameworkdemoiselle.management.internal.notification.event;
  2 +
  3 +import br.gov.frameworkdemoiselle.management.notification.Notification;
  4 +import br.gov.frameworkdemoiselle.management.notification.NotificationManager;
  5 +
  6 +/**
  7 + * Event fired when a notification is sent by {@link NotificationManager}.
  8 + * Implementators can capture this event and by notified when the {@link NotificationManager}
  9 + * sends notifications, so they can pass the notification to a underlying protocol such as JMX.
  10 + *
  11 + * @author serpro
  12 + *
  13 + */
  14 +public class NotificationEvent {
  15 +
  16 + private Notification notification;
  17 +
  18 + public NotificationEvent(Notification notification){
  19 + this.notification = notification;
  20 + }
  21 +
  22 + public Notification getNotification() {
  23 + return notification;
  24 + }
  25 +
  26 + public void setNotification(Notification notification) {
  27 + this.notification = notification;
  28 + }
  29 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/notification/qualifier/AttributeChange.java 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +package br.gov.frameworkdemoiselle.management.internal.notification.qualifier;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +import javax.inject.Qualifier;
  9 +
  10 +import br.gov.frameworkdemoiselle.management.internal.notification.event.NotificationEvent;
  11 +import br.gov.frameworkdemoiselle.management.notification.AttributeChangeNotification;
  12 +
  13 +/**
  14 + *
  15 + * Enables {@link NotificationEvent} observers to trigger only with notifications
  16 + * of the specialized type {@link AttributeChangeNotification}.
  17 + *
  18 + * @author serpro
  19 + *
  20 + */
  21 +@Qualifier
  22 +@Retention(RetentionPolicy.RUNTIME)
  23 +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
  24 +public @interface AttributeChange {
  25 +
  26 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/notification/qualifier/Generic.java 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +package br.gov.frameworkdemoiselle.management.internal.notification.qualifier;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +import javax.inject.Qualifier;
  9 +
  10 +import br.gov.frameworkdemoiselle.management.internal.notification.event.NotificationEvent;
  11 +import br.gov.frameworkdemoiselle.management.notification.Notification;
  12 +
  13 +/**
  14 + *
  15 + * Enables {@link NotificationEvent} observers to trigger only with notifications
  16 + * of the base type {@link Notification}.
  17 + *
  18 + * @author serpro
  19 + *
  20 + */
  21 +@Qualifier
  22 +@Retention(RetentionPolicy.RUNTIME)
  23 +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
  24 +public @interface Generic {
  25 +
  26 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/validators/AllowedValuesValidator.java 0 → 100644
... ... @@ -0,0 +1,68 @@
  1 +package br.gov.frameworkdemoiselle.management.internal.validators;
  2 +
  3 +import java.math.BigDecimal;
  4 +
  5 +import javax.validation.ConstraintValidator;
  6 +import javax.validation.ConstraintValidatorContext;
  7 +
  8 +import br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues;
  9 +
  10 +
  11 +public class AllowedValuesValidator implements ConstraintValidator<AllowedValues, Object> {
  12 +
  13 + private br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues.ValueType valueType;
  14 + private String[] allowedValues;
  15 +
  16 + @Override
  17 + public void initialize(AllowedValues constraintAnnotation) {
  18 + valueType = constraintAnnotation.valueType();
  19 + allowedValues = constraintAnnotation.allows();
  20 + }
  21 +
  22 + @Override
  23 + public boolean isValid(Object value, ConstraintValidatorContext context) {
  24 +
  25 + if (value==null){
  26 + return false;
  27 + }
  28 +
  29 + switch(valueType){
  30 + case STRING:
  31 + for (String str : allowedValues){
  32 + if (str.equals(value)) return true;
  33 + }
  34 + return false;
  35 +
  36 + case INTEGER:
  37 + try{
  38 + Integer number = Integer.valueOf(value.toString());
  39 + String strNumber = number.toString();
  40 + for (String str : allowedValues){
  41 + if (str.equals(strNumber)) return true;
  42 + }
  43 +
  44 + return false;
  45 + }
  46 + catch(NumberFormatException ne){
  47 + return false;
  48 + }
  49 +
  50 + case DECIMAL:
  51 + try{
  52 + BigDecimal number = new BigDecimal(value.toString());
  53 + String strNumber = number.toString();
  54 + for (String str : allowedValues){
  55 + if (str.equals(strNumber)) return true;
  56 + }
  57 + }
  58 + catch(NumberFormatException ne){
  59 + return false;
  60 + }
  61 +
  62 + return false;
  63 + }
  64 +
  65 + return false;
  66 + }
  67 +
  68 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/notification/AttributeChangeNotification.java 0 → 100644
... ... @@ -0,0 +1,74 @@
  1 +package br.gov.frameworkdemoiselle.management.notification;
  2 +
  3 +/**
  4 + * Special notification to denote an attribute has changed values.
  5 + *
  6 + * @see Notification
  7 + *
  8 + * @author serpro
  9 + *
  10 + */
  11 +public class AttributeChangeNotification extends Notification {
  12 +
  13 + private String attributeName;
  14 +
  15 + private Class<? extends Object> attributeType;
  16 +
  17 + private Object oldValue;
  18 +
  19 + private Object newValue;
  20 +
  21 + public AttributeChangeNotification(){}
  22 +
  23 + public AttributeChangeNotification(Object message, String attributeName, Class<? extends Object> attributeType, Object oldValue,
  24 + Object newValue) {
  25 + super(message);
  26 + this.attributeName = attributeName;
  27 + this.attributeType = attributeType;
  28 + this.oldValue = oldValue;
  29 + this.newValue = newValue;
  30 + }
  31 +
  32 +
  33 + public String getAttributeName() {
  34 + return attributeName;
  35 + }
  36 +
  37 +
  38 + public void setAttributeName(String attributeName) {
  39 + this.attributeName = attributeName;
  40 + }
  41 +
  42 +
  43 + public Class<? extends Object> getAttributeType() {
  44 + return attributeType;
  45 + }
  46 +
  47 +
  48 + public void setAttributeType(Class<? extends Object> attributeType) {
  49 + this.attributeType = attributeType;
  50 + }
  51 +
  52 +
  53 + public Object getOldValue() {
  54 + return oldValue;
  55 + }
  56 +
  57 +
  58 + public void setOldValue(Object oldValue) {
  59 + this.oldValue = oldValue;
  60 + }
  61 +
  62 +
  63 + public Object getNewValue() {
  64 + return newValue;
  65 + }
  66 +
  67 +
  68 + public void setNewValue(Object newValue) {
  69 + this.newValue = newValue;
  70 + }
  71 +
  72 +
  73 +
  74 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/notification/Notification.java 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +package br.gov.frameworkdemoiselle.management.notification;
  2 +
  3 +/**
  4 + *
  5 + * Notification that can be sent by the {@link NotificationManager}.
  6 + *
  7 + * @author serpro
  8 + *
  9 + */
  10 +public class Notification {
  11 +
  12 + private Object message;
  13 +
  14 + public Notification(){
  15 + }
  16 +
  17 + public Notification(Object message) {
  18 + super();
  19 + this.message = message;
  20 + }
  21 +
  22 +
  23 + public Object getMessage() {
  24 + return message;
  25 + }
  26 +
  27 +
  28 + public void setMessage(Object message) {
  29 + this.message = message;
  30 + }
  31 +
  32 +
  33 + public Class<? extends Object> getType() {
  34 + if (message!=null){
  35 + return message.getClass();
  36 + }
  37 +
  38 + return null;
  39 + }
  40 +
  41 +}
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/management/notification/NotificationManager.java 0 → 100644
... ... @@ -0,0 +1,63 @@
  1 +package br.gov.frameworkdemoiselle.management.notification;
  2 +
  3 +import java.io.Serializable;
  4 +
  5 +import javax.enterprise.context.ApplicationScoped;
  6 +import javax.enterprise.event.Event;
  7 +import javax.enterprise.event.Observes;
  8 +import javax.inject.Inject;
  9 +
  10 +import br.gov.frameworkdemoiselle.management.internal.notification.event.NotificationEvent;
  11 +import br.gov.frameworkdemoiselle.management.internal.notification.qualifier.AttributeChange;
  12 +import br.gov.frameworkdemoiselle.management.internal.notification.qualifier.Generic;
  13 +import br.gov.frameworkdemoiselle.util.Beans;
  14 +
  15 +/**
  16 + *
  17 + * <p>Central class to manage sending notifications to management clients.
  18 + * This class allows applications to send management notifications without
  19 + * knowledge of the technology used to send those notifications.</p>
  20 + *
  21 + * <p>To obtain an instance of the {@link NotificationManager} simply inject it in
  22 + * your code using {@link Inject} or the {@link Beans#getReference(Class beanType)} method. The {@link NotificationManager}
  23 + * is {@link ApplicationScoped}, so you can inject it as many times as needed and still have only one instance per application.</p>
  24 + *
  25 + * <p>Implementators of management protocols must observe the {@link NotificationEvent} event (using the {@link Observes} annotation), this way
  26 + * they will receive an event containing the original notification and can translate this notification to a specific protocol. Optionaly,
  27 + * the implementator can use qualifiers like the {@link Generic} and {@link AttributeChange} qualifiers
  28 + * to filter what king of notifications they will handle. One example of an implementator is the <b>demoiselle-jmx</b> extension.</p>
  29 + *
  30 + * @author serpro
  31 + *
  32 + */
  33 +@ApplicationScoped
  34 +@SuppressWarnings("serial")
  35 +public class NotificationManager implements Serializable{
  36 +
  37 + @Inject
  38 + @Generic
  39 + private Event<NotificationEvent> genericNotificationEvent;
  40 +
  41 + @Inject
  42 + @AttributeChange
  43 + private Event<NotificationEvent> attributeChangeNotificationEvent;
  44 +
  45 + /**
  46 + * Sends a generic notification to all management clients.
  47 + *
  48 + * @param notification The notification to send
  49 + */
  50 + public void sendNotification(Notification notification) {
  51 + genericNotificationEvent.fire(new NotificationEvent(notification));
  52 + }
  53 +
  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));
  62 + }
  63 +}
... ...
impl/core/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
... ... @@ -3,5 +3,6 @@ br.gov.frameworkdemoiselle.internal.bootstrap.ConfigurationBootstrap
3 3 br.gov.frameworkdemoiselle.internal.bootstrap.TransactionBootstrap
4 4 br.gov.frameworkdemoiselle.internal.bootstrap.AuthenticatorBootstrap
5 5 br.gov.frameworkdemoiselle.internal.bootstrap.AuthorizerBootstrap
  6 +br.gov.frameworkdemoiselle.internal.bootstrap.ManagementBootstrap
6 7 br.gov.frameworkdemoiselle.internal.bootstrap.StartupBootstrap
7 8 br.gov.frameworkdemoiselle.internal.bootstrap.ShutdownBootstrap
... ...
impl/core/src/main/resources/demoiselle-core-bundle.properties
... ... @@ -96,4 +96,17 @@ does-not-have-role=Usu\u00E1rio {0} n\u00E3o possui a(s) role(s)\: {1}
96 96 does-not-have-role-ui=Para acessar este recurso \u00E9 necess\u00E1rio ser {0}
97 97 user-has-role=Usu\u00E1rio {0} possui a(s) role(s)\: {1}
98 98  
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 99 \ No newline at end of file
  100 +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.
  101 +
  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}.
... ...
impl/core/src/test/java/management/DummyManagedClass.java 0 → 100644
... ... @@ -0,0 +1,74 @@
  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 0 → 100644
... ... @@ -0,0 +1,29 @@
  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 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +package management;
  2 +
  3 +import java.util.List;
  4 +
  5 +import javax.enterprise.context.ApplicationScoped;
  6 +
  7 +import br.gov.frameworkdemoiselle.management.internal.ManagedType;
  8 +
  9 +@ApplicationScoped
  10 +public class ManagedClassStore {
  11 +
  12 + private List<ManagedType> managedTypes = null;
  13 +
  14 +
  15 + public List<ManagedType> getManagedTypes() {
  16 + return managedTypes;
  17 + }
  18 +
  19 + public void setManagedTypes(List<ManagedType> managedTypes) {
  20 + this.managedTypes = managedTypes;
  21 + }
  22 +
  23 +}
... ...
impl/core/src/test/java/management/ManagementBootstrapTest.java 0 → 100644
... ... @@ -0,0 +1,68 @@
  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/test/Tests.java
... ... @@ -39,7 +39,6 @@ package test;
39 39 import java.io.File;
40 40  
41 41 import org.jboss.shrinkwrap.api.ShrinkWrap;
42   -import org.jboss.shrinkwrap.api.asset.EmptyAsset;
43 42 import org.jboss.shrinkwrap.api.asset.FileAsset;
44 43 import org.jboss.shrinkwrap.api.spec.JavaArchive;
45 44  
... ...
impl/core/src/test/resources/test/beans.xml
... ... @@ -2,10 +2,10 @@
2 2 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
3 3  
4 4 <interceptors>
  5 + <class>br.gov.frameworkdemoiselle.transaction.TransactionalInterceptor</class>
  6 + <class>br.gov.frameworkdemoiselle.security.RequiredPermissionInterceptor</class>
  7 + <class>br.gov.frameworkdemoiselle.security.RequiredRoleInterceptor</class>
5 8 <class>br.gov.frameworkdemoiselle.exception.ExceptionHandlerInterceptor</class>
6   - <class>br.gov.frameworkdemoiselle.internal.interceptor.RequiredPermissionInterceptor</class>
7   - <class>br.gov.frameworkdemoiselle.internal.interceptor.RequiredRoleInterceptor</class>
8   - <class>br.gov.frameworkdemoiselle.internal.interceptor.TransactionalInterceptor</class>
9 9 </interceptors>
10 10  
11 11 </beans>
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/ViewContext.java
... ... @@ -44,7 +44,7 @@ import br.gov.frameworkdemoiselle.util.Faces;
44 44 public class ViewContext extends AbstractCustomContext {
45 45  
46 46 public ViewContext() {
47   - super(ViewScoped.class, true);
  47 + super(ViewScoped.class);
48 48 }
49 49  
50 50 @Override
... ...