Author: rmannibucau
Date: Thu Nov 17 09:39:37 2011
New Revision: 1203126

URL: http://svn.apache.org/viewvc?rev=1203126&view=rev
Log:
updating dynamic proxy mbean example README

Modified:
    openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/README.md

Modified: openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/README.md
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/README.md?rev=1203126&r1=1203125&r2=1203126&view=diff
==============================================================================
--- openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/README.md 
(original)
+++ openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/README.md Thu 
Nov 17 09:39:37 2011
@@ -17,122 +17,258 @@ it is easy to imagine a remote connectio
 
 Simply an annotation to get the object
 
-       package org.superbiz.dynamic.mbean;
-
-       import java.lang.annotation.Retention;
-       import java.lang.annotation.Target;
+    package org.superbiz.dynamic.mbean;
 
-       import static java.lang.annotation.ElementType.TYPE;
-       import static java.lang.annotation.RetentionPolicy.RUNTIME;
+    import java.lang.annotation.Retention;
+    import java.lang.annotation.Target;
 
-       @Target({TYPE, METHOD})
-       @Retention(RUNTIME)
-       public @interface ObjectName {
-               String value();
-       }
+    import static java.lang.annotation.ElementType.TYPE;
+    import static java.lang.annotation.ElementType.METHOD;
+    import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+    @Target({TYPE, METHOD})
+    @Retention(RUNTIME)
+    public @interface ObjectName {
+        String value();
+
+        // for remote usage only
+        String url() default "";
+        String user() default "";
+        String password() default "";
+    }
 
 ## DynamicMBeanHandler (thr proxy implementation)
 
-       package org.superbiz.dynamic.mbean;
+    package org.superbiz.dynamic.mbean;
 
