Author: rmannibucau
Date: Tue Nov 15 11:03:16 2011
New Revision: 1202127

URL: http://svn.apache.org/viewvc?rev=1202127&view=rev
Log:
enhancing the dynamic mbean proxy to manage remote connections

Added:
    
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicRemoteMBeanClient.java
      - copied, changed from r1201935, 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClient.java
Modified:
    openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/pom.xml
    
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/DynamicMBeanHandler.java
    
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/ObjectName.java
    
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClientTest.java

Modified: openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/pom.xml
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/pom.xml?rev=1202127&r1=1202126&r2=1202127&view=diff
==============================================================================
--- openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/pom.xml 
(original)
+++ openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/pom.xml Tue 
Nov 15 11:03:16 2011
@@ -37,6 +37,14 @@
           <target>1.6</target>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.9</version>
+        <configuration>
+          <argLine>-Dcom.sun.management.jmxremote.port=8243 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false</argLine>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
   <repositories>

Modified: 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/DynamicMBeanHandler.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/DynamicMBeanHandler.java?rev=1202127&r1=1202126&r2=1202127&view=diff
==============================================================================
--- 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/DynamicMBeanHandler.java
 (original)
+++ 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/DynamicMBeanHandler.java
 Tue Nov 15 11:03:16 2011
@@ -1,43 +1,61 @@
 package org.superbiz.dynamic.mbean;
 
+import javax.annotation.PreDestroy;
 import javax.management.Attribute;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanInfo;
 import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
+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.
+ *
  * @author rmannibucau
  */
 public class DynamicMBeanHandler implements InvocationHandler {
-    private Map<Method, ObjectName> objectNames = new 
ConcurrentHashMap<Method, ObjectName>();
+    private final Map<Method, ConnectionInfo> infos = new 
ConcurrentHashMap<Method, ConnectionInfo>();
 
     @Override public Object invoke(Object proxy, Method method, Object[] args) 
throws Throwable {
-        if (method.getDeclaringClass().equals(Object.class) && 
"toString".equals(method.getName())) {
+        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 MBeanServer server = ManagementFactory.getPlatformMBeanServer();
-        final String methodName = method.getName();
-        final ObjectName objectName = getObjectName(method);
-        final MBeanInfo infos = server.getMBeanInfo(objectName);
+        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]);
-            server.setAttribute(objectName, new Attribute(attributeName, 
args[0]));
+            && (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 server.getAttribute(objectName, attributeName);
+            final String attributeName = attributeName(infos, methodName, 
method.getReturnType());
+            return info.getAttribute(attributeName);
         }
         // operation
-        return server.invoke(objectName, methodName, args, 
getSignature(method));
+        return info.invoke(methodName, args, getSignature(method));
+    }
+
+    public Object destroy() {
+        for (ConnectionInfo info : infos.values()) {
+            info.clean();
+        }
+        infos.clear();
+        return null;
     }
 
     private String[] getSignature(Method method) {
@@ -62,7 +80,7 @@ public class DynamicMBeanHandler impleme
                     found = name;
                 }
             } else if (found == null && ((lowerName.equals(name) && 
!attributeName.equals(name))
-                                                || 
lowerName.equalsIgnoreCase(name))) {
+                || lowerName.equalsIgnoreCase(name))) {
                 foundBackUp = name;
                 if (attribute.getType().equals(type.getName())) {
                     found = name;
@@ -70,17 +88,20 @@ public class DynamicMBeanHandler impleme
             }
         }
 
-        if (found == null) {
+        if (found == null && foundBackUp == null) {
             throw new UnsupportedOperationException("cannot find attribute " + 
attributeName);
         }
 
-        return found;
+        if (found != null) {
+            return found;
+        }
+        return foundBackUp;
     }
 
-    private synchronized ObjectName getObjectName(Method method) throws 
MalformedObjectNameException {
-        if (!objectNames.containsKey(method)) {
-            synchronized (objectNames) {
-                if (!objectNames.containsKey(method)) { // double check for 
synchro
+    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();
@@ -92,10 +113,116 @@ public class DynamicMBeanHandler impleme
                             throw new UnsupportedOperationException("class or 
method should define the objectName to use for invocation: " + 
method.toGenericString());
                         }
                     }
-                    objectNames.put(method, new ObjectName(on.value()));
+                    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 objectNames.get(method);
+        return infos.get(method);
+    }
+
+    private abstract static class ConnectionInfo {
+        protected ObjectName objectName;
+
+        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
+            }
+        }
     }
 }

Modified: 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/ObjectName.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/ObjectName.java?rev=1202127&r1=1202126&r2=1202127&view=diff
==============================================================================
--- 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/ObjectName.java
 (original)
+++ 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/main/java/org/superbiz/dynamic/mbean/ObjectName.java
 Tue Nov 15 11:03:16 2011
@@ -14,4 +14,9 @@ import static java.lang.annotation.Reten
 @Retention(RUNTIME)
 public @interface ObjectName {
     String value();
+
+    // for remote usage only
+    String url() default "";
+    String user() default "";
+    String password() default "";
 }

Modified: 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClientTest.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClientTest.java?rev=1202127&r1=1202126&r2=1202127&view=diff
==============================================================================
--- 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClientTest.java
 (original)
+++ 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClientTest.java
 Tue Nov 15 11:03:16 2011
@@ -22,7 +22,8 @@ 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();
@@ -40,20 +41,36 @@ public class DynamicMBeanClientTest {
         }
     }
 
-    @Test public void get() throws Exception {
-        assertEquals(0, client.getCounter());
+    @Test public void localGet() throws Exception {
+        assertEquals(0, localClient.getCounter());
         ManagementFactory.getPlatformMBeanServer().setAttribute(objectName, 
new Attribute("Counter", 5));
-        assertEquals(5, client.getCounter());
+        assertEquals(5, localClient.getCounter());
     }
 
-    @Test public void set() throws Exception {
+    @Test public void localSet() throws Exception {
         assertEquals(0, ((Integer) 
ManagementFactory.getPlatformMBeanServer().getAttribute(objectName, 
"Counter")).intValue());
-        client.setCounter(8);
+        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() {

Copied: 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicRemoteMBeanClient.java
 (from r1201935, 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClient.java)
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicRemoteMBeanClient.java?p2=openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicRemoteMBeanClient.java&p1=openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClient.java&r1=1201935&r2=1202127&rev=1202127&view=diff
==============================================================================
--- 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicMBeanClient.java
 (original)
+++ 
openejb/trunk/openejb/examples/dynamic-proxy-to-access-mbean/src/test/java/org/superbiz/dynamic/mbean/DynamicRemoteMBeanClient.java
 Tue Nov 15 11:03:16 2011
@@ -2,6 +2,7 @@ package org.superbiz.dynamic.mbean;
 
 import org.apache.openejb.api.Proxy;
 
+import javax.annotation.PreDestroy;
 import javax.ejb.Singleton;
 
 /**
@@ -9,11 +10,13 @@ import javax.ejb.Singleton;
  */
 @Singleton
 @Proxy(DynamicMBeanHandler.class)
-@ObjectName(DynamicMBeanClient.OBJECT_NAME)
-public interface DynamicMBeanClient {
+@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();
 }


Reply via email to