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