-       import javax.management.Attribute;
-       import javax.management.MBeanAttributeInfo;
-       import javax.management.MBeanInfo;
-       import javax.management.MBeanServer;
-       import javax.management.MalformedObjectNameException;
-       import javax.management.ObjectName;
-       import java.lang.management.ManagementFactory;
-       import java.lang.reflect.InvocationHandler;
-       import java.lang.reflect.Method;
-       import java.util.Map;
-       import java.util.concurrent.ConcurrentHashMap;
-
-       public class DynamicMBeanHandler implements InvocationHandler {
-               private Map<Method, ObjectName> objectNames = new 
ConcurrentHashMap<Method, ObjectName>();
-
-               @Override public Object invoke(Object proxy, Method method, 
Object[] args) throws Throwable {
-                   if (method.getDeclaringClass().equals(Object.class) && 
"toString".equals(method.getName())) {
-                       return getClass().getSimpleName() + " Proxy";
-                   }
+    import javax.annotation.PreDestroy;
+    import javax.management.Attribute;
+    import javax.management.MBeanAttributeInfo;
+    import javax.management.MBeanInfo;
+    import javax.management.MBeanServer;
+    import javax.management.MBeanServerConnection;
+    import javax.management.ObjectName;
+    import javax.management.remote.JMXConnector;
+    import javax.management.remote.JMXConnectorFactory;
+    import javax.management.remote.JMXServiceURL;
+    import java.io.IOException;
+    import java.lang.management.ManagementFactory;
+    import java.lang.reflect.InvocationHandler;
+    import java.lang.reflect.Method;
+    import java.util.HashMap;
+    import java.util.Map;
+    import java.util.concurrent.ConcurrentHashMap;
+
+    /**
+     * Need a @PreDestroy method to disconnect the remote host when used in 
remote mode.
+     */
+    public class DynamicMBeanHandler implements InvocationHandler {
+        private final Map<Method, ConnectionInfo> infos = new 
ConcurrentHashMap<Method, ConnectionInfo>();
+
+        @Override public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
+            final String methodName = method.getName();
+            if (method.getDeclaringClass().equals(Object.class) && 
"toString".equals(methodName)) {
+                return getClass().getSimpleName() + " Proxy";
+            }
+            if (method.getAnnotation(PreDestroy.class) != null) {
+                return destroy();
+            }
+
+            final ConnectionInfo info = getConnectionInfo(method);
+            final MBeanInfo infos = info.getMBeanInfo();
+            if (methodName.startsWith("set") && methodName.length() > 3 && 
args != null && args.length == 1
+                && (Void.TYPE.equals(method.getReturnType()) || 
Void.class.equals(method.getReturnType()))) {
+                final String attributeName = attributeName(infos, methodName, 
method.getParameterTypes()[0]);
+                info.setAttribute(new Attribute(attributeName, args[0]));
+                return null;
+            } else if (methodName.startsWith("get") && (args == null || 
args.length == 0) && methodName.length() > 3) {
+                final String attributeName = attributeName(infos, methodName, 
method.getReturnType());
+                return info.getAttribute(attributeName);
+            }
+            // operation
+            return info.invoke(methodName, args, getSignature(method));
+        }
 
-                   final MBeanServer server = 
ManagementFactory.getPlatformMBeanServer();
-                   final String methodName = method.getName();
-                   final ObjectName objectName = getObjectName(method);
-                   final MBeanInfo infos = server.getMBeanInfo(objectName);
-                   if (methodName.startsWith("set") && methodName.length() > 3 
&& args != null && args.length == 1
-                           && (Void.TYPE.equals(method.getReturnType()) || 
Void.class.equals(method.getReturnType()))) {
-                       final String attributeName =  attributeName(infos, 
methodName, method.getParameterTypes()[0]);
-                       server.setAttribute(objectName, new 
Attribute(attributeName, args[0]));
-                       return null;
-                   } else if (methodName.startsWith("get") && (args == null || 
args.length == 0) && methodName.length() > 3) {
-                       final String attributeName =  attributeName(infos, 
methodName, method.getReturnType());
-                       return server.getAttribute(objectName, attributeName);
-                   }
-                   // operation
-                   return server.invoke(objectName, methodName, args, 
getSignature(method));
-               }
+        public Object destroy() {
+            for (ConnectionInfo info : infos.values()) {
+                info.clean();
+            }
+            infos.clear();
+            return null;
+        }
 
-               private String[] getSignature(Method method) {
-                   String[] args = new 
String[method.getParameterTypes().length];
-                   for (int i = 0; i < method.getParameterTypes().length; i++) 
{
-                       args[i] = method.getParameterTypes()[i].getName();
-                   }
-                   return args; // note: null should often work...
-               }
+        private String[] getSignature(Method method) {
+            String[] args = new String[method.getParameterTypes().length];
+            for (int i = 0; i < method.getParameterTypes().length; i++) {
+                args[i] = method.getParameterTypes()[i].getName();
+            }
+            return args; // note: null should often work...
+        }
 
-               private String attributeName(MBeanInfo infos, String 
methodName, Class<?> type) {
-                   String found = null;
-                   String foundBackUp = null; // without checking the type
-                   final String attributeName = methodName.substring(3, 
methodName.length());
-                   final String lowerName = 
Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4, 
methodName.length());
-
-                   for (MBeanAttributeInfo attribute : infos.getAttributes()) {
-                       final String name = attribute.getName();
-                       if (attributeName.equals(name)) {
-                           foundBackUp = attributeName;
-                           if (attribute.getType().equals(type.getName())) {
-                               found = name;
-                           }
-                       } else if (found == null && ((lowerName.equals(name) && 
!attributeName.equals(name))
-                                                           || 
lowerName.equalsIgnoreCase(name))) {
-                           foundBackUp = name;
-                           if (attribute.getType().equals(type.getName())) {
-                               found = name;
-                           }
-                       }
-                   }
+        private String attributeName(MBeanInfo infos, String methodName, 
Class<?> type) {
+            String found = null;
+            String foundBackUp = null; // without checking the type
+            final String attributeName = methodName.substring(3, 
methodName.length());
+            final String lowerName = 
Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4, 
methodName.length());
+
+            for (MBeanAttributeInfo attribute : infos.getAttributes()) {
+                final String name = attribute.getName();
+                if (attributeName.equals(name)) {
+                    foundBackUp = attributeName;
+                    if (attribute.getType().equals(type.getName())) {
+                        found = name;
+                    }
+                } else if (found == null && ((lowerName.equals(name) && 
!attributeName.equals(name))
+                    || lowerName.equalsIgnoreCase(name))) {
+                    foundBackUp = name;
+                    if (attribute.getType().equals(type.getName())) {
+                        found = name;
+                    }
+                }
+            }
+
+            if (found == null && foundBackUp == null) {
+                throw new UnsupportedOperationException("cannot find attribute 
" + attributeName);
+            }
+
+            if (found != null) {
+                return found;
+            }
+            return foundBackUp;
+        }
 
-                   if (found == null) {
-                       throw new UnsupportedOperationException("cannot find 
attribute " + attributeName);
-                   }
+        private synchronized ConnectionInfo getConnectionInfo(Method method) 
throws Exception {
+            if (!infos.containsKey(method)) {
+                synchronized (infos) {
+                    if (!infos.containsKey(method)) { // double check for 
synchro
+                        org.superbiz.dynamic.mbean.ObjectName on = 
method.getAnnotation(org.superbiz.dynamic.mbean.ObjectName.class);
+                        if (on == null) {
+                            Class<?> current = method.getDeclaringClass();
+                            do {
+                                on = 
method.getDeclaringClass().getAnnotation(org.superbiz.dynamic.mbean.ObjectName.class);
+                                current = current.getSuperclass();
+                            } while (on == null && current != null);
+                            if (on == null) {
+                                throw new UnsupportedOperationException("class 
or method should define the objectName to use for invocation: " + 
method.toGenericString());
+                            }
+                        }
+                        final ConnectionInfo info;
+                        if (on.url().isEmpty()) {
+                            info = new LocalConnectionInfo();
+                            ((LocalConnectionInfo) info).server = 
ManagementFactory.getPlatformMBeanServer(); // could use an id...
+                        } else {
+                            info = new RemoteConnectionInfo();
+                            final Map<String, String[]> environment = new 
HashMap<String, String[]>();
+                            if (!on.user().isEmpty()) {
+                                environment.put(JMXConnector.CREDENTIALS, new 
String[]{ on.user(), on.password() });
+                            }
+                            // ((RemoteConnectionInfo) info).connector = 
JMXConnectorFactory.newJMXConnector(new JMXServiceURL(on.url()), environment);
+                            ((RemoteConnectionInfo) info).connector = 
JMXConnectorFactory.connect(new JMXServiceURL(on.url()), environment);
+
+                        }
+                        info.objectName = new ObjectName(on.value());
+
+                        infos.put(method, info);
+                    }
+                }
+            }
+            return infos.get(method);
+        }
 
-                   return found;
-               }
+        private abstract static class ConnectionInfo {
+            protected ObjectName objectName;
 
-               private synchronized ObjectName getObjectName(Method method) 
throws MalformedObjectNameException {
-                   if (!objectNames.containsKey(method)) {
-                       synchronized (objectNames) {
-                           if (!objectNames.containsKey(method)) { // double 
check for synchro
-                               org.superbiz.dynamic.mbean.ObjectName on = 
method.getAnnotation(org.superbiz.dynamic.mbean.ObjectName.class);
-                               if (on == null) {
-                                   Class<?> current = 
method.getDeclaringClass();
-                                   do {
-                                       on = 
method.getDeclaringClass().getAnnotation(org.superbiz.dynamic.mbean.ObjectName.class);
-                                       current = current.getSuperclass();
-                                   } while (on == null && current != null);
-                                   if (on == null) {
-                                       throw new 
UnsupportedOperationException("class or method should define the objectName to 
use for invocation: " + method.toGenericString());
-                                   }
-                               }
-                               objectNames.put(method, new 
ObjectName(on.value()));
-                           }
-                       }
-                   }
-                   return objectNames.get(method);
-               }
-       }    
+            public abstract void setAttribute(Attribute attribute) throws 
Exception;
+            public abstract Object getAttribute(String attribute) throws 
Exception;
+            public abstract Object invoke(String operationName, Object 
params[], String signature[]) throws Exception;
+            public abstract MBeanInfo getMBeanInfo() throws Exception;
+            public abstract void clean();
+        }
+
+        private static class LocalConnectionInfo extends ConnectionInfo {
+            private MBeanServer server;
+
+            @Override public void setAttribute(Attribute attribute) throws 
Exception {
+                server.setAttribute(objectName, attribute);
+            }
+
+            @Override public Object getAttribute(String attribute) throws 
Exception {
+                return server.getAttribute(objectName, attribute);
+            }
+
+            @Override
+            public Object invoke(String operationName, Object[] params, 
String[] signature) throws Exception {
+                return server.invoke(objectName, operationName, params, 
signature);
+            }
+
+            @Override public MBeanInfo getMBeanInfo() throws Exception {
+                return server.getMBeanInfo(objectName);
+            }
+
+            @Override public void clean() {
+                // no-op
+            }
+        }
+
+        private static class RemoteConnectionInfo extends ConnectionInfo {
+            private JMXConnector connector;
+            private MBeanServerConnection connection;
+
+            private void before() throws IOException {
+                connection = connector.getMBeanServerConnection();
+            }
+
+            private void after() throws IOException {
+                // no-op
+            }
+
+            @Override public void setAttribute(Attribute attribute) throws 
Exception {
+                before();
+                connection.setAttribute(objectName, attribute);
+                after();
+            }
+
+            @Override public Object getAttribute(String attribute) throws 
Exception {
+                before();
+                try {
+                    return connection.getAttribute(objectName, attribute);
+                } finally {
+                    after();
+                }
+            }
+
+            @Override
+            public Object invoke(String operationName, Object[] params, 
String[] signature) throws Exception {
+                before();
+                try {
+                    return connection.invoke(objectName, operationName, 
params, signature);
+                } finally {
+                    after();
+                }
+            }
+
+            @Override public MBeanInfo getMBeanInfo() throws Exception {
+                before();
+                try {
+                    return connection.getMBeanInfo(objectName);
+                } finally {
+                    after();
+                }
+            }
+
+            @Override public void clean() {
+                try {
+                    connector.close();
+                } catch (IOException e) {
+                    // no-op
+                }
+            }
+        }
+    }
 
