You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2011/11/17 10:39:37 UTC

svn commit: r1203126 - /openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/README.md

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();
+            }
         }
     }
-}