changeset 528:9145ff046bb4

5072476: RFE: support cascaded (federated) MBean Servers 6299231: Add support for named MBean Servers Summary: New javax.management.namespace package. Reviewed-by: emcmanus
author dfuchs
date Thu, 04 Sep 2008 14:46:36 +0200
parents 00ea8fc81867
children 71a5f3f55b9c d276b0716d13
files make/docs/CORE_PKGS.gmk src/share/classes/com/sun/jmx/defaults/JmxProperties.java src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java src/share/classes/com/sun/jmx/mbeanserver/Repository.java src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java src/share/classes/com/sun/jmx/mbeanserver/Util.java src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java src/share/classes/com/sun/jmx/namespace/RoutingProxy.java src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java src/share/classes/com/sun/jmx/namespace/package.html src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java src/share/classes/com/sun/jmx/namespace/serial/package.html src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java src/share/classes/javax/management/InstanceNotFoundException.java src/share/classes/javax/management/MBeanPermission.java src/share/classes/javax/management/MBeanServer.java src/share/classes/javax/management/MBeanServerDelegate.java src/share/classes/javax/management/MBeanServerFactory.java src/share/classes/javax/management/ObjectName.java src/share/classes/javax/management/event/EventClient.java src/share/classes/javax/management/event/EventClientDelegate.java src/share/classes/javax/management/namespace/JMXDomain.java src/share/classes/javax/management/namespace/JMXNamespace.java src/share/classes/javax/management/namespace/JMXNamespaceMBean.java src/share/classes/javax/management/namespace/JMXNamespacePermission.java src/share/classes/javax/management/namespace/JMXNamespaceView.java src/share/classes/javax/management/namespace/JMXNamespaces.java src/share/classes/javax/management/namespace/JMXRemoteNamespace.java src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java src/share/classes/javax/management/namespace/MBeanServerSupport.java src/share/classes/javax/management/namespace/VirtualEventManager.java src/share/classes/javax/management/namespace/package-info.java src/share/classes/javax/management/remote/JMXConnectorFactory.java src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java test/javax/management/ObjectName/ApplyWildcardTest.java test/javax/management/namespace/DomainCreationTest.java test/javax/management/namespace/EventWithNamespaceControlTest.java test/javax/management/namespace/EventWithNamespaceTest.java test/javax/management/namespace/ExportNamespaceTest.java test/javax/management/namespace/JMXDomainTest.java test/javax/management/namespace/JMXNamespaceSecurityTest.java test/javax/management/namespace/JMXNamespaceTest.java test/javax/management/namespace/JMXNamespaceViewTest.java test/javax/management/namespace/JMXNamespacesTest.java test/javax/management/namespace/JMXRemoteNamespaceTest.java test/javax/management/namespace/JMXRemoteTargetNamespace.java test/javax/management/namespace/LazyDomainTest.java test/javax/management/namespace/MXBeanRefTest.java test/javax/management/namespace/NamespaceController.java test/javax/management/namespace/NamespaceControllerMBean.java test/javax/management/namespace/NamespaceCreationTest.java test/javax/management/namespace/NamespaceNotificationsTest.java test/javax/management/namespace/NullDomainObjectNameTest.java test/javax/management/namespace/NullObjectNameTest.java test/javax/management/namespace/QueryNamesTest.java test/javax/management/namespace/RemoveNotificationListenerTest.java test/javax/management/namespace/RoutingServerProxyTest.java test/javax/management/namespace/SerialParamProcessorTest.java test/javax/management/namespace/SourceNamespaceTest.java test/javax/management/namespace/VirtualMBeanNotifTest.java test/javax/management/namespace/VirtualMBeanTest.java test/javax/management/namespace/VirtualNamespaceQueryTest.java test/javax/management/namespace/VirtualPropsTest.java test/javax/management/namespace/Wombat.java test/javax/management/namespace/WombatMBean.java test/javax/management/namespace/namespace.policy
diffstat 89 files changed, 25865 insertions(+), 2441 deletions(-) [+]
line wrap: on
line diff
--- a/make/docs/CORE_PKGS.gmk	Wed Sep 03 14:31:17 2008 +0200
+++ b/make/docs/CORE_PKGS.gmk	Thu Sep 04 14:46:36 2008 +0200
@@ -158,6 +158,7 @@
   javax.management.event                         \
   javax.management.loading                       \
   javax.management.monitor                       \
+  javax.management.namespace                     \
   javax.management.relation                      \
   javax.management.openmbean                     \
   javax.management.timer                         \
--- a/src/share/classes/com/sun/jmx/defaults/JmxProperties.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/defaults/JmxProperties.java	Thu Sep 04 14:46:36 2008 +0200
@@ -177,6 +177,18 @@
             "javax.management.relation";
 
     /**
+     * Logger name for Namespaces.
+     */
+    public static final String NAMESPACE_LOGGER_NAME =
+            "javax.management.namespace";
+
+     /**
+     * Logger name for Namespaces.
+     */
+    public static final Logger NAMESPACE_LOGGER =
+            Logger.getLogger(NAMESPACE_LOGGER_NAME);
+
+    /**
      * Logger for Relation Service.
      */
     public static final Logger RELATION_LOGGER =
--- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -25,33 +25,49 @@
 
 package com.sun.jmx.interceptor;
 
-// java import
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.WeakHashMap;
+
+// JMX RI
+import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
+import com.sun.jmx.mbeanserver.DynamicMBean2;
+import com.sun.jmx.mbeanserver.Introspector;
+import com.sun.jmx.mbeanserver.MBeanInjector;
+import com.sun.jmx.mbeanserver.MBeanInstantiator;
+import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
+import com.sun.jmx.mbeanserver.NamedObject;
+import com.sun.jmx.mbeanserver.NotifySupport;
+import com.sun.jmx.mbeanserver.Repository;
+import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.remote.util.EnvHelp;
+
 import java.lang.ref.WeakReference;
 import java.security.AccessControlContext;
+import java.security.AccessController;
 import java.security.Permission;
+import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
 
 // JMX import
 import javax.management.Attribute;
 import javax.management.AttributeList;
 import javax.management.AttributeNotFoundException;
 import javax.management.DynamicMBean;
+import javax.management.DynamicWrapperMBean;
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.IntrospectionException;
 import javax.management.InvalidAttributeValueException;
 import javax.management.JMRuntimeException;
 import javax.management.ListenerNotFoundException;
-import javax.management.MalformedObjectNameException;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
 import javax.management.MBeanPermission;
@@ -64,6 +80,7 @@
 import javax.management.NotCompliantMBeanException;
 import javax.management.Notification;
 import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
 import javax.management.NotificationEmitter;
 import javax.management.NotificationFilter;
 import javax.management.NotificationListener;
@@ -75,22 +92,7 @@
 import javax.management.RuntimeErrorException;
 import javax.management.RuntimeMBeanException;
 import javax.management.RuntimeOperationsException;
-
-// JMX RI
-import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
-import com.sun.jmx.mbeanserver.DynamicMBean2;
-import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
-import com.sun.jmx.mbeanserver.MBeanInstantiator;
-import com.sun.jmx.mbeanserver.Repository;
-import com.sun.jmx.mbeanserver.NamedObject;
-import com.sun.jmx.mbeanserver.Introspector;
-import com.sun.jmx.mbeanserver.MBeanInjector;
-import com.sun.jmx.mbeanserver.NotifySupport;
-import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
-import com.sun.jmx.mbeanserver.Util;
-import com.sun.jmx.remote.util.EnvHelp;
-import javax.management.DynamicWrapperMBean;
-import javax.management.NotificationBroadcasterSupport;
+import javax.management.namespace.JMXNamespace;
 
 /**
  * This is the default class for MBean manipulation on the agent side. It
@@ -113,7 +115,8 @@
  *
  * @since 1.5
  */
-public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
+public class DefaultMBeanServerInterceptor
+        extends MBeanServerInterceptorSupport {
 
     /** The MBeanInstantiator object used by the
      *  DefaultMBeanServerInterceptor */
@@ -123,7 +126,7 @@
      *  DefaultMBeanServerInterceptor */
     private transient MBeanServer server = null;
 
-    /** The MBean server object taht associated to the
+    /** The MBean server delegate object that is associated to the
      *  DefaultMBeanServerInterceptor */
     private final transient MBeanServerDelegate delegate;
 
@@ -138,13 +141,15 @@
                 new WeakHashMap<ListenerWrapper,
                                 WeakReference<ListenerWrapper>>();
 
+    private final NamespaceDispatchInterceptor dispatcher;
+
     /** The default domain of the object names */
     private final String domain;
 
-    /** True if the repository perform queries, false otherwise */
-    private boolean queryByRepo;
+    /** The mbeanServerName  */
+    private final String mbeanServerName;
 
-    /** The sequence number identifyng the notifications sent */
+    /** The sequence number identifying the notifications sent */
     // Now sequence number is handled by MBeanServerDelegate.
     // private int sequenceNumber=0;
 
@@ -162,11 +167,13 @@
      * @param instantiator The MBeanInstantiator that will be used to
      *        instantiate MBeans and take care of class loading issues.
      * @param repository The repository to use for this MBeanServer.
+     * @param dispatcher The dispatcher used by this MBeanServer
      */
     public DefaultMBeanServerInterceptor(MBeanServer         outer,
                                          MBeanServerDelegate delegate,
                                          MBeanInstantiator   instantiator,
-                                         Repository          repository)  {
+                                         Repository          repository,
+                                         NamespaceDispatchInterceptor dispatcher)  {
         if (outer == null) throw new
             IllegalArgumentException("outer MBeanServer cannot be null");
         if (delegate == null) throw new
@@ -181,6 +188,8 @@
         this.instantiator = instantiator;
         this.repository   = repository;
         this.domain       = repository.getDefaultDomain();
+        this.dispatcher   = dispatcher;
+        this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
     }
 
     public ObjectInstance createMBean(String className, ObjectName name)
@@ -259,8 +268,8 @@
             name = nonDefaultDomain(name);
         }
 