-## DynamicMBeanClient (the dynamic JMX client)
+## Dynamic Proxies    
+
+### DynamicMBeanClient (the dynamic JMX client)
 
        package org.superbiz.dynamic.mbean;
 
@@ -156,6 +292,28 @@ Simply an annotation to get the object
                int length(String aString);
        }
 
+### DynamicMBeanClient (the dynamic JMX client)
+    package org.superbiz.dynamic.mbean;
+
+    import org.apache.openejb.api.Proxy;
+
+    import javax.annotation.PreDestroy;
+    import javax.ejb.Singleton;
+
+
+    @Singleton
+    @Proxy(DynamicMBeanHandler.class)
+    @ObjectName(value = DynamicRemoteMBeanClient.OBJECT_NAME, url = 
"service:jmx:rmi:///jndi/rmi://localhost:8243/jmxrmi")
+    public interface DynamicRemoteMBeanClient {
+        static final String OBJECT_NAME = "test:group=DynamicMBeanClientTest";
+
+        int getCounter();
+        void setCounter(int i);
+        int length(String aString);
+
+        @PreDestroy void clean();
+    }
+
 ## The MBean used for the test
 
 ### SimpleMBean
@@ -194,66 +352,82 @@ Simply an annotation to get the object
 
 ## DynamicMBeanClientTest (The test)
 
