diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/MonitoringManager.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/MonitoringManager.java index bfaf2a4..2b00dd3 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/MonitoringManager.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/management/internal/MonitoringManager.java @@ -63,7 +63,10 @@ public class MonitoringManager { } /** - * Invoke an operation over a managed type. + *

Invoke an operation over a managed type.

+ * + *

This method is not thread-safe, it's the user's responsibility to + * make the operations of the managed type synchronized if necessary.

* * @param managedType * A type annotated with {@link Managed}. This method will create @@ -81,7 +84,7 @@ public class MonitoringManager { * In case the operation doesn't exist or have a different * signature */ - public synchronized Object invoke(ManagedType managedType, String actionName, + public Object invoke(ManagedType managedType, String actionName, Object[] params) { if ( managedTypes.contains(managedType) ) { activateContexts(managedType.getType()); @@ -112,14 +115,17 @@ public class MonitoringManager { } /** - * Retrieve the current value of a property from a managed type. Properties - * are attributes annotated with {@link Property}. + *

Retrieve the current value of a property from a managed type. Properties + * are attributes annotated with {@link Property}.

+ * + *

This method is not thread-safe, it's the user's responsibility to + * create the property's access methods from the managed type synchronized if necessary.

* * @param managedType The type that has the property the client wants to know the value of. * @param propertyName The name of the property * @return The current value of the property */ - public synchronized Object getProperty(ManagedType managedType, String propertyName) { + public Object getProperty(ManagedType managedType, String propertyName) { if ( managedTypes.contains(managedType) ) { Method getterMethod = managedType.getFields().get(propertyName).getGetterMethod(); @@ -153,14 +159,17 @@ public class MonitoringManager { } /** - * Sets a new value for a property contained inside a managed type. A property - * is an attribute annotated with {@link Property}. + *

Sets a new value for a property contained inside a managed type. A property + * is an attribute annotated with {@link Property}.

+ * + *

This method is not thread-safe, it's the user's responsibility to + * create the property's access methods from the managed type synchronized if necessary.

* * @param managedType The type that has access to the property * @param propertyName The name of the property * @param newValue The new value of the property */ - public synchronized void setProperty(ManagedType managedType, String propertyName, + public void setProperty(ManagedType managedType, String propertyName, Object newValue) { if ( managedTypes.contains(managedType) ) { diff --git a/impl/core/src/test/java/management/ManagedClassStore.java b/impl/core/src/test/java/management/ManagedClassStore.java deleted file mode 100644 index 5645590..0000000 --- a/impl/core/src/test/java/management/ManagedClassStore.java +++ /dev/null @@ -1,25 +0,0 @@ -package management; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.enterprise.context.ApplicationScoped; - -import br.gov.frameworkdemoiselle.management.internal.ManagedType; - -@ApplicationScoped -public class ManagedClassStore { - - private List managedTypes = new ArrayList(); - - - public List getManagedTypes() { - return managedTypes; - } - - public void addManagedTypes(Collection managedTypes){ - this.managedTypes.addAll(managedTypes); - } - -} diff --git a/impl/core/src/test/java/management/ManagementBootstrapTestCase.java b/impl/core/src/test/java/management/ManagementBootstrapTestCase.java index 50d30be..73c93f8 100644 --- a/impl/core/src/test/java/management/ManagementBootstrapTestCase.java +++ b/impl/core/src/test/java/management/ManagementBootstrapTestCase.java @@ -6,6 +6,7 @@ import java.util.List; import management.testclasses.DummyManagedClass; import management.testclasses.DummyManagedClassPropertyError; import management.testclasses.DummyManagementExtension; +import management.testclasses.ManagedClassStore; import org.jboss.arquillian.container.test.api.Deployer; import org.jboss.arquillian.container.test.api.Deployment; @@ -44,7 +45,7 @@ public class ManagementBootstrapTestCase { new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"), "services/javax.enterprise.inject.spi.Extension") .addPackages(false, ManagementBootstrapTestCase.class.getPackage()) - .addClasses(DummyManagementExtension.class,DummyManagedClass.class); + .addClasses(DummyManagementExtension.class,DummyManagedClass.class,ManagedClassStore.class); } /** @@ -63,7 +64,7 @@ public class ManagementBootstrapTestCase { new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"), "services/javax.enterprise.inject.spi.Extension") .addPackages(false, ManagementBootstrapTestCase.class.getPackage()) - .addClasses(DummyManagementExtension.class,DummyManagedClassPropertyError.class); + .addClasses(DummyManagementExtension.class,DummyManagedClassPropertyError.class,ManagedClassStore.class); } /** diff --git a/impl/core/src/test/java/management/ManagementTestCase.java b/impl/core/src/test/java/management/ManagementTestCase.java new file mode 100644 index 0000000..4df0bff --- /dev/null +++ b/impl/core/src/test/java/management/ManagementTestCase.java @@ -0,0 +1,128 @@ +package management; + +import java.io.File; + +import junit.framework.Assert; +import management.testclasses.DummyManagedClass; +import management.testclasses.DummyManagementExtension; +import management.testclasses.ManagedClassStore; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.FileAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import test.LocaleProducer; +import br.gov.frameworkdemoiselle.DemoiselleException; +import br.gov.frameworkdemoiselle.util.Beans; + +/** + * Test case that simulates a management extension and tests if properties and operations on a managed class can be + * easily accessed and invoked. + * + * @author serpro + */ +@RunWith(Arquillian.class) +public class ManagementTestCase { + + @Deployment + public static JavaArchive createMultithreadedDeployment() { + return ShrinkWrap + .create(JavaArchive.class) + .addClass(LocaleProducer.class) + .addPackages(true, "br") + .addAsResource(new FileAsset(new File("src/test/resources/test/beans.xml")), "beans.xml") + .addAsManifestResource( + new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"), + "services/javax.enterprise.inject.spi.Extension") + .addPackages(false, ManagementTestCase.class.getPackage()) + .addClasses(DummyManagementExtension.class, DummyManagedClass.class, ManagedClassStore.class); + } + + @Test + public void testReadProperty() { + DummyManagedClass managedClass = Beans.getReference(DummyManagedClass.class); + managedClass.setName("Test Name"); + + // store é nossa extensão de gerenciamento falsa, então estamos testando um "cliente" acessando + // nosso tipo gerenciado DummyManagedClass remotamente. + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); + Object name = store.getProperty(DummyManagedClass.class, "name"); + Assert.assertEquals("Test Name", name); + } + + @Test + public void testWriteProperty() { + // store é nossa extensão de gerenciamento falsa, então estamos testando um "cliente" definindo + // um novo valor em uma propriedade de nosso tipo gerenciado DummyManagedClass remotamente. + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); + store.setProperty(DummyManagedClass.class, "name", "Test Name"); + + DummyManagedClass managedClass = Beans.getReference(DummyManagedClass.class); + Assert.assertEquals("Test Name", managedClass.getName()); + } + + @Test + public void testReadAWriteOnly() { + + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); + + try { + store.getProperty(DummyManagedClass.class, "writeOnlyProperty"); + Assert.fail(); + } catch (DemoiselleException de) { + // SUCCESS + } + + } + + @Test + public void testWriteAReadOnly() { + + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); + + try { + store.setProperty(DummyManagedClass.class, "readOnlyProperty", "New Value"); + Assert.fail(); + } catch (DemoiselleException de) { + // SUCCESS + } + + } + + @Test + public void testInvokeOperation() { + + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); + + try { + store.setProperty(DummyManagedClass.class, "firstFactor", new Integer(10)); + store.setProperty(DummyManagedClass.class, "secondFactor", new Integer(15)); + Integer response = (Integer) store.invoke(DummyManagedClass.class, "sumFactors"); + Assert.assertEquals(new Integer(25), response); + } catch (DemoiselleException de) { + Assert.fail(de.getMessage()); + } + + } + + @Test + public void testInvokeNonAnnotatedOperation() { + + ManagedClassStore store = Beans.getReference(ManagedClassStore.class); + + try { + // O método "nonOperationAnnotatedMethod" existe na classe DummyManagedClass, mas não está anotado como + // "@Operation", então + // ela não pode ser exposta para extensões. + store.invoke(DummyManagedClass.class, "nonOperationAnnotatedMethod"); + Assert.fail(); + } catch (DemoiselleException de) { + // SUCCESS + } + + } +} diff --git a/impl/core/src/test/java/management/NotificationTestCase.java b/impl/core/src/test/java/management/NotificationTestCase.java index 0165f5e..b37a000 100644 --- a/impl/core/src/test/java/management/NotificationTestCase.java +++ b/impl/core/src/test/java/management/NotificationTestCase.java @@ -53,7 +53,7 @@ public class NotificationTestCase { .addAsManifestResource( new File("src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension"), "services/javax.enterprise.inject.spi.Extension") - .addPackages(false, ManagementBootstrapTestCase.class.getPackage()) + .addPackages(false, NotificationTestCase.class.getPackage()) .addClasses(DummyNotificationListener.class,DummyManagedClass.class); } diff --git a/impl/core/src/test/java/management/testclasses/DummyManagedClass.java b/impl/core/src/test/java/management/testclasses/DummyManagedClass.java index 5d0b9b0..a041d14 100644 --- a/impl/core/src/test/java/management/testclasses/DummyManagedClass.java +++ b/impl/core/src/test/java/management/testclasses/DummyManagedClass.java @@ -12,15 +12,24 @@ import br.gov.frameworkdemoiselle.management.annotation.validation.AllowedValues public class DummyManagedClass { @Property + private String name; + + @Property @AllowedValues(allows={"f","m","F","M"},valueType=ValueType.INTEGER) private Integer id; @Property + private Integer firstFactor , secondFactor; + + @Property private String uuid; @Property private String writeOnlyProperty; + @Property + private String readOnlyProperty = "Default Value"; + /** * Propriedade para testar detecção de métodos GET e SET quando propriedade tem apenas uma letra. */ @@ -71,4 +80,87 @@ public class DummyManagedClass { this.uuid = UUID.randomUUID().toString(); return this.uuid; } + + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + + public String getReadOnlyProperty() { + return readOnlyProperty; + } + + + public Integer getFirstFactor() { + return firstFactor; + } + + + public void setFirstFactor(Integer firstFactor) { + this.firstFactor = firstFactor; + } + + + public Integer getSecondFactor() { + return secondFactor; + } + + + public void setSecondFactor(Integer secondFactor) { + this.secondFactor = secondFactor; + } + + @Operation + public Integer calculateFactorsNonSynchronized(Integer firstFactor , Integer secondFactor){ + setFirstFactor(firstFactor); + setSecondFactor(secondFactor); + + try { + int temp = firstFactor + secondFactor; + Thread.sleep( (long)(Math.random() * 100)); + + temp = temp + firstFactor; + Thread.sleep( (long)(Math.random() * 100)); + + temp = temp + secondFactor; + Thread.sleep( (long)(Math.random() * 100)); + + return temp; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Operation + public synchronized Integer calculateFactorsSynchronized(Integer firstFactor , Integer secondFactor){ + setFirstFactor(firstFactor); + setSecondFactor(secondFactor); + + try { + int temp = firstFactor + secondFactor; + Thread.sleep( (long)(Math.random() * 100)); + + temp = temp + firstFactor; + Thread.sleep( (long)(Math.random() * 100)); + + temp = temp + secondFactor; + Thread.sleep( (long)(Math.random() * 100)); + + return temp; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + public void nonOperationAnnotatedMethod(){ + System.out.println("Test"); + } + + } diff --git a/impl/core/src/test/java/management/testclasses/DummyManagementExtension.java b/impl/core/src/test/java/management/testclasses/DummyManagementExtension.java index a1e0c3b..8ce01af 100644 --- a/impl/core/src/test/java/management/testclasses/DummyManagementExtension.java +++ b/impl/core/src/test/java/management/testclasses/DummyManagementExtension.java @@ -4,7 +4,6 @@ import java.util.List; import javax.inject.Inject; -import management.ManagedClassStore; import br.gov.frameworkdemoiselle.management.extension.ManagementExtension; import br.gov.frameworkdemoiselle.management.internal.ManagedType; diff --git a/impl/core/src/test/java/management/testclasses/ManagedClassStore.java b/impl/core/src/test/java/management/testclasses/ManagedClassStore.java new file mode 100644 index 0000000..94a907d --- /dev/null +++ b/impl/core/src/test/java/management/testclasses/ManagedClassStore.java @@ -0,0 +1,66 @@ +package management.testclasses; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.enterprise.context.ApplicationScoped; + +import br.gov.frameworkdemoiselle.management.internal.ManagedType; +import br.gov.frameworkdemoiselle.management.internal.MonitoringManager; +import br.gov.frameworkdemoiselle.util.Beans; + +/** + * Dummy class that stores managed types detected by the management bootstrap + * and can read/write properties and invoke operations on them, simulating a management + * extension like JMX or SNMP. + * + * @author serpro + * + */ +@ApplicationScoped +public class ManagedClassStore { + + private List managedTypes = new ArrayList(); + + + public List getManagedTypes() { + return managedTypes; + } + + public void addManagedTypes(Collection managedTypes){ + this.managedTypes.addAll(managedTypes); + } + + public void setProperty(Class managedClass , String attributeName , Object newValue){ + MonitoringManager manager = Beans.getReference(MonitoringManager.class); + for (ManagedType type : manager.getManagedTypes()){ + if (type.getType().equals(managedClass)){ + manager.setProperty(type, attributeName, newValue); + break; + } + } + } + + public Object getProperty(Class managedClass , String attributeName ){ + MonitoringManager manager = Beans.getReference(MonitoringManager.class); + for (ManagedType type : manager.getManagedTypes()){ + if (type.getType().equals(managedClass)){ + return manager.getProperty(type, attributeName); + } + } + + return null; + } + + public Object invoke(Class managedClass , String operation , Object... params){ + MonitoringManager manager = Beans.getReference(MonitoringManager.class); + for (ManagedType type : manager.getManagedTypes()){ + if (type.getType().equals(managedClass)){ + return manager.invoke(type, operation, params); + } + } + + return null; + } +} -- libgit2 0.21.2