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