-        checkMBeanPermission(className, null, null, "instantiate");
-        checkMBeanPermission(className, null, name, "registerMBean");
+        checkMBeanPermission(mbeanServerName,className, null, null, "instantiate");
+        checkMBeanPermission(mbeanServerName,className, null, name, "registerMBean");
 
         /* Load the appropriate class. */
         if (withDefaultLoaderRepository) {
@@ -324,7 +333,7 @@
 
         final String infoClassName = getNewMBeanClassName(object);
 
-        checkMBeanPermission(infoClassName, null, name, "registerMBean");
+        checkMBeanPermission(mbeanServerName,infoClassName, null, name, "registerMBean");
         checkMBeanTrustPermission(theClass);
 
         return registerObject(infoClassName, object, name);
@@ -433,7 +442,8 @@
         DynamicMBean instance = getMBean(name);
         // may throw InstanceNotFoundException
 
-        checkMBeanPermission(instance, null, name, "unregisterMBean");
+        checkMBeanPermission(mbeanServerName, instance, null, name,
+                "unregisterMBean");
 
         if (instance instanceof MBeanRegistration)
             preDeregisterInvoke((MBeanRegistration) instance);
@@ -467,7 +477,8 @@
         name = nonDefaultDomain(name);
         DynamicMBean instance = getMBean(name);
 
-        checkMBeanPermission(instance, null, name, "getObjectInstance");
+        checkMBeanPermission(mbeanServerName,
+                instance, null, name, "getObjectInstance");
 
         final String className = getClassName(instance);
 
@@ -479,7 +490,7 @@
         if (sm != null) {
             // Check if the caller has the right to invoke 'queryMBeans'
             //
-            checkMBeanPermission((String) null, null, null, "queryMBeans");
+            checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryMBeans");
 
             // Perform query without "query".
             //
@@ -492,7 +503,7 @@
                 new HashSet<ObjectInstance>(list.size());
             for (ObjectInstance oi : list) {
                 try {
-                    checkMBeanPermission(oi.getClassName(), null,
+                    checkMBeanPermission(mbeanServerName,oi.getClassName(), null,
                                          oi.getObjectName(), "queryMBeans");
                     allowedList.add(oi);
                 } catch (SecurityException e) {
@@ -516,11 +527,6 @@
         //
         Set<NamedObject> list = repository.query(name, query);
 
-        if (queryByRepo) {
-            // The repository performs the filtering
-            query = null;
-        }
-
         return (objectInstancesFromFilteredNamedObjects(list, query));
     }
 
@@ -530,7 +536,7 @@
         if (sm != null) {
             // Check if the caller has the right to invoke 'queryNames'
             //
-            checkMBeanPermission((String) null, null, null, "queryNames");
+            checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryNames");
 
             // Perform query without "query".
             //
@@ -543,7 +549,7 @@
                 new HashSet<ObjectInstance>(list.size());
             for (ObjectInstance oi : list) {
                 try {
-                    checkMBeanPermission(oi.getClassName(), null,
+                    checkMBeanPermission(mbeanServerName, oi.getClassName(), null,
                                          oi.getObjectName(), "queryNames");
                     allowedList.add(oi);
                 } catch (SecurityException e) {
@@ -572,11 +578,6 @@
         //
         Set<NamedObject> list = repository.query(name, query);
 
-        if (queryByRepo) {
-            // The repository performs the filtering
-            query = null;
-        }
-
         return (objectNamesFromFilteredNamedObjects(list, query));
     }
 
@@ -589,8 +590,8 @@
 
         name = nonDefaultDomain(name);
 
-//      /* Permission check */
-//      checkMBeanPermission(null, null, name, "isRegistered");
+        /* No Permission check */
+        // isRegistered is always unchecked as per JMX spec.
 
         return (repository.contains(name));
     }
@@ -600,7 +601,7 @@
         if (sm != null) {
             // Check if the caller has the right to invoke 'getDomains'
             //
-            checkMBeanPermission((String) null, null, null, "getDomains");
+            checkMBeanPermission(mbeanServerName, (String) null, null, null, "getDomains");
 
             // Return domains
             //
@@ -612,8 +613,9 @@
             List<String> result = new ArrayList<String>(domains.length);
             for (int i = 0; i < domains.length; i++) {
                 try {
-                    ObjectName domain = Util.newObjectName(domains[i] + ":x=x");
-                    checkMBeanPermission((String) null, null, domain, "getDomains");
+                    ObjectName dom =
+                            Util.newObjectName(domains[i] + ":x=x");
+                    checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains");
                     result.add(domains[i]);
                 } catch (SecurityException e) {
                     // OK: Do not add this domain to the list
@@ -657,7 +659,8 @@
         }
 
         final DynamicMBean instance = getMBean(name);
-        checkMBeanPermission(instance, attribute, name, "getAttribute");
+        checkMBeanPermission(mbeanServerName, instance, attribute,
+                name, "getAttribute");
 
         try {
             return instance.getAttribute(attribute);
@@ -702,7 +705,7 @@
 
             // Check if the caller has the right to invoke 'getAttribute'
             //
-            checkMBeanPermission(classname, null, name, "getAttribute");
+            checkMBeanPermission(mbeanServerName, classname, null, name, "getAttribute");
 
             // Check if the caller has the right to invoke 'getAttribute'
             // on each specific attribute
@@ -711,14 +714,15 @@
                 new ArrayList<String>(attributes.length);
             for (String attr : attributes) {
                 try {
-                    checkMBeanPermission(classname, attr,
+                    checkMBeanPermission(mbeanServerName, classname, attr,
                                          name, "getAttribute");
                     allowedList.add(attr);
                 } catch (SecurityException e) {
                     // OK: Do not add this attribute to the list
                 }
             }
-            allowedAttributes = allowedList.toArray(new String[0]);
+            allowedAttributes =
+                    allowedList.toArray(new String[allowedList.size()]);
         }
 
         try {
@@ -756,7 +760,7 @@
         }
 
         DynamicMBean instance = getMBean(name);
-        checkMBeanPermission(instance, attribute.getName(),
+        checkMBeanPermission(mbeanServerName, instance, attribute.getName(),
                              name, "setAttribute");
 
         try {
@@ -799,7 +803,7 @@
 
             // Check if the caller has the right to invoke 'setAttribute'
             //
-            checkMBeanPermission(classname, null, name, "setAttribute");
+            checkMBeanPermission(mbeanServerName, classname, null, name, "setAttribute");
 
             // Check if the caller has the right to invoke 'setAttribute'
             // on each specific attribute
@@ -808,7 +812,7 @@
             for (Iterator i = attributes.iterator(); i.hasNext();) {
                 try {
                     Attribute attribute = (Attribute) i.next();
-                    checkMBeanPermission(classname, attribute.getName(),
+                    checkMBeanPermission(mbeanServerName, classname, attribute.getName(),
                                          name, "setAttribute");
                     allowedAttributes.add(attribute);
                 } catch (SecurityException e) {
@@ -832,7 +836,8 @@
         name = nonDefaultDomain(name);
 
         DynamicMBean instance = getMBean(name);
-        checkMBeanPermission(instance, operationName, name, "invoke");
+        checkMBeanPermission(mbeanServerName, instance, operationName,
+                name, "invoke");
         try {
             return instance.invoke(operationName, params, signature);
         } catch (Throwable t) {
@@ -934,8 +939,7 @@
                     "registerMBean", "ObjectName = " + name);
         }
 
-        ObjectName logicalName = name;
-        logicalName = preRegister(mbean, server, name);
+        ObjectName logicalName = preRegister(mbean, server, name);
 
         // preRegister returned successfully, so from this point on we
         // must call postRegister(false) if there is any problem.
@@ -961,16 +965,17 @@
 
             if (logicalName != name && logicalName != null) {
                 logicalName =
-                    ObjectName.getInstance(nonDefaultDomain(logicalName));
+                        ObjectName.getInstance(nonDefaultDomain(logicalName));
             }
 
-            checkMBeanPermission(classname, null, logicalName, "registerMBean");
+            checkMBeanPermission(mbeanServerName, classname, null, logicalName,
+                    "registerMBean");
 
             if (logicalName == null) {
                 final RuntimeException wrapped =
-                        new IllegalArgumentException("No object name specified");
+                    new IllegalArgumentException("No object name specified");
                 throw new RuntimeOperationsException(wrapped,
-                                                     "Exception occurred trying to register the MBean");
+                            "Exception occurred trying to register the MBean");
             }
 
             final Object resource = getResource(mbean);
@@ -987,13 +992,15 @@
             //
             context = registerWithRepository(resource, mbean, logicalName);
 
+
             registerFailed = false;
             registered = true;
+
         } finally {
             try {
                 postRegister(logicalName, mbean, registered, registerFailed);
             } finally {
-                if (registered) context.done();
+                if (registered && context!=null) context.done();
             }
         }
         return new ObjectInstance(logicalName, classname);
@@ -1001,20 +1008,19 @@
 
     private static void throwMBeanRegistrationException(Throwable t, String where)
     throws MBeanRegistrationException {
-        try {
-            throw t;
-        } catch (RuntimeException e) {
-                throw new RuntimeMBeanException(
-                        e, "RuntimeException thrown " + where);
-        } catch (Error er) {
-                throw new RuntimeErrorException(er, "Error thrown " + where);
-        } catch (MBeanRegistrationException r) {
-            throw r;
-        } catch (Exception ex) {
-            throw new MBeanRegistrationException(ex, "Exception thrown " + where);
-        } catch (Throwable t1) {
-            throw new RuntimeException(t);  // neither Error nor Exception??
-        }
+        if (t instanceof RuntimeException) {
+            throw new RuntimeMBeanException((RuntimeException)t,
+                    "RuntimeException thrown " + where);
+        } else if (t instanceof Error) {
+            throw new RuntimeErrorException((Error)t,
+                    "Error thrown " + where);
+        } else if (t instanceof MBeanRegistrationException) {
+            throw (MBeanRegistrationException)t;
+        } else if (t instanceof Exception) {
+            throw new MBeanRegistrationException((Exception)t,
+                    "Exception thrown " + where);
+        } else // neither Error nor Exception??
+            throw new RuntimeException(t);
     }
 
     private static ObjectName preRegister(
@@ -1230,7 +1236,8 @@
         }
 
         DynamicMBean instance = getMBean(name);
-        checkMBeanPermission(instance, null, name, "addNotificationListener");
+        checkMBeanPermission(mbeanServerName, instance, null,
+                name, "addNotificationListener");
 
         NotificationBroadcaster broadcaster =
                 getNotificationBroadcaster(name, instance,
@@ -1367,7 +1374,7 @@
         }
 
         DynamicMBean instance = getMBean(name);
-        checkMBeanPermission(instance, null, name,
+        checkMBeanPermission(mbeanServerName, instance, null, name,
                              "removeNotificationListener");
 
         /* We could simplify the code by assigning broadcaster after
@@ -1438,7 +1445,7 @@
             throw new JMRuntimeException("MBean " + name +
                                          "has no MBeanInfo");
 
-        checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo");
+        checkMBeanPermission(mbeanServerName, mbi.getClassName(), null, name, "getMBeanInfo");
 
         return mbi;
     }
@@ -1446,8 +1453,9 @@
     public boolean isInstanceOf(ObjectName name, String className)
         throws InstanceNotFoundException {
 
-        DynamicMBean instance = getMBean(name);
-        checkMBeanPermission(instance, null, name, "isInstanceOf");
+        final DynamicMBean instance = getMBean(name);
+        checkMBeanPermission(mbeanServerName,
+                instance, null, name, "isInstanceOf");
 
         try {
             Object resource = getResource(instance);
@@ -1498,7 +1506,8 @@
         throws InstanceNotFoundException {
 
         DynamicMBean instance = getMBean(mbeanName);
-        checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor");
+        checkMBeanPermission(mbeanServerName, instance, null, mbeanName,
+                "getClassLoaderFor");
         return getResourceLoader(instance);
     }
 
@@ -1513,12 +1522,13 @@
             throws InstanceNotFoundException {
 
         if (loaderName == null) {
-            checkMBeanPermission((String) null, null, null, "getClassLoader");
+            checkMBeanPermission(mbeanServerName, (String) null, null, null, "getClassLoader");
             return server.getClass().getClassLoader();
         }
 
         DynamicMBean instance = getMBean(loaderName);
-        checkMBeanPermission(instance, null, loaderName, "getClassLoader");
+        checkMBeanPermission(mbeanServerName, instance, null, loaderName,
+                "getClassLoader");
 
         Object resource = getResource(instance);
 
@@ -1568,7 +1578,7 @@
             }
         } else {
             // Access the filter
-            MBeanServer oldServer = QueryEval.getMBeanServer();
+            final MBeanServer oldServer = QueryEval.getMBeanServer();
             query.setMBeanServer(server);
             try {
                 for (NamedObject no : list) {
@@ -1817,26 +1827,30 @@
             return mbean.getMBeanInfo().getClassName();
     }
 
-    private static void checkMBeanPermission(DynamicMBean mbean,
+    private static void checkMBeanPermission(String mbeanServerName,
+                                             DynamicMBean mbean,
                                              String member,
                                              ObjectName objectName,
                                              String actions) {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            checkMBeanPermission(safeGetClassName(mbean),
+            checkMBeanPermission(mbeanServerName,
+                                 safeGetClassName(mbean),
                                  member,
                                  objectName,
                                  actions);
         }
     }
 
-    private static void checkMBeanPermission(String classname,
+    private static void checkMBeanPermission(String mbeanServerName,
+                                             String classname,
                                              String member,
                                              ObjectName objectName,
                                              String actions) {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            Permission perm = new MBeanPermission(classname,
+            Permission perm = new MBeanPermission(mbeanServerName,
+                                                  classname,
                                                   member,
                                                   objectName,
                                                   actions);
@@ -1902,6 +1916,12 @@
             throws InstanceAlreadyExistsException,
             MBeanRegistrationException {
 
+        // this will throw an exception if the pair (resource, logicalName)
+        // violates namespace conventions - for instance, if logicalName
+        // ends with // but resource is not a JMXNamespace.
+        //
+        checkResourceObjectNameConstraints(resource, logicalName);
+
         // Creates a registration context, if needed.
         //
         final ResourceContext context =
@@ -1967,6 +1987,57 @@
         return context;
     }
 
+
+    /**
+     * Checks that the ObjectName is legal with regards to the
+     * type of the MBean resource.
+     * If the MBean name is  domain:type=JMXDomain, the
+     *     MBean must be a JMXDomain.
+     * If the MBean name is  namespace//:type=JMXNamespace, the
+     *     MBean must be a JMXNamespace.
+     * If the MBean is a JMXDomain, its name
+     *      must be domain:type=JMXDomain.
+     * If the MBean is a JMXNamespace,  its name
+     *      must be namespace//:type=JMXNamespace.
+     */
+    private void checkResourceObjectNameConstraints(Object resource,
+            ObjectName logicalName)
+            throws MBeanRegistrationException {
+        try {
+            dispatcher.checkLocallyRegistrable(resource, logicalName);
+        } catch (Throwable x) {
+            DefaultMBeanServerInterceptor.throwMBeanRegistrationException(x, "validating ObjectName");
+        }
+    }
+
+    /**
+     * Registers a JMXNamespace with the dispatcher.
+     * This method is called by the ResourceContext from within the
+     * repository lock.
+     * @param namespace    The JMXNamespace
+     * @param logicalName  The JMXNamespaceMBean ObjectName
+     * @param postQueue    A queue that will be processed after postRegister.
+     */
+    private void addJMXNamespace(JMXNamespace namespace,
+            final ObjectName logicalName,
+            final Queue<Runnable> postQueue) {
+        dispatcher.addNamespace(logicalName, namespace, postQueue);
+    }
+
+    /**
+     * Unregisters a JMXNamespace from the dispatcher.
+     * This method is called by the ResourceContext from within the
+     * repository lock.
+     * @param namespace    The JMXNamespace
+     * @param logicalName  The JMXNamespaceMBean ObjectName
+     * @param postQueue    A queue that will be processed after postDeregister.
+     */
+    private void removeJMXNamespace(JMXNamespace namespace,
+            final ObjectName logicalName,
+            final Queue<Runnable> postQueue) {
+        dispatcher.removeNamespace(logicalName, namespace, postQueue);
+    }
+
     /**
      * Registers a ClassLoader with the CLR.
      * This method is called by the ResourceContext from within the
@@ -2020,6 +2091,52 @@
         }
     }
 
+
+    /**
+     * Creates a ResourceContext for a JMXNamespace MBean.
+     * The resource context makes it possible to add the JMXNamespace to
+     * (ResourceContext.registering) or resp. remove the JMXNamespace from
+     * (ResourceContext.unregistered) the NamespaceDispatchInterceptor
+     * when the associated MBean is added to or resp. removed from the
+     * repository.
+     * Note: JMXDomains are special sub classes of JMXNamespaces and
+     *       are also handled by this object.
+     *
+     * @param namespace    The JMXNamespace MBean being registered or
+     *                     unregistered.
+     * @param logicalName  The name of the JMXNamespace MBean.
+     * @return a ResourceContext that takes in charge the addition or removal
+     *         of the namespace to or from the NamespaceDispatchInterceptor.
+     */
+    private ResourceContext createJMXNamespaceContext(
+            final JMXNamespace namespace,
+            final ObjectName logicalName) {
+        final Queue<Runnable> doneTaskQueue = new LinkedList<Runnable>();
+        return new ResourceContext() {
+
+            public void registering() {
+                addJMXNamespace(namespace, logicalName, doneTaskQueue);
+            }
+
+            public void unregistered() {
+                removeJMXNamespace(namespace, logicalName,
+                                   doneTaskQueue);
+            }
+
+            public void done() {
+                for (Runnable r : doneTaskQueue) {
+                    try {
+                        r.run();
+                    } catch (RuntimeException x) {
+                        MBEANSERVER_LOGGER.log(Level.FINE,
+                                "Failed to process post queue for "+
+                                logicalName, x);
+                    }
+                }
+            }
+        };
+    }
+
     /**
      * Creates a ResourceContext for a ClassLoader MBean.
      * The resource context makes it possible to add the ClassLoader to
@@ -2065,10 +2182,16 @@
      */
     private ResourceContext makeResourceContextFor(Object resource,
             ObjectName logicalName) {
+        if (resource instanceof JMXNamespace) {
+            return createJMXNamespaceContext((JMXNamespace) resource,
+                    logicalName);
+        }
         if (resource instanceof ClassLoader) {
             return createClassLoaderContext((ClassLoader) resource,
                     logicalName);
         }
         return ResourceContext.NONE;
     }
+
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.interceptor;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.namespace.JMXNamespace;
+
+/**
+ * A dispatcher that dispatches to MBeanServers.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+//
+// This is the base class for implementing dispatchers. We have two concrete
+// dispatcher implementations:
+//
+//   * A NamespaceDispatchInterceptor, which dispatch calls to existing
+//     namespace interceptors
+//   * A DomainDispatchInterceptor, which dispatch calls to existing domain
+//     interceptors.
+//
+// With the JMX Namespaces feature, the JMX MBeanServer is now structured
+// as follows:
+//
+// The JMX MBeanServer delegates to a NamespaceDispatchInterceptor,
+// which either dispatches to a namespace, or delegates to the
+// DomainDispatchInterceptor (if the object name contained no namespace).
+// The DomainDispatchInterceptor in turn either dispatches to a domain (if
+// there is a JMXDomain for that domain) or delegates to the
+// DefaultMBeanServerInterceptor (if there is no JMXDomain for that
+// domain). This makes the following picture:
+//
+//             JMX MBeanServer (outer shell)
+//                          |
+//                          |
+//              NamespaceDispatchInterceptor
+//                   /               \
+//     no namespace in object name?   \
+//                 /                   \
+//                /                   dispatch to namespace
+//         DomainDispatchInterceptor
+//              /              \
+//    no JMXDomain for domain?  \
+//            /                  \
+//           /                   dispatch to domain
+//  DefaultMBeanServerInterceptor
+//         /
+//   invoke locally registered MBean
+//
+//  The logic for maintaining a map of interceptors
+//  and dispatching to impacted interceptor, is implemented in this
+//  base class, which both NamespaceDispatchInterceptor and
+//  DomainDispatchInterceptor extend.
+//
+public abstract class DispatchInterceptor
+        <T extends MBeanServer, N extends JMXNamespace>
+        extends MBeanServerInterceptorSupport {
+
+    /**
+     * This is an abstraction which allows us to handle queryNames
+     * and queryMBeans with the same algorithm. There are some subclasses
+     * where we need to override both queryNames & queryMBeans to apply
+     * the same transformation (usually aggregation of results when
+     * several namespaces/domains are impacted) to both algorithms.
+     * Usually the only thing that varies between the algorithm of
+     * queryNames & the algorithm of queryMBean is the type of objects
+     * in the returned Set. By using a QueryInvoker we can implement the
+     * transformation only once and apply it to both queryNames &
+     * queryMBeans.
+     * @see QueryInterceptor below, and its subclass in
+     * {@link DomainDispatcher}.
+     **/
+    static abstract class QueryInvoker<T> {
+        abstract Set<T> query(MBeanServer mbs,
+                        ObjectName pattern, QueryExp query);
+    }
+
+    /**
+     * Used to perform queryNames. A QueryInvoker that invokes
+     * queryNames on an MBeanServer.
+     **/
+    final static QueryInvoker<ObjectName> queryNamesInvoker =
+            new QueryInvoker<ObjectName>() {
+        Set<ObjectName> query(MBeanServer mbs,
+                        ObjectName pattern, QueryExp query) {
+            return mbs.queryNames(pattern,query);
+        }
+    };
+
+    /**
+     * Used to perform queryMBeans. A QueryInvoker that invokes
+     * queryMBeans on an MBeanServer.
+     **/
+    final static QueryInvoker<ObjectInstance> queryMBeansInvoker =
+            new QueryInvoker<ObjectInstance>() {
+        Set<ObjectInstance> query(MBeanServer mbs,
+                        ObjectName pattern, QueryExp query) {
+            return mbs.queryMBeans(pattern,query);
+        }
+    };
+
+    /**
+     * We use this class to intercept queries.
+     * There's a special case for JMXNamespace MBeans, because
+     * "namespace//*:*" matches both "namespace//domain:k=v" and
+     * "namespace//:type=JMXNamespace".
+     * Therefore, queries may need to be forwarded to more than
+     * on interceptor and the results aggregated...
+     */
+     static class QueryInterceptor {
+        final MBeanServer wrapped;
+        QueryInterceptor(MBeanServer mbs) {
+            wrapped = mbs;
+        }
+        <X> Set<X> query(ObjectName pattern, QueryExp query,
+                QueryInvoker<X> invoker, MBeanServer server) {
+            return invoker.query(server, pattern, query);
+        }
+
+        public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
+            return query(pattern,query,queryNamesInvoker,wrapped);
+        }
+
+        public Set<ObjectInstance> queryMBeans(ObjectName pattern,
+                QueryExp query) {
+            return query(pattern,query,queryMBeansInvoker,wrapped);
+        }
+    }
+
+    // We don't need a ConcurrentHashMap here because getkeys() returns
+    // an array of keys. Therefore there's no risk to have a
+    // ConcurrentModificationException. We must however take into
+    // account the fact that there can be no interceptor for
+    // some of the returned keys if the map is being modified by
+    // another thread, or by a callback within the same thread...
+    // See getKeys() in this class and query() in DomainDispatcher.
+    //
+    private final Map<String,T> handlerMap =
+            Collections.synchronizedMap(
+            new HashMap<String,T>());
+
+    // The key at which an interceptor for accessing the named MBean can be
+    // found in the handlerMap. Note: there doesn't need to be an interceptor
+    // for that key in the Map.
+    //
+    public abstract String getHandlerKey(ObjectName name);
+
+    // Returns an interceptor for that name, or null if there's no interceptor
+    // for that name.
+    abstract MBeanServer getInterceptorOrNullFor(ObjectName name);
+
+    // Returns a QueryInterceptor for that pattern.
+    abstract QueryInterceptor getInterceptorForQuery(ObjectName pattern);
+
+    // Returns the ObjectName of the JMXNamespace (or JMXDomain) for that
+    // key (a namespace or a domain name).
+    abstract ObjectName getHandlerNameFor(String key)
+        throws MalformedObjectNameException;
+
+    // Creates an interceptor for the given key, name, JMXNamespace (or
+    // JMXDomain). Note: this will be either a NamespaceInterceptor
+    // wrapping a JMXNamespace, if this object is an instance of
+    // NamespaceDispatchInterceptor, or a DomainInterceptor wrapping a
+    // JMXDomain, if this object is an instance of DomainDispatchInterceptor.
+    abstract T createInterceptorFor(String key, ObjectName name,
+            N jmxNamespace, Queue<Runnable> postRegisterQueue);
+    //
+    // The next interceptor in the chain.
+    //
+    // For the NamespaceDispatchInterceptor, this the DomainDispatchInterceptor.
+    // For the DomainDispatchInterceptor, this is the
+    // DefaultMBeanServerInterceptor.
+    //
+    // The logic of when to invoke the next interceptor in the chain depends
+    // on the logic of the concrete dispatcher class.
+    //
+    // For instance, the NamespaceDispatchInterceptor invokes the next
+    // interceptor when the object name doesn't contain any namespace.
+    //
+    // On the other hand, the DomainDispatchInterceptor invokes the
+    // next interceptor when there's no interceptor for the accessed domain.
+    //
+    abstract MBeanServer getNextInterceptor();
+
+    // hook for cleanup in subclasses.
+    void interceptorReleased(T interceptor,
+            Queue<Runnable> postDeregisterQueue) {
+        // hook
+    }
+
+    // Hook for subclasses.
+    MBeanServer getInterceptorForCreate(ObjectName name)
+        throws MBeanRegistrationException {
+        final MBeanServer ns = getInterceptorOrNullFor(name);
+        if (ns == null) // name cannot be null here.
+            throw new MBeanRegistrationException(
+                    new IllegalArgumentException("No such MBean handler: " +
+                        getHandlerKey(name) + " for " +name));
+        return ns;
+    }
+
+    // Hook for subclasses.
+    MBeanServer getInterceptorForInstance(ObjectName name)
+        throws InstanceNotFoundException {
+        final MBeanServer ns = getInterceptorOrNullFor(name);
+        if (ns == null) // name cannot be null here.
+            throw new InstanceNotFoundException(String.valueOf(name));
+        return ns;
+    }
+
+    // sanity checks
+    void validateHandlerNameFor(String key, ObjectName name) {
+        if (key == null || key.equals(""))
+            throw new IllegalArgumentException("invalid key for "+name+": "+key);
+        try {
+            final ObjectName handlerName = getHandlerNameFor(key);
+            if (!name.equals(handlerName))
+                throw new IllegalArgumentException("bad handler name: "+name+
+                        ". Should be: "+handlerName);
+        } catch (MalformedObjectNameException x) {
+            throw new IllegalArgumentException(name.toString(),x);
+        }
+    }
+
+    // Called by the DefaultMBeanServerInterceptor when an instance
+    // of JMXNamespace (or a subclass of it) is registered as an MBean.
+    // This method is usually invoked from within the repository lock,
+    // hence the necessity of the postRegisterQueue.
+    public void addNamespace(ObjectName name, N jmxNamespace,
+            Queue<Runnable> postRegisterQueue) {
+        final String key = getHandlerKey(name);
+        validateHandlerNameFor(key,name);
+        synchronized (handlerMap) {
+            final T exists =
+                    handlerMap.get(key);
+            if (exists != null)
+                throw new IllegalArgumentException(key+
+                        ": handler already exists");
+
+            final T ns = createInterceptorFor(key,name,jmxNamespace,
+                    postRegisterQueue);
+            handlerMap.put(key,ns);
+        }
+    }
+
+    // Called by the DefaultMBeanServerInterceptor when an instance
+    // of JMXNamespace (or a subclass of it) is deregistered.
+    // This method is usually invoked from within the repository lock,
+    // hence the necessity of the postDeregisterQueue.
+    public void removeNamespace(ObjectName name, N jmxNamespace,
+            Queue<Runnable> postDeregisterQueue) {
+        final String key = getHandlerKey(name);
+        final T ns;
+        synchronized(handlerMap) {
+            ns = handlerMap.remove(key);
+        }
+        interceptorReleased(ns,postDeregisterQueue);
+    }
+
+    // Get the interceptor for that key.
+    T getInterceptor(String key) {
+        synchronized (handlerMap) {
+            return handlerMap.get(key);
+        }
+    }
+
+    // We return an array of keys, which makes it possible to make
+    // concurrent modifications of the handlerMap, provided that
+    // the code which loops over the keys is prepared to handle null
+    // interceptors.
+    // See declaration of handlerMap above, and see also query() in
+    // DomainDispatcher
+    //
+    public String[] getKeys() {
+        synchronized (handlerMap) {
+            final int size = handlerMap.size();
+            return handlerMap.keySet().toArray(new String[size]);
+        }
+    }
+
+    // From MBeanServer
+    public ObjectInstance createMBean(String className, ObjectName name)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException {
+        return getInterceptorForCreate(name).createMBean(className,name);
+    }
+
+    // From MBeanServer
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                      ObjectName loaderName)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException, InstanceNotFoundException{
+        return getInterceptorForCreate(name).createMBean(className,name,loaderName);
+    }
+
+    // From MBeanServer
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                      Object params[], String signature[])
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException{
+        return getInterceptorForCreate(name).
+                createMBean(className,name,params,signature);
+    }
+
+    // From MBeanServer
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                      ObjectName loaderName, Object params[],
+                                      String signature[])
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException, InstanceNotFoundException{
+        return getInterceptorForCreate(name).createMBean(className,name,loaderName,
+                                                   params,signature);
+    }
+
+    // From MBeanServer
+    public ObjectInstance registerMBean(Object object, ObjectName name)
+            throws InstanceAlreadyExistsException, MBeanRegistrationException,
+                   NotCompliantMBeanException {
+        return getInterceptorForCreate(name).registerMBean(object,name);
+    }
+
+    // From MBeanServer
+    public void unregisterMBean(ObjectName name)
+            throws InstanceNotFoundException, MBeanRegistrationException {
+        getInterceptorForInstance(name).unregisterMBean(name);
+    }
+
+    // From MBeanServer
+    public ObjectInstance getObjectInstance(ObjectName name)
+            throws InstanceNotFoundException {
+        return getInterceptorForInstance(name).getObjectInstance(name);
+    }
+
+    // From MBeanServer
+    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        final QueryInterceptor mbs =
+                getInterceptorForQuery(name);
+        if (mbs == null)  return Collections.emptySet();
+        else return mbs.queryMBeans(name,query);
+    }
+
+    // From MBeanServer
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        final QueryInterceptor mbs =
+                getInterceptorForQuery(name);
+        if (mbs == null)  return Collections.emptySet();
+        else return mbs.queryNames(name,query);
+    }
+
+    // From MBeanServer
+    public boolean isRegistered(ObjectName name) {
+        final MBeanServer mbs = getInterceptorOrNullFor(name);
+        if (mbs == null) return false;
+        else return mbs.isRegistered(name);
+    }
+
+    // From MBeanServer
+    public Integer getMBeanCount() {
+        return getNextInterceptor().getMBeanCount();
+    }
+
+    // From MBeanServer
+    public Object getAttribute(ObjectName name, String attribute)
+            throws MBeanException, AttributeNotFoundException,
+                   InstanceNotFoundException, ReflectionException {
+        return getInterceptorForInstance(name).getAttribute(name,attribute);
+    }
+
+    // From MBeanServer
+    public AttributeList getAttributes(ObjectName name, String[] attributes)
+            throws InstanceNotFoundException, ReflectionException {
+        return getInterceptorForInstance(name).getAttributes(name,attributes);
+    }
+
+    // From MBeanServer
+    public void setAttribute(ObjectName name, Attribute attribute)
+            throws InstanceNotFoundException, AttributeNotFoundException,
+                   InvalidAttributeValueException, MBeanException,
+                   ReflectionException {
+        getInterceptorForInstance(name).setAttribute(name,attribute);
+    }
+
+    // From MBeanServer
+    public AttributeList setAttributes(ObjectName name,
+                                       AttributeList attributes)
+        throws InstanceNotFoundException, ReflectionException {
+        return getInterceptorForInstance(name).setAttributes(name,attributes);
+    }
+
+    // From MBeanServer
+    public Object invoke(ObjectName name, String operationName,
+                         Object params[], String signature[])
+            throws InstanceNotFoundException, MBeanException,
+                   ReflectionException {
+        return getInterceptorForInstance(name).invoke(name,operationName,params,
+                signature);
+    }
+
+    // From MBeanServer
+    public String getDefaultDomain() {
+        return getNextInterceptor().getDefaultDomain();
+    }
+
+    /**
+     * Returns the list of domains in which any MBean is currently
+     * registered.
+     */
+    public abstract String[] getDomains();
+
+    // From MBeanServer
+    public void addNotificationListener(ObjectName name,
+                                        NotificationListener listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+            throws InstanceNotFoundException {
+        getInterceptorForInstance(name).addNotificationListener(name,listener,filter,
+                handback);
+    }
+
+
+    // From MBeanServer
+    public void addNotificationListener(ObjectName name,
+                                        ObjectName listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+            throws InstanceNotFoundException {
+        getInterceptorForInstance(name).addNotificationListener(name,listener,filter,
+                handback);
+    }
+
+    // From MBeanServer
+    public void removeNotificationListener(ObjectName name,
+                                           ObjectName listener)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        getInterceptorForInstance(name).removeNotificationListener(name,listener);
+    }
+
+    // From MBeanServer
+    public void removeNotificationListener(ObjectName name,
+                                           ObjectName listener,
+                                           NotificationFilter filter,
+                                           Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        getInterceptorForInstance(name).removeNotificationListener(name,listener,filter,
+                handback);
+    }
+
+
+    // From MBeanServer
+    public void removeNotificationListener(ObjectName name,
+                                           NotificationListener listener)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        getInterceptorForInstance(name).removeNotificationListener(name,listener);
+    }
+
+    // From MBeanServer
+    public void removeNotificationListener(ObjectName name,
+                                           NotificationListener listener,
+                                           NotificationFilter filter,
+                                           Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        getInterceptorForInstance(name).removeNotificationListener(name,listener,filter,
+                handback);
+    }
+
+    // From MBeanServer
+    public MBeanInfo getMBeanInfo(ObjectName name)
+            throws InstanceNotFoundException, IntrospectionException,
+                   ReflectionException {
+        return getInterceptorForInstance(name).getMBeanInfo(name);
+    }
+
+
+    // From MBeanServer
+    public boolean isInstanceOf(ObjectName name, String className)
+            throws InstanceNotFoundException {
+        return getInterceptorForInstance(name).isInstanceOf(name,className);
+    }
+
+    // From MBeanServer
+    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+        throws InstanceNotFoundException {
+        return getInterceptorForInstance(mbeanName).getClassLoaderFor(mbeanName);
+    }
+
+    // From MBeanServer
+    public ClassLoader getClassLoader(ObjectName loaderName)
+        throws InstanceNotFoundException {
+        return getInterceptorForInstance(loaderName).getClassLoader(loaderName);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.interceptor;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.mbeanserver.MBeanInstantiator;
+import com.sun.jmx.mbeanserver.Repository;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.namespace.DomainInterceptor;
+import java.util.Queue;
+import java.util.Set;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.namespace.JMXDomain;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
+
+/**
+ * A dispatcher that dispatch incoming MBeanServer requests to
+ * DomainInterceptors.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+//
+// See comments in  DispatchInterceptor.
+//
+class DomainDispatchInterceptor
+        extends DispatchInterceptor<DomainInterceptor, JMXDomain> {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    private static final ObjectName ALL_DOMAINS =
+            JMXDomain.getDomainObjectName("*");
+
+
+    /**
+     *  A QueryInterceptor that perform & aggregates queries spanning several
+     *  domains.
+     */
+    final static class AggregatingQueryInterceptor extends QueryInterceptor {
+
+        private final DomainDispatchInterceptor parent;
+        AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) {
+            super(dispatcher.localNamespace);
+            parent = dispatcher;
+        }
+
+        /**
+         * Perform queryNames or queryMBeans, depending on which QueryInvoker
+         * is passed as argument. This is closures without closures.
+         **/
+        @Override
+        <T> Set<T> query(ObjectName pattern, QueryExp query,
+                QueryInvoker<T> invoker, MBeanServer localNamespace) {
+            final Set<T> local = invoker.query(localNamespace, pattern, query);
+
+            // Add all matching MBeans from local namespace.
+            final Set<T> res = Util.cloneSet(local);
+
+            final boolean all = (pattern == null ||
+                    pattern.getDomain().equals("*"));
+            if (pattern == null) pattern = ObjectName.WILDCARD;
+
+            final String domain = pattern.getDomain();
+
+            // If there's no domain pattern, just include the pattern's domain.
+            // Otherwiae, loop over all virtual domains (parent.getKeys()).
+            final String[] keys =
+                (pattern.isDomainPattern() ?
+                    parent.getKeys() : new String[]{domain});
+
+            // Add all matching MBeans from each virtual domain
+            //
+            for (String key : keys) {
+                // Only invoke those virtual domain which are selected
+                // by the domain pattern
+                //
+                if (!all && !Util.isDomainSelected(key, domain))
+                    continue;
+
+                try {
+                    final MBeanServer mbs = parent.getInterceptor(key);
+
+                    // mbs can be null if the interceptor was removed
+                    // concurrently...
+                    // See handlerMap and getKeys() in DispatchInterceptor
+                    //
+                    if (mbs == null) continue;
+
+                    // If the domain is selected, we can replace the pattern
+                    // by the actual domain. This is safer if we want to avoid
+                    // a domain (which could be backed up by an MBeanServer) to
+                    // return names from outside the domain.
+                    // So instead of asking the domain handler for "foo" to
+                    // return all names which match "?o*:type=Bla,*" we're
+                    // going to ask it to return all names which match
+                    // "foo:type=Bla,*"
+                    //
+                    final ObjectName subPattern = pattern.withDomain(key);
+                    res.addAll(invoker.query(mbs, subPattern, query));
+                } catch (Exception x) {
+                    LOG.finest("Ignoring exception " +
+                            "when attempting to query namespace "+key+": "+x);
+                    continue;
+                }
+            }
+            return res;
+        }
+    }
+
+    private final DefaultMBeanServerInterceptor localNamespace;
+    private final String mbeanServerName;
+    private final MBeanServerDelegate delegate;
+
+    /**
+     * Creates a DomainDispatchInterceptor with the specified
+     * repository instance.
+     *
+     * @param outer A pointer to the MBeanServer object that must be
+     *        passed to the MBeans when invoking their
+     *        {@link javax.management.MBeanRegistration} interface.
+     * @param delegate A pointer to the MBeanServerDelegate associated
+     *        with the new MBeanServer. The new MBeanServer must register
+     *        this MBean in its MBean repository.
+     * @param instantiator The MBeanInstantiator that will be used to
+     *        instantiate MBeans and take care of class loading issues.
+     * @param repository The repository to use for this MBeanServer
+     */
+    public DomainDispatchInterceptor(MBeanServer         outer,
+                            MBeanServerDelegate delegate,
+                            MBeanInstantiator   instantiator,
+                            Repository          repository,
+                            NamespaceDispatchInterceptor namespaces)  {
+           localNamespace = new DefaultMBeanServerInterceptor(outer,
+                   delegate, instantiator,repository,namespaces);
+           mbeanServerName = Util.getMBeanServerSecurityName(delegate);
+           this.delegate = delegate;
+    }
+
+    final boolean isLocalHandlerNameFor(String domain,
+            ObjectName handlerName) {
+        if (domain == null) return true;
+        return handlerName.getDomain().equals(domain) &&
+               JMXDomain.TYPE_ASSIGNMENT.equals(
+               handlerName.getKeyPropertyListString());
+    }
+
+    @Override
+    void validateHandlerNameFor(String key, ObjectName name) {
+        super.validateHandlerNameFor(key,name);
+        final String[] domains = localNamespace.getDomains();
+        for (int i=0;i<domains.length;i++) {
+            if (domains[i].equals(key))
+                throw new IllegalArgumentException("domain "+key+
+                        " is not empty");
+        }
+    }
+
+    @Override
+    final MBeanServer getInterceptorOrNullFor(ObjectName name) {
+        if (name == null) return localNamespace;
+        final String domain = name.getDomain();
+        if (domain.endsWith(NAMESPACE_SEPARATOR)) return localNamespace;
+        if (domain.contains(NAMESPACE_SEPARATOR)) return null;
+        final String localDomain = domain;
+        if (isLocalHandlerNameFor(localDomain,name)) {
+            LOG.finer("dispatching to local namespace");
+            return localNamespace;
+        }
+        final DomainInterceptor ns = getInterceptor(localDomain);
+        if (ns == null) {
+            if (LOG.isLoggable(Level.FINER)) {
+                LOG.finer("dispatching to local namespace: " + localDomain);
+            }
+            return getNextInterceptor();
+        }
+        if (LOG.isLoggable(Level.FINER)) {
+            LOG.finer("dispatching to domain: " + localDomain);
+        }
+        return ns;
+    }
+
+    private boolean multipleQuery(ObjectName pattern) {
+        if (pattern == null) return true;
+        if (pattern.isDomainPattern()) return true;
+
+        try {
+            // This is a bit of a hack. If there's any chance that a JMXDomain
+            // MBean name is selected by the given pattern then we must include
+            // the local namespace in our search.
+            // Returning true will have this effect.
+            if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain())))
+                return true;
+        } catch (MalformedObjectNameException x) {
+            // should not happen
+            throw new IllegalArgumentException(String.valueOf(pattern), x);
+        }
+        return false;
+    }
+
+    @Override
+    final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
+
+        // Check if we need to aggregate.
+        if (multipleQuery(pattern))
+            return new AggregatingQueryInterceptor(this);
+
+        // We don't need to aggregate: do the "simple" thing...
+        final String domain = pattern.getDomain();
+
+        // Do we have a virtual domain?
+        final DomainInterceptor ns = getInterceptor(domain);
+        if (ns != null) {
+            if (LOG.isLoggable(Level.FINER))
+                LOG.finer("dispatching to domain: " + domain);
+            return new QueryInterceptor(ns);
+        }
+
+        // We don't have a virtual domain. Send to local domains.
+        if (LOG.isLoggable(Level.FINER))
+             LOG.finer("dispatching to local namespace: " + domain);
+        return new QueryInterceptor(localNamespace);
+    }
+
+    @Override
+    final ObjectName getHandlerNameFor(String key)
+        throws MalformedObjectNameException {
+        return JMXDomain.getDomainObjectName(key);
+    }
+
+    @Override
+    final public String getHandlerKey(ObjectName name) {
+        return name.getDomain();
+    }
+
+    @Override
+    final DomainInterceptor createInterceptorFor(String key,
+            ObjectName name, JMXDomain handler,
+            Queue<Runnable> postRegisterQueue) {
+        final DomainInterceptor ns =
+                new DomainInterceptor(mbeanServerName,handler,key);
+        ns.addPostRegisterTask(postRegisterQueue, delegate);
+        if (LOG.isLoggable(Level.FINER)) {
+            LOG.finer("DomainInterceptor created: "+ns);
+        }
+        return ns;
+    }
+
+    @Override
+    final void interceptorReleased(DomainInterceptor interceptor,
+            Queue<Runnable> postDeregisterQueue) {
+        interceptor.addPostDeregisterTask(postDeregisterQueue, delegate);
+    }
+
+    @Override
+    final DefaultMBeanServerInterceptor getNextInterceptor() {
+        return localNamespace;
+    }
+
+    /**
+     * Returns the list of domains in which any MBean is currently
+     * registered.
+     */
+    @Override
+    public String[] getDomains() {
+        // A JMXDomain is registered in its own domain.
+        // Therefore, localNamespace.getDomains() contains all domains.
+        // In addition, localNamespace will perform the necessary
+        // MBeanPermission checks for getDomains().
+        //
+        return localNamespace.getDomains();
+    }
+
+    /**
+     * Returns the number of MBeans registered in the MBean server.
+     */
+    @Override
+    public Integer getMBeanCount() {
+        int count = getNextInterceptor().getMBeanCount().intValue();
+        final String[] keys = getKeys();
+        for (String key:keys) {
+            final MBeanServer mbs = getInterceptor(key);
+            if (mbs == null) continue;
+            count += mbs.getMBeanCount().intValue();
+        }
+        return Integer.valueOf(count);
+    }
+}
--- a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,35 +25,14 @@
 
 package com.sun.jmx.interceptor;
 
-import java.util.Set;
 
-// RI import
-import javax.management.DynamicMBean;
-import javax.management.AttributeNotFoundException;
+import java.io.ObjectInputStream;
+import javax.management.InstanceNotFoundException;
 import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
 import javax.management.ReflectionException;
-import javax.management.MBeanAttributeInfo;
-import javax.management.MBeanInfo;
-import javax.management.QueryExp;
-import javax.management.NotificationListener;
-import javax.management.NotificationFilter;
-import javax.management.ListenerNotFoundException;
-import javax.management.IntrospectionException;
-import javax.management.OperationsException;
-import javax.management.MBeanNotificationInfo;
-import javax.management.JMRuntimeException;
-import javax.management.InstanceNotFoundException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.MBeanRegistrationException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InvalidAttributeValueException;
-import javax.management.ObjectName;
-import javax.management.ObjectInstance;
-import javax.management.Attribute;
-import javax.management.AttributeList;
-import javax.management.RuntimeOperationsException;
-import javax.management.MBeanServerConnection;
-import javax.management.MBeanServerDelegate;
 import javax.management.loading.ClassLoaderRepository;
 
 /**
@@ -85,618 +64,67 @@
  *
  * @since 1.5
  */
-public interface MBeanServerInterceptor extends MBeanServerConnection {
+public interface MBeanServerInterceptor extends MBeanServer {
     /**
-     * Instantiates and registers an MBean in the MBean server.  The
-     * MBean server will use its {@link
-     * javax.management.loading.ClassLoaderRepository Default Loader
-     * Repository} to load the class of the MBean.  An object name is
-     * associated to the MBean.  If the object name given is null, the
-     * MBean must provide its own name by implementing the {@link
-     * javax.management.MBeanRegistration MBeanRegistration} interface
-     * and returning the name from the {@link
-     * javax.management.MBeanRegistration#preRegister preRegister} method.
-     *
-     * @param className The class name of the MBean to be instantiated.
-     * @param name The object name of the MBean. May be null.
-     * @param params An array containing the parameters of the
-     * constructor to be invoked.
-     * @param signature An array containing the signature of the
-     * constructor to be invoked.
-     *
-     * @return An <CODE>ObjectInstance</CODE>, containing the
-     * <CODE>ObjectName</CODE> and the Java class name of the newly
-     * instantiated MBean.
-     *
-     * @exception ReflectionException Wraps a
-     * <CODE>java.lang.ClassNotFoundException</CODE> or a
-     * <CODE>java.lang.Exception</CODE> that occurred when trying to
-     * invoke the MBean's constructor.
-     * @exception InstanceAlreadyExistsException The MBean is already
-     * under the control of the MBean server.
-     * @exception MBeanRegistrationException The
-     * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
-     * interface) method of the MBean has thrown an exception. The
-     * MBean will not be registered.
-     * @exception MBeanException The constructor of the MBean has
-     * thrown an exception
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The className
-     * passed in parameter is null, the <CODE>ObjectName</CODE> passed
-     * in parameter contains a pattern or no <CODE>ObjectName</CODE>
-     * is specified for the MBean.
+     * This method should never be called.
+     * Usually hrows UnsupportedOperationException.
      */
-    public ObjectInstance createMBean(String className, ObjectName name,
-                                      Object params[], String signature[])
-            throws ReflectionException, InstanceAlreadyExistsException,
-                   MBeanRegistrationException, MBeanException,
-                   NotCompliantMBeanException;
+    public Object instantiate(String className)
+            throws ReflectionException, MBeanException;
+    /**
+     * This method should never be called.
+     * Usually throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, ObjectName loaderName)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException;
+    /**
+     * This method should never be called.
+     * Usually throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, Object[] params,
+            String[] signature) throws ReflectionException, MBeanException;
 
     /**
-     * Instantiates and registers an MBean in the MBean server.  The
-     * class loader to be used is identified by its object name. An
-     * object name is associated to the MBean. If the object name of
-     * the loader is not specified, the ClassLoader that loaded the
-     * MBean server will be used.  If the MBean object name given is
-     * null, the MBean must provide its own name by implementing the
-     * {@link javax.management.MBeanRegistration MBeanRegistration}
-     * interface and returning the name from the {@link
-     * javax.management.MBeanRegistration#preRegister preRegister} method.
-     *
-     * @param className The class name of the MBean to be instantiated.
-     * @param name The object name of the MBean. May be null.
-     * @param params An array containing the parameters of the
-     * constructor to be invoked.
-     * @param signature An array containing the signature of the
-     * constructor to be invoked.
-     * @param loaderName The object name of the class loader to be used.
-     *
-     * @return An <CODE>ObjectInstance</CODE>, containing the
-     * <CODE>ObjectName</CODE> and the Java class name of the newly
-     * instantiated MBean.
-     *
-     * @exception ReflectionException Wraps a
-     * <CODE>java.lang.ClassNotFoundException</CODE> or a
-     * <CODE>java.lang.Exception</CODE> that occurred when trying to
-     * invoke the MBean's constructor.
-     * @exception InstanceAlreadyExistsException The MBean is already
-     * under the control of the MBean server.
-     * @exception MBeanRegistrationException The
-     * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
-     * interface) method of the MBean has thrown an exception. The
-     * MBean will not be registered.
-     * @exception MBeanException The constructor of the MBean has
-     * thrown an exception
-     * @exception InstanceNotFoundException The specified class loader
-     * is not registered in the MBean server.
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The className
-     * passed in parameter is null, the <CODE>ObjectName</CODE> passed
-     * in parameter contains a pattern or no <CODE>ObjectName</CODE>
-     * is specified for the MBean.
-     *
+     * This method should never be called.
+     * Usually throws UnsupportedOperationException.
      */
-    public ObjectInstance createMBean(String className, ObjectName name,
-                                      ObjectName loaderName, Object params[],
-                                      String signature[])
-            throws ReflectionException, InstanceAlreadyExistsException,
-                   MBeanRegistrationException, MBeanException,
-                   NotCompliantMBeanException, InstanceNotFoundException;
+    public Object instantiate(String className, ObjectName loaderName,
+            Object[] params, String[] signature)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException;
 
     /**
-     * Registers a pre-existing object as an MBean with the MBean
-     * server. If the object name given is null, the MBean must
-     * provide its own name by implementing the {@link
-     * javax.management.MBeanRegistration MBeanRegistration} interface
-     * and returning the name from the {@link
-     * javax.management.MBeanRegistration#preRegister preRegister} method.
-     *
-     * @param object The  MBean to be registered as an MBean.
-     * @param name The object name of the MBean. May be null.
-     *
-     * @return The <CODE>ObjectInstance</CODE> for the MBean that has
-     * been registered.
-     *
-     * @exception InstanceAlreadyExistsException The MBean is already
-     * under the control of the MBean server.
-     * @exception MBeanRegistrationException The
-     * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
-     * interface) method of the MBean has thrown an exception. The
-     * MBean will not be registered.
-     * @exception NotCompliantMBeanException This object is not a JMX
-     * compliant MBean
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * passed in parameter is null or no object name is specified.
+     * This method should never be called.
+     * Usually throws UnsupportedOperationException.
      */
-    public ObjectInstance registerMBean(Object object, ObjectName name)
-            throws InstanceAlreadyExistsException, MBeanRegistrationException,
-                   NotCompliantMBeanException;
+    @Deprecated
+    public ObjectInputStream deserialize(ObjectName name, byte[] data)
+            throws InstanceNotFoundException, OperationsException;
 
     /**
-     * Unregisters an MBean from the MBean server. The MBean is
-     * identified by its object name. Once the method has been
-     * invoked, the MBean may no longer be accessed by its object
-     * name.
-     *
-     * @param name The object name of the MBean to be unregistered.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     * @exception MBeanRegistrationException The preDeregister
-     * ((<CODE>MBeanRegistration</CODE> interface) method of the MBean
-     * has thrown an exception.
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * name in parameter is null or the MBean you are when trying to
-     * unregister is the {@link javax.management.MBeanServerDelegate
-     * MBeanServerDelegate} MBean.
-     *
+     * This method should never be called.
+     * Usually throws UnsupportedOperationException.
      */
-    public void unregisterMBean(ObjectName name)
-            throws InstanceNotFoundException, MBeanRegistrationException;
+    @Deprecated
+    public ObjectInputStream deserialize(String className, byte[] data)
+            throws OperationsException, ReflectionException;
 
     /**
-     * Gets the <CODE>ObjectInstance</CODE> for a given MBean
-     * registered with the MBean server.
-     *
-     * @param name The object name of the MBean.
-     *
-     * @return The <CODE>ObjectInstance</CODE> associated to the MBean
-     * specified by <VAR>name</VAR>.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
+     * This method should never be called.
+     * Usually hrows UnsupportedOperationException.
      */
-    public ObjectInstance getObjectInstance(ObjectName name)
-            throws InstanceNotFoundException;
+    @Deprecated
+    public ObjectInputStream deserialize(String className,
+            ObjectName loaderName, byte[] data)
+            throws InstanceNotFoundException, OperationsException,
+            ReflectionException;
 
     /**
-     * Gets MBeans controlled by the MBean server. This method allows
-     * any of the following to be obtained: All MBeans, a set of
-     * MBeans specified by pattern matching on the
-     * <CODE>ObjectName</CODE> and/or a Query expression, a specific
-     * MBean. When the object name is null or no domain and key
-     * properties are specified, all objects are to be selected (and
-     * filtered if a query is specified). It returns the set of
-     * <CODE>ObjectInstance</CODE> objects (containing the
-     * <CODE>ObjectName</CODE> and the Java Class name) for the
-     * selected MBeans.
-     *
-     * @param name The object name pattern identifying the MBeans to
-     * be retrieved. If null or no domain and key properties are
-     * specified, all the MBeans registered will be retrieved.
-     * @param query The query expression to be applied for selecting
-     * MBeans. If null no query expression will be applied for
-     * selecting MBeans.
-     *
-     * @return A set containing the <CODE>ObjectInstance</CODE>
-     * objects for the selected MBeans.  If no MBean satisfies the
-     * query an empty list is returned.
+     * This method should never be called.
+     * Usually throws UnsupportedOperationException.
      */
-    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query);
-
-    /**
-     * Gets the names of MBeans controlled by the MBean server. This
-     * method enables any of the following to be obtained: The names
-     * of all MBeans, the names of a set of MBeans specified by
-     * pattern matching on the <CODE>ObjectName</CODE> and/or a Query
-     * expression, a specific MBean name (equivalent to testing
-     * whether an MBean is registered). When the object name is null
-     * or no domain and key properties are specified, all objects are
-     * selected (and filtered if a query is specified). It returns the
-     * set of ObjectNames for the MBeans selected.
-     *
-     * @param name The object name pattern identifying the MBean names
-     * to be retrieved. If null oror no domain and key properties are
-     * specified, the name of all registered MBeans will be retrieved.
-     * @param query The query expression to be applied for selecting
-     * MBeans. If null no query expression will be applied for
-     * selecting MBeans.
-     *
-     * @return A set containing the ObjectNames for the MBeans
-     * selected.  If no MBean satisfies the query, an empty list is
-     * returned.
-     */
-    public Set<ObjectName> queryNames(ObjectName name, QueryExp query);
-
-    /**
-     * Checks whether an MBean, identified by its object name, is
-     * already registered with the MBean server.
-     *
-     * @param name The object name of the MBean to be checked.
-     *
-     * @return True if the MBean is already registered in the MBean
-     * server, false otherwise.
-     *
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * name in parameter is null.
-     */
-    public boolean isRegistered(ObjectName name);
-
-    /**
-     * Returns the number of MBeans registered in the MBean server.
-     */
-    public Integer getMBeanCount();
-
-    /**
-     * Gets the value of a specific attribute of a named MBean. The MBean
-     * is identified by its object name.
-     *
-     * @param name The object name of the MBean from which the
-     * attribute is to be retrieved.
-     * @param attribute A String specifying the name of the attribute
-     * to be retrieved.
-     *
-     * @return  The value of the retrieved attribute.
-     *
-     * @exception AttributeNotFoundException The attribute specified
-     * is not accessible in the MBean.
-     * @exception MBeanException Wraps an exception thrown by the
-     * MBean's getter.
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     * @exception ReflectionException Wraps a
-     * <CODE>java.lang.Exception</CODE> thrown when trying to invoke
-     * the setter.
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * name in parameter is null or the attribute in parameter is
-     * null.
-     */
-    public Object getAttribute(ObjectName name, String attribute)
-            throws MBeanException, AttributeNotFoundException,
-                   InstanceNotFoundException, ReflectionException;
-
-    /**
-     * Enables the values of several attributes of a named MBean. The MBean
-     * is identified by its object name.
-     *
-     * @param name The object name of the MBean from which the
-     * attributes are retrieved.
-     * @param attributes A list of the attributes to be retrieved.
-     *
-     * @return The list of the retrieved attributes.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     * @exception ReflectionException An exception occurred when
-     * trying to invoke the getAttributes method of a Dynamic MBean.
-     * @exception RuntimeOperationsException Wrap a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * name in parameter is null or attributes in parameter is null.
-     */
-    public AttributeList getAttributes(ObjectName name, String[] attributes)
-            throws InstanceNotFoundException, ReflectionException;
-
-    /**
-     * Sets the value of a specific attribute of a named MBean. The MBean
-     * is identified by its object name.
-     *
-     * @param name The name of the MBean within which the attribute is
-     * to be set.
-     * @param attribute The identification of the attribute to be set
-     * and the value it is to be set to.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     * @exception AttributeNotFoundException The attribute specified
-     * is not accessible in the MBean.
-     * @exception InvalidAttributeValueException The value specified
-     * for the attribute is not valid.
-     * @exception MBeanException Wraps an exception thrown by the
-     * MBean's setter.
-     * @exception ReflectionException Wraps a
-     * <CODE>java.lang.Exception</CODE> thrown when trying to invoke
-     * the setter.
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * name in parameter is null or the attribute in parameter is
-     * null.
-     */
-    public void setAttribute(ObjectName name, Attribute attribute)
-            throws InstanceNotFoundException, AttributeNotFoundException,
-                   InvalidAttributeValueException, MBeanException,
-                   ReflectionException;
-
-
-
-    /**
-     * Sets the values of several attributes of a named MBean. The MBean is
-     * identified by its object name.
-     *
-     * @param name The object name of the MBean within which the
-     * attributes are to be set.
-     * @param attributes A list of attributes: The identification of
-     * the attributes to be set and the values they are to be set to.
-     *
-     * @return The list of attributes that were set, with their new
-     * values.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     * @exception ReflectionException An exception occurred when
-     * trying to invoke the getAttributes method of a Dynamic MBean.
-     * @exception RuntimeOperationsException Wraps a
-     * <CODE>java.lang.IllegalArgumentException</CODE>: The object
-     * name in parameter is null or attributes in parameter is null.
-     */
-    public AttributeList setAttributes(ObjectName name,
-                                       AttributeList attributes)
-        throws InstanceNotFoundException, ReflectionException;
-
-    /**
-     * Invokes an operation on an MBean.
-     *
-     * @param name The object name of the MBean on which the method is
-     * to be invoked.
-     * @param operationName The name of the operation to be invoked.
-     * @param params An array containing the parameters to be set when
-     * the operation is invoked
-     * @param signature An array containing the signature of the
-     * operation. The class objects will be loaded using the same
-     * class loader as the one used for loading the MBean on which the
-     * operation was invoked.
-     *
-     * @return The object returned by the operation, which represents
-     * the result ofinvoking the operation on the MBean specified.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     * @exception MBeanException Wraps an exception thrown by the
-     * MBean's invoked method.
-     * @exception ReflectionException Wraps a
-     * <CODE>java.lang.Exception</CODE> thrown while trying to invoke
-     * the method.
-     */
-    public Object invoke(ObjectName name, String operationName,
-                         Object params[], String signature[])
-            throws InstanceNotFoundException, MBeanException,
-                   ReflectionException;
-
-    /**
-     * Returns the default domain used for naming the MBean.
-     * The default domain name is used as the domain part in the ObjectName
-     * of MBeans if no domain is specified by the user.
-     */
-    public String getDefaultDomain();
-
-    /**
-     * Returns the list of domains in which any MBean is currently
-     * registered.
-     */
-    public String[] getDomains();
-
-    /**
-     * <p>Adds a listener to a registered MBean.</p>
-     *
-     * <P> A notification emitted by an MBean will be forwarded by the
-     * MBeanServer to the listener.  If the source of the notification
-     * is a reference to an MBean object, the MBean server will replace it
-     * by that MBean's ObjectName.  Otherwise the source is unchanged.
-     *
-     * @param name The name of the MBean on which the listener should
-     * be added.
-     * @param listener The listener object which will handle the
-     * notifications emitted by the registered MBean.
-     * @param filter The filter object. If filter is null, no
-     * filtering will be performed before handling notifications.
-     * @param handback The context to be sent to the listener when a
-     * notification is emitted.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     */
-    public void addNotificationListener(ObjectName name,
-                                        NotificationListener listener,
-                                        NotificationFilter filter,
-                                        Object handback)
-            throws InstanceNotFoundException;
-
-
-    /**
-     * <p>Adds a listener to a registered MBean.</p>
-     *
-     * <p>A notification emitted by an MBean will be forwarded by the
-     * MBeanServer to the listener.  If the source of the notification
-     * is a reference to an MBean object, the MBean server will
-     * replace it by that MBean's ObjectName.  Otherwise the source is
-     * unchanged.</p>
-     *
-     * <p>The listener object that receives notifications is the one
-     * that is registered with the given name at the time this method
-     * is called.  Even if it is subsequently unregistered, it will
-     * continue to receive notifications.</p>
-     *
-     * @param name The name of the MBean on which the listener should
-     * be added.
-     * @param listener The object name of the listener which will
-     * handle the notifications emitted by the registered MBean.
-     * @param filter The filter object. If filter is null, no
-     * filtering will be performed before handling notifications.
-     * @param handback The context to be sent to the listener when a
-     * notification is emitted.
-     *
-     * @exception InstanceNotFoundException The MBean name of the
-     * notification listener or of the notification broadcaster does
-     * not match any of the registered MBeans.
-     * @exception RuntimeOperationsException Wraps an {@link
-     * IllegalArgumentException}.  The MBean named by
-     * <code>listener</code> exists but does not implement the {@link
-     * NotificationListener} interface.
-     * @exception IOException A communication problem occurred when
-     * talking to the MBean server.
-     */
-    public void addNotificationListener(ObjectName name,
-                                        ObjectName listener,
-                                        NotificationFilter filter,
-                                        Object handback)
-            throws InstanceNotFoundException;
-
-    /**
-     * Removes a listener from a registered MBean.
-     *
-     * <P> If the listener is registered more than once, perhaps with
-     * different filters or callbacks, this method will remove all
-     * those registrations.
-     *
-     * @param name The name of the MBean on which the listener should
-     * be removed.
-     * @param listener The object name of the listener to be removed.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception ListenerNotFoundException The listener is not
-     * registered in the MBean.
-     */
-    public void removeNotificationListener(ObjectName name,
-                                           ObjectName listener)
-        throws InstanceNotFoundException, ListenerNotFoundException;
-
-    /**
-     * <p>Removes a listener from a registered MBean.</p>
-     *
-     * <p>The MBean must have a listener that exactly matches the
-     * given <code>listener</code>, <code>filter</code>, and
-     * <code>handback</code> parameters.  If there is more than one
-     * such listener, only one is removed.</p>
-     *
-     * <p>The <code>filter</code> and <code>handback</code> parameters
-     * may be null if and only if they are null in a listener to be
-     * removed.</p>
-     *
-     * @param name The name of the MBean on which the listener should
-     * be removed.
-     * @param listener A listener that was previously added to this
-     * MBean.
-     * @param filter The filter that was specified when the listener
-     * was added.
-     * @param handback The handback that was specified when the
-     * listener was added.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception ListenerNotFoundException The listener is not
-     * registered in the MBean, or it is not registered with the given
-     * filter and handback.
-     */
-    public void removeNotificationListener(ObjectName name,
-                                           ObjectName listener,
-                                           NotificationFilter filter,
-                                           Object handback)
-            throws InstanceNotFoundException, ListenerNotFoundException;
-
-
-    /**
-     * <p>Removes a listener from a registered MBean.</p>
-     *
-     * <P> If the listener is registered more than once, perhaps with
-     * different filters or callbacks, this method will remove all
-     * those registrations.
-     *
-     * @param name The name of the MBean on which the listener should
-     * be removed.
-     * @param listener The listener object which will handle the
-     * notifications emitted by the registered MBean.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception ListenerNotFoundException The listener is not
-     * registered in the MBean.
-     */
-    public void removeNotificationListener(ObjectName name,
-                                           NotificationListener listener)
-            throws InstanceNotFoundException, ListenerNotFoundException;
-
-    /**
-     * <p>Removes a listener from a registered MBean.</p>
-     *
-     * <p>The MBean must have a listener that exactly matches the
-     * given <code>listener</code>, <code>filter</code>, and
-     * <code>handback</code> parameters.  If there is more than one
-     * such listener, only one is removed.</p>
-     *
-     * <p>The <code>filter</code> and <code>handback</code> parameters
-     * may be null if and only if they are null in a listener to be
-     * removed.</p>
-     *
-     * @param name The name of the MBean on which the listener should
-     * be removed.
-     * @param listener A listener that was previously added to this
-     * MBean.
-     * @param filter The filter that was specified when the listener
-     * was added.
-     * @param handback The handback that was specified when the
-     * listener was added.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception ListenerNotFoundException The listener is not
-     * registered in the MBean, or it is not registered with the given
-     * filter and handback.
-     */
-    public void removeNotificationListener(ObjectName name,
-                                           NotificationListener listener,
-                                           NotificationFilter filter,
-                                           Object handback)
-            throws InstanceNotFoundException, ListenerNotFoundException;
-
-    /**
-     * This method discovers the attributes and operations that an
-     * MBean exposes for management.
-     *
-     * @param name The name of the MBean to analyze
-     *
-     * @return An instance of <CODE>MBeanInfo</CODE> allowing the
-     * retrieval of all attributes and operations of this MBean.
-     *
-     * @exception IntrospectionException An exception occurred during
-     * introspection.
-     * @exception InstanceNotFoundException The MBean specified was
-     * not found.
-     * @exception ReflectionException An exception occurred when
-     * trying to invoke the getMBeanInfo of a Dynamic MBean.
-     */
-    public MBeanInfo getMBeanInfo(ObjectName name)
-            throws InstanceNotFoundException, IntrospectionException,
-                   ReflectionException;
-
-
-    /**
-     * Returns true if the MBean specified is an instance of the
-     * specified class, false otherwise.
-     *
-     * @param name The <CODE>ObjectName</CODE> of the MBean.
-     * @param className The name of the class.
-     *
-     * @return true if the MBean specified is an instance of the
-     * specified class, false otherwise.
-     *
-     * @exception InstanceNotFoundException The MBean specified is not
-     * registered in the MBean server.
-     */
-    public boolean isInstanceOf(ObjectName name, String className)
-            throws InstanceNotFoundException;
-
-    /**
-     * <p>Return the {@link java.lang.ClassLoader} that was used for
-     * loading the class of the named MBean.
-     * @param mbeanName The ObjectName of the MBean.
-     * @return The ClassLoader used for that MBean.
-     * @exception InstanceNotFoundException if the named MBean is not found.
-     */
-    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
-        throws InstanceNotFoundException;
-
-    /**
-     * <p>Return the named {@link java.lang.ClassLoader}.
-     * @param loaderName The ObjectName of the ClassLoader.
-     * @return The named ClassLoader.
-     * @exception InstanceNotFoundException if the named ClassLoader is
-     * not found.
-     */
-    public ClassLoader getClassLoader(ObjectName loaderName)
-        throws InstanceNotFoundException;
+    public ClassLoaderRepository getClassLoaderRepository();
 
 }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.interceptor;
+
+import java.io.ObjectInputStream;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * An abstract class for MBeanServerInterceptorSupport.
+ * Some methods in MBeanServerInterceptor should never be called.
+ * This base class provides an implementation of these methods that simply
+ * throw an {@link UnsupportedOperationException}.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public abstract class MBeanServerInterceptorSupport
+        implements MBeanServerInterceptor {
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className)
+            throws ReflectionException, MBeanException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, ObjectName loaderName)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, Object[] params,
+            String[] signature) throws ReflectionException, MBeanException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, ObjectName loaderName,
+            Object[] params, String[] signature)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(ObjectName name, byte[] data)
+            throws InstanceNotFoundException, OperationsException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className, byte[] data)
+            throws OperationsException, ReflectionException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className,
+            ObjectName loaderName, byte[] data)
+            throws InstanceNotFoundException, OperationsException,
+            ReflectionException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public ClassLoaderRepository getClassLoaderRepository() {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+}
--- a/src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java	Wed Sep 03 14:31:17 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1341 +0,0 @@
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-package com.sun.jmx.interceptor;
-
-import com.sun.jmx.mbeanserver.Util;
-import java.io.ObjectInputStream;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.management.Attribute;
-import javax.management.AttributeList;
-import javax.management.AttributeNotFoundException;
-import javax.management.DynamicMBean;
-import javax.management.DynamicWrapperMBean;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.IntrospectionException;
-import javax.management.InvalidAttributeValueException;
-import javax.management.JMRuntimeException;
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanException;
-import javax.management.MBeanInfo;
-import javax.management.MBeanRegistrationException;
-import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.NotificationBroadcaster;
-import javax.management.NotificationEmitter;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectInstance;
-import javax.management.ObjectName;
-import javax.management.OperationsException;
-import javax.management.QueryEval;
-import javax.management.QueryExp;
-import javax.management.ReflectionException;
-import javax.management.RuntimeOperationsException;
-import javax.management.loading.ClassLoaderRepository;
-
-/**
- * <p>Base class for custom implementations of the {@link MBeanServer}
- * interface. The commonest use of this class is as the {@linkplain
- * JMXNamespace#getSourceServer() source server} for a {@link
- * JMXNamespace}, although this class can be used anywhere an {@code
- * MBeanServer} instance is required. Note that the usual ways to
- * obtain an {@code MBeanServer} instance are either to use {@link
- * java.lang.management.ManagementFactory#getPlatformMBeanServer()
- * ManagementFactory.getPlatformMBeanServer()} or to use the {@code
- * newMBeanServer} or {@code createMBeanServer} methods from {@link
- * javax.management.MBeanServerFactory MBeanServerFactory}. {@code
- * MBeanServerSupport} is for certain cases where those are not
- * appropriate.</p>
- *
- * <p>There are two main use cases for this class: <a
- * href="#special-purpose">special-purpose MBeanServer implementations</a>,
- * and <a href="#virtual">namespaces containing Virtual MBeans</a>. The next
- * sections explain these use cases.</p>
- *
- * <p>In the simplest case, a subclass needs to implement only two methods:</p>
- *
- * <ul>
- *     <li>
- *         {@link #getNames getNames} which returns the name of
- *         all MBeans handled by this {@code MBeanServer}.
- *     </li>
- *     <li>
- *         {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a
- *         {@link DynamicMBean} that can be used to invoke operations and
- *         obtain meta data (MBeanInfo) on a given MBean.
- *     </li>
- * </ul>
- *
- * <p>Subclasses can create such {@link DynamicMBean} MBeans on the fly - for
- * instance, using the class {@link javax.management.StandardMBean}, just for
- * the duration of an MBeanServer method call.</p>
- *
- * <h4 id="special-purpose">Special-purpose MBeanServer implementations</h4>
- *
- * <p>In some cases
- * the general-purpose {@code MBeanServer} that you get from
- * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not
- * appropriate.  You might need different security checks, or you might
- * want a mock {@code MBeanServer} suitable for use in tests, or you might
- * want a simplified and optimized {@code MBeanServer} for a special purpose.</p>
- *
- * <p>As an example of a special-purpose {@code MBeanServer}, the class {@link
- * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs
- * an {@code MBeanServer} instance every time it filters a notification,
- * with just one MBean that represents the notification. Although it could
- * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code
- * MBeanServer} will be quicker to create, use less memory, and have simpler
- * methods that execute faster.</p>
- *
- * <p>Here is an example of a special-purpose {@code MBeanServer}
- * implementation that contains exactly one MBean, which is specified at the
- * time of creation.</p>
- *
- * <pre>
- * public class SingletonMBeanServer extends MBeanServerSupport {
- *     private final ObjectName objectName;
- *     private final DynamicMBean mbean;
- *
- *     public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) {
- *         this.objectName = objectName;
- *         this.mbean = mbean;
- *     }
- *
- *     &#64;Override
- *     protected {@code Set<ObjectName>} {@link #getNames getNames}() {
- *         return Collections.singleton(objectName);
- *     }
- *
- *     &#64;Override
- *     public DynamicMBean {@link #getDynamicMBeanFor
- *                                getDynamicMBeanFor}(ObjectName name)
- *             throws InstanceNotFoundException {
- *         if (objectName.equals(name))
- *             return mbean;
- *         else
- *             throw new InstanceNotFoundException(name);
- *     }
- * }
- * </pre>
- *
- * <p>Using this class, you could make an {@code MBeanServer} that contains
- * a {@link javax.management.timer.Timer Timer} MBean like this:</p>
- *
- * <pre>
- *     Timer timer = new Timer();
- *     DynamicMBean mbean = new {@link javax.management.StandardMBean
- *                                     StandardMBean}(timer, TimerMBean.class);
- *     ObjectName name = new ObjectName("com.example:type=Timer");
- *     MBeanServer timerMBS = new SingletonMBeanServer(name, mbean);
- * </pre>
- *
- * <p>When {@code getDynamicMBeanFor} always returns the same object for the
- * same name, as here, notifications work in the expected way: if the object
- * is a {@link NotificationEmitter} then listeners can be added using
- * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener,
- * NotificationFilter, Object) MBeanServer.addNotificationListener}.  If
- * {@code getDynamicMBeanFor} does not always return the same object for the
- * same name, more work is needed to make notifications work, as described
- * <a href="#notifs">below</a>.</p>
- *
- * <h4 id="virtual">Namespaces containing Virtual MBeans</h4>
- *
- * <p>Virtual MBeans are MBeans that do not exist as Java objects,
- * except transiently while they are being accessed.  This is useful when
- * there might be very many of them, or when keeping track of their creation
- * and deletion might be expensive or hard.  For example, you might have one
- * MBean per system process.  With an ordinary {@code MBeanServer}, you would
- * have to list the system processes in order to create an MBean object for
- * each one, and you would have to track the arrival and departure of system
- * processes in order to create or delete the corresponding MBeans.  With
- * Virtual MBeans, you only need the MBean for a given process at the exact
- * point where it is referenced with a call such as
- * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.</p>
- *
- * <p>Here is an example of an {@code MBeanServer} implementation that has
- * one MBean for every system property.  The system property {@code "java.home"}
- * is represented by the MBean called {@code
- * com.example:type=Property,name="java.home"}, with an attribute called
- * {@code Value} that is the value of the property.</p>
- *
- * <pre>
- * public interface PropertyMBean {
- *     public String getValue();
- * }
- *
- * <a name="PropsMBS"></a>public class PropsMBS extends MBeanServerSupport {
- *     private static ObjectName newObjectName(String name) {
- *         try {
- *             return new ObjectName(name);
- *         } catch (MalformedObjectNameException e) {
- *             throw new AssertionError(e);
- *         }
- *     }
- *
- *     public static class PropertyImpl implements PropertyMBean {
- *         private final String name;
- *
- *         public PropertyImpl(String name) {
- *             this.name = name;
- *         }
- *
- *         public String getValue() {
- *             return System.getProperty(name);
- *         }
- *     }
- *
- *     &#64;Override
- *     public DynamicMBean {@link #getDynamicMBeanFor
- *                                getDynamicMBeanFor}(ObjectName name)
- *             throws InstanceNotFoundException {
- *
- *         // Check that the name is a legal one for a Property MBean
- *         ObjectName namePattern = newObjectName(
- *                     "com.example:type=Property,name=\"*\"");
- *         if (!namePattern.apply(name))
- *             throw new InstanceNotFoundException(name);
- *
- *         // Extract the name of the property that the MBean corresponds to
- *         String propName = ObjectName.unquote(name.getKeyProperty("name"));
- *         if (System.getProperty(propName) == null)
- *             throw new InstanceNotFoundException(name);
- *
- *         // Construct and return a transient MBean object
- *         PropertyMBean propMBean = new PropertyImpl(propName);
- *         return new StandardMBean(propMBean, PropertyMBean.class, false);
- *     }
- *
- *     &#64;Override
- *     protected {@code Set<ObjectName>} {@link #getNames getNames}() {
- *         {@code Set<ObjectName> names = new TreeSet<ObjectName>();}
- *         Properties props = System.getProperties();
- *         for (String propName : props.stringPropertyNames()) {
- *             ObjectName objectName = newObjectName(
- *                     "com.example:type=Property,name=" +
- *                     ObjectName.quote(propName));
- *             names.add(objectName);
- *         }
- *         return names;
- *     }
- * }
- * </pre>
- *
- * <p id="virtual-notif-example">Because the {@code getDynamicMBeanFor} method
- * returns a different object every time it is called, the default handling
- * of notifications will not work, as explained <a href="#notifs">below</a>.
- * In this case it does not matter, because the object returned by {@code
- * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link
- * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
- * NotificationFilter, Object) MBeanServer.addNotificationListener} will
- * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean
- * for property {@code "foo"} emitted a notification every time that property
- * changed, we would need to do it as shown below. (Because there is no API to
- * be informed when a property changes, this code assumes that some other code
- * calls the {@code propertyChanged} method every time a property changes.)</p>
- *
- * <pre>
- * public class PropsMBS {
- *     ...as <a href="#PropsMBS">above</a>...
- *
- *     private final {@link VirtualEventManager} vem = new VirtualEventManager();
- *
- *     &#64;Override
- *     public NotificationEmitter {@link #getNotificationEmitterFor
- *                                       getNotificationEmitterFor}(
- *             ObjectName name) throws InstanceNotFoundException {
- *         getDynamicMBeanFor(name);  // check that the name is valid
- *         return vem.{@link VirtualEventManager#getNotificationEmitterFor
- *                           getNotificationEmitterFor}(name);
- *     }
- *
- *     public void propertyChanged(String name, String newValue) {
- *         ObjectName objectName = newObjectName(
- *                 "com.example:type=Property,name=" + ObjectName.quote(name));
- *         Notification n = new Notification(
- *                 "com.example.property.changed", objectName, 0L,
- *                 "Property " + name + " changed");
- *         n.setUserData(newValue);
- *         vem.{@link VirtualEventManager#publish publish}(objectName, n);
- *     }
- * }
- * </pre>
- *
- * <h4 id="creation">MBean creation and deletion</h4>
- *
- * <p>MBean creation through {@code MBeanServer.createMBean} is disabled
- * by default. Subclasses which need to support MBean creation
- * through {@code createMBean} need to implement a single method {@link
- * #createMBean(String, ObjectName, ObjectName, Object[], String[],
- * boolean)}.</p>
- *
- * <p>Similarly MBean registration and unregistration through {@code
- * registerMBean} and {@code unregisterMBean} are disabled by default.
- * Subclasses which need to support MBean registration and
- * unregistration will need to implement {@link #registerMBean registerMBean}
- * and {@link #unregisterMBean unregisterMBean}.</p>
- *
- * <h4 id="notifs">Notifications</h4>
- *
- * <p>By default {@link MBeanServer#addNotificationListener(ObjectName,
- * NotificationListener, NotificationFilter, Object) addNotificationListener}
- * is accepted for an MBean <em>{@code name}</em> if {@link #getDynamicMBeanFor
- * getDynamicMBeanFor}<code>(<em>name</em>)</code> returns an object that is a
- * {@link NotificationEmitter}.  That is appropriate if
- * {@code getDynamicMBeanFor}<code>(<em>name</em>)</code> always returns the
- * same object for the same <em>{@code name}</em>.  But with
- * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
- * which is discarded as soon as the MBean request has finished.
- * So a listener added to that object would be immediately forgotten.</p>
- *
- * <p>The simplest way for a subclass that defines Virtual MBeans
- * to support notifications is to create a private {@link VirtualEventManager}
- * and override the method {@link
- * #getNotificationEmitterFor getNotificationEmitterFor} as follows:</p>
- *
- * <pre>
- *     private final VirtualEventManager vem = new VirtualEventManager();
- *
- *     &#64;Override
- *     public NotificationEmitter getNotificationEmitterFor(
- *             ObjectName name) throws InstanceNotFoundException {
- *         // Check that the name is a valid Virtual MBean.
- *         // This is the easiest way to do that, but not always the
- *         // most efficient:
- *         getDynamicMBeanFor(name);
- *
- *         // Return an object that supports add/removeNotificationListener
- *         // through the VirtualEventManager.
- *         return vem.getNotificationEmitterFor(name);
- *     }
- * </pre>
- *
- * <p>A notification <em>{@code n}</em> can then be sent from the Virtual MBean
- * called <em>{@code name}</em> by calling {@link VirtualEventManager#publish
- * vem.publish}<code>(<em>name</em>, <em>n</em>)</code>.  See the example
- * <a href="#virtual-notif-example">above</a>.</p>
- *
- * @since Java SE 7
- */
-public abstract class MBeanServerSupport implements MBeanServer {
-
-    /**
-     * A logger for this class.
-     */
-    private static final Logger LOG =
-            Logger.getLogger(MBeanServerSupport.class.getName());
-
-    /**
-     * <p>Make a new {@code MBeanServerSupport} instance.</p>
-     */
-    protected MBeanServerSupport() {
-    }
-
-    /**
-     * <p>Returns a dynamically created handle that makes it possible to
-     * access the named MBean for the duration of a method call.</p>
-     *
-     * <p>An easy way to create such a {@link DynamicMBean} handle is, for
-     * instance, to create a temporary MXBean instance and to wrap it in
-     * an instance of
-     * {@link javax.management.StandardMBean}.
-     * This handle should remain valid for the duration of the call
-     * but can then be discarded.</p>
-     * @param name the name of the MBean for which a request was received.
-     * @return a {@link DynamicMBean} handle that can be used to invoke
-     * operations on the named MBean.
-     * @throws InstanceNotFoundException if no such MBean is supposed
-     *         to exist.
-     */
-    public abstract DynamicMBean getDynamicMBeanFor(ObjectName name)
-                        throws InstanceNotFoundException;
-
-    /**
-     * <p>Subclasses should implement this method to return
-     * the names of all MBeans handled by this object instance.</p>
-     *
-     * <p>The object returned by getNames() should be safely {@linkplain
-     * Set#iterator iterable} even in the presence of other threads that may
-     * cause the set of names to change. Typically this means one of the
-     * following:</p>
-     *
-     * <ul>
-     * <li>the returned set of names is always the same; or
-     * <li>the returned set of names is an object such as a {@link
-     * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is
-     * safely iterable even if the set is changed by other threads; or
-     * <li>a new Set is constructed every time this method is called.
-     * </ul>
-     *
-     * @return the names of all MBeans handled by this object.
-     */
-    protected abstract Set<ObjectName> getNames();
-
-    /**
-     * <p>List names matching the given pattern.
-     * The default implementation of this method calls {@link #getNames()}
-     * and returns the subset of those names matching {@code pattern}.</p>
-     *
-     * @param pattern an ObjectName pattern
-     * @return the list of MBean names that match the given pattern.
-     */
-    protected Set<ObjectName> getMatchingNames(ObjectName pattern) {
-        return Util.filterMatchingNames(pattern, getNames());
-    }
-
-    /**
-     * <p>Returns a {@link NotificationEmitter} which can be used to
-     * subscribe or unsubscribe for notifications with the named
-     * mbean.</p>
-     *
-     * <p>The default implementation of this method calls {@link
-     * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object
-     * if it is a {@code NotificationEmitter}, otherwise null. See <a
-     * href="#notifs">above</a> for further discussion of notification
-     * handling.</p>
-     *
-     * @param name The name of the MBean whose notifications are being
-     * subscribed, or unsuscribed.
-     *
-     * @return A {@link NotificationEmitter} that can be used to subscribe or
-     * unsubscribe for notifications emitted by the named MBean, or {@code
-     * null} if the MBean does not emit notifications and should not be
-     * considered as a {@code NotificationEmitter}.
-     *
-     * @throws InstanceNotFoundException if {@code name} is not the name of
-     * an MBean in this {@code MBeanServer}.
-     */
-    public NotificationEmitter getNotificationEmitterFor(ObjectName name)
-            throws InstanceNotFoundException {
-        DynamicMBean mbean = getDynamicMBeanFor(name);
-        if (mbean instanceof NotificationEmitter)
-            return (NotificationEmitter) mbean;
-        else
-            return null;
-    }
-
-    private NotificationEmitter getNonNullNotificationEmitterFor(
-            ObjectName name)
-            throws InstanceNotFoundException {
-        NotificationEmitter emitter = getNotificationEmitterFor(name);
-        if (emitter == null) {
-            IllegalArgumentException iae = new IllegalArgumentException(
-                    "Not a NotificationEmitter: " + name);
-            throw new RuntimeOperationsException(iae);
-        }
-        return emitter;
-    }
-
-    /**
-     * <p>Creates a new MBean in the MBean name space.
-     * This operation is not supported in this base class implementation.</p>
-     * The default implementation of this method always throws an {@link
-     * UnsupportedOperationException}
-     * wrapped in a {@link RuntimeOperationsException}.</p>
-     *
-     * <p>Subclasses may redefine this method to provide an implementation.
-     * All the various flavors of {@code MBeanServer.createMBean} methods
-     * will eventually call this method. A subclass that wishes to
-     * support MBean creation through {@code createMBean} thus only
-     * needs to provide an implementation for this one method.
-     *
-     * @param className The class name of the MBean to be instantiated.
-     * @param name The object name of the MBean. May be null.
-     * @param params An array containing the parameters of the
-     * constructor to be invoked.
-     * @param signature An array containing the signature of the
-     * constructor to be invoked.
-     * @param loaderName The object name of the class loader to be used.
-     * @param useCLR This parameter is {@code true} when this method
-     *        is called from one of the {@code MBeanServer.createMBean} methods
-     *        whose signature does not include the {@code ObjectName} of an
-     *        MBean class loader to use for loading the MBean class.
-     *
-     * @return An <CODE>ObjectInstance</CODE>, containing the
-     * <CODE>ObjectName</CODE> and the Java class name of the newly
-     * instantiated MBean.  If the contained <code>ObjectName</code>
-     * is <code>n</code>, the contained Java class name is
-     * <code>{@link javax.management.MBeanServer#getMBeanInfo
-     * getMBeanInfo(n)}.getClassName()</code>.
-     *
-     * @exception ReflectionException Wraps a
-     * <CODE>java.lang.ClassNotFoundException</CODE> or a
-     * <CODE>java.lang.Exception</CODE> that occurred when trying to
-     * invoke the MBean's constructor.
-     * @exception InstanceAlreadyExistsException The MBean is already
-     * under the control of the MBean server.
-     * @exception MBeanRegistrationException The
-     * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
-     * interface) method of the MBean has thrown an exception. The
-     * MBean will not be registered.
-     * @exception MBeanException The constructor of the MBean has
-     * thrown an exception
-     * @exception NotCompliantMBeanException This class is not a JMX
-     * compliant MBean
-     * @exception InstanceNotFoundException The specified class loader
-     * is not registered in the MBean server.
-     * @exception RuntimeOperationsException Wraps either:
-     * <ul>
-     * <li>a <CODE>java.lang.IllegalArgumentException</CODE>: The className
-     * passed in parameter is null, the <CODE>ObjectName</CODE> passed in
-     * parameter contains a pattern or no <CODE>ObjectName</CODE> is specified
-     * for the MBean; or</li>
-     * <li>an {@code UnsupportedOperationException} if creating MBeans is not
-     * supported by this {@code MBeanServer} implementation.
-     * </ul>
-     */
-    public ObjectInstance createMBean(String className,
-            ObjectName name, ObjectName loaderName, Object[] params,
-            String[] signature, boolean useCLR)
-            throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException, InstanceNotFoundException {
-        throw newUnsupportedException("createMBean");
-    }
-
-
-    /**
-     * <p>Attempts to determine whether the named MBean should be
-     * considered as an instance of a given class.  The default implementation
-     * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
-     * to get an MBean object.  Then its behaviour is the same as the standard
-     * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.</p>
-     *
-     * {@inheritDoc}
-     */
-    public boolean isInstanceOf(ObjectName name, String className)
-        throws InstanceNotFoundException {
-
-        final DynamicMBean instance = nonNullMBeanFor(name);
-
-        try {
-            final String mbeanClassName = instance.getMBeanInfo().getClassName();
-
-            if (mbeanClassName.equals(className))
-                return true;
-
-            final Object resource;
-            final ClassLoader cl;
-            if (instance instanceof DynamicWrapperMBean) {
-                DynamicWrapperMBean d = (DynamicWrapperMBean) instance;
-                resource = d.getWrappedObject();
-                cl = d.getWrappedClassLoader();
-            } else {
-                resource = instance;
-                cl = instance.getClass().getClassLoader();
-            }
-
-            final Class<?> classNameClass = Class.forName(className, false, cl);
-
-            if (classNameClass.isInstance(resource))
-                return true;
-
-            if (classNameClass == NotificationBroadcaster.class ||
-                    classNameClass == NotificationEmitter.class) {
-                try {
-                    getNotificationEmitterFor(name);
-                    return true;
-                } catch (Exception x) {
-                    LOG.finest("MBean " + name +
-                            " is not a notification emitter. Ignoring: "+x);
-                    return false;
-                }
-            }
-
-            final Class<?> resourceClass = Class.forName(mbeanClassName, false, cl);
-            return classNameClass.isAssignableFrom(resourceClass);
-        } catch (Exception x) {
-            /* Could be SecurityException or ClassNotFoundException */
-            LOG.logp(Level.FINEST,
-                    MBeanServerSupport.class.getName(),
-                    "isInstanceOf", "Exception calling isInstanceOf", x);
-            return false;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method returns the string
-     * "DefaultDomain".</p>
-     */
-    public String getDefaultDomain() {
-        return "DefaultDomain";
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method returns
-     * {@link #getNames()}.size().</p>
-     */
-    public Integer getMBeanCount() {
-        return getNames().size();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method first calls {@link #getNames
-     * getNames()} to get a list of all MBean names,
-     * and from this set of names, derives the set of domains which contain
-     * MBeans.</p>
-     */
-    public String[] getDomains() {
-        final Set<ObjectName> names = getNames();
-        final Set<String> res = new TreeSet<String>();
-        for (ObjectName n : names) {
-            if (n == null) continue; // not allowed but you never know.
-            res.add(n.getDomain());
-        }
-        return res.toArray(new String[res.size()]);
-    }
-
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link
-     *    #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle
-     * to the named MBean,
-     * and then call {@link DynamicMBean#getAttribute getAttribute}
-     * on that {@link DynamicMBean} handle.</p>
-     *
-     * @throws RuntimeOperationsException {@inheritDoc}
-     */
-    public Object getAttribute(ObjectName name, String attribute)
-        throws MBeanException, AttributeNotFoundException,
-               InstanceNotFoundException, ReflectionException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        return mbean.getAttribute(attribute);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
-     * to obtain a handle to the named MBean,
-     * and then call {@link DynamicMBean#setAttribute setAttribute}
-     * on that {@link DynamicMBean} handle.</p>
-     *
-     * @throws RuntimeOperationsException {@inheritDoc}
-     */
-    public void setAttribute(ObjectName name, Attribute attribute)
-        throws InstanceNotFoundException, AttributeNotFoundException,
-            InvalidAttributeValueException, MBeanException,
-            ReflectionException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        mbean.setAttribute(attribute);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
-     * handle to the named MBean,
-     * and then call {@link DynamicMBean#getAttributes getAttributes}
-     * on that {@link DynamicMBean} handle.</p>
-     *
-     * @throws RuntimeOperationsException {@inheritDoc}
-     */
-    public AttributeList getAttributes(ObjectName name,
-            String[] attributes) throws InstanceNotFoundException,
-            ReflectionException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        return mbean.getAttributes(attributes);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
-     * handle to the named MBean,
-     * and then call {@link DynamicMBean#setAttributes setAttributes}
-     * on that {@link DynamicMBean} handle.</p>
-     *
-     * @throws RuntimeOperationsException {@inheritDoc}
-     */
-    public AttributeList setAttributes(ObjectName name, AttributeList attributes)
-        throws InstanceNotFoundException, ReflectionException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        return mbean.setAttributes(attributes);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
-     * handle to the named MBean,
-     * and then call {@link DynamicMBean#invoke invoke}
-     * on that {@link DynamicMBean} handle.</p>
-     */
-    public Object invoke(ObjectName name, String operationName,
-                Object[] params, String[] signature)
-                throws InstanceNotFoundException, MBeanException,
-                       ReflectionException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        return mbean.invoke(operationName, params, signature);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
-     * handle to the named MBean,
-     * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo}
-     * on that {@link DynamicMBean} handle.</p>
-     */
-    public MBeanInfo getMBeanInfo(ObjectName name)
-        throws InstanceNotFoundException, IntrospectionException,
-               ReflectionException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        return mbean.getMBeanInfo();
-   }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will call
-     * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.<!--
-     * -->{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.<!--
-     * -->{@link MBeanInfo#getClassName getClassName()} to get the
-     * class name to combine with {@code name} to produce a new
-     * {@code ObjectInstance}.</p>
-     */
-    public ObjectInstance getObjectInstance(ObjectName name)
-            throws InstanceNotFoundException {
-        final DynamicMBean mbean = nonNullMBeanFor(name);
-        final String className = mbean.getMBeanInfo().getClassName();
-        return new ObjectInstance(name, className);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first call {@link
-     * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the
-     * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code
-     * isRegistered} will return true. If {@code getDynamicMBeanFor} returns
-     * null or throws {@link InstanceNotFoundException}, {@code isRegistered}
-     * will return false.</p>
-     *
-     * @throws RuntimeOperationsException {@inheritDoc}
-     */
-    public boolean isRegistered(ObjectName name) {
-        try {
-            final DynamicMBean mbean = getDynamicMBeanFor(name);
-            return mbean!=null;
-        } catch (InstanceNotFoundException x) {
-            if (LOG.isLoggable(Level.FINEST))
-                LOG.finest("MBean "+name+" is not registered: "+x);
-            return false;
-        }
-    }
-
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method will first
-     * call {@link #queryNames queryNames}
-     * to get a list of all matching MBeans, and then, for each returned name,
-     * call {@link #getObjectInstance getObjectInstance(name)}.</p>
-     */
-    public Set<ObjectInstance> queryMBeans(ObjectName pattern, QueryExp query) {
-        final Set<ObjectName> names = queryNames(pattern, query);
-        if (names.isEmpty()) return Collections.emptySet();
-        final Set<ObjectInstance> mbeans = new HashSet<ObjectInstance>();
-        for (ObjectName name : names) {
-            try {
-                mbeans.add(getObjectInstance(name));
-            } catch (SecurityException x) { // DLS: OK
-                continue;
-            } catch (InstanceNotFoundException x) { // DLS: OK
-                continue;
-            }
-        }
-        return mbeans;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method calls {@link #getMatchingNames
-     * getMatchingNames(pattern)} to obtain a list of MBeans matching
-     * the given name pattern. If the {@code query} parameter is null,
-     * this will be the result. Otherwise, it will evaluate the
-     * {@code query} parameter for each of the returned names, exactly
-     * as an {@code MBeanServer} would. This might result in
-     * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called
-     * several times for each returned name.</p>
-     */
-    public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
-        try {
-            final Set<ObjectName> res = getMatchingNames(pattern);
-            return filterListOfObjectNames(res, query);
-        } catch (Exception x) {
-            LOG.fine("Unexpected exception raised in queryNames: "+x);
-            LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x);
-        }
-        // We reach here only when an exception was raised.
-        //
-        return Collections.emptySet();
-    }
-
-    private final static boolean apply(final QueryExp query,
-                  final ObjectName on,
-                  final MBeanServer srv) {
-        boolean res = false;
-        MBeanServer oldServer = QueryEval.getMBeanServer();
-        query.setMBeanServer(srv);
-        try {
-            res = query.apply(on);
-        } catch (Exception e) {
-            LOG.finest("QueryExp.apply threw exception, returning false." +
-                    " Cause: "+e);
-            res = false;
-        } finally {
-           /*
-            * query.setMBeanServer is probably
-            * QueryEval.setMBeanServer so put back the old
-            * value.  Since that method uses a ThreadLocal
-            * variable, this code is only needed for the
-            * unusual case where the user creates a custom
-            * QueryExp that calls a nested query on another
-            * MBeanServer.
-            */
-            query.setMBeanServer(oldServer);
-        }
-        return res;
-    }
-
-    /**
-     * Filters a {@code Set<ObjectName>} according to a pattern and a query.
-     * This might be quite inefficient for virtual name spaces.
-     */
-    Set<ObjectName>
-            filterListOfObjectNames(Set<ObjectName> list,
-                                    QueryExp query) {
-        if (list.isEmpty() || query == null)
-            return list;
-
-        // create a new result set
-        final Set<ObjectName> result = new HashSet<ObjectName>();
-
-        for (ObjectName on : list) {
-            // if on doesn't match query exclude it.
-            if (apply(query, on, this))
-                result.add(on);
-        }
-        return result;
-    }
-
-
-    // Don't use {@inheritDoc}, because we don't want to say that the
-    // MBeanServer replaces a reference to the MBean by its ObjectName.
-    /**
-     * <p>Adds a listener to a registered MBean. A notification emitted by
-     * the MBean will be forwarded to the listener.</p>
-     *
-     * <p>This implementation calls
-     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
-     * and invokes {@code addNotificationListener} on the
-     * {@link NotificationEmitter} it returns.
-     *
-     * @see #getDynamicMBeanFor getDynamicMBeanFor
-     * @see #getNotificationEmitterFor getNotificationEmitterFor
-     */
-    public void addNotificationListener(ObjectName name,
-            NotificationListener listener, NotificationFilter filter,
-            Object handback) throws InstanceNotFoundException {
-        final NotificationEmitter emitter =
-                getNonNullNotificationEmitterFor(name);
-        emitter.addNotificationListener(listener, filter, handback);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation calls
-     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
-     * and invokes {@code removeNotificationListener} on the
-     * {@link NotificationEmitter} it returns.
-     * @see #getDynamicMBeanFor getDynamicMBeanFor
-     * @see #getNotificationEmitterFor getNotificationEmitterFor
-     */
-    public void removeNotificationListener(ObjectName name,
-            NotificationListener listener)
-            throws InstanceNotFoundException, ListenerNotFoundException {
-        final NotificationEmitter emitter =
-                getNonNullNotificationEmitterFor(name);
-        emitter.removeNotificationListener(listener);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation calls
-     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
-     * and invokes {@code removeNotificationListener} on the
-     * {@link NotificationEmitter} it returns.
-     * @see #getDynamicMBeanFor getDynamicMBeanFor
-     * @see #getNotificationEmitterFor getNotificationEmitterFor
-     */
-    public void removeNotificationListener(ObjectName name,
-            NotificationListener listener, NotificationFilter filter,
-            Object handback)
-            throws InstanceNotFoundException, ListenerNotFoundException {
-        NotificationEmitter emitter =
-                getNonNullNotificationEmitterFor(name);
-        emitter.removeNotificationListener(listener);
-    }
-
-
-    /**
-     * <p>Adds a listener to a registered MBean.</p>
-     *
-     * <p>The default implementation of this method first calls
-     * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}.
-     * If that successfully returns an object, call it {@code
-     * mbean}, then (a) if {@code mbean} is an instance of {@link
-     * NotificationListener} then this method calls {@link
-     * #addNotificationListener(ObjectName, NotificationListener,
-     * NotificationFilter, Object) addNotificationListener(name, mbean, filter,
-     * handback)}, otherwise (b) this method throws an exception as specified
-     * for this case.</p>
-     *
-     * <p>This default implementation is not appropriate for Virtual MBeans,
-     * although that only matters if the object returned by {@code
-     * getDynamicMBeanFor} can be an instance of
-     * {@code NotificationListener}.</p>
-     *
-     * @throws RuntimeOperationsException {@inheritDoc}
-     */
-    public void addNotificationListener(ObjectName name, ObjectName listenerName,
-            NotificationFilter filter, Object handback)
-            throws InstanceNotFoundException {
-        NotificationListener listener = getListenerMBean(listenerName);
-        addNotificationListener(name, listener, filter, handback);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public void removeNotificationListener(ObjectName name,
-            ObjectName listenerName)
-            throws InstanceNotFoundException, ListenerNotFoundException {
-        NotificationListener listener = getListenerMBean(listenerName);
-        removeNotificationListener(name, listener);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public void removeNotificationListener(ObjectName name,
-            ObjectName listenerName, NotificationFilter filter,
-            Object handback)
-            throws InstanceNotFoundException, ListenerNotFoundException {
-        NotificationListener listener = getListenerMBean(listenerName);
-        removeNotificationListener(name, listener, filter, handback);
-    }
-
-    private NotificationListener getListenerMBean(ObjectName listenerName)
-            throws InstanceNotFoundException {
-        Object mbean = getDynamicMBeanFor(listenerName);
-        if (mbean instanceof NotificationListener)
-            return (NotificationListener) mbean;
-        else {
-            throw newIllegalArgumentException(
-                    "MBean is not a NotificationListener: " + listenerName);
-        }
-    }
-
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link InstanceNotFoundException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @return the default implementation of this method never returns.
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public ClassLoader getClassLoader(ObjectName loaderName)
-            throws InstanceNotFoundException {
-        final UnsupportedOperationException failed =
-                new UnsupportedOperationException("getClassLoader");
-        final InstanceNotFoundException x =
-                new InstanceNotFoundException(String.valueOf(loaderName));
-        x.initCause(failed);
-        throw x;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method calls
-     * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies
-     * the logic just described to the result.</p>
-     */
-    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
-            throws InstanceNotFoundException {
-        final DynamicMBean mbean = nonNullMBeanFor(mbeanName);
-        if (mbean instanceof DynamicWrapperMBean)
-            return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
-        else
-            return mbean.getClass().getClassLoader();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>The default implementation of this method returns a
-     * {@link ClassLoaderRepository} containing exactly one loader,
-     * the {@linkplain Thread#getContextClassLoader() context class loader}
-     * for the current thread.
-     * Subclasses can override this method to return a different
-     * {@code ClassLoaderRepository}.</p>
-     */
-    public ClassLoaderRepository getClassLoaderRepository() {
-        // We return a new ClassLoaderRepository each time this
-        // method is called. This is by design, because the
-        // SingletonClassLoaderRepository is a very small object and
-        // getClassLoaderRepository() will not be called very often
-        // (the connector server calls it once) - in the context of
-        // MBeanServerSupport there's a very good chance that this method will
-        // *never* be called.
-        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
-        return Util.getSingleClassLoaderRepository(ccl);
-    }
-
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public ObjectInstance registerMBean(Object object, ObjectName name)
-            throws InstanceAlreadyExistsException, MBeanRegistrationException,
-            NotCompliantMBeanException {
-        throw newUnsupportedException("registerMBean");
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public void unregisterMBean(ObjectName name)
-            throws InstanceNotFoundException, MBeanRegistrationException {
-        throw newUnsupportedException("unregisterMBean");
-    }
-
-    /**
-     * Calls {@link #createMBean(String, ObjectName,
-     *           ObjectName, Object[], String[], boolean)
-     * createMBean(className, name, null, params, signature, true)};
-     */
-    public final ObjectInstance createMBean(String className, ObjectName name,
-            Object[] params, String[] signature)
-            throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException {
-        try {
-            return safeCreateMBean(className, name, null, params, signature, true);
-        } catch (InstanceNotFoundException ex) {
-            // should not happen!
-            throw new MBeanException(ex, "Unexpected exception: " + ex);
-        }
-    }
-
-    /**
-     * Calls {@link #createMBean(String, ObjectName,
-     *           ObjectName, Object[], String[], boolean)
-     * createMBean(className,name, loaderName, params, signature, false)};
-     */
-    public final ObjectInstance createMBean(String className, ObjectName name,
-            ObjectName loaderName, Object[] params, String[] signature)
-            throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException, InstanceNotFoundException {
-        return safeCreateMBean(className, name, loaderName, params, signature, false);
-    }
-
-    /**
-     * Calls {@link #createMBean(String, ObjectName,
-     *           ObjectName, Object[], String[], boolean)
-     * createMBean(className, name, null, null, null, true)};
-     */
-    public final ObjectInstance createMBean(String className, ObjectName name)
-        throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException {
-        try {
-            return safeCreateMBean(className, name, null, null, null, true);
-        } catch (InstanceNotFoundException ex) {
-            // should not happen!
-            throw new MBeanException(ex, "Unexpected exception: " + ex);
-        }
-    }
-
-    /**
-     * Calls {@link #createMBean(String, ObjectName,
-     *           ObjectName, Object[], String[], boolean)
-     * createMBean(className, name, loaderName, null, null, false)};
-     */
-    public final ObjectInstance createMBean(String className, ObjectName name,
-            ObjectName loaderName)
-            throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException, InstanceNotFoundException {
-        return safeCreateMBean(className, name, loaderName, null, null, false);
-    }
-
-    // make sure all exceptions are correctly wrapped in a JMXException
-    private ObjectInstance safeCreateMBean(String className,
-            ObjectName name, ObjectName loaderName, Object[] params,
-            String[] signature, boolean useRepository)
-            throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException, InstanceNotFoundException {
-        try {
-            return createMBean(className, name, loaderName, params,
-                               signature, useRepository);
-        } catch (ReflectionException x) { throw x;
-        } catch (InstanceAlreadyExistsException x) { throw x;
-        } catch (MBeanRegistrationException x) { throw x;
-        } catch (MBeanException x) { throw x;
-        } catch (NotCompliantMBeanException x) { throw x;
-        } catch (InstanceNotFoundException x) { throw x;
-        } catch (SecurityException x) { throw x;
-        } catch (JMRuntimeException x) { throw x;
-        } catch (RuntimeException x) {
-            throw new RuntimeOperationsException(x, x.toString());
-        } catch (Exception x) {
-            throw new MBeanException(x, x.toString());
-        }
-    }
-
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public Object instantiate(String className)
-            throws ReflectionException, MBeanException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public Object instantiate(String className, ObjectName loaderName)
-            throws ReflectionException, MBeanException,
-            InstanceNotFoundException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public Object instantiate(String className, Object[] params,
-            String[] signature) throws ReflectionException, MBeanException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    public Object instantiate(String className, ObjectName loaderName,
-            Object[] params, String[] signature)
-            throws ReflectionException, MBeanException,
-            InstanceNotFoundException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    @Deprecated
-    public ObjectInputStream deserialize(ObjectName name, byte[] data)
-            throws InstanceNotFoundException, OperationsException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    @Deprecated
-    public ObjectInputStream deserialize(String className, byte[] data)
-            throws OperationsException, ReflectionException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This operation is not supported in this base class implementation.
-     * The default implementation of this method always throws
-     * {@link RuntimeOperationsException} wrapping
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * @throws javax.management.RuntimeOperationsException wrapping
-     *        {@link UnsupportedOperationException}
-     */
-    @Deprecated
-    public ObjectInputStream deserialize(String className,
-            ObjectName loaderName, byte[] data)
-            throws InstanceNotFoundException, OperationsException,
-            ReflectionException {
-        throw new UnsupportedOperationException("Not applicable.");
-    }
-
-
-    // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException
-    // if the returned mbean is null.
-    // The DynamicMBean returned by this method is thus guaranteed to be
-    // non null.
-    //
-    private DynamicMBean nonNullMBeanFor(ObjectName name)
-            throws InstanceNotFoundException {
-        if (name == null)
-            throw newIllegalArgumentException("Null ObjectName");
-        if (name.getDomain().equals("")) {
-            String defaultDomain = getDefaultDomain();
-            try {
-                // XXX change to ObjectName.switchDomain
-                // current code DOES NOT PRESERVE the order of keys
-                name = new ObjectName(defaultDomain, name.getKeyPropertyList());
-            } catch (Exception e) {
-                throw newIllegalArgumentException(
-                        "Illegal default domain: " + defaultDomain);
-            }
-        }
-        final DynamicMBean mbean = getDynamicMBeanFor(name);
-        if (mbean!=null) return mbean;
-        throw new InstanceNotFoundException(String.valueOf(name));
-    }
-
-    static RuntimeException newUnsupportedException(String operation) {
-        return new RuntimeOperationsException(
-            new UnsupportedOperationException(
-                operation+": Not supported in this namespace"));
-    }
-
-    static RuntimeException newIllegalArgumentException(String msg) {
-        return new RuntimeOperationsException(
-                new IllegalArgumentException(msg));
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.interceptor;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.mbeanserver.MBeanInstantiator;
+import com.sun.jmx.mbeanserver.Repository;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.namespace.NamespaceInterceptor;
+
+import java.util.Queue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.namespace.JMXDomain;
+import javax.management.namespace.JMXNamespace;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
+
+/**
+ * A dispatcher that dispatches to NamespaceInterceptors.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public class NamespaceDispatchInterceptor
+        extends DispatchInterceptor<NamespaceInterceptor, JMXNamespace> {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    private static final int NAMESPACE_SEPARATOR_LENGTH =
+            NAMESPACE_SEPARATOR.length();
+
+    private final DomainDispatchInterceptor localNamespace;
+    private final String           serverName;
+
+    /**
+     * Creates a NamespaceDispatchInterceptor with the specified
+     * repository instance.
+     * <p>Do not forget to call <code>initialize(outer,delegate)</code>
+     * before using this object.
+     *
+     * @param outer A pointer to the MBeanServer object that must be
+     *        passed to the MBeans when invoking their
+     *        {@link javax.management.MBeanRegistration} interface.
+     * @param delegate A pointer to the MBeanServerDelegate associated
+     *        with the new MBeanServer. The new MBeanServer must register
+     *        this MBean in its MBean repository.
+     * @param instantiator The MBeanInstantiator that will be used to
+     *        instantiate MBeans and take care of class loading issues.
+     * @param repository The repository to use for this MBeanServer
+     */
+    public NamespaceDispatchInterceptor(MBeanServer         outer,
+                               MBeanServerDelegate delegate,
+                               MBeanInstantiator   instantiator,
+                               Repository          repository)  {
+           localNamespace = new DomainDispatchInterceptor(outer,delegate,
+                   instantiator,repository,this);
+           serverName = Util.getMBeanServerSecurityName(delegate);
+    }
+
+    // TODO: Should move that to JMXNamespace? or to ObjectName?
+    /**
+     * Get first name space in ObjectName path. Ignore leading namespace
+     * separators.
+     **/
+    public static String getFirstNamespace(ObjectName name) {
+        if (name == null) return "";
+        final String domain = name.getDomain();
+        if (domain.equals("")) return "";
+
+        int first = 0;
+        int end = domain.indexOf(NAMESPACE_SEPARATOR,first);
+        while (end == first) {
+            first = end+NAMESPACE_SEPARATOR_LENGTH;
+            end = domain.indexOf(NAMESPACE_SEPARATOR,first);
+            if (end == -1) break;
+        }
+
+        if (end == -1) return "";
+
+        final String namespace = domain.substring(first,end);
+
+        return namespace;
+    }
+
+    /**
+     * Called by the DefaultMBeanServerInterceptor, just before adding an
+     * MBean to the repository.
+     *
+     * @param resource the MBean to be registered.
+     * @param logicalName the name of the MBean to be registered.
+     */
+    final void checkLocallyRegistrable(Object resource,
+            ObjectName logicalName) {
+        if (!(resource instanceof JMXNamespace) &&
+                logicalName.getDomain().contains(NAMESPACE_SEPARATOR))
+            throw new IllegalArgumentException(String.valueOf(logicalName)+
+                    ": Invalid ObjectName for an instance of " +
+                    resource.getClass().getName());
+    }
+
+    final boolean isLocalHandlerNameFor(String namespace,
+            ObjectName handlerName) {
+        return handlerName.getDomain().equals(namespace+NAMESPACE_SEPARATOR) &&
+               JMXNamespace.TYPE_ASSIGNMENT.equals(
+               handlerName.getKeyPropertyListString());
+    }
+
+    @Override
+    final MBeanServer getInterceptorOrNullFor(ObjectName name) {
+        final String namespace = getFirstNamespace(name);
+        if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) ||
+            name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
+            LOG.finer("dispatching to local name space");
+            return localNamespace;
+        }
+        final NamespaceInterceptor ns = getInterceptor(namespace);
+        if (LOG.isLoggable(Level.FINER)) {
+            if (ns != null) {
+                LOG.finer("dispatching to name space: " + namespace);
+            } else {
+                LOG.finer("no handler for: " + namespace);
+            }
+        }
+        return ns;
+    }
+
+    @Override
+    final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
+        final String namespace = getFirstNamespace(pattern);
+        if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) ||
+            pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
+            LOG.finer("dispatching to local name space");
+            return new QueryInterceptor(localNamespace);
+        }
+        final NamespaceInterceptor ns = getInterceptor(namespace);
+        if (LOG.isLoggable(Level.FINER)) {
+            if (ns != null) {
+                LOG.finer("dispatching to name space: " + namespace);
+            } else {
+                LOG.finer("no handler for: " + namespace);
+            }
+        }
+        if (ns == null) return null;
+        return new QueryInterceptor(ns);
+    }
+
+    @Override
+    final ObjectName getHandlerNameFor(String key)
+        throws MalformedObjectNameException {
+        return ObjectName.getInstance(key+NAMESPACE_SEPARATOR,
+                    "type", JMXNamespace.TYPE);
+    }
+
+    @Override
+    final public String getHandlerKey(ObjectName name) {
+        return getFirstNamespace(name);
+    }
+
+    @Override
+    final NamespaceInterceptor createInterceptorFor(String key,
+            ObjectName name, JMXNamespace handler,
+            Queue<Runnable> postRegisterQueue) {
+        final NamespaceInterceptor ns =
+                new NamespaceInterceptor(serverName,handler,key);
+        if (LOG.isLoggable(Level.FINER)) {
+            LOG.finer("NamespaceInterceptor created: "+ns);
+        }
+        return ns;
+    }
+
+    @Override
+    final DomainDispatchInterceptor getNextInterceptor() {
+        return localNamespace;
+    }
+
+    /**
+     * Returns the list of domains in which any MBean is currently
+     * registered.
+     */
+    @Override
+    public String[] getDomains() {
+        return localNamespace.getDomains();
+    }
+
+    @Override
+    public void addNamespace(ObjectName name, JMXNamespace handler,
+            Queue<Runnable> postRegisterQueue) {
+        if (handler instanceof JMXDomain)
+            localNamespace.addNamespace(name,
+                    (JMXDomain)handler,postRegisterQueue);
+        else super.addNamespace(name,handler,postRegisterQueue);
+    }
+
+    @Override
+    public void removeNamespace(ObjectName name, JMXNamespace handler,
+            Queue<Runnable> postDeregisterQueue) {
+        if (handler instanceof JMXDomain)
+            localNamespace.removeNamespace(name,(JMXDomain)handler,
+                    postDeregisterQueue);
+        else super.removeNamespace(name,handler,postDeregisterQueue);
+    }
+
+
+}
--- a/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java	Thu Sep 04 14:46:36 2008 +0200
@@ -51,6 +51,8 @@
 import javax.management.ObjectName;
 import javax.management.QueryExp;
 import javax.management.ReflectionException;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.MBeanServerSupport;
 import javax.management.remote.IdentityMBeanServerForwarder;
 
 public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
@@ -285,14 +287,14 @@
         if (!pattern.apply(mbeanName))
             return false;
 
-//        final String dompat = pattern.getDomain();
-//        if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR))
-//            return true; // We already checked that patterns apply.
-//
-//        if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) {
-//            // only matches if pattern ends with //
-//            return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR);
-//        }
+        final String dompat = pattern.getDomain();
+        if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR))
+            return true; // We already checked that patterns apply.
+
+        if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) {
+            // only matches if pattern ends with //
+            return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR);
+        }
 
         // should not come here, unless mbeanName contains a // in the
         // middle of its domain, which would be weird.
--- a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java	Thu Sep 04 14:46:36 2008 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,44 +25,42 @@
 
 package com.sun.jmx.mbeanserver;
 
-import java.util.Iterator;
-import java.util.logging.Level;
-import java.util.Set;
+import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
+import com.sun.jmx.interceptor.NamespaceDispatchInterceptor;
+
 import java.io.ObjectInputStream;
 import java.security.AccessController;
 import java.security.Permission;
 import java.security.PrivilegedExceptionAction;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.logging.Level;
 
-// RI import
-import javax.management.MBeanPermission;
-import javax.management.AttributeNotFoundException;
-import javax.management.MBeanException;
-import javax.management.ReflectionException;
-import javax.management.MBeanInfo;
-import javax.management.QueryExp;
-import javax.management.NotificationListener;
-import javax.management.NotificationFilter;
-import javax.management.ListenerNotFoundException;
-import javax.management.IntrospectionException;
-import javax.management.OperationsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.MBeanRegistrationException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InvalidAttributeValueException;
-import javax.management.ObjectName;
-import javax.management.ObjectInstance;
 import javax.management.Attribute;
 import javax.management.AttributeList;
-import javax.management.RuntimeOperationsException;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanPermission;
+import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerDelegate;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
 import javax.management.loading.ClassLoaderRepository;
 
-import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
-import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;
-import com.sun.jmx.interceptor.MBeanServerInterceptor;
-
 /**
  * This is the base class for MBean manipulation on the agent side. It
  * contains the methods necessary for the creation, registration, and
@@ -102,15 +100,14 @@
     /** true if interceptors are enabled **/
     private final boolean interceptorsEnabled;
 
-    /** Revisit: transient ??? **/
-    private final transient MBeanServer outerShell;
+    private final MBeanServer outerShell;
 
-    /** Revisit: transient ??? **/
-    private transient MBeanServerInterceptor mbsInterceptor = null;
+    private volatile MBeanServer mbsInterceptor = null;
 
-    /** Revisit: transient ??? **/
     /** The MBeanServerDelegate object representing the MBean Server */
-    private final transient MBeanServerDelegate mBeanServerDelegateObject;
+    private final MBeanServerDelegate mBeanServerDelegateObject;
+
+    private final String mbeanServerName;
 
     /**
      * <b>Package:</b> Creates an MBeanServer with the
@@ -243,9 +240,10 @@
 
         final Repository repository = new Repository(domain,fairLock);
         this.mbsInterceptor =
-            new DefaultMBeanServerInterceptor(outer, delegate, instantiator,
+            new NamespaceDispatchInterceptor(outer, delegate, instantiator,
                                               repository);
         this.interceptorsEnabled = interceptors;
+        this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
         initialize();
     }
 
@@ -941,7 +939,8 @@
         throws ReflectionException, MBeanException {
 
         /* Permission check */
-        checkMBeanPermission(className, null, null, "instantiate");
+        checkMBeanPermission(mbeanServerName, className, null, null,
+                "instantiate");
 
         return instantiator.instantiate(className);
     }
@@ -978,7 +977,8 @@
                InstanceNotFoundException {
 
         /* Permission check */
-        checkMBeanPermission(className, null, null, "instantiate");
+        checkMBeanPermission(mbeanServerName, className, null,
+                null, "instantiate");
 
         ClassLoader myLoader = outerShell.getClass().getClassLoader();
         return instantiator.instantiate(className, loaderName, myLoader);
@@ -1016,7 +1016,8 @@
         throws ReflectionException, MBeanException {
 
         /* Permission check */
-        checkMBeanPermission(className, null, null, "instantiate");
+        checkMBeanPermission(mbeanServerName, className, null, null,
+                "instantiate");
 
         ClassLoader myLoader = outerShell.getClass().getClassLoader();
         return instantiator.instantiate(className, params, signature,
@@ -1059,7 +1060,8 @@
                InstanceNotFoundException {
 
         /* Permission check */
-        checkMBeanPermission(className, null, null, "instantiate");
+        checkMBeanPermission(mbeanServerName, className, null,
+                null, "instantiate");
 
         ClassLoader myLoader = outerShell.getClass().getClassLoader();
         return instantiator.instantiate(className,loaderName,params,signature,
@@ -1236,7 +1238,7 @@
                         "Unexpected exception occurred", e);
             }
             throw new
-                IllegalStateException("Can't register delegate.");
+                IllegalStateException("Can't register delegate.",e);
         }
 
 
@@ -1278,7 +1280,7 @@
      *            are not enabled on this object.
      * @see #interceptorsEnabled
      **/
-    public synchronized MBeanServerInterceptor getMBeanServerInterceptor() {
+    public synchronized MBeanServer getMBeanServerInterceptor() {
         if (interceptorsEnabled) return mbsInterceptor;
         else throw new UnsupportedOperationException(
                        "MBeanServerInterceptors are disabled.");
@@ -1292,7 +1294,7 @@
      * @see #interceptorsEnabled
      **/
     public synchronized void
-        setMBeanServerInterceptor(MBeanServerInterceptor interceptor) {
+        setMBeanServerInterceptor(MBeanServer interceptor) {
         if (!interceptorsEnabled) throw new UnsupportedOperationException(
                        "MBeanServerInterceptors are disabled.");
         if (interceptor == null) throw new
@@ -1330,7 +1332,8 @@
      **/
     public ClassLoaderRepository getClassLoaderRepository() {
         /* Permission check */
-        checkMBeanPermission(null, null, null, "getClassLoaderRepository");
+        checkMBeanPermission(mbeanServerName, null, null,
+                null, "getClassLoaderRepository");
         return secureClr;
     }
 
@@ -1484,14 +1487,16 @@
     // SECURITY CHECKS
     //----------------
 
-    private static void checkMBeanPermission(String classname,
+    private static void checkMBeanPermission(String serverName,
+                                             String classname,
                                              String member,
                                              ObjectName objectName,
                                              String actions)
         throws SecurityException {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            Permission perm = new MBeanPermission(classname,
+            Permission perm = new MBeanPermission(serverName,
+                                                  classname,
                                                   member,
                                                   objectName,
                                                   actions);
--- a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java	Thu Sep 04 14:46:36 2008 +0200
@@ -224,7 +224,7 @@
         throws InvalidObjectException {
             String domain = prefix + name.getDomain();
             try {
-                name = switchDomain(domain, name);
+                name = name.withDomain(domain);
             } catch (MalformedObjectNameException e) {
                 throw EnvHelp.initCause(
                         new InvalidObjectException(e.getMessage()), e);
@@ -242,7 +242,7 @@
                         "Proxy's name does not start with " + prefix + ": " + name);
             }
             try {
-                name = switchDomain(domain.substring(prefix.length()), name);
+                name = name.withDomain(domain.substring(prefix.length()));
             } catch (MalformedObjectNameException e) {
                 throw EnvHelp.initCause(new OpenDataException(e.getMessage()), e);
             }
@@ -269,14 +269,6 @@
         currentLookup.set(lookup);
     }
 
-    // Method temporarily added until we have ObjectName.switchDomain in the
-    // public API.  Note that this method DOES NOT PRESERVE the order of
-    // keys in the ObjectName so it must not be used in the final release.
-    static ObjectName switchDomain(String domain, ObjectName name)
-            throws MalformedObjectNameException {
-        return new ObjectName(domain, name.getKeyPropertyList());
-    }
-
     private static final ThreadLocal<MXBeanLookup> currentLookup =
             new ThreadLocal<MXBeanLookup>();
 
--- a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java	Thu Sep 04 14:46:36 2008 +0200
@@ -45,7 +45,6 @@
 import javax.management.RuntimeOperationsException;
 
 /**
- * The RepositorySupport implements the Repository interface.
  * This repository does not support persistency.
  *
  * @since 1.5
@@ -197,9 +196,9 @@
                     if (isPropertyValuePattern &&
                         pattern.isPropertyValuePattern(keys[i])) {
                         // wildmatch key property values
-                        final char[] val_pattern = values[i].toCharArray();
-                        final char[] val_string  = v.toCharArray();
-                        if (wildmatch(val_string,val_pattern))
+                        // values[i] is the pattern;
+                        // v is the string
+                        if (Util.wildmatch(v,values[i]))
                             continue;
                         else
                             return false;
@@ -236,86 +235,6 @@
         }
     }
 
-    /** Match a string against a shell-style pattern.  The only pattern
-        characters recognised are <code>?</code>, standing for any one
-        character, and <code>*</code>, standing for any string of
-        characters, including the empty string.
-
-        @param str the string to match, as a character array.
-        @param pat the pattern to match the string against, as a
-        character array.
-
-        @return true if and only if the string matches the pattern.
-    */
-    /* The algorithm is a classical one.  We advance pointers in
-       parallel through str and pat.  If we encounter a star in pat,
-       we remember its position and continue advancing.  If at any
-       stage we get a mismatch between str and pat, we look to see if
-       there is a remembered star.  If not, we fail.  If so, we
-       retreat pat to just past that star and str to the position
-       after the last one we tried, and we let the match advance
-       again.
-
-       Even though there is only one remembered star position, the
-       algorithm works when there are several stars in the pattern.
-       When we encounter the second star, we forget the first one.
-       This is OK, because if we get to the second star in A*B*C
-       (where A etc are arbitrary strings), we have already seen AXB.
-       We're therefore setting up a match of *C against the remainder
-       of the string, which will match if that remainder looks like
-       YC, so the whole string looks like AXBYC.
-    */
-    public static boolean wildmatch(char[] str, char[] pat) {
-        int stri;     // index in str
-        int pati;     // index in pat
-        int starstri; // index for backtrack if "*" attempt fails
-        int starpati; // index for backtrack if "*" attempt fails, +1
-        final int strlen = str.length;
-        final int patlen = pat.length;
-
-        stri = pati = 0;
-        starstri = starpati = -1;
-
-        /* On each pass through this loop, we either advance pati,
-           or we backtrack pati and advance starstri.  Since starstri
-           is only ever assigned from pati, the loop must terminate.  */
-        while (true) {
-            if (pati < patlen) {
-                final char patc = pat[pati];
-                switch (patc) {
-                case '?':
-                    if (stri == strlen)
-                        break;
-                    stri++;
-                    pati++;
-                    continue;
-                case '*':
-                    pati++;
-                    starpati = pati;
-                    starstri = stri;
-                    continue;
-                default:
-                    if (stri < strlen && str[stri] == patc) {
-                        stri++;
-                        pati++;
-                        continue;
-                    }
-                    break;
-                }
-            } else if (stri == strlen)
-                return true;
-
-            // Mismatched, can we backtrack to a "*"?
-            if (starpati < 0 || starstri == strlen)
-                return false;
-
-            // Retry the match one position later in str
-            pati = starpati;
-            starstri++;
-            stri = starstri;
-        }
-    }
-
     private void addNewDomMoi(final DynamicMBean object,
                               final String dom,
                               final ObjectName name,
@@ -370,7 +289,7 @@
         if (name.isPattern()) return null;
 
         // Extract the domain name.
-        String dom= name.getDomain().intern();
+        String dom = name.getDomain().intern();
 
         // Default domain case
         if (dom.length() == 0) {
@@ -480,7 +399,7 @@
             name = Util.newObjectName(domain + name.toString());
 
         // Do we have default domain ?
-        if (dom == domain) {
+        if (dom == domain) {  // ES: OK (dom & domain are interned)
             to_default_domain = true;
             dom = domain;
         } else {
@@ -652,10 +571,9 @@
             }
 
             // Pattern matching in the domain name (*, ?)
-            char[] dom2Match = name.getDomain().toCharArray();
+            final String dom2Match = name.getDomain();
             for (String dom : domainTb.keySet()) {
-                char[] theDom = dom.toCharArray();
-                if (wildmatch(theDom, dom2Match)) {
+                if (Util.wildpathmatch(dom, dom2Match)) {
                     final Map<String,NamedObject> moiTb = domainTb.get(dom);
                     if (allNames)
                         result.addAll(moiTb.values());
@@ -726,7 +644,7 @@
                 // need to reinstantiate a hashtable because of possible
                 // big buckets array size inside table, never cleared,
                 // thus the new !
-                if (dom == domain)
+                if (dom == domain) // ES: OK dom and domain are interned.
                     domainTb.put(domain, new HashMap<String,NamedObject>());
             }
 
--- a/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java	Thu Sep 04 14:46:36 2008 +0200
@@ -28,17 +28,16 @@
 import javax.management.MBeanServer;
 import javax.management.MBeanServerDelegate;
 
-import com.sun.jmx.interceptor.MBeanServerInterceptor;
 
 /**
- * Extends the MBeanServer and MBeanServerInterceptor interface to
+ * Extends the MBeanServer interface to
  * provide methods for getting the MetaData and MBeanServerInstantiator
  * objects associated with an MBeanServer.
  *
  * @since 1.5
  */
 public interface SunJmxMBeanServer
-    extends MBeanServerInterceptor, MBeanServer {
+    extends MBeanServer {
 
     /**
      * Return the MBeanInstantiator associated to this MBeanServer.
@@ -68,7 +67,7 @@
      *            are not enabled on this object.
      * @see #interceptorsEnabled
      **/
-    public MBeanServerInterceptor getMBeanServerInterceptor();
+    public MBeanServer getMBeanServerInterceptor();
 
     /**
      * Set the MBeanServerInterceptor.
@@ -77,7 +76,7 @@
      *            are not enabled on this object.
      * @see #interceptorsEnabled
      **/
-    public void setMBeanServerInterceptor(MBeanServerInterceptor interceptor);
+    public void setMBeanServerInterceptor(MBeanServer interceptor);
 
     /**
      * <p>Return the MBeanServerDelegate representing the MBeanServer.
--- a/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Wed Sep 03 14:31:17 2008 +0200
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Thu Sep 04 14:46:36 2008 +0200
@@ -25,6 +25,8 @@
 
 package com.sun.jmx.mbeanserver;
 
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -42,11 +44,22 @@
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.WeakHashMap;
+import java.util.logging.Level;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerFactory;
 import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 import javax.management.loading.ClassLoaderRepository;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
 
 public class Util {
+    private final static int NAMESPACE_SEPARATOR_LENGTH =
+            NAMESPACE_SEPARATOR.length();
+    public final static String ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?";
+
+
     static <K, V> Map<K, V> newMap() {
         return new HashMap<K, V>();
     }
@@ -145,6 +158,270 @@
         return hash;
     }
 
+    /** Match a part of a string against a shell-style pattern.
+        The only pattern characters recognized are <code>?</code>,
+        standing for any one character,
+        and <code>*</code>, standing for any string of
+        characters, including the empty string. For instance,
+        {@code wildmatch("sandwich","sa?d*ch",1,4,1,4)} will match
+        {@code "and"} against {@code "a?d"}.
+
+        @param str  the string containing the sequence to match.
+        @param pat  a string containing a pattern to match the sub string
+                    against.
+        @param stri   the index in the string at which matching should begin.
+        @param strend the index in the string at which the matching should
+                      end.
+        @param pati   the index in the pattern at which matching should begin.
+        @param patend the index in the pattern at which the matching should
+                      end.
+
+        @return true if and only if the string matches the pattern.
+    */
+    /* The algorithm is a classical one.  We advance pointers in
+       parallel through str and pat.  If we encounter a star in pat,
+       we remember its position and continue advancing.  If at any
+       stage we get a mismatch between str and pat, we look to see if
+       there is a remembered star.  If not, we fail.  If so, we
+       retreat pat to just past that star and str to the position
+       after the last one we tried, and we let the match advance
+       again.
+
+       Even though there is only one remembered star position, the
+       algorithm works when there are several stars in the pattern.
+       When we encounter the second star, we forget the first one.
+       This is OK, because if we get to the second star in A*B*C
+       (where A etc are arbitrary strings), we have already seen AXB.
+       We're therefore setting up a match of *C against the remainder
+       of the string, which will match if that remainder looks like
+       YC, so the whole string looks like AXBYC.
+    */
+    private static boolean wildmatch(final String str, final String pat,
+            int stri, final int strend, int pati, final int patend) {
+
+        // System.out.println("matching "+pat.substring(pati,patend)+
+        //        " against "+str.substring(stri, strend));
+        int starstri; // index for backtrack if "*" attempt fails
+        int starpati; // index for backtrack if "*" attempt fails, +1
+
+        starstri = starpati = -1;
+
+        /* On each pass through this loop, we either advance pati,
+           or we backtrack pati and advance starstri.  Since starstri
+           is only ever assigned from pati, the loop must terminate.  */
+        while (true) {
+            if (pati < patend) {
+                final char patc = pat.charAt(pati);
+                switch (patc) {
+                case '?':
+                    if (stri == strend)
+                        break;
+                    stri++;
+                    pati++;
+                    continue;
+                case '*':
+                    pati++;
+                    starpati = pati;
+                    starstri = stri;
+                    continue;
+                default:
+                    if (stri < strend && str.charAt(stri) == patc) {
+                        stri++;
+                        pati++;
+                        continue;
+                    }
+                    break;
+                }
+            } else if (stri == strend)
+                return true;
+
+            // Mismatched, can we backtrack to a "*"?
+            if (starpati < 0 || starstri == strend)
+                return false;
+
+            // Retry the match one position later in str
+            pati = starpati;
+            starstri++;
+            stri = starstri;
+        }
+    }
+
+    /** Match a string against a shell-style pattern.  The only pattern
+        characters recognized are <code>?</code>, standing for any one
+        character, and <code>*</code>, standing for any string of
+        characters, including the empty string.
+
+        @param str the string to match.
+        @param pat the pattern to match the string against.
+
+        @return true if and only if the string matches the pattern.
+    */
+    public static boolean wildmatch(String str, String pat) {
+        return wildmatch(str,pat,0,str.length(),0,pat.length());
+    }
+
+    /**
+     * Matches a string against a pattern, as a name space path.
+     * This is a special matching where * and ?? don't match //.
+     * The string is split in sub-strings separated by //, and the
+     * pattern is split in sub-patterns separated by //. Each sub-string
+     * is matched against its corresponding sub-pattern.
+     * so <elt-1>//<elt2>//...//<elt-n> matches <pat-1>//<pat-2>//...//<pat-q>
+     * only if n==q and for ( i = 1 => n) elt-i matches pat-i.
+     *
+     * In addition, if we encounter a pattern element which is exactly
+     * **, it can match any number of path-elements - but it must match at
+     * least one element.
+     * When we encounter such a meta-wildcard, we remember its position
+     * and the position in the string path, and we advance both the pattern
+     * and the string. Later, if we encounter a mismatch in pattern & string,
+     * we rewind the position in pattern to just after the meta-wildcard,
+     * and we backtrack the string to i+1 element after the position
+     * we had when we first encountered the meta-wildcard, i being the
+     * position when we last backtracked the string.
+     *
+     * The backtracking logic is an adaptation of the logic in wildmatch
+     * above.
+     * See test/javax/mangement/ObjectName/ApplyWildcardTest.java
+     *
+     * Note: this thing is called 'wild' - and that's for a reason ;-)
+     **/
+    public static boolean wildpathmatch(String str, String pat) {
+        final int strlen = str.length();
+        final int patlen = pat.length();
+        int stri = 0;
+        int pati = 0;
+
+        int starstri; // index for backtrack if "**" attempt fails
+        int starpati; // index for backtrack if "**" attempt fails
+
+        starstri = starpati = -1;
+
+        while (true) {
+            // System.out.println("pati="+pati+", stri="+stri);
+            final int strend = str.indexOf(NAMESPACE_SEPARATOR, stri);
+            final int patend = pat.indexOf(NAMESPACE_SEPARATOR, pati);
+
+            // no // remaining in either string or pattern: simple wildmatch
+            // until end of string.
+            if (strend == -1 && patend == -1) {
+                // System.out.println("last sub pattern, last sub element...");
+                // System.out.println("wildmatch("+str.substring(stri,strlen)+
+                //    ","+pat.substring(pati,patlen)+")");
+                return wildmatch(str,pat,stri,strlen,pati,patlen);
+            }
+
+            // no // remaining in string, but at least one remaining in
+            // pattern
+            // => no match
+            if (strend == -1) {
+                // System.out.println("pattern has more // than string...");
+                return false;
+            }
+
+            // strend is != -1, but patend might.
+            // detect wildcard **
+            if (patend == pati+2 && pat.charAt(pati)=='*' &&
+                    pat.charAt(pati+1)=='*') {
+                // if we reach here we know that neither strend nor patend are
+                // equals to -1.
+                stri     = strend + NAMESPACE_SEPARATOR_LENGTH;
+                pati     = patend + NAMESPACE_SEPARATOR_LENGTH;
+                starpati = pati; // position just after **// in pattern
+                starstri = stri; // we eat 1 element in string, and remember
+                                 // the position for backtracking and eating
+                                 // one more element if needed.
+                // System.out.println("starpati="+pati);
+                continue;
+            }
+
+            // This is a bit hacky: * can match // when // is at the end
+            // of the string, so we include the // delimiter in the pattern
+            // matching. Either we're in the middle of the path, so including
+            // // both at the end of the pattern and at the end of the string
+            // has no effect - match(*//,dfsd//) is equivalent to match(*,dfsd)
+            // or we're at the end of the pattern path, in which case
+            // including // at the end of the string will have the desired
+            // effect (provided that we detect the end of matching correctly,
+            // see further on).
+            //
+            final int endpat =
+                    ((patend > -1)?patend+NAMESPACE_SEPARATOR_LENGTH:patlen);
+            final int endstr =
+                    ((strend > -1)?strend+NAMESPACE_SEPARATOR_LENGTH:strlen);
+
+            // if we reach the end of the pattern, or if elt-i & pat-i
+            // don't match, we have a mismatch.
+
+            // Note: we know that strend != -1, therefore patend==-1
+            //       indicates a mismatch unless pattern can match
+            //       a // at the end, and strend+2=strlen.
+            // System.out.println("wildmatch("+str.substring(stri,endstr)+","+
+            //        pat.substring(pati,endpat)+")");
+            if (!wildmatch(str,pat,stri,endstr,pati,endpat)) {
+
+                // System.out.println("nomatch");
+                // if we have a mismatch and didn't encounter any meta-wildcard,
+                // we return false. String & pattern don't match.
+                if (starpati < 0) return false;
+
+                // If we reach here, we had a meta-wildcard.
+                // We need to backtrack to the wildcard, and make it eat an
+                // additional string element.
+                //
+                stri = str.indexOf(NAMESPACE_SEPARATOR, starstri);
+                // System.out.println("eating one additional element? "+stri);
+
+                // If there's no more elements to eat, string and pattern
+                // don't match => return false.
+                if (stri == -1) return false;
+
+                // Backtrack to where we were when we last matched against
+                // the meta-wildcard, make it eat an additional path element,
+                // remember the new positions, and continue from there...
+                //
+                stri = stri + NAMESPACE_SEPARATOR_LENGTH;
+                starstri = stri;
+                pati = starpati;
+                // System.out.println("skiping to stri="+stri);
+                continue;
+            }
+
+            // Here we know that strend > -1 but we can have patend == -1.
+            //
+            // So if we reach here, we know pat-i+//? has matched
+            // elt-i+//
+            //
+            // If patend==-1, we know that there was no delimiter
+            // at the end of the pattern, that we are at the last pattern,
+            // and therefore that pat-i has matched elt-i+//
+            //
+            // In that case we can consider that we have a match only if
+            // elt-i is also the last path element in the string, which is
+            // equivalent to saying that strend+2==strlen.
+            //
+            if (patend == -1 && starpati == -1)
+                return (strend+NAMESPACE_SEPARATOR_LENGTH==strlen);
+
+            // patend != -1, or starpati > -1 so there remains something
+            // to match.
+
+            // go to next pair: elt-(i+1) pat-(i+1);
+            stri = strend + NAMESPACE_SEPARATOR_LENGTH;
+            pati = (patend==-1)?pati:(patend + NAMESPACE_SEPARATOR_LENGTH);
+        }
+    }
+
+    /**
+     * Returns true if the ObjectName's {@code domain} is selected by the
+     * given {@code pattern}.
+     */
+    public static boolean isDomainSelected(String domain, String pattern) {
+        if  (domain == null || pattern == null)
+            throw new IllegalArgumentException("null");
+        return Util.wildpathmatch(domain,pattern);
+    }
+
     /**
      * Filters a set of ObjectName according to a given pattern.
      *
@@ -167,6 +444,34 @@
         return res;
     }
 
+
+    /**
+     * Filters a set of ObjectInstance according to a given pattern.
+     *
+     * @param pattern the pattern that the returned names must match.
+     * @param all     the set of instances to filter.
+     * @return a set of ObjectInstance from which non matching instances
+     *         have been removed.
+     */
+    public static Set<ObjectInstance>
+            filterMatchingInstances(ObjectName pattern,
+                                        Set<ObjectInstance> all) {
+        // If no pattern, just return all names
+        if (pattern == null
+                || all.isEmpty()
+                || ObjectName.WILDCARD.equals(pattern))
+            return all;
+
+        // If there's a pattern, do the matching.
+        final Set<ObjectInstance> res = equivalentEmptySet(all);
+        for (ObjectInstance n : all) {
+            if (n == null) continue;
+            if (pattern.apply(n.getObjectName()))
+                res.add(n);
+        }
+        return res;
+    }
+
     /**
      * An abstract ClassLoaderRepository that contains a single class loader.
      **/
@@ -216,6 +521,160 @@
         return new SingleClassLoaderRepository(loader);
     }
 
+    /**
+     * Returns the name of the given MBeanServer that should be put in a
+     * permission you need.
+     * This corresponds to the
+     * {@code *[;mbeanServerName=<mbeanServerName>[;*]]} property
+     * embedded in the MBeanServerId attribute of the
+     * server's {@link MBeanServerDelegate}.
+     *
+     * @param server The MBean server
+     * @return the name of the MBeanServer, or "*" if the name couldn't be
+     *         obtained, or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}
+     *         if there was no name.
+     */
+    public static String getMBeanServerSecurityName(MBeanServer server) {
+        final String notfound = "*";
+        try {
+            final String mbeanServerId = (String)
+                    server.getAttribute(MBeanServerDelegate.DELEGATE_NAME,
+                    "MBeanServerId");
+            final String found = extractMBeanServerName(mbeanServerId);
+            if (found.length()==0)
+                return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
+            return found;
+        } catch (Exception x) {
+            logshort("Failed to retrieve MBeanServerName for server, " +
+                    "using \"*\"",x);
+            return notfound;
+        }
+    }
+
+    /**
+     * Returns the name of the MBeanServer embedded in the given
+     * mbeanServerId. If the given mbeanServerId doesn't contain any name,
+     * an empty String is returned.
+     * The MBeanServerId is expected to be of the form:
+     * {@code *[;mbeanServerName=<mbeanServerName>[;*]]}
+     * @param mbeanServerId The MBean server ID
+     * @return the name of the MBeanServer if found, or "" if the name was
+     *         not present in the mbeanServerId.
+     */
+    public static String extractMBeanServerName(String mbeanServerId) {
+        if (mbeanServerId==null) return "";
+        final String beginMarker=";mbeanServerName=";
+        final String endMarker=";";
+        final int found = mbeanServerId.indexOf(beginMarker);
+        if (found < 0) return "";
+        final int start = found + beginMarker.length();
+        final int stop = mbeanServerId.indexOf(endMarker, start);
+        return mbeanServerId.substring(start,
+                (stop < 0 ? mbeanServerId.length() : stop));
+    }
+
+    /**
+     * Insert the given mbeanServerName into the given mbeanServerId.
+     * If mbeanServerName is null, empty, or equals to "-", the returned
+     * mbeanServerId will not contain any mbeanServerName.
+     * @param mbeanServerId    The mbeanServerId in which to insert
+     *                         mbeanServerName
+     * @param mbeanServerName  The mbeanServerName
+     * @return an mbeanServerId containing the given mbeanServerName
+     * @throws IllegalArgumentException if mbeanServerId already contains
+     *         a different name, or if the given mbeanServerName is not valid.
+     */
+    public static String insertMBeanServerName(String mbeanServerId,
+            String mbeanServerName) {
+        final String found = extractMBeanServerName(mbeanServerId);
+        if (found.length() > 0 &&
+                found.equals(checkServerName(mbeanServerName)))
+            return mbeanServerId;
+        if (found.length() > 0 && !isMBeanServerNameUndefined(found))
+            throw new IllegalArgumentException(
+                    "MBeanServerName already defined");
+        if (isMBeanServerNameUndefined(mbeanServerName))
+            return mbeanServerId;
+        final String beginMarker=";mbeanServerName=";
+        return mbeanServerId+beginMarker+checkServerName(mbeanServerName);
+    }
+
+    /**
+     * Returns true if the given mbeanServerName corresponds to an
+     * undefined MBeanServerName.
+     * The mbeanServerName is considered undefined if it is one of:
+     * {@code null} or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}.
+     * @param mbeanServerName The mbeanServerName, as returned by
+     *        {@link #extractMBeanServerName(String)}.
+     * @return true if the given name corresponds to one of the forms that
+     *         denotes an undefined MBeanServerName.
+     */
+    public static boolean isMBeanServerNameUndefined(String mbeanServerName) {
+        return mbeanServerName == null ||
+           MBeanServerFactory.DEFAULT_MBEANSERVER_NAME.equals(mbeanServerName);
+    }
+    /**
+     * Check that the provided mbeanServername is syntactically valid.
+     * @param mbeanServerName An mbeanServerName, or {@code null}.
+     * @return mbeanServerName, or {@value
+     * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if {@code mbeanServerName}
+     * is {@code null}.
+     * @throws IllegalArgumentException if mbeanServerName contains illegal
+     *         characters, or is empty, or is {@code "-"}.
+     *         Illegal characters are {@value #ILLEGAL_MBEANSERVER_NAME_CHARS}.
+     */
+    public static String checkServerName(String mbeanServerName) {
+        if ("".equals(mbeanServerName))
+            throw new IllegalArgumentException(
+                    "\"\" is not a valid MBean server name");
+        if ("-".equals(mbeanServerName))
+            throw new IllegalArgumentException(
+                    "\"-\" is not a valid MBean server name");
+        if (isMBeanServerNameUndefined(mbeanServerName))
+            return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
+        for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS.toCharArray()) {
+            if (mbeanServerName.indexOf(c) >= 0)
+                throw new IllegalArgumentException(
+                        "invalid character in MBeanServer name: "+c);
+        }
+        return mbeanServerName;
+    }
+
+    /**
+     * Get the MBeanServer name that should be put in a permission you need.
+     *
+     * @param delegate The MBeanServerDelegate
+     * @return The MBeanServer name - or {@value
+     * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if there was no name.
+     */
+    public static String getMBeanServerSecurityName(
+            MBeanServerDelegate delegate) {
+        try {
+            final String serverName = delegate.getMBeanServerName();
+            if (isMBeanServerNameUndefined(serverName))
+                return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
+            return serverName;
+        } catch (Exception x) {
+            logshort("Failed to retrieve MBeanServerName from delegate, " +
+                    "using \"*\"",x);
+            return "*";
+        }
+    }
+
+    // Log the exception and its causes without logging the stack trace.
+    // Use with care - it is usally preferable to log the whole stack trace!
+    // We don't want to log the whole stack trace here: logshort() is
+    // called in those cases where the exception might not be abnormal.
+    private static void logshort(String msg, Throwable t) {
+        if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) {
+            StringBuilder toprint = new StringBuilder(msg);
+               toprint.append("\nCaused By: ").append(String.valueOf(t));
+            while ((t=t.getCause())!=null)
+               toprint.append("\nCaused By: ").append(String.valueOf(t));
+            JmxProperties.MISC_LOGGER.fine(toprint.toString());
+       }
+    }
+
     public static <T> Set<T> cloneSet(Set<T> set) {
         if (set instanceof SortedSet) {
             @SuppressWarnings("unchecked")
@@ -232,10 +691,19 @@
             @SuppressWarnings("unchecked")
             SortedSet<T> sset = (SortedSet<T>) set;
             set = new TreeSet<T>(sset.comparator());
-        } else if (set != null) {
-            set = new HashSet<T>(set.size());
         } else
             set = new HashSet<T>();
         return set;
     }
+
+    // This exception is used when wrapping a class that throws IOException
+    // in a class that doesn't.
+    // The typical example for this are JMXNamespaces, when the sub
+    // MBeanServer can be remote.
+    //
+    public static RuntimeException newRuntimeIOException(IOException io) {
+        final String msg = "Communication failed with underlying resource: "+
+                io.getMessage();
+        return new RuntimeException(msg,io);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.mbeanserver.Util;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanPermission;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.namespace.JMXDomain;
+
+/**
+ * A DomainInterceptor wraps a JMXDomain.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
+
+    // TODO: Ideally DomainInterceptor should be replaced by
+    //       something at Repository level.
+    //       The problem there will be that we may need to
+    //       reinstantiate the 'queryPerformedByRepos' boolean
+    //       [or we will need to wrap the repository in
+    //        a 'RepositoryInterceptor'?]
+    //       Also there's no real need for a DomainInterceptor to
+    //       extend RewritingMBeanServerConnection.
+
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    private final String           domainName;
+    private volatile ObjectName    ALL;
+    private final String           serverName;
+    private volatile NotificationListener mbsListener;
+
+    private static class PatternNotificationFilter
+            implements NotificationFilter {
+
+        final ObjectName pattern;
+        public PatternNotificationFilter(ObjectName pattern) {
+            this.pattern = pattern;
+        }
+
+        public boolean isNotificationEnabled(Notification notification) {
+            if (!(notification instanceof MBeanServerNotification))
+                return false;
+            final MBeanServerNotification mbsn =
+                    (MBeanServerNotification) notification;
+            if (pattern == null || pattern.apply(mbsn.getMBeanName()))
+                return true;
+            return false;
+        }
+
+        static final long serialVersionUID = 7409950927025262111L;
+    }
+
+    /**
+     * Creates a new instance of NamespaceInterceptor
+     */
+    public DomainInterceptor(String serverName,
+                             JMXDomain handler,
+                             String domainName) {
+        super(handler);
+        this.domainName = domainName;
+        this.serverName = serverName;
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass().getName()+"(parent="+serverName+
+                ", domain="+this.domainName+")";
+    }
+
+    public void connectDelegate(final MBeanServerDelegate delegate)
+            throws InstanceNotFoundException {
+        final NotificationFilter filter =
+                new PatternNotificationFilter(getPatternFor(null));
+        synchronized (this) {
+            if (mbsListener == null)
+                mbsListener = new NotificationListener() {
+
+               public void handleNotification(Notification notification,
+                    Object handback) {
+                    if (filter.isNotificationEnabled(notification))
+                        delegate.sendNotification(notification);
+                }
+            };
+        }
+
+        getNamespace().
+                addMBeanServerNotificationListener(mbsListener, filter);
+    }
+
+    public void disconnectDelegate()
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        final NotificationListener l;
+        synchronized (this) {
+            l = mbsListener;
+            if (l == null) return;
+            mbsListener = null;
+        }
+        getNamespace().removeMBeanServerNotificationListener(l);
+    }
+
+    public void addPostRegisterTask(Queue<Runnable> queue,
+            final MBeanServerDelegate delegate) {
+        if (queue == null)
+            throw new IllegalArgumentException("task queue must not be null");
+        final Runnable task1 = new Runnable() {
+            public void run() {
+                try {
+                    connectDelegate(delegate);
+                } catch (Exception x) {
+                    throw new UnsupportedOperationException("notification forwarding",x);
+                }
+            }
+        };
+        queue.add(task1);
+    }
+
+    public void addPostDeregisterTask(Queue<Runnable> queue,
+            final MBeanServerDelegate delegate) {
+        if (queue == null)
+            throw new IllegalArgumentException("task queue must not be null");
+        final Runnable task1 = new Runnable() {
+            public void run() {
+                try {
+                    disconnectDelegate();
+                } catch (Exception x) {
+                    throw new UnsupportedOperationException("notification forwarding",x);
+                }
+            }
+        };
+        queue.add(task1);
+    }
+
+    /**
+     * Throws IllegalArgumentException if targetName.getDomain() is not
+     * in the domain handled.
+     **/
+    @Override
+    protected ObjectName toSource(ObjectName targetName) {
+        if (targetName == null) return null;
+        if (targetName.isDomainPattern()) return targetName;
+        final String targetDomain = targetName.getDomain();
+
+        // TODO: revisit this. RuntimeOperationsException may be better?
+        //
+        if (!targetDomain.equals(domainName))
+            throw new IllegalArgumentException(targetName.toString());
+        return targetName;
+    }
+
+    @Override
+    protected ObjectName toTarget(ObjectName sourceName) {
+        return sourceName;
+    }
+
+
+
+    /**
+     * No rewriting: always return sources - stripping instances for which
+     * the caller doesn't have permissions.
+     **/
+    @Override
+    Set<ObjectInstance> processOutputInstances(Set<ObjectInstance> sources) {
+        if (sources == null || sources.isEmpty() || !checkOn())
+            return sources;
+        final Set<ObjectInstance> res = Util.equivalentEmptySet(sources);
+        for (ObjectInstance o : sources) {
+            if (checkQuery(o.getObjectName(), "queryMBeans"))
+                res.add(o);
+        }
+        return res;
+    }
+
+
+    /**
+     * No rewriting: always return sourceNames - stripping names for which
+     * the caller doesn't have permissions.
+     **/
+    @Override
+    Set<ObjectName> processOutputNames(Set<ObjectName> sourceNames) {
+        if (sourceNames == null || sourceNames.isEmpty() || !checkOn())
+            return sourceNames;
+        final Set<ObjectName> res = Util.equivalentEmptySet(sourceNames);
+        for (ObjectName o : sourceNames) {
+            if (checkQuery(o, "queryNames"))
+                res.add(o);
+        }
+        return res;
+    }
+
+    /** No rewriting: always return source **/
+    @Override
+    ObjectInstance processOutputInstance(ObjectInstance source) {
+        return source;
+    }
+
+    @Override
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        try {
+            // We don't trust the wrapped JMXDomain...
+            final ObjectName pattern = getPatternFor(name);
+            final Set<ObjectName> res = super.queryNames(pattern,query);
+            return Util.filterMatchingNames(pattern,res);
+        } catch (Exception x) {
+            if (LOG.isLoggable(Level.FINE))
+                LOG.fine("Unexpected exception raised in queryNames: "+x);
+            LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
+        }
+        // We reach here only when an exception was raised.
+        //
+        final Set<ObjectName> empty = Collections.emptySet();
+        return empty;
+    }
+
+    private ObjectName getPatternFor(final ObjectName name) {
+        try {
+            if (ALL == null) ALL = ObjectName.getInstance(domainName + ":*");
+            if (name == null) return ALL;
+            if (name.getDomain().equals(domainName)) return name;
+            return name.withDomain(domainName);
+        } catch (MalformedObjectNameException x) {
+            throw new IllegalArgumentException(String.valueOf(name),x);
+        }
+   }
+
+    @Override
+    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        try {
+            // We don't trust the wrapped JMXDomain...
+            final ObjectName pattern = getPatternFor(name);
+            final Set<ObjectInstance> res = super.queryMBeans(pattern,query);
+            return Util.filterMatchingInstances(pattern,res);
+        } catch (Exception x) {
+            if (LOG.isLoggable(Level.FINE))
+                LOG.fine("Unexpected exception raised in queryNames: "+x);
+            LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
+        }
+        // We reach here only when an exception was raised.
+        //
+        final Set<ObjectInstance> empty = Collections.emptySet();
+        return empty;
+    }
+
+    @Override
+    public String getDefaultDomain() {
+        return domainName;
+    }
+
+    @Override
+    public String[] getDomains() {
+        return new String[] {domainName};
+    }
+
+    // We call getMBeanCount() on the namespace rather than on the
+    // source server in order to avoid counting MBeans which are not
+    // in the domain.
+    @Override
+    public Integer getMBeanCount() {
+        return getNamespace().getMBeanCount();
+    }
+
+    private boolean checkOn() {
+        final SecurityManager sm = System.getSecurityManager();
+        return (sm != null);
+    }
+
+    //
+    // Implements permission checks.
+    //
+    @Override
+    void check(ObjectName routingName, String member, String action) {
+        if (!checkOn()) return;
+        final String act = (action==null)?"-":action.intern();
+        if(act == "queryMBeans" || act == "queryNames") { // ES: OK
+            // This is tricky. check with 3 parameters is called
+            // by queryNames/queryMBeans before performing the query.
+            // At this point we must check with no class name.
+            // Therefore we pass a className of "-".
+            // The filtering will be done later - processOutputNames and
+            // processOutputInstance will call checkQuery.
+            //
+            check(routingName, "-", "-", act);
+        } else {
+            // This is also tricky:
+            // passing null here will cause check to retrieve the classname,
+            // if needed.
+            check(routingName, null, member, act);
+        }
+    }
+
+    //
+    // Implements permission checks.
+    //
+    @Override
+    void checkCreate(ObjectName routingName, String className, String action) {
+        if (!checkOn()) return;
+        check(routingName,className,"-",action);
+    }
+
+    //
+    // Implements permission checks.
+    //
+    void check(ObjectName routingName, String className, String member,
+            String action) {
+        if (!checkOn()) return;
+        final MBeanPermission perm;
+
+        // action is most probably already an intern string.
+        // string literals are intern strings.
+        // we create a new intern string for 'action' - just to be on
+        // the safe side...
+        // We intern it in order to be able to use == rather than equals
+        // below, because if we don't, and if action is not one of the
+        // 4 literals below, we would have to do a full string comparison.
+        //
+        final String act = (action==null)?"-":action.intern();
+        if (act == "getDomains") { // ES: OK
+            perm = new  MBeanPermission(serverName,"-",member,
+                    routingName,act);
+        } else {
+            final String clazz =
+                    (className==null)?getClassName(routingName):className;
+            perm = new  MBeanPermission(serverName,clazz,member,
+                    routingName,act);
+        }
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(perm);
+    }
+
+    String getClassName(ObjectName routingName) {
+        if (routingName == null || routingName.isPattern()) return "-";
+        try {
+            return getNamespace().getSourceServer().
+                    getObjectInstance(routingName).getClassName();
+        } catch (InstanceNotFoundException ex) {
+            LOG.finest("Can't get class name for "+routingName+
+                    ", using \"-\". Cause is: "+ex);
+            return "-";
+        }
+    }
+
+    //
+    // Implements permission filters for attributes...
+    //
+    @Override
+    AttributeList checkAttributes(ObjectName routingName,
+            AttributeList attributes, String action) {
+        if (!checkOn()) return attributes;
+        final String className = getClassName(routingName);
+        check(routingName,className,"-",action);
+        if (attributes == null || attributes.isEmpty()) return attributes;
+        final AttributeList res = new AttributeList();
+        for (Attribute at : attributes.asList()) {
+            try {
+                check(routingName,className,at.getName(),action);
+                res.add(at);
+            } catch (SecurityException x) { // DLS: OK
+                continue;
+            }
+        }
+        return res;
+    }
+
+    //
+    // Implements permission filters for attributes...
+    //
+    @Override
+    String[] checkAttributes(ObjectName routingName, String[] attributes,
+            String action) {
+        if (!checkOn()) return attributes;
+        final String className = getClassName(routingName);
+        check(routingName,className,"-",action);
+        if (attributes == null || attributes.length==0) return attributes;
+        final List<String> res = new ArrayList<String>(attributes.length);
+        for (String at : attributes) {
+            try {
+                check(routingName,className,at,action);
+                res.add(at);
+            } catch (SecurityException x) { // DLS: OK
+                continue;
+            }
+        }
+        return res.toArray(new String[res.size()]);
+    }
+
+    //
+    // Implements permission filters for domains...
+    //
+    @Override
+    String[] checkDomains(String[] domains, String action) {
+         if (domains == null || domains.length==0 || !checkOn())
+             return domains;
+         int count=0;
+         for (int i=0;i<domains.length;i++) {
+             try {
+                 check(Util.newObjectName(domains[i]+":x=x"),"-",
+                         "-","getDomains");
+             } catch (SecurityException x) { // DLS: OK
+                 count++;
+                 domains[i]=null;
+             }
+         }
+         if (count == 0) return domains;
+         final String[] res = new String[domains.length-count];
+         count = 0;
+         for (int i=0;i<domains.length;i++)
+             if (domains[i]!=null) res[count++]=domains[i];
+         return res;
+    }
+
+    //
+    // Implements permission filters for queries...
+    //
+    @Override
+    boolean checkQuery(ObjectName routingName, String action) {
+        try {
+            final String className = getClassName(routingName);
+            check(routingName,className,"-",action);
+            return true;
+        } catch (SecurityException x) { // DLS: OK
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.interceptor.MBeanServerInterceptor;
+
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.loading.ClassLoaderRepository;
+import javax.management.namespace.JMXNamespace;
+
+/**
+ * This interceptor wraps a JMXNamespace, and performs
+ * {@code ObjectName} rewriting. {@code HandlerInterceptor} are
+ * usually created and managed by a {@link NamespaceDispatcher} or
+ * {@link DomainDispatcher}.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public abstract class HandlerInterceptor<T extends JMXNamespace>
+        extends RoutingMBeanServerConnection<MBeanServer>
+        implements MBeanServerInterceptor {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    // The wrapped JMXNamespace
+    private final T handler;
+
+    /**
+     * Creates a new instance of HandlerInterceptor
+     */
+    public HandlerInterceptor(T handler) {
+        if (handler == null) throw new IllegalArgumentException("null");
+        this.handler = handler;
+    }
+
+    @Override
+    protected MBeanServer source() {
+         return handler.getSourceServer();
+    }
+
+    // The MBeanServer on which getClassLoader / getClassLoaderFor
+    // will be called.
+    // The NamespaceInterceptor overrides this method - so that it
+    // getClassLoader / getClassLoaderFor don't trigger the loop
+    // detection mechanism.
+    //
+    MBeanServer getServerForLoading() {
+         return source();
+    }
+
+    T getNamespace() {
+        return handler;
+    }
+
+    // If the underlying JMXNamespace throws an IO, the IO will be
+    // wrapped in a RuntimeOperationsException.
+    RuntimeException handleIOException(IOException x,String fromMethodName,
+            Object... params) {
+            // Must do something here?
+        if (LOG.isLoggable(Level.FINEST)) {
+            LOG.finest("IO Exception in "+fromMethodName+": "+x+
+                    " - "+" rethrowing as RuntimeOperationsException.");
+        }
+        throw new RuntimeOperationsException(
+                    Util.newRuntimeIOException(x));
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public AttributeList getAttributes(ObjectName name, String[] attributes)
+        throws InstanceNotFoundException, ReflectionException {
+        try {
+            return super.getAttributes(name, attributes);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getAttributes",name,attributes);
+        }
+    }
+
+    // From MBeanServer
+    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+        throws InstanceNotFoundException {
+        final ObjectName sourceName = toSourceOrRuntime(mbeanName);
+        try {
+            check(mbeanName,null,"getClassLoaderFor");
+            return getServerForLoading().getClassLoaderFor(sourceName);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+
+    // From MBeanServer
+    public ClassLoader getClassLoader(ObjectName loaderName)
+        throws InstanceNotFoundException {
+        final ObjectName sourceName = toSourceOrRuntime(loaderName);
+        try {
+            check(loaderName,null,"getClassLoader");
+            return getServerForLoading().getClassLoader(sourceName);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // From MBeanServer
+    public ObjectInstance registerMBean(Object object, ObjectName name)
+        throws InstanceAlreadyExistsException, MBeanRegistrationException,
+            NotCompliantMBeanException {
+        final ObjectName sourceName = newSourceMBeanName(name);
+        try {
+            checkCreate(name,object.getClass().getName(),"registerMBean");
+            return processOutputInstance(
+                    source().registerMBean(object,sourceName));
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void removeNotificationListener(ObjectName name, ObjectName listener)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"removeNotificationListener",name,listener);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public String getDefaultDomain() {
+        try {
+            return super.getDefaultDomain();
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getDefaultDomain");
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public String[] getDomains() {
+        try {
+            return super.getDomains();
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getDomains");
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public Integer getMBeanCount() {
+        try {
+            return super.getMBeanCount();
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getMBeanCount");
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void setAttribute(ObjectName name, Attribute attribute)
+        throws InstanceNotFoundException, AttributeNotFoundException,
+            InvalidAttributeValueException, MBeanException,
+            ReflectionException {
+        try {
+            super.setAttribute(name, attribute);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"setAttribute",name, attribute);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        try {
+            return super.queryNames(name, query);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"queryNames",name, query);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        try {
+            return super.queryMBeans(name, query);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"queryMBeans",name, query);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public boolean isInstanceOf(ObjectName name, String className)
+        throws InstanceNotFoundException {
+        try {
+            return super.isInstanceOf(name, className);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"isInstanceOf",name, className);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name)
+        throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException {
+        try {
+            return super.createMBean(className, name);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"createMBean",className, name);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                        ObjectName loaderName)
+        throws ReflectionException, InstanceAlreadyExistsException,
+                MBeanRegistrationException, MBeanException,
+                NotCompliantMBeanException, InstanceNotFoundException {
+        try {
+            return super.createMBean(className, name, loaderName);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"createMBean",className, name, loaderName);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public Object getAttribute(ObjectName name, String attribute)
+        throws MBeanException, AttributeNotFoundException,
+            InstanceNotFoundException, ReflectionException {
+        try {
+            return super.getAttribute(name, attribute);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getAttribute",name, attribute);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void removeNotificationListener(ObjectName name, ObjectName listener,
+                            NotificationFilter filter, Object handback)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener, filter, handback);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"removeNotificationListener",name,
+                    listener, filter, handback);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                      NotificationListener listener, NotificationFilter filter,
+                      Object handback)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener, filter, handback);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"removeNotificationListener",name,
+                    listener, filter, handback);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                NotificationListener listener)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"removeNotificationListener",name,
+                    listener);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void addNotificationListener(ObjectName name,
+                    NotificationListener listener, NotificationFilter filter,
+                    Object handback) throws InstanceNotFoundException {
+        try {
+            super.addNotificationListener(name, listener, filter, handback);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"addNotificationListener",name,
+                    listener, filter, handback);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void addNotificationListener(ObjectName name, ObjectName listener,
+                NotificationFilter filter, Object handback)
+        throws InstanceNotFoundException {
+        try {
+            super.addNotificationListener(name, listener, filter, handback);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"addNotificationListener",name,
+                    listener, filter, handback);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public boolean isRegistered(ObjectName name) {
+        try {
+            return super.isRegistered(name);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"isRegistered",name);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public void unregisterMBean(ObjectName name)
+        throws InstanceNotFoundException, MBeanRegistrationException {
+        try {
+            super.unregisterMBean(name);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"unregisterMBean",name);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public MBeanInfo getMBeanInfo(ObjectName name)
+        throws InstanceNotFoundException, IntrospectionException,
+            ReflectionException {
+        try {
+            return super.getMBeanInfo(name);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getMBeanInfo",name);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public ObjectInstance getObjectInstance(ObjectName name)
+        throws InstanceNotFoundException {
+        try {
+            return super.getObjectInstance(name);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"getObjectInstance",name);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                Object[] params, String[] signature)
+        throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException {
+        try {
+            return super.createMBean(className, name, params, signature);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"createMBean",className, name,
+                    params, signature);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                ObjectName loaderName, Object[] params, String[] signature)
+        throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException {
+        try {
+            return super.createMBean(className, name, loaderName, params,
+                    signature);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"createMBean",className, name,loaderName,
+                    params, signature);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public AttributeList setAttributes(ObjectName name,AttributeList attributes)
+    throws InstanceNotFoundException, ReflectionException {
+        try {
+            return super.setAttributes(name, attributes);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"setAttributes",name, attributes);
+        }
+    }
+
+    // From MBeanServer: catch & handles IOException
+    @Override
+    public Object invoke(ObjectName name, String operationName, Object[] params,
+                String[] signature)
+        throws InstanceNotFoundException, MBeanException, ReflectionException {
+        try {
+            return super.invoke(name, operationName, params, signature);
+        } catch (IOException ex) {
+            throw handleIOException(ex,"invoke",name, operationName,
+                    params, signature);
+        }
+    }
+
+    //
+    //  These methods are inherited from MBeanServer....
+    //
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className)
+            throws ReflectionException, MBeanException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported instantiate method: " +
+                    "trowing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, ObjectName loaderName)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: instantiate(...) -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, Object[] params,
+            String[] signature) throws ReflectionException, MBeanException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: instantiate(...) -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public Object instantiate(String className, ObjectName loaderName,
+            Object[] params, String[] signature)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: instantiate(...) -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(ObjectName name, byte[] data)
+            throws InstanceNotFoundException, OperationsException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: deserialize(...) -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className, byte[] data)
+            throws OperationsException, ReflectionException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: deserialize(...) -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className,
+            ObjectName loaderName, byte[] data)
+            throws InstanceNotFoundException, OperationsException,
+            ReflectionException {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: deserialize(...) -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * This method should never be called.
+     * Throws UnsupportedOperationException.
+     */
+    public ClassLoaderRepository getClassLoaderRepository() {
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("call to unsupported method: getClassLoaderRepository() -" +
+                    "throwing UnsupportedOperationException");
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    static RuntimeException newUnsupportedException(String namespace) {
+        return new RuntimeOperationsException(
+            new UnsupportedOperationException(
+                "Not supported in this namespace: "+namespace));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanServerConnection;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.event.EventClient;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.remote.JMXAddressable;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXServiceURL;
+import javax.security.auth.Subject;
+
+/**
+ * A collection of methods that provide JMXConnector wrappers for
+ * JMXRemoteNamepaces underlying connectors.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public final class JMXNamespaceUtils {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+
+    private static <K,V> Map<K,V> newWeakHashMap() {
+        return new WeakHashMap<K,V>();
+    }
+
+    /** Creates a new instance of JMXNamespaces */
+    private JMXNamespaceUtils() {
+    }
+
+    /**
+     * Returns an unmodifiable option map in which the given keys have been
+     * filtered out.
+     * @param keys keys to filter out from the map.
+     * @return An unmodifiable option map in which the given keys have been
+     * filtered out.
+     */
+    public static <K,V> Map<K,V> filterMap(Map<K,V> map, K... keys) {
+        final Map<K,V> filtered;
+        filtered=new HashMap<K,V>(map);
+        for (K key : keys) {
+            filtered.remove(key);
+        }
+        return unmodifiableMap(filtered);
+    }
+
+    // returns un unmodifiable view of a map.
+    public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) {
+        if (aMap == null || aMap.isEmpty())
+            return Collections.emptyMap();
+        return Collections.unmodifiableMap(aMap);
+    }
+
+
+    /**
+     * A base class that helps writing JMXConnectors that return
+     * MBeanServerConnection wrappers.
+     * This base class wraps an inner JMXConnector (the source), and preserve
+     * its caching policy. If a connection is cached in the source, its wrapper
+     * will be cached in this connector too.
+     * Author's note: rewriting this with java.lang.reflect.Proxy could be
+     * envisaged. It would avoid the combinatory sub-classing introduced by
+     * JMXAddressable.
+     * <p>
+     * Note: all the standard JMXConnector implementations are serializable.
+     *       This implementation here is not. Should it be?
+     *       I believe it must not be serializable unless it becomes
+     *       part of a public API (either standard or officially exposed
+     *       and supported in a documented com.sun package)
+     **/
+     static class JMXCachingConnector
+            implements JMXConnector  {
+
+        // private static final long serialVersionUID = -2279076110599707875L;
+
+        final JMXConnector source;
+
+        // if this object is made serializable, then the variable below
+        // needs to become volatile transient and be lazyly-created...
+        private final
+                Map<MBeanServerConnection,MBeanServerConnection> connectionMap;
+
+
+        public JMXCachingConnector(JMXConnector source) {
+            this.source = checkNonNull(source, "source");
+            connectionMap = newWeakHashMap();
+        }
+
+        private MBeanServerConnection
+                getCached(MBeanServerConnection inner) {
+            return connectionMap.get(inner);
+        }
+
+        private MBeanServerConnection putCached(final MBeanServerConnection inner,
+                final MBeanServerConnection wrapper) {
+            if (inner == wrapper) return wrapper;
+            synchronized (this) {
+                final MBeanServerConnection concurrent =
+                        connectionMap.get(inner);
+                if (concurrent != null) return concurrent;
+                connectionMap.put(inner,wrapper);
+            }
+            return wrapper;
+        }
+
+        public void addConnectionNotificationListener(NotificationListener
+                listener, NotificationFilter filter, Object handback) {
+            source.addConnectionNotificationListener(listener,filter,handback);
+        }
+
+        public void close() throws IOException {
+            source.close();
+        }
+
+        public void connect() throws IOException {
+            source.connect();
+        }
+
+        public void connect(Map<String,?> env) throws IOException {
+            source.connect(env);
+        }
+
+        public String getConnectionId() throws IOException {
+            return source.getConnectionId();
+        }
+
+        /**
+         * Preserve caching policy of the underlying connector.
+         **/
+        public MBeanServerConnection
+                getMBeanServerConnection() throws IOException {
+            final MBeanServerConnection inner =
+                    source.getMBeanServerConnection();
+            final MBeanServerConnection cached = getCached(inner);
+            if (cached != null) return cached;
+            final MBeanServerConnection wrapper = wrap(inner);
+            return putCached(inner,wrapper);
+        }
+
+        public MBeanServerConnection
+                getMBeanServerConnection(Subject delegationSubject)
+                throws IOException {
+            final MBeanServerConnection wrapped =
+                    source.getMBeanServerConnection(delegationSubject);
+            synchronized (this) {
+                final MBeanServerConnection cached = getCached(wrapped);
+                if (cached != null) return cached;
+                final MBeanServerConnection wrapper =
+                    wrapWithSubject(wrapped,delegationSubject);
+                return putCached(wrapped,wrapper);
+            }
+        }
+
+        public void removeConnectionNotificationListener(
+                NotificationListener listener)
+                throws ListenerNotFoundException {
+            source.removeConnectionNotificationListener(listener);
+        }
+
+        public void removeConnectionNotificationListener(
+                NotificationListener l, NotificationFilter f,
+                Object handback) throws ListenerNotFoundException {
+            source.removeConnectionNotificationListener(l,f,handback);
+        }
+
+        /**
+         * This is the method that subclass will redefine. This method
+         * is called by {@code this.getMBeanServerConnection()}.
+         * {@code inner} is the connection returned by
+         * {@code source.getMBeanServerConnection()}.
+         **/
+        protected MBeanServerConnection wrap(MBeanServerConnection inner)
+            throws IOException {
+            return inner;
+        }
+
+        /**
+         * Subclass may also want to redefine this method.
+         * By default it calls wrap(inner). This method
+         * is called by {@code this.getMBeanServerConnection(Subject)}.
+         * {@code inner} is the connection returned by
+         * {@code source.getMBeanServerConnection(Subject)}.
+         **/
+        protected MBeanServerConnection wrapWithSubject(
+                MBeanServerConnection inner, Subject delegationSubject)
+            throws IOException {
+                return wrap(inner);
+        }
+
+        @Override
+        public String toString() {
+            if (source instanceof JMXAddressable) {
+                final JMXServiceURL address =
+                        ((JMXAddressable)source).getAddress();
+                if (address != null)
+                    return address.toString();
+            }
+            return source.toString();
+        }
+
+    }
+
+
+    /**
+     * The name space connector can do 'cd'
+     **/
+    static class JMXNamespaceConnector extends JMXCachingConnector {
+
+        // private static final long serialVersionUID = -4813611540843020867L;
+
+        private final String toDir;
+        private final boolean closeable;
+
+        public JMXNamespaceConnector(JMXConnector source, String toDir,
+                boolean closeable) {
+            super(source);
+            this.toDir = toDir;
+            this.closeable = closeable;
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closeable)
+                throw new UnsupportedOperationException("close");
+            else super.close();
+        }
+
+        @Override
+        protected MBeanServerConnection wrap(MBeanServerConnection wrapped)
+               throws IOException {
+            if (LOG.isLoggable(Level.FINER))
+                LOG.finer("Creating name space proxy connection for source: "+
+                        "namespace="+toDir);
+            return JMXNamespaces.narrowToNamespace(wrapped,toDir);
+        }
+
+        @Override
+        public String toString() {
+            return "JMXNamespaces.narrowToNamespace("+
+                    super.toString()+
+                    ", \""+toDir+"\")";
+        }
+
+    }
+
+    static class JMXEventConnector extends JMXCachingConnector {
+
+        // private static final long serialVersionUID = 4742659236340242785L;
+
+        JMXEventConnector(JMXConnector wrapped) {
+            super(wrapped);
+        }
+
+        @Override
+        protected MBeanServerConnection wrap(MBeanServerConnection inner)
+                throws IOException {
+            return EventClient.getEventClientConnection(inner);
+        }
+
+
+        @Override
+        public String toString() {
+            return "EventClient.withEventClient("+super.toString()+")";
+        }
+    }
+
+    static class JMXAddressableEventConnector extends JMXEventConnector
+        implements JMXAddressable {
+
+        // private static final long serialVersionUID = -9128520234812124712L;
+
+        JMXAddressableEventConnector(JMXConnector wrapped) {
+            super(wrapped);
+        }
+
+        public JMXServiceURL getAddress() {
+            return ((JMXAddressable)source).getAddress();
+        }
+    }
+
+    /**
+     * Creates a connector whose MBeamServerConnection will point to the
+     * given sub name space inside the source connector.
+     * @see JMXNamespace
+     **/
+    public static JMXConnector cd(final JMXConnector source,
+                                  final String toNamespace,
+                                  final boolean closeable)
+        throws IOException {
+
+        checkNonNull(source, "JMXConnector");
+
+        if (toNamespace == null || toNamespace.equals(""))
+            return source;
+
+        return new JMXNamespaceConnector(source,toNamespace,closeable);
+    }
+
+
+    /**
+     * Returns a JMX Connector that will use an {@link EventClient}
+     * to subscribe for notifications. If the server doesn't have
+     * an {@link EventClientDelegateMBean}, then the connector will
+     * use the legacy notification mechanism instead.
+     *
+     * @param source The underlying JMX Connector wrapped by the returned
+     *               connector.
+     * @return A JMX Connector that will uses an {@link EventClient}, if
+     *         available.
+     * @see EventClient#getEventClientConnection(MBeanServerConnection)
+     */
+    public static JMXConnector withEventClient(final JMXConnector source) {
+        checkNonNull(source, "JMXConnector");
+        if (source instanceof JMXAddressable)
+            return new JMXAddressableEventConnector(source);
+        else
+            return new JMXEventConnector(source);
+    }
+
+    public static <T> T checkNonNull(T parameter, String name) {
+        if (parameter == null)
+            throw new IllegalArgumentException(name+" must not be null");
+         return parameter;
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXNamespace;
+import javax.management.namespace.JMXNamespacePermission;
+
+/**
+ * A NamespaceInterceptor wraps a JMXNamespace, performing
+ * ObjectName rewriting.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+    private static final Logger PROBE_LOG = Logger.getLogger(
+            JmxProperties.NAMESPACE_LOGGER+".probe");
+
+    // The target name space in which the NamepsaceHandler is mounted.
+    private final String           targetNs;
+
+    private final String           serverName;
+
+    private final ObjectNameRouter proc;
+
+    /**
+     * Internal hack. The JMXRemoteNamespace can be closed and reconnected.
+     * Each time the JMXRemoteNamespace connects, a probe should be sent
+     * to detect cycle. The MBeanServer exposed by JMXRemoteNamespace thus
+     * implements the DynamicProbe interface, which makes it possible for
+     * this handler to know that it should send a new probe.
+     *
+     * XXX: TODO this probe thing is way too complex and fragile.
+     *      This *must* go away or be replaced by something simpler.
+     *      ideas are welcomed.
+     **/
+    public static interface DynamicProbe {
+        public boolean isProbeRequested();
+    }
+
+    /**
+     * Creates a new instance of NamespaceInterceptor
+     */
+    public NamespaceInterceptor(
+            String serverName,
+            JMXNamespace handler,
+            String targetNamespace) {
+        super(handler);
+        this.serverName = serverName;
+        this.targetNs =
+                ObjectNameRouter.normalizeNamespacePath(targetNamespace,
+                true, true, false);
+        proc = new ObjectNameRouter(targetNamespace, "");
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass().getName()+"(parent="+serverName+
+                ", namespace="+this.targetNs+")";
+    }
+
+    /*
+     * XXX: TODO this probe thing is way too complex and fragile.
+     *      This *must* go away or be replaced by something simpler.
+     *      ideas are welcomed.
+     */
+    private volatile boolean probed = false;
+    private volatile ObjectName probe;
+
+    // Query Pattern that we will send through the source server in order
+    // to detect self-linking namespaces.
+    //
+    // XXX: TODO this probe thing is way too complex and fragile.
+    //      This *must* go away or be replaced by something simpler.
+    //      ideas are welcomed.
+    final ObjectName makeProbePattern(ObjectName probe)
+            throws MalformedObjectNameException {
+
+        // we could probably link the probe pattern with the probe - e.g.
+        // using the UUID as key in the pattern - but is it worth it? it
+        // also has some side effects on the context namespace - because
+        // such a probe may get rejected by the jmx.context// namespace.
+        //
+        // The trick here is to devise a pattern that is not likely to
+        // be blocked by intermediate levels. Querying for all namespace
+        // handlers in the source (or source namespace) is more likely to
+        // achieve this goal.
+        //
+        return ObjectName.getInstance("*" +
+                JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
+                JMXNamespace.TYPE_ASSIGNMENT);
+    }
+
+    // tell whether the name pattern corresponds to what might have been
+    // sent as a probe.
+    // XXX: TODO this probe thing is way too complex and fragile.
+    //      This *must* go away or be replaced by something simpler.
+    //      ideas are welcomed.
+    final boolean isProbePattern(ObjectName name) {
+        final ObjectName p = probe;
+        if (p == null) return false;
+        try {
+            return String.valueOf(name).endsWith(targetNs+
+                JMXNamespaces.NAMESPACE_SEPARATOR + "*" +
+                JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
+                JMXNamespace.TYPE_ASSIGNMENT);
+        } catch (RuntimeException x) {
+            // should not happen.
+            PROBE_LOG.finest("Ignoring unexpected exception in self link detection: "+
+                    x);
+            return false;
+        }
+    }
+
+    // The first time a request reaches this NamespaceInterceptor, the
+    // interceptor will send a probe to detect whether the underlying
+    // JMXNamespace links to itslef.
+    //
+    // One way to create such self-linking namespace would be for instance
+    // to create a JMXNamespace whose getSourceServer() method would return:
+    // JMXNamespaces.narrowToNamespace(getMBeanServer(),
+    //                                 getObjectName().getDomain())
+    //
+    // If such an MBeanServer is returned, then any call to that MBeanServer
+    // will trigger an infinite loop.
+    // There can be even trickier configurations if remote connections are
+    // involved.
+    //
+    // In order to prevent this from happening, the NamespaceInterceptor will
+    // send a probe, in an attempt to detect whether it will receive it at
+    // the other end. If the probe is received, an exception will be thrown
+    // in order to break the recursion. The probe is only sent once - when
+    // the first request to the namespace occurs. The DynamicProbe interface
+    // can also be used by a Sun JMXNamespace implementation to request the
+    // emission of a probe at any time (see JMXRemoteNamespace
+    // implementation).
+    //
+    // Probes work this way: the NamespaceInterceptor sets a flag and sends
+    // a queryNames() request. If a queryNames() request comes in when the flag
+    // is on, then it deduces that there is a self-linking loop - and instead
+    // of calling queryNames() on the source MBeanServer of the JMXNamespace
+    // handler (which would cause the loop to go on) it breaks the recursion
+    // by returning the probe ObjectName.
+    // If the NamespaceInterceptor receives the probe ObjectName as result of
+    // its original sendProbe() request it knows that it has been looping
+    // back on itslef and throws an IOException...
+    //
+    //
+    // XXX: TODO this probe thing is way too complex and fragile.
+    //      This *must* go away or be replaced by something simpler.
+    //      ideas are welcomed.
+    //
+    final void sendProbe(MBeanServerConnection msc)
+            throws IOException {
+        try {
+            PROBE_LOG.fine("Sending probe");
+
+            // This is just to prevent any other thread to modify
+            // the probe while the detection cycle is in progress.
+            //
+            final ObjectName probePattern;
+            // we don't want to synchronize on this - we use targetNs
+            // because it's non null and final.
+            synchronized (targetNs) {
+                probed = false;
+                if (probe != null) {
+                    throw new IOException("concurent connection in progress");
+                }
+                final String uuid = UUID.randomUUID().toString();
+                final String endprobe =
+                        JMXNamespaces.NAMESPACE_SEPARATOR + uuid +
+                        ":type=Probe,key="+uuid;
+                final ObjectName newprobe =
+                        ObjectName.getInstance(endprobe);
+                probePattern = makeProbePattern(newprobe);
+                probe = newprobe;
+            }
+
+            try {
+                PROBE_LOG.finer("Probe query: "+probePattern+" expecting: "+probe);
+                final Set<ObjectName> res = msc.queryNames(probePattern, null);
+                final ObjectName expected = probe;
+                PROBE_LOG.finer("Probe res: "+res);
+                if (res.contains(expected)) {
+                    throw new IOException("namespace " +
+                            targetNs + " is linking to itself: " +
+                            "cycle detected by probe");
+                }
+            } catch (SecurityException x) {
+                PROBE_LOG.finer("Can't check for cycles: " + x);
+                // can't do anything....
+            } catch (RuntimeException x) {
+                PROBE_LOG.finer("Exception raised by queryNames: " + x);
+                throw x;
+            } finally {
+                probe = null;
+            }
+        } catch (MalformedObjectNameException x) {
+            final IOException io =
+                    new IOException("invalid name space: probe failed");
+            io.initCause(x);
+            throw io;
+        }
+        PROBE_LOG.fine("Probe returned - no cycles");
+        probed = true;
+    }
+
+    // allows a Sun implementation JMX Namespace, such as the
+    // JMXRemoteNamespace, to control when a probe should be sent.
+    //
+    // XXX: TODO this probe thing is way too complex and fragile.
+    //      This *must* go away or be replaced by something simpler.
+    //      ideas are welcomed.
+    private boolean isProbeRequested(Object o) {
+        if (o instanceof DynamicProbe)
+            return ((DynamicProbe)o).isProbeRequested();
+        return false;
+    }
+
+    /**
+     * This method will send a probe to detect self-linking name spaces.
+     * A self linking namespace is a namespace that links back directly
+     * on itslef. Calling a method on such a name space always results
+     * in an infinite loop going through:
+     * [1]MBeanServer -> [2]NamespaceDispatcher -> [3]NamespaceInterceptor
+     * [4]JMXNamespace -> { network // or cd // or ... } -> [5]MBeanServer
+     * with exactly the same request than [1]...
+     *
+     * The namespace interceptor [2] tries to detect such condition the
+     * *first time* that the connection is used. It does so by setting
+     * a flag, and sending a queryNames() through the name space. If the
+     * queryNames comes back, it knows that there's a loop.
+     *
+     * The DynamicProbe interface can also be used by a Sun JMXNamespace
+     * implementation to request the emission of a probe at any time
+     * (see JMXRemoteNamespace implementation).
+     */
+    private MBeanServer connection() {
+        try {
+            final MBeanServer c = super.source();
+            if (probe != null) // should not happen
+                throw new RuntimeException("connection is being probed");
+
+            if (probed == false || isProbeRequested(c)) {
+                try {
+                    // Should not happen if class well behaved.
+                    // Never probed. Force it.
+                    //System.err.println("sending probe for " +
+                    //        "target="+targetNs+", source="+srcNs);
+                    sendProbe(c);
+                } catch (IOException io) {
+                    throw new RuntimeException(io.getMessage(), io);
+                }
+            }
+
+            if (c != null) {
+                return c;
+            }
+        } catch (RuntimeException x) {
+            throw x;
+        }
+        throw new NullPointerException("getMBeanServerConnection");
+    }
+
+
+    @Override
+    protected MBeanServer source() {
+        return connection();
+    }
+
+    @Override
+    protected MBeanServer getServerForLoading() {
+        // don't want to send probe on getClassLoader/getClassLoaderFor
+        return super.source();
+    }
+
+    /**
+     * Calls {@link MBeanServerConnection#queryNames queryNames}
+     * on the underlying
+     * {@link #getMBeanServerConnection MBeanServerConnection}.
+     **/
+    @Override
+    public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        // XXX: TODO this probe thing is way too complex and fragile.
+        //      This *must* go away or be replaced by something simpler.
+        //      ideas are welcomed.
+        PROBE_LOG.finer("probe is: "+probe+" pattern is: "+name);
+        if (probe != null && isProbePattern(name)) {
+            PROBE_LOG.finer("Return probe: "+probe);
+            return Collections.singleton(probe);
+        }
+        return super.queryNames(name, query);
+    }
+
+    @Override
+    protected ObjectName toSource(ObjectName targetName)
+            throws MalformedObjectNameException {
+        return proc.toSourceContext(targetName, true);
+    }
+
+    @Override
+    protected ObjectName toTarget(ObjectName sourceName)
+            throws MalformedObjectNameException {
+        return proc.toTargetContext(sourceName, false);
+    }
+
+    //
+    // Implements permission checks.
+    //
+    @Override
+    void check(ObjectName routingName, String member, String action) {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm == null) return;
+        if ("getDomains".equals(action)) return;
+        final JMXNamespacePermission perm =
+                new  JMXNamespacePermission(serverName,member,
+                routingName,action);
+        sm.checkPermission(perm);
+    }
+
+    @Override
+    void checkCreate(ObjectName routingName, String className, String action) {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm == null) return;
+        final JMXNamespacePermission perm =
+                new  JMXNamespacePermission(serverName,className,
+                routingName,action);
+        sm.checkPermission(perm);
+    }
+
+    //
+    // Implements permission filters for attributes...
+    //
+    @Override
+    AttributeList checkAttributes(ObjectName routingName,
+            AttributeList attributes, String action) {
+        check(routingName,null,action);
+        if (attributes == null || attributes.isEmpty()) return attributes;
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm == null) return attributes;
+        final AttributeList res = new AttributeList();
+        for (Attribute at : attributes.asList()) {
+            try {
+                check(routingName,at.getName(),action);
+                res.add(at);
+            } catch (SecurityException x) { // DLS: OK
+                continue;
+            }
+        }
+        return res;
+    }
+
+    //
+    // Implements permission filters for attributes...
+    //
+    @Override
+    String[] checkAttributes(ObjectName routingName, String[] attributes,
+            String action) {
+        check(routingName,null,action);
+        if (attributes == null || attributes.length==0) return attributes;
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm == null) return attributes;
+        final List<String> res = new ArrayList<String>(attributes.length);
+        for (String at : attributes) {
+            try {
+                check(routingName,at,action);
+                res.add(at);
+            } catch (SecurityException x) { // DLS: OK
+                continue;
+            }
+        }
+        return res.toArray(new String[res.size()]);
+    }
+
+    //
+    // Implements permission filters for domains...
+    //
+    @Override
+    String[] checkDomains(String[] domains, String action) {
+        // in principle, this method is never called because
+        // getDomains() will never be called - since there's
+        // no way that MBeanServer.getDomains() can be routed
+        // to a NamespaceInterceptor.
+        //
+        // This is also why there's no getDomains() in a
+        // JMXNamespacePermission...
+        //
+        return super.checkDomains(domains, action);
+    }
+
+    //
+    // Implements permission filters for queries...
+    //
+    @Override
+    boolean checkQuery(ObjectName routingName, String action) {
+        try {
+            check(routingName,null,action);
+            return true;
+        } catch (SecurityException x) { // DLS: OK
+            return false;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+/**
+ * The ObjectNameRouter is used to rewrite routing object names.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public class ObjectNameRouter {
+
+    private static final int NAMESPACE_SEPARATOR_LENGTH =
+            NAMESPACE_SEPARATOR.length();
+
+    final String targetPrefix;
+    final String sourcePrefix;
+    final int slen;
+    final int tlen;
+    final boolean identity;
+
+
+    public ObjectNameRouter(String targetDirName) {
+        this(targetDirName,null);
+    }
+
+    /** Creates a new instance of ObjectNameRouter */
+    public ObjectNameRouter(final String remove, final String add) {
+        this.targetPrefix = (remove==null?"":remove);
+        this.sourcePrefix = (add==null?"":add);
+        tlen = targetPrefix.length();
+        slen = sourcePrefix.length();
+        identity = targetPrefix.equals(sourcePrefix);
+    }
+
+    public final ObjectName toTargetContext(ObjectName sourceName,
+            boolean removeLeadingSeparators) {
+        if (sourceName == null) return null;
+        if (identity) return sourceName;
+        String srcDomain = sourceName.getDomain();
+
+        // if the ObjectName starts with // and removeLeadingSeparators is
+        // true, then recursively strip leading //.
+        // Otherwise, do not rewrite ObjectName.
+        //
+        if (srcDomain.startsWith(NAMESPACE_SEPARATOR)) {
+            if (!removeLeadingSeparators) return sourceName;
+            else srcDomain = normalizeDomain(srcDomain,true);
+        }
+        if (slen != 0) {
+            if (!srcDomain.startsWith(sourcePrefix) ||
+                    !srcDomain.startsWith(NAMESPACE_SEPARATOR,slen))
+                throw new IllegalArgumentException(
+                        "ObjectName does not start with expected prefix "
+                        + sourcePrefix + ": " +
+                        String.valueOf(sourceName));
+            srcDomain = srcDomain.substring(slen+NAMESPACE_SEPARATOR_LENGTH);
+        }
+        final String targetDomain =
+                (tlen>0?targetPrefix+NAMESPACE_SEPARATOR+srcDomain:srcDomain);
+        try {
+            return sourceName.withDomain(targetDomain);
+        } catch (MalformedObjectNameException x) {
+            throw new IllegalArgumentException(String.valueOf(sourceName),x);
+        }
+    }
+
+    public final ObjectName toSourceContext(ObjectName targetName,
+            boolean removeLeadingSeparators) {
+        if (targetName == null) return null;
+        if (identity) return targetName;
+        String targetDomain = targetName.getDomain();
+        if (targetDomain.startsWith(NAMESPACE_SEPARATOR)) {
+            if (!removeLeadingSeparators) return targetName;
+            else targetDomain =
+                    normalizeDomain(targetDomain,true);
+        }
+        if (tlen != 0) {
+            if (!targetDomain.startsWith(targetPrefix) ||
+                    !targetDomain.startsWith(NAMESPACE_SEPARATOR,tlen))
+                throw new IllegalArgumentException(
+                        "ObjectName does not start with expected prefix "
+                        + targetPrefix + ": " +
+                        String.valueOf(targetName));
+            targetDomain = targetDomain.
+                    substring(tlen+NAMESPACE_SEPARATOR_LENGTH);
+        }
+        final String sourceDomain =
+                (slen>0?sourcePrefix+NAMESPACE_SEPARATOR+targetDomain:
+                    targetDomain);
+        try {
+            return targetName.withDomain(sourceDomain);
+        } catch (MalformedObjectNameException x) {
+            throw new IllegalArgumentException(String.valueOf(targetName),x);
+        }
+    }
+
+    public final ObjectInstance toTargetContext(ObjectInstance sourceMoi,
+            boolean removeLeadingSeparators) {
+        if (sourceMoi == null) return null;
+        if (identity) return sourceMoi;
+        return new ObjectInstance(
+                toTargetContext(sourceMoi.getObjectName(),
+                    removeLeadingSeparators),
+                    sourceMoi.getClassName());
+    }
+
+    /**
+     * Removes leading, trailing, or duplicate // in a name space path.
+     **/
+    public static String normalizeDomain(String domain,
+                                         boolean removeLeadingSep) {
+        return normalizeNamespacePath(domain,removeLeadingSep,false,true);
+    }
+
+    /**
+     * Removes leading, trailing, or duplicate // in a name space path.
+     **/
+    public static String normalizeNamespacePath(String namespacePath,
+                                            boolean removeLeadingSep,
+                                            boolean removeTrailingSep,
+                                            boolean endsWithDomain) {
+        if (namespacePath.equals(""))
+            return "";
+        final String[] components = namespacePath.split(NAMESPACE_SEPARATOR);
+        final StringBuilder b =
+                new StringBuilder(namespacePath.length()+NAMESPACE_SEPARATOR_LENGTH);
+        String sep = null;
+        if (!removeLeadingSep && namespacePath.startsWith(NAMESPACE_SEPARATOR))
+            b.append(NAMESPACE_SEPARATOR);
+        int count = 0;
+        for (int i=0; i<components.length; i++) {
+            final String n=components[i];
+            if (n.equals("")) continue;
+            if (n.startsWith("/")||n.endsWith("/")) {
+                // throw exception unless we're looking at the last domain
+                // part of the ObjectName
+                if (! (endsWithDomain && i==(components.length-1))) {
+                    throw new IllegalArgumentException(n+
+                        " is not a valid name space identifier");
+                } else {
+                    // There's a dirty little corner case when the domain
+                    // part (last item) is exactly '/' - in that case we must
+                    // not append '//'
+                    //
+                    removeTrailingSep = removeTrailingSep || n.equals("/");
+                }
+            }
+            if (sep != null) b.append(sep);
+            b.append(n);
+            sep = NAMESPACE_SEPARATOR;
+            count++;
+        }
+        if (!removeTrailingSep && namespacePath.endsWith(NAMESPACE_SEPARATOR)
+            && count > 0)
+            b.append(NAMESPACE_SEPARATOR);
+        return b.toString();
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+
+import com.sun.jmx.defaults.JmxProperties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.MBeanServerConnection;
+import javax.management.namespace.JMXNamespaces;
+
+
+/**
+ * A RoutingConnectionProxy is an MBeanServerConnection proxy that proxies a
+ * source name space in a source MBeanServerConnection.
+ * It wraps a source MBeanServerConnection, and rewrites routing
+ * ObjectNames. It is used to implement
+ * {@code JMXNamespaces.narrowToNamespace(MBeanServerConnection)}.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public class RoutingConnectionProxy
+        extends RoutingProxy<MBeanServerConnection> {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+
+    /**
+     * Creates a new instance of RoutingConnectionProxy
+     */
+    public RoutingConnectionProxy(MBeanServerConnection source,
+                               String sourceDir) {
+        this(source,sourceDir,"",false);
+    }
+
+    /**
+     * Creates a new instance of RoutingConnectionProxy
+     */
+    public RoutingConnectionProxy(MBeanServerConnection source,
+                               String sourceDir,
+                               String targetDir,
+                               boolean forwardsContext) {
+        super(source,sourceDir,targetDir,forwardsContext);
+
+        if (LOG.isLoggable(Level.FINER))
+            LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
+                      " created");
+    }
+
+    @Override
+    public String toString() {
+        final String targetNs = getTargetNamespace();
+        final String sourceNs = getSourceNamespace();
+        String wrapped = String.valueOf(source());
+        if ("".equals(targetNs)) {
+            if (forwardsContext)
+                wrapped = "ClientContext.withDynamicContext("+wrapped+")";
+            return "JMXNamespaces.narrowToNamespace("+
+                    wrapped+", \""+
+                    sourceNs+"\")";
+        }
+        return this.getClass().getSimpleName()+"("+wrapped+", \""+
+               sourceNs+"\", \""+
+               targetNs+"\", "+forwardsContext+")";
+    }
+
+    public static MBeanServerConnection cd(MBeanServerConnection source,
+            String sourcePath) {
+        if (source == null) throw new IllegalArgumentException("null");
+        if (source.getClass().equals(RoutingConnectionProxy.class)) {
+            // cast is OK here, but findbugs complains unless we use class.cast
+            final RoutingConnectionProxy other =
+                    RoutingConnectionProxy.class.cast(source);
+            final String target = other.getTargetNamespace();
+
+            // Avoid multiple layers of serialization.
+            //
+            // We construct a new proxy from the original source instead of
+            // stacking a new proxy on top of the old one.
+            // - that is we replace
+            //      cd ( cd ( x, dir1), dir2);
+            // by
+            //      cd (x, dir1//dir2);
+            //
+            // We can do this only when the source class is exactly
+            //    NamespaceConnectionProxy.
+            //
+            if (target == null || target.equals("")) {
+                final String path =
+                    JMXNamespaces.concat(other.getSourceNamespace(),
+                    sourcePath);
+                return new RoutingConnectionProxy(other.source(),path,"",
+                        other.forwardsContext);
+            }
+            // Note: we could do possibly something here - but it would involve
+            //       removing part of targetDir, and possibly adding
+            //       something to sourcePath.
+            //       Too complex to bother! => simply default to stacking...
+        }
+        return new RoutingConnectionProxy(source,sourcePath);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,671 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMRuntimeException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import javax.management.RuntimeOperationsException;
+
+/**
+ * A RoutingMBeanServerConnection wraps a MBeanServerConnection, defining
+ * abstract methods that can be implemented by subclasses to rewrite
+ * routing ObjectNames. It is used to implement
+ * HandlerInterceptors (wrapping JMXNamespace instances) and routing
+ * proxies (used to implement cd operations).
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnection>
+        implements MBeanServerConnection {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    /**
+     * Creates a new instance of RoutingMBeanServerConnection
+     */
+    public RoutingMBeanServerConnection() {
+    }
+
+    /**
+     * Returns the wrapped source connection.
+     **/
+    protected abstract T source() throws IOException;
+
+    /**
+     * Converts a target ObjectName to a source ObjectName.
+     **/
+    protected abstract ObjectName toSource(ObjectName targetName)
+        throws MalformedObjectNameException;
+
+    /**
+     * Converts a source ObjectName to a target ObjectName.
+     **/
+    protected abstract ObjectName toTarget(ObjectName sourceName)
+        throws MalformedObjectNameException;
+
+    /**
+     * Can be overridden by subclasses to check the validity of a new
+     * ObjectName used in createMBean or registerMBean.
+     * This method is typically used by subclasses which might require
+     * special handling for "null";
+     **/
+    protected ObjectName newSourceMBeanName(ObjectName targetName)
+        throws MBeanRegistrationException {
+        try {
+            return toSource(targetName);
+        } catch (Exception x) {
+            throw new MBeanRegistrationException(x,"Illegal MBean Name");
+        }
+    }
+
+    // Calls toSource(), Wraps MalformedObjectNameException.
+    ObjectName toSourceOrRuntime(ObjectName targetName)
+        throws RuntimeOperationsException {
+        try {
+            return toSource(targetName);
+        } catch (MalformedObjectNameException x) {
+            final IllegalArgumentException x2 =
+                    new IllegalArgumentException(String.valueOf(targetName),x);
+            final RuntimeOperationsException x3 =
+                    new RuntimeOperationsException(x2);
+            throw x3;
+        }
+    }
+
+
+    // Wraps given exception if needed.
+    RuntimeException makeCompliantRuntimeException(Exception x) {
+        if (x instanceof SecurityException)  return (SecurityException)x;
+        if (x instanceof JMRuntimeException) return (JMRuntimeException)x;
+        if (x instanceof RuntimeException)
+            return new RuntimeOperationsException((RuntimeException)x);
+        if (x instanceof IOException)
+            return Util.newRuntimeIOException((IOException)x);
+        // shouldn't come here...
+        final RuntimeException x2 = new UndeclaredThrowableException(x);
+        return new RuntimeOperationsException(x2);
+    }
+
+    /**
+     * This method is a hook to implement permission checking in subclasses.
+     * By default, this method does nothing and simply returns
+     * {@code attribute}.
+     *
+     * @param routingName The name of the MBean in the enclosing context.
+     *        This is of the form {@code <namespace>//<ObjectName>}.
+     * @param attributes  The list of attributes to check permission for.
+     * @param action one of "getAttribute" or "setAttribute"
+     * @return The list of attributes for which the callers has the
+     *         appropriate {@link
+     *         javax.management.namespace.JMXNamespacePermission}.
+     */
+    String[] checkAttributes(ObjectName routingName,
+            String[] attributes, String action) {
+        check(routingName,null,action);
+        return attributes;
+    }
+
+    /**
+     * This method is a hook to implement permission checking in subclasses.
+     * By default, this method does nothing and simply returns
+     * {@code attribute}.
+     *
+     * @param routingName The name of the MBean in the enclosing context.
+     *        This is of the form {@code <namespace>//<ObjectName>}.
+     * @param attributes The list of attributes to check permission for.
+     * @param action one of "getAttribute" or "setAttribute"
+     * @return The list of attributes for which the callers has the
+     *         appropriate {@link
+     *         javax.management.namespace.JMXNamespacePermission}.
+     */
+    AttributeList checkAttributes(ObjectName routingName,
+            AttributeList attributes, String action) {
+        check(routingName,null,action);
+        return attributes;
+    }
+
+    // from MBeanServerConnection
+    public AttributeList getAttributes(ObjectName name, String[] attributes)
+        throws InstanceNotFoundException, ReflectionException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            final String[] authorized =
+                    checkAttributes(name,attributes,"getAttribute");
+            final AttributeList attrList =
+                    source().getAttributes(sourceName,authorized);
+            return attrList;
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+   /**
+     * This method is a hook to implement permission checking in subclasses.
+     * By default, this method does nothing.
+     * A subclass may override this method and throw a {@link
+     * SecurityException} if the permission is denied.
+     *
+     * @param routingName The name of the MBean in the enclosing context.
+     *        This is of the form {@code <namespace>//<ObjectName>}.
+     * @param member The {@link
+     *  javax.management.namespace.JMXNamespacePermission#getMember member}
+     *  name.
+     * @param action The {@link
+     *  javax.management.namespace.JMXNamespacePermission#getActions action}
+     *  name.
+     */
+    void check(ObjectName routingName,
+               String member, String action) {
+    }
+
+    void checkPattern(ObjectName routingPattern,
+               String member, String action) {
+        // pattern is checked only at posteriori by checkQuery.
+        // checking it a priori usually doesn't work, because ObjectName.apply
+        // does not work between two patterns.
+        check(null,null,action);
+    }
+
+    void checkCreate(ObjectName routingName, String className,
+                     String action) {
+    }
+
+    // from MBeanServerConnection
+    public Object invoke(ObjectName name, String operationName, Object[] params,
+                         String[] signature)
+        throws InstanceNotFoundException, MBeanException, ReflectionException,
+            IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name, operationName, "invoke");
+            final Object result =
+                    source().invoke(sourceName,operationName,params,
+                                   signature);
+            return result;
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void unregisterMBean(ObjectName name)
+        throws InstanceNotFoundException, MBeanRegistrationException,
+            IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name, null, "unregisterMBean");
+            source().unregisterMBean(sourceName);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public MBeanInfo getMBeanInfo(ObjectName name)
+        throws InstanceNotFoundException, IntrospectionException,
+            ReflectionException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name, null, "getMBeanInfo");
+            return source().getMBeanInfo(sourceName);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public ObjectInstance getObjectInstance(ObjectName name)
+        throws InstanceNotFoundException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name, null, "getObjectInstance");
+            return processOutputInstance(
+                    source().getObjectInstance(sourceName));
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public boolean isRegistered(ObjectName name) throws IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            return source().isRegistered(sourceName);
+        } catch (RuntimeMBeanException x) {
+            throw new RuntimeOperationsException(x.getTargetException());
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void setAttribute(ObjectName name, Attribute attribute)
+        throws InstanceNotFoundException, AttributeNotFoundException,
+            InvalidAttributeValueException, MBeanException,
+            ReflectionException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name,
+                  (attribute==null?null:attribute.getName()),
+                  "setAttribute");
+            source().setAttribute(sourceName,attribute);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public ObjectInstance createMBean(String className,
+            ObjectName name, ObjectName loaderName,
+            Object[] params, String[] signature)
+        throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException, IOException {
+        final ObjectName sourceName = newSourceMBeanName(name);
+        // Loader Name is already a sourceLoaderName.
+        final ObjectName sourceLoaderName = loaderName;
+        try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
+            final ObjectInstance instance =
+                    source().createMBean(className,sourceName,
+                                         sourceLoaderName,
+                                         params,signature);
+            return processOutputInstance(instance);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public ObjectInstance createMBean(String className, ObjectName name,
+            Object[] params, String[] signature)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, IOException {
+        final ObjectName sourceName = newSourceMBeanName(name);
+        try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
+            return processOutputInstance(source().createMBean(className,
+                    sourceName,params,signature));
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public ObjectInstance createMBean(String className, ObjectName name,
+            ObjectName loaderName)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException, IOException {
+        final ObjectName sourceName = newSourceMBeanName(name);
+        // Loader Name is already a source Loader Name.
+        final ObjectName sourceLoaderName = loaderName;
+        try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
+            return processOutputInstance(source().createMBean(className,
+                    sourceName,sourceLoaderName));
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public ObjectInstance createMBean(String className, ObjectName name)
+        throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, IOException {
+        final ObjectName sourceName = newSourceMBeanName(name);
+        try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
+            return processOutputInstance(source().
+                    createMBean(className,sourceName));
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+     }
+
+    // from MBeanServerConnection
+    public Object getAttribute(ObjectName name, String attribute)
+        throws MBeanException, AttributeNotFoundException,
+            InstanceNotFoundException, ReflectionException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name, attribute, "getAttribute");
+            return source().getAttribute(sourceName,attribute);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public boolean isInstanceOf(ObjectName name, String className)
+        throws InstanceNotFoundException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name, null, "isInstanceOf");
+            return source().isInstanceOf(sourceName,className);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public AttributeList setAttributes(ObjectName name, AttributeList attributes)
+        throws InstanceNotFoundException, ReflectionException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            final AttributeList authorized =
+                    checkAttributes(name, attributes, "setAttribute");
+            return source().
+                    setAttributes(sourceName,authorized);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // Return names in the target's context.
+    Set<ObjectInstance> processOutputInstances(Set<ObjectInstance> sources) {
+
+        final Set<ObjectInstance> result = Util.equivalentEmptySet(sources);
+        for (ObjectInstance i : sources) {
+            try {
+                final ObjectInstance target = processOutputInstance(i);
+                if (!checkQuery(target.getObjectName(), "queryMBeans"))
+                    continue;
+                result.add(target);
+            } catch (Exception x) {
+                if (LOG.isLoggable(Level.FINE)) {
+                    LOG.fine("Skiping returned item: " +
+                             "Unexpected exception while processing " +
+                             "ObjectInstance: " + x);
+                }
+                continue;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * This is a hook to implement permission checking in subclasses.
+     *
+     * Checks that the caller has sufficient permission for returning
+     * information about {@code sourceName} in {@code action}.
+     *
+     * By default always return true. Subclass may override this method
+     * and return false if the caller doesn't have sufficient permissions.
+     *
+     * @param routingName The name of the MBean to include or exclude from
+     *        the query, expressed in the enclosing context.
+     *        This is of the form {@code <namespace>//<ObjectName>}.
+     * @param action one of "queryNames" or "queryMBeans"
+     * @return true if {@code sourceName} can be returned.
+     */
+    boolean checkQuery(ObjectName routingName, String action) {
+        return true;
+    }
+
+    // Return names in the target's context.
+    ObjectInstance processOutputInstance(ObjectInstance source) {
+        if (source == null) return null;
+        final ObjectName sourceName = source.getObjectName();
+        try {
+            final ObjectName targetName = toTarget(sourceName);
+            return new ObjectInstance(targetName,source.getClassName());
+        } catch (MalformedObjectNameException x) {
+            final IllegalArgumentException x2 =
+                    new IllegalArgumentException(String.valueOf(sourceName),x);
+            final RuntimeOperationsException x3 =
+                    new RuntimeOperationsException(x2);
+            throw x3;
+        }
+    }
+
+    // Returns names in the target's context.
+    Set<ObjectName> processOutputNames(Set<ObjectName> sourceNames) {
+
+        final Set<ObjectName> names = Util.equivalentEmptySet(sourceNames);
+        for (ObjectName n : sourceNames) {
+            try {
+                final ObjectName targetName = toTarget(n);
+                if (!checkQuery(targetName, "queryNames")) continue;
+                names.add(targetName);
+            } catch (Exception x) {
+                if (LOG.isLoggable(Level.FINE)) {
+                    LOG.fine("Skiping returned item: " +
+                             "Unexpected exception while processing " +
+                             "ObjectInstance: " + x);
+                }
+                continue;
+            }
+        }
+        return names;
+    }
+
+    // from MBeanServerConnection
+    public Set<ObjectInstance> queryMBeans(ObjectName name,
+            QueryExp query) throws IOException {
+        if (name == null) name=ObjectName.WILDCARD;
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            checkPattern(name,null,"queryMBeans");
+            return processOutputInstances(
+                    source().queryMBeans(sourceName,query));
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query)
+        throws IOException {
+        if (name == null) name=ObjectName.WILDCARD;
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            checkPattern(name,null,"queryNames");
+            final Set<ObjectName> tmp = source().queryNames(sourceName,query);
+            final Set<ObjectName> out = processOutputNames(tmp);
+            //System.err.println("queryNames: out: "+out);
+            return out;
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener)
+        throws InstanceNotFoundException,
+        ListenerNotFoundException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name,null,"removeNotificationListener");
+            source().removeNotificationListener(sourceName,listener);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void addNotificationListener(ObjectName name, ObjectName listener,
+            NotificationFilter filter, Object handback)
+            throws InstanceNotFoundException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        // Listener name is already a source listener name.
+        try {
+            check(name,null,"addNotificationListener");
+            source().addNotificationListener(sourceName,listener,
+                    filter,handback);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void addNotificationListener(ObjectName name,
+                NotificationListener listener, NotificationFilter filter,
+                Object handback) throws InstanceNotFoundException, IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name,null,"addNotificationListener");
+            source().addNotificationListener(sourceName, listener, filter,
+                    handback);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+
+    // from MBeanServerConnection
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener, NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException,
+                IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name,null,"removeNotificationListener");
+            source().removeNotificationListener(sourceName,listener,filter,
+                    handback);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void removeNotificationListener(ObjectName name, ObjectName listener,
+            NotificationFilter filter, Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException,
+            IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            check(name,null,"removeNotificationListener");
+            source().removeNotificationListener(sourceName,listener,
+                    filter,handback);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public void removeNotificationListener(ObjectName name, ObjectName listener)
+        throws InstanceNotFoundException, ListenerNotFoundException,
+               IOException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        // listener name is already a source name...
+        final ObjectName sourceListener = listener;
+        try {
+            check(name,null,"removeNotificationListener");
+            source().removeNotificationListener(sourceName,sourceListener);
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public Integer getMBeanCount() throws IOException {
+        try {
+            return source().getMBeanCount();
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // from MBeanServerConnection
+    public String[] getDomains() throws IOException {
+        try {
+            check(null,null,"getDomains");
+            final String[] domains = source().getDomains();
+            return checkDomains(domains,"getDomains");
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    /**
+     * This method is a hook to implement permission checking in subclasses.
+     * Checks that the caller as the necessary permissions to view the
+     * given domain. If not remove the domains for which the caller doesn't
+     * have permission from the list.
+     * <p>
+     * By default, this method always returns {@code domains}
+     *
+     * @param domains The domains to return.
+     * @param action  "getDomains"
+     * @return a filtered list of domains.
+     */
+    String[] checkDomains(String[] domains, String action) {
+        return domains;
+    }
+
+    // from MBeanServerConnection
+    public String getDefaultDomain() throws IOException {
+        try {
+            return source().getDefaultDomain();
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanRegistrationException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.namespace.JMXNamespaces;
+
+
+/**
+ * An RoutingProxy narrows on a given name space in a
+ * source object implementing MBeanServerConnection.
+ * It is used to implement
+ * {@code JMXNamespaces.narrowToNamespace(...)}.
+ * This abstract class has two concrete subclasses:
+ * <p>{@link RoutingConnectionProxy}: to cd in an MBeanServerConnection.</p>
+ * <p>{@link RoutingServerProxy}: to cd in an MBeanServer.</p>
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public abstract class RoutingProxy<T extends MBeanServerConnection>
+        extends RoutingMBeanServerConnection<T> {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    // The source MBeanServerConnection
+    private final T source;
+
+    // The name space we're narrowing to (usually some name space in
+    // the source MBeanServerConnection
+    private final String                sourceNs;
+
+    // The name space we pretend to be mounted in (usually "")
+    private final String                targetNs;
+
+    // The name of the JMXNamespace that handles the source name space
+    private final ObjectName            handlerName;
+    private final ObjectNameRouter      router;
+    final boolean forwardsContext;
+    private volatile String             defaultDomain = null;
+
+    /**
+     * Creates a new instance of RoutingProxy
+     */
+    protected RoutingProxy(T source,
+                          String sourceNs,
+                          String targetNs,
+                          boolean forwardsContext) {
+        if (source == null) throw new IllegalArgumentException("null");
+        this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs);
+
+        // Usually sourceNs is not null, except when implementing
+        // Client Contexts
+        //
+        if (sourceNs.equals("")) {
+            this.handlerName = null;
+        } else {
+            // System.err.println("sourceNs: "+sourceNs);
+            this.handlerName =
+                JMXNamespaces.getNamespaceObjectName(this.sourceNs);
+            try {
+                // System.err.println("handlerName: "+handlerName);
+                if (!source.isRegistered(handlerName))
+                    throw new IllegalArgumentException(sourceNs +
+                            ": no such name space");
+            } catch (IOException x) {
+                throw new IllegalArgumentException("source stale: "+x,x);
+            }
+        }
+        this.source = source;
+        this.targetNs = (targetNs==null?"":
+            JMXNamespaces.normalizeNamespaceName(targetNs));
+        this.router =
+                new ObjectNameRouter(this.targetNs,this.sourceNs);
+        this.forwardsContext = forwardsContext;
+
+        if (LOG.isLoggable(Level.FINER))
+            LOG.finer("RoutingProxy for " + this.sourceNs + " created");
+    }
+
+    @Override
+    public T source() { return source; }
+
+    ObjectNameRouter getObjectNameRouter() {
+// TODO: uncomment this when contexts are added
+//        if (forwardsContext)
+//            return ObjectNameRouter.wrapWithContext(router);
+//        else
+            return router;
+    }
+
+    @Override
+    public ObjectName toSource(ObjectName targetName)
+        throws MalformedObjectNameException {
+        if (targetName == null) return null;
+        if (targetName.getDomain().equals("") && targetNs.equals("")) {
+            try {
+                if (defaultDomain == null)
+                    defaultDomain = getDefaultDomain();
+            } catch(Exception x) {
+                LOG.log(Level.FINEST,"Failed to get default domain",x);
+            }
+            if (defaultDomain != null)
+                targetName = targetName.withDomain(defaultDomain);
+        }
+        final ObjectNameRouter r = getObjectNameRouter();
+        return r.toSourceContext(targetName,true);
+    }
+
+    @Override
+    protected ObjectName newSourceMBeanName(ObjectName targetName)
+        throws MBeanRegistrationException {
+        if (targetName != null) return super.newSourceMBeanName(targetName);
+
+        // OK => we can accept null if sourceNs is empty.
+        if (sourceNs.equals("")) return null;
+
+        throw new MBeanRegistrationException(
+                new IllegalArgumentException(
+                "Can't use null ObjectName with namespaces"));
+    }
+
+    @Override
+    public ObjectName toTarget(ObjectName sourceName)
+        throws MalformedObjectNameException {
+        if (sourceName == null) return null;
+        final ObjectNameRouter r = getObjectNameRouter();
+        return r.toTargetContext(sourceName,false);
+    }
+
+    private Object getAttributeFromHandler(String attributeName)
+            throws IOException {
+
+        try {
+            return source().getAttribute(handlerName,attributeName);
+         } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+         } catch (IOException x) {
+             throw x;
+         } catch (MBeanException ex) {
+             throw new IOException("Failed to get "+attributeName+": "+
+                     ex.getMessage(),
+                     ex.getTargetException());
+         } catch (AttributeNotFoundException ex) {
+             throw new IOException("Failed to get "+attributeName+": "+
+                     ex.getMessage(),ex);
+         } catch (InstanceNotFoundException ex) {
+             throw new IOException("Failed to get "+attributeName+": "+
+                     ex.getMessage(),ex);
+         } catch (ReflectionException ex) {
+             throw new IOException("Failed to get "+attributeName+": "+
+                     ex.getMessage(),ex);
+         }
+    }
+
+    // We cannot call getMBeanCount() on the underlying
+    // MBeanServerConnection, because it would return the number of
+    // 'top-level' MBeans, not the number of MBeans in the name space
+    // we are narrowing to. Instead we're calling getMBeanCount() on
+    // the JMXNamespace that handles the source name space.
+    //
+    // There is however one particular case when the sourceNs is empty.
+    // In that case, there's no handler - and the 'source' is the top
+    // level namespace. In that particular case, handlerName will be null,
+    // and we directly invoke the top level source().
+    // This later complex case is only used when implementing ClientContexts.
+    //
+    @Override
+    public Integer getMBeanCount() throws IOException {
+        try {
+            if (handlerName == null) return source().getMBeanCount();
+            return (Integer) getAttributeFromHandler("MBeanCount");
+         } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+         }
+    }
+
+    // We cannot call getDomains() on the underlying
+    // MBeanServerConnection, because it would return the domains of
+    // 'top-level' MBeans, not the domains of MBeans in the name space
+    // we are narrowing to. Instead we're calling getDomains() on
+    // the JMXNamespace that handles the source name space.
+    //
+    // There is however one particular case when the sourceNs is empty.
+    // In that case, there's no handler - and the 'source' is the top
+    // level namespace. In that particular case, handlerName will be null,
+    // and we directly invoke the top level source().
+    // This later complex case is only used when implementing ClientContexts.
+    //
+    @Override
+    public String[] getDomains() throws IOException {
+        try {
+            if (handlerName == null) return source().getDomains();
+            return (String[]) getAttributeFromHandler("Domains");
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    // We cannot call getDefaultDomain() on the underlying
+    // MBeanServerConnection, because it would return the default domain of
+    // 'top-level' namespace, not the default domain in the name space
+    // we are narrowing to. Instead we're calling getDefaultDomain() on
+    // the JMXNamespace that handles the source name space.
+    //
+    // There is however one particular case when the sourceNs is empty.
+    // In that case, there's no handler - and the 'source' is the top
+    // level namespace. In that particular case, handlerName will be null,
+    // and we directly invoke the top level source().
+    // This later complex case is only used when implementing ClientContexts.
+    //
+    @Override
+    public String getDefaultDomain() throws IOException {
+        try {
+            if (handlerName == null) {
+                defaultDomain = source().getDefaultDomain();
+            } else {
+                defaultDomain =(String)
+                        getAttributeFromHandler("DefaultDomain");
+            }
+            return defaultDomain;
+        } catch (RuntimeException ex) {
+            throw makeCompliantRuntimeException(ex);
+        }
+    }
+
+    public String getSourceNamespace() {
+        return sourceNs;
+    }
+
+    public String getTargetNamespace() {
+        return targetNs;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+", sourceNs="+
+                sourceNs + (targetNs.equals("")?"":
+                    (" mounted on targetNs="+targetNs));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.loading.ClassLoaderRepository;
+import javax.management.namespace.JMXNamespaces;
+
+/**
+ * A RoutingServerProxy is an MBeanServer proxy that proxies a
+ * source name space in a source MBeanServer.
+ * It wraps a source MBeanServer, and rewrites routing ObjectNames.
+ * It is typically use for implementing 'cd' operations, and
+ * will add the source name space to routing ObjectNames at input,
+ * and remove it at output.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ *
+ * @since 1.7
+ */
+public class RoutingServerProxy
+        extends RoutingProxy<MBeanServer>
+        implements MBeanServer {
+
+    /**
+     * Creates a new instance of RoutingServerProxy
+     */
+    public RoutingServerProxy(MBeanServer source,
+                           String sourceNs) {
+        this(source,sourceNs,"",false);
+    }
+
+    public RoutingServerProxy(MBeanServer source,
+                                String sourceNs,
+                                String targetNs,
+                                boolean forwardsContext) {
+        super(source,sourceNs,targetNs,forwardsContext);
+    }
+
+    /**
+     * This method is called each time an IOException is raised when
+     * trying to forward an operation to the underlying
+     * MBeanServerConnection, as a result of calling
+     * {@link #getMBeanServerConnection()} or as a result of invoking the
+     * operation on the returned connection.
+     * Subclasses may redefine this method if they need to perform any
+     * specific handling of IOException (logging etc...).
+     * @param x The raised IOException.
+     * @param method The name of the method in which the exception was
+     *        raised. This is one of the methods of the MBeanServer
+     *        interface.
+     * @return A RuntimeException that should be thrown by the caller.
+     *         In this default implementation, this is an
+     *         {@link UndeclaredThrowableException} wrapping <var>x</var>.
+     **/
+    protected RuntimeException handleIOException(IOException x,
+                                                 String method) {
+        return Util.newRuntimeIOException(x);
+    }
+
+
+    //--------------------------------------------
+    //--------------------------------------------
+    //
+    // Implementation of the MBeanServer interface
+    //
+    //--------------------------------------------
+    //--------------------------------------------
+    @Override
+    public void addNotificationListener(ObjectName name,
+                                        NotificationListener listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+        throws InstanceNotFoundException {
+        try {
+            super.addNotificationListener(name, listener,
+                                                 filter, handback);
+        } catch (IOException x) {
+            throw handleIOException(x,"addNotificationListener");
+        }
+    }
+
+    @Override
+    public void addNotificationListener(ObjectName name,
+                                        ObjectName listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+        throws InstanceNotFoundException {
+        try {
+            super.addNotificationListener(name, listener,
+                                                 filter, handback);
+        } catch (IOException x) {
+            throw handleIOException(x,"addNotificationListener");
+        }
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException {
+        try {
+            return super.createMBean(className, name);
+        } catch (IOException x) {
+            throw handleIOException(x,"createMBean");
+        }
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                      Object params[], String signature[])
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException {
+        try {
+            return super.createMBean(className, name,
+                                     params, signature);
+        } catch (IOException x) {
+            throw handleIOException(x,"createMBean");
+        }
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      ObjectName loaderName)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        InstanceNotFoundException {
+        try {
+            return super.createMBean(className, name, loaderName);
+        } catch (IOException x) {
+            throw handleIOException(x,"createMBean");
+        }
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      ObjectName loaderName,
+                                      Object params[],
+                                      String signature[])
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        InstanceNotFoundException {
+        try {
+            return super.createMBean(className, name, loaderName,
+                                            params, signature);
+        } catch (IOException x) {
+            throw handleIOException(x,"createMBean");
+        }
+    }
+
+    /**
+     * @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[])
+     *                 MBeanServer}
+     **/
+    @Deprecated
+    public ObjectInputStream deserialize(ObjectName name, byte[] data)
+        throws InstanceNotFoundException, OperationsException {
+        final ObjectName sourceName = toSourceOrRuntime(name);
+        try {
+            return source().deserialize(sourceName,data);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    /**
+     * @deprecated see {@link MBeanServer#deserialize(String,byte[])
+     *                 MBeanServer}
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className, byte[] data)
+        throws OperationsException, ReflectionException {
+        try {
+            return source().deserialize(className,data);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    /**
+     * @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[])
+     *                 MBeanServer}
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className,
+                                         ObjectName loaderName,
+                                         byte[] data)
+        throws
+        InstanceNotFoundException,
+        OperationsException,
+        ReflectionException {
+        try {
+            return source().deserialize(className,loaderName,data);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    @Override
+    public Object getAttribute(ObjectName name, String attribute)
+        throws
+        MBeanException,
+        AttributeNotFoundException,
+        InstanceNotFoundException,
+        ReflectionException {
+        try {
+            return super.getAttribute(name, attribute);
+        } catch (IOException x) {
+            throw handleIOException(x,"getAttribute");
+        }
+    }
+
+    @Override
+    public AttributeList getAttributes(ObjectName name, String[] attributes)
+        throws InstanceNotFoundException, ReflectionException {
+        try {
+            return super.getAttributes(name, attributes);
+        } catch (IOException x) {
+            throw handleIOException(x,"getAttributes");
+        }
+    }
+
+    public ClassLoader getClassLoader(ObjectName loaderName)
+        throws InstanceNotFoundException {
+        final ObjectName sourceName = toSourceOrRuntime(loaderName);
+        try {
+            return source().getClassLoader(sourceName);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+        throws InstanceNotFoundException {
+        final ObjectName sourceName = toSourceOrRuntime(mbeanName);
+        try {
+            return source().getClassLoaderFor(sourceName);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    public ClassLoaderRepository getClassLoaderRepository() {
+        try {
+            return source().getClassLoaderRepository();
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    @Override
+    public String getDefaultDomain() {
+        try {
+            return super.getDefaultDomain();
+        } catch (IOException x) {
+            throw handleIOException(x,"getDefaultDomain");
+        }
+    }
+
+    @Override
+    public String[] getDomains() {
+        try {
+            return super.getDomains();
+        } catch (IOException x) {
+            throw handleIOException(x,"getDomains");
+        }
+    }
+
+    @Override
+    public Integer getMBeanCount() {
+        try {
+            return super.getMBeanCount();
+        } catch (IOException x) {
+            throw handleIOException(x,"getMBeanCount");
+        }
+    }
+
+    @Override
+    public MBeanInfo getMBeanInfo(ObjectName name)
+        throws
+        InstanceNotFoundException,
+        IntrospectionException,
+        ReflectionException {
+        try {
+            return super.getMBeanInfo(name);
+        } catch (IOException x) {
+            throw handleIOException(x,"getMBeanInfo");
+        }
+    }
+
+    @Override
+    public ObjectInstance getObjectInstance(ObjectName name)
+        throws InstanceNotFoundException {
+        try {
+            return super.getObjectInstance(name);
+        } catch (IOException x) {
+            throw handleIOException(x,"getObjectInstance");
+        }
+    }
+
+    public Object instantiate(String className)
+        throws ReflectionException, MBeanException {
+        try {
+            return source().instantiate(className);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    public Object instantiate(String className,
+                              Object params[],
+                              String signature[])
+        throws ReflectionException, MBeanException {
+        try {
+            return source().instantiate(className,
+                    params,signature);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    public Object instantiate(String className, ObjectName loaderName)
+        throws ReflectionException, MBeanException,
+               InstanceNotFoundException {
+        final ObjectName srcLoaderName = toSourceOrRuntime(loaderName);
+        try {
+            return source().instantiate(className,srcLoaderName);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    public Object instantiate(String className, ObjectName loaderName,
+                              Object params[], String signature[])
+        throws ReflectionException, MBeanException,
+               InstanceNotFoundException {
+        final ObjectName srcLoaderName = toSourceOrRuntime(loaderName);
+        try {
+            return source().instantiate(className,srcLoaderName,
+                    params,signature);
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    @Override
+    public Object invoke(ObjectName name, String operationName,
+                         Object params[], String signature[])
+        throws
+        InstanceNotFoundException,
+        MBeanException,
+        ReflectionException {
+        try {
+            return super.invoke(name,operationName,params,signature);
+        } catch (IOException x) {
+            throw handleIOException(x,"invoke");
+        }
+    }
+
+    @Override
+    public boolean isInstanceOf(ObjectName name, String className)
+        throws InstanceNotFoundException {
+        try {
+            return super.isInstanceOf(name, className);
+        } catch (IOException x) {
+            throw handleIOException(x,"isInstanceOf");
+        }
+    }
+
+    @Override
+    public boolean isRegistered(ObjectName name) {
+        try {
+            return super.isRegistered(name);
+        } catch (IOException x) {
+            throw handleIOException(x,"isRegistered");
+        }
+    }
+
+    @Override
+    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        try {
+            return super.queryMBeans(name, query);
+        } catch (IOException x) {
+            handleIOException(x,"queryMBeans");
+            return Collections.emptySet();
+        }
+    }
+
+    @Override
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        try {
+            return super.queryNames(name, query);
+        } catch (IOException x) {
+            handleIOException(x,"queryNames");
+            return Collections.emptySet();
+        }
+    }
+
+    public ObjectInstance registerMBean(Object object, ObjectName name)
+        throws
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        NotCompliantMBeanException {
+        final ObjectName sourceName = newSourceMBeanName(name);
+        try {
+            return processOutputInstance(
+                    source().registerMBean(object,sourceName));
+        } catch (RuntimeException x) {
+            throw makeCompliantRuntimeException(x);
+        }
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                                           NotificationListener listener)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener);
+        } catch (IOException x) {
+            throw handleIOException(x,"removeNotificationListener");
+        }
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                                           NotificationListener listener,
+                                           NotificationFilter filter,
+                                           Object handback)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener,
+                                                    filter, handback);
+        } catch (IOException x) {
+            throw handleIOException(x,"removeNotificationListener");
+        }
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                                           ObjectName listener)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener);
+        } catch (IOException x) {
+            throw handleIOException(x,"removeNotificationListener");
+        }
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                                           ObjectName listener,
+                                           NotificationFilter filter,
+                                           Object handback)
+        throws InstanceNotFoundException, ListenerNotFoundException {
+        try {
+            super.removeNotificationListener(name, listener,
+                                                    filter, handback);
+        } catch (IOException x) {
+            throw handleIOException(x,"removeNotificationListener");
+        }
+    }
+
+    @Override
+    public void setAttribute(ObjectName name, Attribute attribute)
+        throws
+        InstanceNotFoundException,
+        AttributeNotFoundException,
+        InvalidAttributeValueException,
+        MBeanException,
+        ReflectionException {
+        try {
+            super.setAttribute(name, attribute);
+        } catch (IOException x) {
+            throw handleIOException(x,"setAttribute");
+        }
+    }
+
+    @Override
+    public AttributeList setAttributes(ObjectName name,
+                                       AttributeList attributes)
+        throws InstanceNotFoundException, ReflectionException {
+        try {
+            return super.setAttributes(name, attributes);
+        } catch (IOException x) {
+            throw handleIOException(x,"setAttributes");
+        }
+    }
+
+    @Override
+    public void unregisterMBean(ObjectName name)
+        throws InstanceNotFoundException, MBeanRegistrationException {
+        try {
+           super.unregisterMBean(name);
+        } catch (IOException x) {
+            throw handleIOException(x,"unregisterMBean");
+        }
+    }
+
+
+    public static MBeanServer cd(MBeanServer source, String sourcePath) {
+        if (source == null) throw new IllegalArgumentException("null");
+        if (source.getClass().equals(RoutingServerProxy.class)) {
+            // cast is OK here, but findbugs complains unless we use class.cast
+            final RoutingServerProxy other =
+                    RoutingServerProxy.class.cast(source);
+            final String target = other.getTargetNamespace();
+
+            // Avoid multiple layers of serialization.
+            //
+            // We construct a new proxy from the original source instead of
+            // stacking a new proxy on top of the old one.
+            // - that is we replace
+            //      cd ( cd ( x, dir1), dir2);
+            // by
+            //      cd (x, dir1//dir2);
+            //
+            // We can do this only when the source class is exactly
+            //    NamespaceServerProxy.
+            //
+            if (target == null || target.equals("")) {
+                final String path =
+                    JMXNamespaces.concat(other.getSourceNamespace(),
+                    sourcePath);
+                return new RoutingServerProxy(other.source(),path,"",
+                                              other.forwardsContext);
+            }
+            // Note: we could do possibly something here - but it would involve
+            //       removing part of targetDir, and possibly adding
+            //       something to sourcePath.
+            //       Too complex to bother! => simply default to stacking...
+        }
+        return new RoutingServerProxy(source,sourcePath);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/package.html	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+  <head>
+    <title>The <code>com.sun.jmx.namespace</code> package</title>
+<!--
+Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 only, as
+published by the Free Software Foundation.  Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun in the LICENSE file that accompanied this code.
+
+This code is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+version 2 for more details (a copy is included in the LICENSE file that
+accompanied this code).
+
+You should have received a copy of the GNU General Public License version
+2 along with this work; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+-->
+  </head>
+    <body bgcolor="white">
+        <p>The <code>com.sun.jmx.namespace</code> package contains
+            sun specific implementation classes used to implement the
+            JMX namespaces. 
+        </p>
+        <p><b>DO NOT USE THESE CLASSES DIRECTLY</b></p>
+        <p><b>
+        This API is a Sun internal API and is subject to changes without notice.
+        </b></p>
+        <p>The public API through wich these proprietary classes can be 
+           invoked is located in <code>javax.management.namespace</code>
+           package.
+        </p>
+    </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace.serial;
+
+
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+/**
+ * Class DefaultRewritingProcessor. Rewrite ObjectName in input & output
+ * parameters.
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+// We know that rewriting using serialization is costly.
+// This object tries to determine whether an object needs rewriting prior
+// to rewriting, and rewrites by creating a new object in those cases
+// where we know how to recreate a new object (e.g. a Notification).
+// Rewriting is however usually not used - so this object is just a
+// skeleton that eventually uses serialization...
+//
+class DefaultRewritingProcessor extends RewritingProcessor {
+
+
+    private static enum RewriteMode {
+        INPUT,  // Input from target to source  (parameters)
+        OUTPUT  // Output from source to target (results)
+    };
+
+    private final boolean identity;
+
+    public DefaultRewritingProcessor(String targetDirName) {
+        this(targetDirName,null);
+    }
+
+    /** Creates a new instance of SerialParamProcessor */
+    public DefaultRewritingProcessor(final String remove, final String add) {
+        super(new SerialRewritingProcessor(remove, add));
+        identity = remove.equals(add);
+    }
+
+    private ObjectName rewriteObjectName(RewriteMode mode,
+            ObjectName name) {
+        return changeContext(mode, name);
+    }
+
+    private ObjectInstance rewriteObjectInstance(RewriteMode mode,
+            ObjectInstance moi) {
+        final ObjectName srcName = moi.getObjectName();
+        final ObjectName targetName = changeContext(mode,srcName);
+        if (targetName == srcName) return moi;
+        return new ObjectInstance(targetName,moi.getClassName());
+    }
+
+
+    private Object processObject(RewriteMode mode, Object obj) {
+        if (obj == null) return null;
+
+        // Some things which will always needs rewriting:
+        // ObjectName, ObjectInstance, and Notifications.
+        // Take care of those we can handle here...
+        //
+        if (obj instanceof ObjectName)
+            return rewriteObjectName(mode,(ObjectName) obj);
+        else if (obj instanceof ObjectInstance)
+            return rewriteObjectInstance(mode,(ObjectInstance) obj);
+
+        // TODO: add other standard JMX classes - like e.g. MBeanInfo...
+        //
+
+        // Well, the object may contain an ObjectName => pass it to
+        // our serial rewriting delegate...
+        //
+        return processAnyObject(mode,obj);
+    }
+
+
+    private Object processAnyObject(RewriteMode mode, Object obj) {
+        switch (mode) {
+            case INPUT:
+                return super.rewriteInput(obj);
+            case OUTPUT:
+                return super.rewriteOutput(obj);
+            default: // can't happen.
+                throw new AssertionError();
+        }
+    }
+
+    private ObjectName changeContext(RewriteMode mode, ObjectName name) {
+        switch (mode) {
+            case INPUT:
+                return toSourceContext(name);
+            case OUTPUT:
+                return toTargetContext(name);
+            default: // can't happen.
+                throw new AssertionError();
+        }
+    }
+
+    @Override
+    public ObjectName toTargetContext(ObjectName srcName) {
+        if (identity) return srcName;
+        return super.toTargetContext(srcName);
+    }
+
+    @Override
+    public ObjectName toSourceContext(ObjectName targetName) {
+        if (identity) return targetName;
+        return super.toSourceContext(targetName);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T rewriteInput(T input) {
+        if (identity) return input;
+        return (T) processObject(RewriteMode.INPUT,input);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T rewriteOutput(T result) {
+        if (identity) return result;
+        return (T) processObject(RewriteMode.OUTPUT,result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace.serial;
+
+
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+/**
+ * Class RoutingOnlyProcessor. A RewritingProcessor that uses
+ * Java Serialization to rewrite ObjectNames contained in
+ * input & results...
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ *
+ * @since 1.7
+ */
+class IdentityProcessor extends RewritingProcessor {
+
+
+    /** Creates a new instance of SerialRewritingProcessor */
+    public IdentityProcessor() {
+    }
+
+    @Override
+    public <T> T rewriteOutput(T result) {
+        return result;
+    }
+
+    @Override
+    public <T> T rewriteInput(T input) {
+        return input;
+    }
+
+    @Override
+    public final ObjectName toTargetContext(ObjectName sourceName) {
+        return sourceName;
+    }
+
+    @Override
+    public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) {
+        return sourceMoi;
+    }
+
+    @Override
+    public final ObjectName toSourceContext(ObjectName targetName) {
+        return targetName;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace.serial;
+
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * The JMXNamespaceContext class is used to implement a thread local
+ * serialization / deserialization context for namespaces.
+ * <p>
+ * This class is consulted by {@link javax.management.ObjectName} at
+ * serialization / deserialization time.
+ * The serialization or deserialization context is established by
+ * by the {@link SerialRewritingProcessor} defined in this package.
+ * <p>
+ * These classes are Sun proprietary APIs, subject to change without
+ * notice. Do not use these classes directly.
+ * The public API to rewrite ObjectNames embedded in parameters is
+ * defined in {@link javax.management.namespace.JMXNamespaces}.
+ *
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public class JMXNamespaceContext {
+
+    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+    public final String prefixToRemove;
+    public final String prefixToAdd;
+
+    private JMXNamespaceContext(String add, String remove) {
+        prefixToRemove = (remove==null?"":remove);
+        prefixToAdd    = (add==null?"":add);
+    }
+
+    private final static class SerialContext {
+        private JMXNamespaceContext serializationContext;
+        private JMXNamespaceContext deserializationContext;
+        public SerialContext(){
+            serializationContext = new JMXNamespaceContext("","");
+            deserializationContext = new JMXNamespaceContext("","");
+        }
+    }
+
+    private final static ThreadLocal<SerialContext> prefix =
+            new ThreadLocal<SerialContext>() {
+        @Override
+        protected SerialContext initialValue() {
+            return new SerialContext();
+        }
+    };
+
+    public static JMXNamespaceContext getSerializationContext() {
+        return prefix.get().serializationContext;
+    }
+
+    public static JMXNamespaceContext getDeserializationContext() {
+        return prefix.get().deserializationContext;
+    }
+
+    private static String[] setSerializationContext(String oldPrefix,
+            String newPrefix) {
+        final SerialContext c = prefix.get();
+        JMXNamespaceContext dc = c.serializationContext;
+        String[] old = {dc.prefixToRemove, dc.prefixToAdd};
+        c.serializationContext = new JMXNamespaceContext(newPrefix,oldPrefix);
+        return old;
+    }
+
+    private static String[] setDeserializationContext(String oldPrefix,
+            String newPrefix) {
+        final SerialContext c = prefix.get();
+        JMXNamespaceContext dc = c.deserializationContext;
+        String[] old = {dc.prefixToRemove, dc.prefixToAdd};
+        c.deserializationContext = new JMXNamespaceContext(newPrefix,oldPrefix);
+        return old;
+    }
+
+    static void serialize(ObjectOutputStream stream, Object obj,
+            String prefixToRemove, String prefixToAdd)
+            throws IOException {
+        final String[] old =
+                setSerializationContext(prefixToRemove,prefixToAdd);
+        try {
+            stream.writeObject(obj);
+        } finally {
+            try {
+                setSerializationContext(old[0],old[1]);
+            } catch (Exception x) {
+                LOG.log(Level.FINEST,
+                        "failed to restore serialization context",x);
+            }
+        }
+    }
+
+    static Object deserialize(ObjectInputStream stream,
+            String prefixToRemove,
+            String prefixToAdd)
+            throws IOException, ClassNotFoundException {
+        final String[] old =
+                setDeserializationContext(prefixToRemove,prefixToAdd);
+        try {
+            return stream.readObject();
+        } finally {
+            try {
+                setDeserializationContext(old[0],old[1]);
+            } catch (Exception x) {
+                LOG.log(Level.FINEST,
+                        "failed to restore serialization context",x);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace.serial;
+
+
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+/**
+ * An object that can rewrite ObjectNames contained in input/output
+ * parameters when entering/leaving a {@link javax.management.namespace
+ * namespace}.
+ * <p>When entering a {@link javax.management.namespace
+ *    namespace}, the {@code namespace} prefix is stripped from
+ *    ObjectNames contained in input parameters. When leaving a
+ *    {@code namespace},
+ *    the {@code namespace} prefix is prepended to the ObjectNames contained in
+ *    the result parameters returned from that {@code namespace}.
+ * </p>
+ * <p>Objects that need to perform these operations usually use a
+ *    {@code RewritingProcessor} for that purpose.<br>
+ *    The {@code RewritingProcessor} allows a somewhat larger
+ *    transformation in which part of a prefix {@link #newRewritingProcessor
+ *    remove} can be replaced by another prefix {@link #newRewritingProcessor
+ *    add}. The transformation described above correspond to the case where
+ *    {@code remove} is the stripped {@link javax.management.namespace
+ *    namespace} prefix (removed when entering the {@code namespace}) and
+ *    {@code add} is the empty String {@code ""}.
+ *    <br>
+ *    It is interesting to note that {@link
+ *    javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace}
+ *    operations use the inverse transformation (that is, {@code remove} is
+ *    the empty String {@code ""} and {@code add} is the {@link
+ *    javax.management.namespace namespace} prefix).
+ *    <br>
+ *    On a more general scale, {@link #rewriteInput rewriteInput} removes
+ *    {@link #newRewritingProcessor remove} and the prepend {@link
+ *     #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput}
+ *    does the opposite, removing {@link #newRewritingProcessor add}, and
+ *    then adding {@link #newRewritingProcessor remove}.
+ *    <br>
+ *    An implementation of {@code RewritingProcessor} should make sure that
+ *    <code>rewriteInput(rewriteOutput(x,clp),clp)</code> and
+ *    <code>rewriteOutput(rewriteInput(x,clp),clp)</code> always return
+ *    {@code x} or an exact clone of {@code x}.
+ * </p>
+ * <p>A default implementation of {@code RewritingProcessor} based on
+ * Java Object Serialization can be
+ * obtained from {@link #newRewritingProcessor newRewritingProcessor}.
+ * </p>
+ * <p>
+ * By default, the instances of {@code RewritingProcessor} returned by
+ * {@link #newRewritingProcessor newRewritingProcessor} will rewrite
+ * ObjectNames contained in instances of classes they don't know about by
+ * serializing and then deserializing such object instances. This will
+ * happen even if such instances don't - or can't contain ObjectNames,
+ * because the default implementation of {@code RewritingProcessor} will
+ * not be able to determine whether instances of such classes can/do contain
+ * instance of ObjectNames before serializing/deserializing them.
+ * </p>
+ * <p>If you are using custom classes that the default implementation of
+ * {@code RewritingProcessor} don't know about, it can be interesting to
+ * prevent an instance of {@code RewritingProcessor} to serialize/deserialize
+ * instances of such classes for nothing. In that case, you could customize
+ * the behavior of such a {@code RewritingProcessor} by wrapping it in a
+ * custom subclass of {@code RewritingProcessor} as shown below:
+ * <pre>
+ * public class MyRewritingProcessor extends RewritingProcessor {
+ *      MyRewritingProcessor(String remove, String add) {
+ *          this(RewritingProcessor.newRewritingProcessor(remove,add));
+ *      }
+ *      MyRewritingProcessor(RewritingProcessor delegate) {
+ *          super(delegate);
+ *      }
+ *
+ *  <T> T rewriteInput(T input) {
+ *          if (input == null) return null;
+ *          if (MyClass.equals(input.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) input;
+ *          }
+ *          return super.rewriteInput(input);
+ *      }
+ *  <T> T rewriteOutput(T result) {
+ *          if (result == null) return null;
+ *          if (MyClass.equals(result.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) result;
+ *          }
+ *          return super.rewriteOutput(result);
+ *      }
+ * }
+ * </pre>
+ * </p>
+ * <p>Such a subclass may also provide an alternate way of rewriting
+ *    custom subclasses for which rewriting is needed - for instance:
+ * <pre>
+ * public class MyRewritingProcessor extends RewritingProcessor {
+ *      MyRewritingProcessor(String remove, String add) {
+ *          this(RewritingProcessor.newRewritingProcessor(remove,add));
+ *      }
+ *      MyRewritingProcessor(RewritingProcessor delegate) {
+ *          super(delegate);
+ *      }
+ *
+ *  <T> T rewriteInput(T input) {
+ *          if (input == null) return null;
+ *          if (MyClass.equals(input.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) input;
+ *          } else if (MyOtherClass.equals(input.getClass())) {
+ *              // Returns a new instance in which ObjectNames have been
+ *              // replaced.
+ *              final ObjectName aname = ((MyOtherClass)input).getName();
+ *              return (T) (new MyOtherClass(super.rewriteInput(aname)));
+ *          }
+ *          return super.rewriteInput(input,clp);
+ *      }
+ *  <T> T rewriteOutput(T result) {
+ *          if (result == null) return null;
+ *          if (MyClass.equals(result.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) result;
+ *          } else if (MyOtherClass.equals(result.getClass())) {
+ *              // Returns a new instance in which ObjectNames have been
+ *              // replaced.
+ *              final ObjectName aname = ((MyOtherClass)result).getName();
+ *              return (T) (new MyOtherClass(super.rewriteOutput(aname)));
+ *          }
+ *          return super.rewriteOutput(result,clp);
+ *      }
+ * }
+ * </pre>
+ * </p>
+ * <p>If your application only uses {@link javax.management.MXBean MXBeans},
+ * or MBeans using simple types, and doesn't define any custom subclass of
+ * {@link javax.management.Notification}, you should never write such
+ * such {@code RewitingProcessor} implementations.
+ * </p>
+ * <p><b>
+ * This API is a Sun internal API and is subject to changes without notice.
+ * </b></p>
+ * @since 1.7
+ */
+public abstract class RewritingProcessor {
+    /**
+     * A logger for this class.
+     **/
+    private final RewritingProcessor delegate;
+
+    /**
+     * Creates a new instance of RewritingProcessor.
+     * <p>This is equivalent to calling {@link
+     * #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}.
+     * </p>
+     **/
+    protected RewritingProcessor() {
+        this(null);
+    }
+
+    /**
+     * Creates a new instance of RewritingProcessor, with a delegate.
+     * @param delegate a {@code RewritingProcessor} to which all the
+     *        calls will be delegated. When implementing a subclass
+     *        of  {@code RewritingProcessor}, calling {@link
+     *        #rewriteInput super.rewriteInput} will invoke
+     *        {@code delegate.rewriteInput} and calling {@link
+     *        #rewriteOutput super.rewriteOutput} will invoke
+     *        {@code delegate.rewriteOutput}.
+     *
+     **/
+    protected RewritingProcessor(RewritingProcessor delegate) {
+        this.delegate = delegate;
+    }
+
+    /**
+     * Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link
+     * javax.management.namespace namespace}.
+     * <p>
+     * Returns {@code obj}, if it is known that {@code obj} doesn't contain
+     * any ObjectName, or a new copied instance of {@code obj} in which
+     * ObjectNames (if any) will have been rewritten, if {@code obj} contains
+     * ObjectNames, or if it is not known whether {@code obj} contains