-package org.superbiz.dynamic.mbean;
+    package org.superbiz.dynamic.mbean;
 
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.superbiz.dynamic.mbean.simple.Simple;
-
-import javax.ejb.EJB;
-import javax.ejb.Stateless;
-import javax.ejb.embeddable.EJBContainer;
-import javax.management.Attribute;
-import javax.management.ObjectName;
-import java.lang.management.ManagementFactory;
-
-import static junit.framework.Assert.assertEquals;
-
-public class DynamicMBeanClientTest {
-    private static ObjectName objectName;
-    private static EJBContainer container;
+    import org.junit.After;
+    import org.junit.AfterClass;
+    import org.junit.Before;
+    import org.junit.BeforeClass;
+    import org.junit.Test;
+    import org.superbiz.dynamic.mbean.simple.Simple;
+
+    import javax.ejb.EJB;
+    import javax.ejb.embeddable.EJBContainer;
+    import javax.management.Attribute;
+    import javax.management.ObjectName;
+    import java.lang.management.ManagementFactory;
+
+    import static junit.framework.Assert.assertEquals;
+
+    public class DynamicMBeanClientTest {
+        private static ObjectName objectName;
+        private static EJBContainer container;
 
-    @EJB private DynamicMBeanClient client;
+        @EJB private DynamicMBeanClient localClient;
+        @EJB private DynamicRemoteMBeanClient remoteClient;
 
-    @BeforeClass public static void start() {
-        container = EJBContainer.createEJBContainer();
-    }
+        @BeforeClass public static void start() {
+            container = EJBContainer.createEJBContainer();
+        }
 
-    @Before public void injectAndRegisterMBean() throws Exception {
-        container.getContext().bind("inject", this);
-        objectName = new ObjectName(DynamicMBeanClient.OBJECT_NAME);
-        ManagementFactory.getPlatformMBeanServer().registerMBean(new Simple(), 
objectName);
-    }
+        @Before public void injectAndRegisterMBean() throws Exception {
+            container.getContext().bind("inject", this);
+            objectName = new ObjectName(DynamicMBeanClient.OBJECT_NAME);
+            ManagementFactory.getPlatformMBeanServer().registerMBean(new 
Simple(), objectName);
+        }
 
-    @After public void unregisterMBean() throws Exception {
-        if (objectName != null) {
-            
ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName);
+        @After public void unregisterMBean() throws Exception {
+            if (objectName != null) {
+                
ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName);
+            }
         }
-    }
 
-    @Test public void get() throws Exception {
-        assertEquals(0, client.getCounter());
-        ManagementFactory.getPlatformMBeanServer().setAttribute(objectName, 
new Attribute("Counter", 5));
-        assertEquals(5, client.getCounter());
-    }
+        @Test public void localGet() throws Exception {
+            assertEquals(0, localClient.getCounter());
+            
ManagementFactory.getPlatformMBeanServer().setAttribute(objectName, new 
Attribute("Counter", 5));
+            assertEquals(5, localClient.getCounter());
+        }
 
-    @Test public void set() throws Exception {
-        assertEquals(0, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
-        client.setCounter(8);
-        assertEquals(8, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
-    }
+        @Test public void localSet() throws Exception {
+            assertEquals(0, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
+            localClient.setCounter(8);
+            assertEquals(8, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
+        }
 
-    @Test public void operation() {
-        assertEquals(7, client.length("openejb"));
-    }
+        @Test public void localOperation() {
+            assertEquals(7, localClient.length("openejb"));
+        }
+
+        @Test public void remoteGet() throws Exception {
+            assertEquals(0, remoteClient.getCounter());
+            
ManagementFactory.getPlatformMBeanServer().setAttribute(objectName, new 
Attribute("Counter", 5));
+            assertEquals(5, remoteClient.getCounter());
+        }
+
+        @Test public void remoteSet() throws Exception {
+            assertEquals(0, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
+            remoteClient.setCounter(8);
+            assertEquals(8, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
+        }
+
+        @Test public void remoteOperation() {
+            assertEquals(7, remoteClient.length("openejb"));
+        }
 
-    @AfterClass public static void close() {
-        if (container != null) {
-            container.close();
+        @AfterClass public static void close() {
+            if (container != null) {
+                container.close();
+            }
         }
     }
-}
 


Reply via email to