User: ejort
Date: 02/04/14 08:28:07
Modified: src/main/org/jboss/mx/server MBeanServerImpl.java
ServerConstants.java
Added: src/main/org/jboss/mx/server NotificationListenerProxy.java
Log:
POJO Registry and correct Notification source from the MBeanServer
Revision Changes Path
1.22 +251 -18 jmx/src/main/org/jboss/mx/server/MBeanServerImpl.java
Index: MBeanServerImpl.java
===================================================================
RCS file: /cvsroot/jboss/jmx/src/main/org/jboss/mx/server/MBeanServerImpl.java,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- MBeanServerImpl.java 9 Apr 2002 00:08:32 -0000 1.21
+++ MBeanServerImpl.java 14 Apr 2002 15:28:07 -0000 1.22
@@ -51,9 +51,13 @@
import java.io.ObjectInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -91,7 +95,7 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Juha Lindfors</a>.
* @author <a href="mailto:[EMAIL PROTECTED]">Trevor Squires</a>.
* @author <a href="mailto:[EMAIL PROTECTED]">Adrian Brock</a>.
- * @version $Revision: 1.21 $
+ * @version $Revision: 1.22 $
*/
public class MBeanServerImpl
implements MBeanServer, ServerConstants
@@ -116,10 +120,16 @@
protected MBeanRegistry registry = null;
/**
- * Registry proxy, used for dynamic invocations on register/unregister
+ * Registry MBean, used for dynamic invocations on register/unregister
*/
- protected MBeanRegistry registryProxy = null;
-
+ protected ObjectName registryName = null;
+
+ /**
+ * The notification listener proxies. It is a map of object names
+ * to another map of listeners to another map of handback objects to
+ * proxies. Phew!
+ */
+ private Map listenerProxies = Collections.synchronizedMap(new HashMap());
// Static --------------------------------------------------------
@@ -172,16 +182,22 @@
throw new RuntimeException("Unable to create the MBean registry instance.
Class " + registryClass + " has raised an exception in constructor: " +
e.getTargetException().toString());
}
- // Get a proxy for dynamic invocation on the proxy
+ /**
+ * Check for a mbean version of the registry
+ */
try
{
- ObjectName name = new ObjectName(MBEAN_REGISTRY);
- registryProxy = (MBeanRegistry) MBeanProxy.get(MBeanRegistry.class,
- name, this);
+ registryName = new ObjectName(MBEAN_REGISTRY);
+ registry.get(registryName);
+ }
+ catch (MalformedObjectNameException e)
+ {
+ throw new RuntimeException("The registry name is not valid +: " +
MBEAN_REGISTRY);
}
- catch (Exception e)
+ catch (InstanceNotFoundException e)
{
- throw new Error("Error generating registry proxy: " + e.toString());
+ // POJO Registry
+ registryName = null;
}
}
@@ -264,7 +280,36 @@
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException
{
- registryProxy.unregisterMBean(name);
+ // Get the mbean to remove
+ Object mbean = registry.get(name).getResourceInstance();
+
+ // Dynamic Invocation
+ if (registryName != null)
+ {
+ try
+ {
+ invoke(registryName, "unregisterMBean",
+ new Object[] { name },
+ new String[] { ObjectName.class.getName() }
+ );
+ }
+ catch (Exception e)
+ {
+ Exception result = handleInvocationException(registryName, e);
+ if (result instanceof InstanceNotFoundException)
+ throw (InstanceNotFoundException) result;
+ if (result instanceof MBeanRegistrationException)
+ throw (MBeanRegistrationException) result;
+ throw new RuntimeException(result.toString());
+ }
+ }
+ else
+ // POJO Registry
+ registry.unregisterMBean(name);
+
+ // Unregistration worked, remove any proxies for a broadcaster
+ if (mbean instanceof NotificationBroadcaster)
+ removeListenerProxies((NotificationBroadcaster) mbean, name);
}
public ObjectInstance getObjectInstance(ObjectName name)
@@ -483,8 +528,6 @@
public void addNotificationListener(ObjectName name, NotificationListener
listener, NotificationFilter filter, Object handback)
throws InstanceNotFoundException
{
-
- // FIXME: need to set source on outgoing notifications
MBeanEntry entry = registry.get(name);
ClassLoader newTCL = entry.getClassLoader();
NotificationBroadcaster broadcaster = null;
@@ -497,6 +540,9 @@
throw new RuntimeOperationsException(e, "MBean " + name + " does not
implement the NotificationBroadcaster interface.");
}
+ NotificationListener proxy = createListenerProxy(entry.getObjectName(),
+ listener, handback);
+
Thread thread = Thread.currentThread();
ClassLoader oldTCL = thread.getContextClassLoader();
try
@@ -504,7 +550,7 @@
if (newTCL != oldTCL && newTCL != null)
thread.setContextClassLoader(newTCL);
- broadcaster.addNotificationListener(listener, filter, handback);
+ broadcaster.addNotificationListener(proxy, filter, handback);
}
finally
{
@@ -528,6 +574,10 @@
throw new RuntimeOperationsException(e, "MBean " + listener + " is not a
notification listener or " + name + " does not implement notification broadcaster
interface.");
}
+ NotificationListener proxy = createListenerProxy(entry.getObjectName(),
+ (NotificationListener)registry.get(listener).getResourceInstance(),
+ handback);
+
Thread thread = Thread.currentThread();
ClassLoader oldTCL = thread.getContextClassLoader();
try
@@ -535,7 +585,7 @@
if (newTCL != oldTCL && newTCL != null)
thread.setContextClassLoader(newTCL);
-
broadcaster.addNotificationListener((NotificationListener)registry.get(listener).getResourceInstance(),
filter, handback);
+ broadcaster.addNotificationListener(proxy, filter, handback);
}
finally
{
@@ -559,6 +609,8 @@
throw new RuntimeOperationsException(e, "MBean " + name + " does not
implement the NotificationBroadcaster interface.");
}
+ Iterator proxies = removeListenerProxies(entry.getObjectName(), listener);
+
Thread thread = Thread.currentThread();
ClassLoader oldTCL = thread.getContextClassLoader();
try
@@ -566,7 +618,10 @@
if (newTCL != oldTCL && newTCL != null)
thread.setContextClassLoader(newTCL);
- broadcaster.removeNotificationListener(listener);
+ // REVIEW: Try to remove all before throwing an exception?
+ while (proxies.hasNext())
+ broadcaster.removeNotificationListener(
+ (NotificationListener) proxies.next());
}
finally
{
@@ -590,6 +645,9 @@
throw new RuntimeOperationsException(e, "MBean " + name + " does not
implement the NotificationBroadcaster interface.");
}
+ Iterator proxies = removeListenerProxies(entry.getObjectName(),
+ (NotificationListener)registry.get(listener).getResourceInstance());
+
Thread thread = Thread.currentThread();
ClassLoader oldTCL = thread.getContextClassLoader();
try
@@ -597,7 +655,10 @@
if (newTCL != oldTCL && newTCL != null)
thread.setContextClassLoader(newTCL);
-
broadcaster.removeNotificationListener((NotificationListener)registry.get(listener).getResourceInstance());
+ // REVIEW: Try to remove all before throwing an exception?
+ while (proxies.hasNext())
+ broadcaster.removeNotificationListener(
+ (NotificationListener) proxies.next());
}
finally
{
@@ -859,10 +920,182 @@
MBeanRegistrationException,
NotCompliantMBeanException
{
- return registryProxy.registerMBean(object, name, cl, null);
+ // Dynamic Invocation
+ if (registryName != null)
+ {
+ try
+ {
+ return (ObjectInstance) invoke(registryName, "registerMBean",
+ new Object[] { object, name, cl, null },
+ new String[] { Object.class.getName(),
+ ObjectName.class.getName(),
+ ClassLoader.class.getName(),
+ Object.class.getName() }
+ );
+ }
+ catch (Exception e)
+ {
+ Exception result = handleInvocationException(registryName, e);
+ if (result instanceof InstanceAlreadyExistsException)
+ throw (InstanceAlreadyExistsException) result;
+ if (result instanceof MBeanRegistrationException)
+ throw (MBeanRegistrationException) result;
+ if (result instanceof NotCompliantMBeanException)
+ throw (NotCompliantMBeanException) result;
+ throw new RuntimeException(result.toString());
+ }
+ }
+ else
+ // POJO Registry
+ return registry.registerMBean(object, name, cl, null);
+ }
+
+ /**
+ * Add a notification listener proxy
+ *
+ * @param name the broadcaster's object name
+ * @param listener the original listener
+ * @return a proxy notification listener
+ * @exception IllegalArgumentException for a null listener
+ */
+ protected NotificationListener createListenerProxy(ObjectName name,
+ NotificationListener listener, Object handback)
+ {
+ // Sanity check
+ if (listener == null)
+ throw new IllegalArgumentException("Null listener");
+
+ NotificationListener result = null;
+
+ // Retrieve any previous listener or construct the data structure
+ HashMap listeners = (HashMap) listenerProxies.get(name);
+ HashMap handbacks = null;
+ if (listeners == null)
+ {
+ listeners = new HashMap();
+ listenerProxies.put(name, listeners);
+ handbacks = new HashMap();
+ listeners.put(listener, handbacks);
+ }
+ else
+ {
+ handbacks = (HashMap) listeners.get(listener);
+ if (handbacks == null)
+ {
+ handbacks = new HashMap();
+ listeners.put(listener, handbacks);
+ }
+ else
+ {
+ result = (NotificationListener) handbacks.get(handback);
+ if (result != null)
+ return result;
+ }
+ }
+
+ // Create a new proxy
+ result = new NotificationListenerProxy(name, listener);
+ handbacks.put(handback, result);
+ return result;
+ }
+
+ /**
+ * Remove notification listener proxies for a listener
+ *
+ * @param name the broadcaster's object name
+ * @param listener the original listener
+ * @return an iterator of notification listeners
+ */
+ protected Iterator removeListenerProxies(ObjectName name,
+ NotificationListener listener)
+ {
+ // See if we know this listener
+ HashMap listeners = (HashMap) listenerProxies.get(name);
+ if (listeners != null)
+ {
+ HashMap handbacks = (HashMap) listeners.remove(listener);
+ if (handbacks != null && handbacks.size() != 0)
+ return handbacks.values().iterator();
+ }
+
+ // Give the broadcaster chance to remove the original listener
+ // REVIEW: Is this correct? Or do we just throw a not found?
+ return Arrays.asList(new Object[]{ listener }).iterator();
+ }
+
+ /**
+ * Remove notification listener proxies for a broadcaster
+ *
+ * @param broadcaster the broadcaster implementation
+ * @param name the broadcaster's object name
+ */
+ protected void removeListenerProxies(NotificationBroadcaster broadcaster,
+ ObjectName name)
+ {
+ // See if we know this broadcaster
+ HashMap listeners = (HashMap) listenerProxies.remove(name);
+ if (listeners == null)
+ return;
+ Iterator listener = listeners.values().iterator();
+ while (listener.hasNext())
+ {
+ Iterator handback = ((HashMap) listener.next()).values().iterator();
+ while (handback.hasNext())
+ {
+ NotificationListener original = (NotificationListener) handback.next();
+ try
+ {
+ broadcaster.removeNotificationListener(original);
+ }
+ catch (Exception ignored)
+ {
+ }
+ }
+ }
}
// Private -------------------------------------------------------
+
+ /**
+ * Handles exceptions thrown by the implementation MBeans<p>
+ *
+ * Either returns a wrapped exception or throws a runtime exception
+ *
+ * @param name the ObjectName of the implementation invoked
+ * @param e the exception thrown by the invocation
+ * @return any wrapped exception
+ */
+ private Exception handleInvocationException(ObjectName name, Exception e)
+ {
+ // Return the wrapped exception
+ if (e instanceof MBeanException)
+ {
+ return ((MBeanException) e).getTargetException();
+ }
+ // The following are runtime errors, normally caused by the user
+ if (e instanceof RuntimeOperationsException)
+ {
+ throw ((RuntimeOperationsException) e).getTargetException();
+ }
+ if (e instanceof ReflectionException)
+ {
+ Exception target = ((ReflectionException) e).getTargetException();
+ if (target instanceof RuntimeException)
+ throw (RuntimeException) target;
+ else
+ throw new RuntimeException(target.toString());
+ }
+ if (e instanceof RuntimeMBeanException)
+ {
+ throw ((RuntimeMBeanException) e).getTargetException();
+ }
+ if (e instanceof RuntimeErrorException)
+ {
+ throw ((RuntimeErrorException) e).getTargetError();
+ }
+ // Don't know what to do with this, wrap it in a runtime error
+ throw new RuntimeException(e.toString());
+ }
/**
* Query an MBean against the query
1.8 +2 -2 jmx/src/main/org/jboss/mx/server/ServerConstants.java
Index: ServerConstants.java
===================================================================
RCS file: /cvsroot/jboss/jmx/src/main/org/jboss/mx/server/ServerConstants.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- ServerConstants.java 17 Mar 2002 10:22:50 -0000 1.7
+++ ServerConstants.java 14 Apr 2002 15:28:07 -0000 1.8
@@ -18,7 +18,7 @@
*
* @author <a href="mailto:[EMAIL PROTECTED]">Juha Lindfors</a>.
* @author <a href="mailto:[EMAIL PROTECTED]">Adrian Brock</a>.
- * @version $Revision: 1.7 $
+ * @version $Revision: 1.8 $
*
*/
public interface ServerConstants
@@ -73,7 +73,7 @@
/**
* The version of the implementation. This value can be retrieved from the MBean
server delegate.
*/
- final static String IMPLEMENTATION_VERSION = "1.0 Alpha 2";
+ final static String IMPLEMENTATION_VERSION = "1.1 Development";
/**
* The vendor of the implementation. This value can be retrieved from the MBean
server delegate.
1.1 jmx/src/main/org/jboss/mx/server/NotificationListenerProxy.java
Index: NotificationListenerProxy.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.mx.server;
import java.io.ObjectStreamException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
/**
* A notification listener used to forward notifications to listeners
* added through the mbean server.<p>
*
* The original source is replaced with the object name.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Adrian Brock</a>.
* @version $Revision: 1.1 $
*/
public class NotificationListenerProxy
implements NotificationListener
{
// Constants ---------------------------------------------------
// Attributes --------------------------------------------------
/**
* The original listener
*/
private NotificationListener listener;
/**
* The object name we are proxying
*/
private ObjectName name;
// Static ------------------------------------------------------
// Constructors ------------------------------------------------
/**
* Create a new Notification Listener Proxy
*
* @param name the object name
* @param listener the original listener
*/
public NotificationListenerProxy(ObjectName name,
NotificationListener listener)
{
this.name = name;
this.listener = listener;
}
// Public ------------------------------------------------------
// implementation NotificationListener -------------------------
public void handleNotification(Notification notification, Object handback)
{
if (notification == null)
return;
// Forward the notification with the object name as source
// FIXME: This overwrites the original source, there is no way
// to put it back with the current spec
notification.setSource(name);
listener.handleNotification(notification, handback);
}
// overrides ---------------------------------------------------
// Protected ---------------------------------------------------
// Private -----------------------------------------------------
// Inner classes -----------------------------------------------
}
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development