Merge
authortbell
Fri, 12 Sep 2008 23:31:43 -0700
changeset 1232 7128121645f7
parent 1160 fe006e99708a (current diff)
parent 1231 9b3e98cca850 (diff)
child 1233 3b08cf0cab53
child 1241 495a689dfc36
Merge
--- a/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java	Fri Sep 12 23:31:43 2008 -0700
@@ -27,7 +27,6 @@
 
 import com.sun.jmx.remote.util.ClassLogger;
 import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -115,6 +114,7 @@
                 scheduled = null;
             }
             callback.run();
+            executor.shutdown();
         }
     }
 
@@ -131,6 +131,13 @@
         logger.trace("stop", "canceling lease");
         scheduled.cancel(false);
         scheduled = null;
+        try {
+            executor.shutdown();
+        } catch (SecurityException e) {
+            // OK: caller doesn't have RuntimePermission("modifyThread")
+            // which is unlikely in reality but triggers a test failure otherwise
+            logger.trace("stop", "exception from executor.shutdown", e);
+        }
     }
 
     private final Runnable callback;
@@ -138,7 +145,7 @@
 
     private final ScheduledExecutorService executor
             = Executors.newScheduledThreadPool(1,
-            new DaemonThreadFactory("LeaseManager"));
+            new DaemonThreadFactory("JMX LeaseManager %d"));
 
     private static final ClassLogger logger =
             new ClassLogger("javax.management.event", "LeaseManager");
--- a/jdk/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java	Fri Sep 12 23:31:43 2008 -0700
@@ -95,7 +95,9 @@
             executor.execute(this);
         } catch (RejectedExecutionException e) {
             logger.warning(
-                    "setEventReceiver", "Executor threw exception", e);
+                    "execute",
+                    "Executor threw exception (" + this.getClass().getName() + ")",
+                    e);
             throw new RejectedExecutionException(
                     "Executor.execute threw exception -" +
                     "should not be possible", e);
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -613,8 +613,7 @@
             List<String> result = new ArrayList<String>(domains.length);
             for (int i = 0; i < domains.length; i++) {
                 try {
-                    ObjectName dom =
-                            Util.newObjectName(domains[i] + ":x=x");
+                    ObjectName dom = ObjectName.valueOf(domains[i] + ":x=x");
                     checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains");
                     result.add(domains[i]);
                 } catch (SecurityException e) {
@@ -1170,7 +1169,7 @@
            if one is supplied where it shouldn't be).  */
         final String completeName = domain + name;
 
-        return Util.newObjectName(completeName);
+        return ObjectName.valueOf(completeName);
     }
 
     public String getDefaultDomain()  {
@@ -2021,7 +2020,7 @@
     private void addJMXNamespace(JMXNamespace namespace,
             final ObjectName logicalName,
             final Queue<Runnable> postQueue) {
-        dispatcher.addNamespace(logicalName, namespace, postQueue);
+        dispatcher.addInterceptorFor(logicalName, namespace, postQueue);
     }
 
     /**
@@ -2035,7 +2034,7 @@
     private void removeJMXNamespace(JMXNamespace namespace,
             final ObjectName logicalName,
             final Queue<Runnable> postQueue) {
-        dispatcher.removeNamespace(logicalName, namespace, postQueue);
+        dispatcher.removeInterceptorFor(logicalName, namespace, postQueue);
     }
 
     /**
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -194,7 +194,7 @@
     // 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);
+    abstract String getHandlerKey(ObjectName name);
 
     // Returns an interceptor for that name, or null if there's no interceptor
     // for that name.
@@ -277,7 +277,7 @@
     // 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,
+    public void addInterceptorFor(ObjectName name, N jmxNamespace,
             Queue<Runnable> postRegisterQueue) {
         final String key = getHandlerKey(name);
         validateHandlerNameFor(key,name);
@@ -298,7 +298,7 @@
     // 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,
+    public void removeInterceptorFor(ObjectName name, N jmxNamespace,
             Queue<Runnable> postDeregisterQueue) {
         final String key = getHandlerKey(name);
         final T ns;
@@ -330,7 +330,7 @@
     }
 
     // From MBeanServer
-    public ObjectInstance createMBean(String className, ObjectName name)
+    public final ObjectInstance createMBean(String className, ObjectName name)
             throws ReflectionException, InstanceAlreadyExistsException,
                    MBeanRegistrationException, MBeanException,
                    NotCompliantMBeanException {
@@ -338,7 +338,7 @@
     }
 
     // From MBeanServer
-    public ObjectInstance createMBean(String className, ObjectName name,
+    public final ObjectInstance createMBean(String className, ObjectName name,
                                       ObjectName loaderName)
             throws ReflectionException, InstanceAlreadyExistsException,
                    MBeanRegistrationException, MBeanException,
@@ -347,7 +347,7 @@
     }
 
     // From MBeanServer
-    public ObjectInstance createMBean(String className, ObjectName name,
+    public final ObjectInstance createMBean(String className, ObjectName name,
                                       Object params[], String signature[])
             throws ReflectionException, InstanceAlreadyExistsException,
                    MBeanRegistrationException, MBeanException,
@@ -357,7 +357,7 @@
     }
 
     // From MBeanServer
-    public ObjectInstance createMBean(String className, ObjectName name,
+    public final ObjectInstance createMBean(String className, ObjectName name,
                                       ObjectName loaderName, Object params[],
                                       String signature[])
             throws ReflectionException, InstanceAlreadyExistsException,
@@ -368,42 +368,43 @@
     }
 
     // From MBeanServer
-    public ObjectInstance registerMBean(Object object, ObjectName name)
+    public final ObjectInstance registerMBean(Object object, ObjectName name)
             throws InstanceAlreadyExistsException, MBeanRegistrationException,
                    NotCompliantMBeanException {
         return getInterceptorForCreate(name).registerMBean(object,name);
     }
 
     // From MBeanServer
-    public void unregisterMBean(ObjectName name)
+    public final void unregisterMBean(ObjectName name)
             throws InstanceNotFoundException, MBeanRegistrationException {
         getInterceptorForInstance(name).unregisterMBean(name);
     }
 
     // From MBeanServer
-    public ObjectInstance getObjectInstance(ObjectName name)
+    public final ObjectInstance getObjectInstance(ObjectName name)
             throws InstanceNotFoundException {
         return getInterceptorForInstance(name).getObjectInstance(name);
     }
 
     // From MBeanServer
-    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
-        final QueryInterceptor mbs =
+    public final Set<ObjectInstance> queryMBeans(ObjectName name,
+            QueryExp query) {
+        final QueryInterceptor queryInvoker =
                 getInterceptorForQuery(name);
-        if (mbs == null)  return Collections.emptySet();
-        else return mbs.queryMBeans(name,query);
+        if (queryInvoker == null)  return Collections.emptySet();
+        else return queryInvoker.queryMBeans(name,query);
     }
 
     // From MBeanServer
-    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
-        final QueryInterceptor mbs =
+    public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        final QueryInterceptor queryInvoker =
                 getInterceptorForQuery(name);
-        if (mbs == null)  return Collections.emptySet();
-        else return mbs.queryNames(name,query);
+        if (queryInvoker == null)  return Collections.emptySet();
+        else return queryInvoker.queryNames(name,query);
     }
 
     // From MBeanServer
-    public boolean isRegistered(ObjectName name) {
+    public final boolean isRegistered(ObjectName name) {
         final MBeanServer mbs = getInterceptorOrNullFor(name);
         if (mbs == null) return false;
         else return mbs.isRegistered(name);
@@ -415,20 +416,21 @@
     }
 
     // From MBeanServer
-    public Object getAttribute(ObjectName name, String attribute)
+    public final 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)
+    public final AttributeList getAttributes(ObjectName name,
+            String[] attributes)
             throws InstanceNotFoundException, ReflectionException {
         return getInterceptorForInstance(name).getAttributes(name,attributes);
     }
 
     // From MBeanServer
-    public void setAttribute(ObjectName name, Attribute attribute)
+    public final void setAttribute(ObjectName name, Attribute attribute)
             throws InstanceNotFoundException, AttributeNotFoundException,
                    InvalidAttributeValueException, MBeanException,
                    ReflectionException {
@@ -436,14 +438,14 @@
     }
 
     // From MBeanServer
-    public AttributeList setAttributes(ObjectName name,
+    public final AttributeList setAttributes(ObjectName name,
                                        AttributeList attributes)
         throws InstanceNotFoundException, ReflectionException {
         return getInterceptorForInstance(name).setAttributes(name,attributes);
     }
 
     // From MBeanServer
-    public Object invoke(ObjectName name, String operationName,
+    public final Object invoke(ObjectName name, String operationName,
                          Object params[], String signature[])
             throws InstanceNotFoundException, MBeanException,
                    ReflectionException {
@@ -463,63 +465,69 @@
     public abstract String[] getDomains();
 
     // From MBeanServer
-    public void addNotificationListener(ObjectName name,
+    public final void addNotificationListener(ObjectName name,
                                         NotificationListener listener,
                                         NotificationFilter filter,
                                         Object handback)
             throws InstanceNotFoundException {
-        getInterceptorForInstance(name).addNotificationListener(name,listener,filter,
+        getInterceptorForInstance(name).
+                addNotificationListener(name,listener,filter,
                 handback);
     }
 
 
     // From MBeanServer
-    public void addNotificationListener(ObjectName name,
+    public final void addNotificationListener(ObjectName name,
                                         ObjectName listener,
                                         NotificationFilter filter,
                                         Object handback)
             throws InstanceNotFoundException {
-        getInterceptorForInstance(name).addNotificationListener(name,listener,filter,
+        getInterceptorForInstance(name).
+                addNotificationListener(name,listener,filter,
                 handback);
     }
 
     // From MBeanServer
-    public void removeNotificationListener(ObjectName name,
+    public final void removeNotificationListener(ObjectName name,
                                            ObjectName listener)
         throws InstanceNotFoundException, ListenerNotFoundException {
-        getInterceptorForInstance(name).removeNotificationListener(name,listener);
+        getInterceptorForInstance(name).
+                removeNotificationListener(name,listener);
     }
 
     // From MBeanServer
-    public void removeNotificationListener(ObjectName name,
+    public final void removeNotificationListener(ObjectName name,
                                            ObjectName listener,
                                            NotificationFilter filter,
                                            Object handback)
             throws InstanceNotFoundException, ListenerNotFoundException {
-        getInterceptorForInstance(name).removeNotificationListener(name,listener,filter,
+        getInterceptorForInstance(name).
+                removeNotificationListener(name,listener,filter,
                 handback);
     }
 
 
     // From MBeanServer
-    public void removeNotificationListener(ObjectName name,
+    public final void removeNotificationListener(ObjectName name,
                                            NotificationListener listener)
             throws InstanceNotFoundException, ListenerNotFoundException {
-        getInterceptorForInstance(name).removeNotificationListener(name,listener);
+        getInterceptorForInstance(name).
+                removeNotificationListener(name,listener);
     }
 
     // From MBeanServer
-    public void removeNotificationListener(ObjectName name,
+    public final void removeNotificationListener(ObjectName name,
                                            NotificationListener listener,
                                            NotificationFilter filter,
                                            Object handback)
             throws InstanceNotFoundException, ListenerNotFoundException {
-        getInterceptorForInstance(name).removeNotificationListener(name,listener,filter,
+        getInterceptorForInstance(name).
+                removeNotificationListener(name,listener,filter,
                 handback);
     }
 
     // From MBeanServer
-    public MBeanInfo getMBeanInfo(ObjectName name)
+    public final MBeanInfo getMBeanInfo(ObjectName name)
             throws InstanceNotFoundException, IntrospectionException,
                    ReflectionException {
         return getInterceptorForInstance(name).getMBeanInfo(name);
@@ -527,21 +535,23 @@
 
 
     // From MBeanServer
-    public boolean isInstanceOf(ObjectName name, String className)
+    public final boolean isInstanceOf(ObjectName name, String className)
             throws InstanceNotFoundException {
         return getInterceptorForInstance(name).isInstanceOf(name,className);
     }
 
     // From MBeanServer
-    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+    public final ClassLoader getClassLoaderFor(ObjectName mbeanName)
         throws InstanceNotFoundException {
-        return getInterceptorForInstance(mbeanName).getClassLoaderFor(mbeanName);
+        return getInterceptorForInstance(mbeanName).
+                getClassLoaderFor(mbeanName);
     }
 
     // From MBeanServer
-    public ClassLoader getClassLoader(ObjectName loaderName)
+    public final ClassLoader getClassLoader(ObjectName loaderName)
         throws InstanceNotFoundException {
-        return getInterceptorForInstance(loaderName).getClassLoader(loaderName);
+        return getInterceptorForInstance(loaderName).
+                getClassLoader(loaderName);
     }
 
 }
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -75,7 +75,7 @@
 
         private final DomainDispatchInterceptor parent;
         AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) {
-            super(dispatcher.localNamespace);
+            super(dispatcher.nextInterceptor);
             parent = dispatcher;
         }
 
@@ -91,9 +91,8 @@
             // 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 boolean all = pattern.getDomain().equals("*");
 
             final String domain = pattern.getDomain();
 
@@ -142,7 +141,7 @@
         }
     }
 
-    private final DefaultMBeanServerInterceptor localNamespace;
+    private final DefaultMBeanServerInterceptor nextInterceptor;
     private final String mbeanServerName;
     private final MBeanServerDelegate delegate;
 
@@ -165,7 +164,7 @@
                             MBeanInstantiator   instantiator,
                             Repository          repository,
                             NamespaceDispatchInterceptor namespaces)  {
-           localNamespace = new DefaultMBeanServerInterceptor(outer,
+           nextInterceptor = new DefaultMBeanServerInterceptor(outer,
                    delegate, instantiator,repository,namespaces);
            mbeanServerName = Util.getMBeanServerSecurityName(delegate);
            this.delegate = delegate;
@@ -182,7 +181,7 @@
     @Override
     void validateHandlerNameFor(String key, ObjectName name) {
         super.validateHandlerNameFor(key,name);
-        final String[] domains = localNamespace.getDomains();
+        final String[] domains = nextInterceptor.getDomains();
         for (int i=0;i<domains.length;i++) {
             if (domains[i].equals(key))
                 throw new IllegalArgumentException("domain "+key+
@@ -192,37 +191,72 @@
 
     @Override
     final MBeanServer getInterceptorOrNullFor(ObjectName name) {
-        if (name == null) return localNamespace;
+
+        if (name == null) return nextInterceptor;
+
         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)) {
+        if (domain.endsWith(NAMESPACE_SEPARATOR))
+            return nextInterceptor; // This can be a namespace handler.
+        if (domain.contains(NAMESPACE_SEPARATOR))
+            return null; // shouldn't reach here.
+        if (isLocalHandlerNameFor(domain,name)) {
+            // This is the name of a JMXDomain MBean. Return nextInterceptor.
             LOG.finer("dispatching to local namespace");
-            return localNamespace;
+            return nextInterceptor;
         }
-        final DomainInterceptor ns = getInterceptor(localDomain);
+
+        final DomainInterceptor ns = getInterceptor(domain);
         if (ns == null) {
+            // no JMXDomain found for that domain - return nextInterceptor.
             if (LOG.isLoggable(Level.FINER)) {
-                LOG.finer("dispatching to local namespace: " + localDomain);
+                LOG.finer("dispatching to local namespace: " + domain);
             }
             return getNextInterceptor();
         }
+
         if (LOG.isLoggable(Level.FINER)) {
-            LOG.finer("dispatching to domain: " + localDomain);
+            LOG.finer("dispatching to domain: " + domain);
         }
         return ns;
     }
 
+    // This method returns true if the given pattern must be evaluated against
+    // several interceptors. This happens when either:
+    //
+    //   a) the pattern can select several domains (it's null, or it's a
+    //        domain pattern)
+    //   or b) it's not a domain pattern, but it might select the name of a
+    //        JMXDomain MBean in charge of that domain. Since the JMXDomain
+    //        MBean is located in the nextInterceptor, the pattern might need
+    //        to be evaluated on two interceptors.
+    //
+    // 1. When this method returns false, the query is evaluated on a single
+    // interceptor:
+    //    The interceptor for pattern.getDomain(), if there is one,
+    //    or the next interceptor, if there is none.
+    //
+    // 2. When this method returns true, we loop over all the domain
+    // interceptors:
+    //    in the list, and if the domain pattern matches the interceptor domain
+    //    we evaluate the query on that interceptor and aggregate the results.
+    //    Eventually we also evaluate the pattern against the next interceptor.
+    //
+    // See getInterceptorForQuery below.
+    //
     private boolean multipleQuery(ObjectName pattern) {
+        // case a) above
         if (pattern == null) return true;
         if (pattern.isDomainPattern()) return true;
 
         try {
+            // case b) above.
+            //
             // 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.
+            //
+            // Returning true will have this effect. see 2. above.
+            //
             if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain())))
                 return true;
         } catch (MalformedObjectNameException x) {
@@ -253,7 +287,7 @@
         // 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);
+        return new QueryInterceptor(nextInterceptor);
     }
 
     @Override
@@ -288,7 +322,7 @@
 
     @Override
     final DefaultMBeanServerInterceptor getNextInterceptor() {
-        return localNamespace;
+        return nextInterceptor;
     }
 
     /**
@@ -298,11 +332,11 @@
     @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
+        // Therefore, nextInterceptor.getDomains() contains all domains.
+        // In addition, nextInterceptor will perform the necessary
         // MBeanPermission checks for getDomains().
         //
-        return localNamespace.getDomains();
+        return nextInterceptor.getDomains();
     }
 
     /**
@@ -310,13 +344,13 @@
      */
     @Override
     public Integer getMBeanCount() {
-        int count = getNextInterceptor().getMBeanCount().intValue();
+        int count = getNextInterceptor().getMBeanCount();
         final String[] keys = getKeys();
         for (String key:keys) {
             final MBeanServer mbs = getInterceptor(key);
             if (mbs == null) continue;
-            count += mbs.getMBeanCount().intValue();
+            count += mbs.getMBeanCount();
         }
-        return Integer.valueOf(count);
+        return count;
     }
 }
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -61,7 +61,7 @@
     private static final int NAMESPACE_SEPARATOR_LENGTH =
             NAMESPACE_SEPARATOR.length();
 
-    private final DomainDispatchInterceptor localNamespace;
+    private final DomainDispatchInterceptor nextInterceptor;
     private final String           serverName;
 
     /**
@@ -84,7 +84,7 @@
                                MBeanServerDelegate delegate,
                                MBeanInstantiator   instantiator,
                                Repository          repository)  {
-           localNamespace = new DomainDispatchInterceptor(outer,delegate,
+           nextInterceptor = new DomainDispatchInterceptor(outer,delegate,
                    instantiator,repository,this);
            serverName = Util.getMBeanServerSecurityName(delegate);
     }
@@ -94,21 +94,21 @@
      * Get first name space in ObjectName path. Ignore leading namespace
      * separators.
      **/
-    public static String getFirstNamespace(ObjectName name) {
+    static String getFirstNamespace(ObjectName name) {
         if (name == null) return "";
         final String domain = name.getDomain();
         if (domain.equals("")) return "";
 
+        // skip leading separators
         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;
-        }
+        while (domain.startsWith(NAMESPACE_SEPARATOR,first))
+            first += NAMESPACE_SEPARATOR_LENGTH;
 
-        if (end == -1) return "";
+        // go to next separator
+        final int end = domain.indexOf(NAMESPACE_SEPARATOR,first);
+        if (end == -1) return ""; // no namespace
 
+        // This is the first element in the namespace path.
         final String namespace = domain.substring(first,end);
 
         return namespace;
@@ -143,7 +143,7 @@
         if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) ||
             name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
             LOG.finer("dispatching to local name space");
-            return localNamespace;
+            return nextInterceptor;
         }
         final NamespaceInterceptor ns = getInterceptor(namespace);
         if (LOG.isLoggable(Level.FINER)) {
@@ -162,7 +162,7 @@
         if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) ||
             pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
             LOG.finer("dispatching to local name space");
-            return new QueryInterceptor(localNamespace);
+            return new QueryInterceptor(nextInterceptor);
         }
         final NamespaceInterceptor ns = getInterceptor(namespace);
         if (LOG.isLoggable(Level.FINER)) {
@@ -202,7 +202,7 @@
 
     @Override
     final DomainDispatchInterceptor getNextInterceptor() {
-        return localNamespace;
+        return nextInterceptor;
     }
 
     /**
@@ -211,25 +211,25 @@
      */
     @Override
     public String[] getDomains() {
-        return localNamespace.getDomains();
+        return nextInterceptor.getDomains();
     }
 
     @Override
-    public void addNamespace(ObjectName name, JMXNamespace handler,
+    public void addInterceptorFor(ObjectName name, JMXNamespace handler,
             Queue<Runnable> postRegisterQueue) {
         if (handler instanceof JMXDomain)
-            localNamespace.addNamespace(name,
+            nextInterceptor.addInterceptorFor(name,
                     (JMXDomain)handler,postRegisterQueue);
-        else super.addNamespace(name,handler,postRegisterQueue);
+        else super.addInterceptorFor(name,handler,postRegisterQueue);
     }
 
     @Override
-    public void removeNamespace(ObjectName name, JMXNamespace handler,
+    public void removeInterceptorFor(ObjectName name, JMXNamespace handler,
             Queue<Runnable> postDeregisterQueue) {
         if (handler instanceof JMXDomain)
-            localNamespace.removeNamespace(name,(JMXDomain)handler,
+            nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler,
                     postDeregisterQueue);
-        else super.removeNamespace(name,handler,postDeregisterQueue);
+        else super.removeInterceptorFor(name,handler,postDeregisterQueue);
     }
 
 
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Fri Sep 12 23:31:43 2008 -0700
@@ -1172,10 +1172,10 @@
             final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class;
 
             Class targetClass = getTargetClass();
-            Constructor[] constrs = targetClass.getConstructors();
+            Constructor<?>[] constrs = targetClass.getConstructors();
 
             // Applicable if and only if there are any annotated constructors
-            List<Constructor> annotatedConstrList = newList();
+            List<Constructor<?>> annotatedConstrList = newList();
             for (Constructor<?> constr : constrs) {
                 if (Modifier.isPublic(constr.getModifiers())
                         && constr.getAnnotation(propertyNamesClass) != null)
@@ -1206,7 +1206,7 @@
             // Also remember the set of properties in that constructor
             // so we can test unambiguity.
             Set<BitSet> getterIndexSets = newSet();
-            for (Constructor constr : annotatedConstrList) {
+            for (Constructor<?> constr : annotatedConstrList) {
                 String[] propertyNames =
                     constr.getAnnotation(propertyNamesClass).value();
 
@@ -1363,10 +1363,10 @@
         }
 
         private static class Constr {
-            final Constructor constructor;
+            final Constructor<?> constructor;
             final int[] paramIndexes;
             final BitSet presentParams;
-            Constr(Constructor constructor, int[] paramIndexes,
+            Constr(Constructor<?> constructor, int[] paramIndexes,
                    BitSet presentParams) {
                 this.constructor = constructor;
                 this.paramIndexes = paramIndexes;
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java	Fri Sep 12 23:31:43 2008 -0700
@@ -623,7 +623,7 @@
     }
 
     private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
-        Constructor[] cons = c.getConstructors();
+        Constructor<?>[] cons = c.getConstructors();
         MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
         for (int i = 0; i < cons.length; i++) {
             String descr = "Public constructor of the MBean";
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java	Fri Sep 12 23:31:43 2008 -0700
@@ -396,7 +396,7 @@
 
         // Set domain to default if domain is empty and not already set
         if (dom.length() == 0)
-            name = Util.newObjectName(domain + name.toString());
+            name = ObjectName.valueOf(domain + name.toString());
 
         // Do we have default domain ?
         if (dom == domain) {  // ES: OK (dom & domain are interned)
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Fri Sep 12 23:31:43 2008 -0700
@@ -57,7 +57,8 @@
 public class Util {
     private final static int NAMESPACE_SEPARATOR_LENGTH =
             NAMESPACE_SEPARATOR.length();
-    public final static String ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?";
+    public final static char[] ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?".
+            toCharArray();
 
 
     static <K, V> Map<K, V> newMap() {
@@ -109,14 +110,6 @@
         return new ArrayList<E>(c);
     }
 
-    public static ObjectName newObjectName(String s) {
-        try {
-            return new ObjectName(s);
-        } catch (MalformedObjectNameException e) {
-            throw new IllegalArgumentException(e);
-        }
-    }
-
     /* This method can be used by code that is deliberately violating the
      * allowed checked casts.  Rather than marking the whole method containing
      * the code with @SuppressWarnings, you can use a call to this method for
@@ -621,7 +614,7 @@
      * is {@code null}.
      * @throws IllegalArgumentException if mbeanServerName contains illegal
      *         characters, or is empty, or is {@code "-"}.
-     *         Illegal characters are {@value #ILLEGAL_MBEANSERVER_NAME_CHARS}.
+     *         Illegal characters are {@link #ILLEGAL_MBEANSERVER_NAME_CHARS}.
      */
     public static String checkServerName(String mbeanServerName) {
         if ("".equals(mbeanServerName))
@@ -632,7 +625,7 @@
                     "\"-\" is not a valid MBean server name");
         if (isMBeanServerNameUndefined(mbeanServerName))
             return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
-        for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS.toCharArray()) {
+        for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS) {
             if (mbeanServerName.indexOf(c) >= 0)
                 throw new IllegalArgumentException(
                         "invalid character in MBeanServer name: "+c);
@@ -662,15 +655,15 @@
     }
 
     // Log the exception and its causes without logging the stack trace.
-    // Use with care - it is usally preferable to log the whole stack trace!
+    // Use with care - it is usually 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));
+            do {
+                toprint.append("\nCaused By: ").append(String.valueOf(t));
+            } while ((t=t.getCause())!=null);
             JmxProperties.MISC_LOGGER.fine(toprint.toString());
        }
     }
--- a/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -85,7 +85,7 @@
 
         final ObjectName pattern;
         public PatternNotificationFilter(ObjectName pattern) {
-            this.pattern = pattern;
+            this.pattern = pattern==null?ObjectName.WILDCARD:pattern;
         }
 
         public boolean isNotificationEnabled(Notification notification) {
@@ -93,7 +93,7 @@
                 return false;
             final MBeanServerNotification mbsn =
                     (MBeanServerNotification) notification;
-            if (pattern == null || pattern.apply(mbsn.getMBeanName()))
+            if (pattern.apply(mbsn.getMBeanName()))
                 return true;
             return false;
         }
@@ -110,6 +110,7 @@
         super(handler);
         this.domainName = domainName;
         this.serverName = serverName;
+        ALL = ObjectName.valueOf(domainName+":*");
     }
 
     @Override
@@ -118,27 +119,27 @@
                 ", domain="+this.domainName+")";
     }
 
-    public void connectDelegate(final MBeanServerDelegate delegate)
+    final void connectDelegate(final MBeanServerDelegate delegate)
             throws InstanceNotFoundException {
         final NotificationFilter filter =
                 new PatternNotificationFilter(getPatternFor(null));
         synchronized (this) {
-            if (mbsListener == null)
+            if (mbsListener == null) {
                 mbsListener = new NotificationListener() {
-
-               public void handleNotification(Notification notification,
-                    Object handback) {
-                    if (filter.isNotificationEnabled(notification))
-                        delegate.sendNotification(notification);
-                }
-            };
+                    public void handleNotification(Notification notification,
+                        Object handback) {
+                        if (filter.isNotificationEnabled(notification))
+                            delegate.sendNotification(notification);
+                    }
+                };
+            }
         }
 
-        getNamespace().
+        getHandlerInterceptorMBean().
                 addMBeanServerNotificationListener(mbsListener, filter);
     }
 
-    public void disconnectDelegate()
+    final void disconnectDelegate()
             throws InstanceNotFoundException, ListenerNotFoundException {
         final NotificationListener l;
         synchronized (this) {
@@ -146,10 +147,10 @@
             if (l == null) return;
             mbsListener = null;
         }
-        getNamespace().removeMBeanServerNotificationListener(l);
+        getHandlerInterceptorMBean().removeMBeanServerNotificationListener(l);
     }
 
-    public void addPostRegisterTask(Queue<Runnable> queue,
+    public final void addPostRegisterTask(Queue<Runnable> queue,
             final MBeanServerDelegate delegate) {
         if (queue == null)
             throw new IllegalArgumentException("task queue must not be null");
@@ -158,14 +159,15 @@
                 try {
                     connectDelegate(delegate);
                 } catch (Exception x) {
-                    throw new UnsupportedOperationException("notification forwarding",x);
+                    throw new UnsupportedOperationException(
+                            "notification forwarding",x);
                 }
             }
         };
         queue.add(task1);
     }
 
-    public void addPostDeregisterTask(Queue<Runnable> queue,
+    public final void addPostDeregisterTask(Queue<Runnable> queue,
             final MBeanServerDelegate delegate) {
         if (queue == null)
             throw new IllegalArgumentException("task queue must not be null");
@@ -174,17 +176,18 @@
                 try {
                     disconnectDelegate();
                 } catch (Exception x) {
-                    throw new UnsupportedOperationException("notification forwarding",x);
+                    throw new UnsupportedOperationException(
+                            "notification forwarding",x);
                 }
             }
         };
         queue.add(task1);
     }
 
-    /**
-     * Throws IllegalArgumentException if targetName.getDomain() is not
-     * in the domain handled.
-     **/
+    // No name conversion for JMXDomains...
+    // Throws IllegalArgumentException if targetName.getDomain() is not
+    // in the domain handled.
+    //
     @Override
     protected ObjectName toSource(ObjectName targetName) {
         if (targetName == null) return null;
@@ -198,6 +201,7 @@
         return targetName;
     }
 
+    // No name conversion for JMXDomains...
     @Override
     protected ObjectName toTarget(ObjectName sourceName) {
         return sourceName;
@@ -255,16 +259,16 @@
             if (LOG.isLoggable(Level.FINE))
                 LOG.fine("Unexpected exception raised in queryNames: "+x);
             LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
+            return Collections.emptySet();
         }
-        // We reach here only when an exception was raised.
-        //
-        final Set<ObjectName> empty = Collections.emptySet();
-        return empty;
     }
 
+    // Compute a new pattern which is a sub pattern of 'name' but only selects
+    // the MBeans in domain 'domainName'
+    // When we reach here, it has been verified that 'name' matches our domain
+    // name (done by DomainDispatchInterceptor)
     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);
@@ -284,11 +288,8 @@
             if (LOG.isLoggable(Level.FINE))
                 LOG.fine("Unexpected exception raised in queryNames: "+x);
             LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
+            return Collections.emptySet();
         }
-        // We reach here only when an exception was raised.
-        //
-        final Set<ObjectInstance> empty = Collections.emptySet();
-        return empty;
     }
 
     @Override
@@ -306,7 +307,7 @@
     // in the domain.
     @Override
     public Integer getMBeanCount() {
-        return getNamespace().getMBeanCount();
+        return getHandlerInterceptorMBean().getMBeanCount();
     }
 
     private boolean checkOn() {
@@ -320,8 +321,8 @@
     @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
+        final String act = (action==null)?"-":action;
+        if("queryMBeans".equals(act) || "queryNames".equals(act)) {
             // 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.
@@ -355,16 +356,8 @@
         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
+        final String act = (action==null)?"-":action;
+        if ("getDomains".equals(act)) { // ES: OK
             perm = new  MBeanPermission(serverName,"-",member,
                     routingName,act);
         } else {
@@ -381,7 +374,7 @@
     String getClassName(ObjectName routingName) {
         if (routingName == null || routingName.isPattern()) return "-";
         try {
-            return getNamespace().getSourceServer().
+            return getHandlerInterceptorMBean().getSourceServer().
                     getObjectInstance(routingName).getClassName();
         } catch (InstanceNotFoundException ex) {
             LOG.finest("Can't get class name for "+routingName+
@@ -444,7 +437,7 @@
          int count=0;
          for (int i=0;i<domains.length;i++) {
              try {
-                 check(Util.newObjectName(domains[i]+":x=x"),"-",
+                 check(ObjectName.valueOf(domains[i]+":x=x"),"-",
                          "-","getDomains");
              } catch (SecurityException x) { // DLS: OK
                  count++;
--- a/jdk/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -63,8 +63,8 @@
 /**
  * This interceptor wraps a JMXNamespace, and performs
  * {@code ObjectName} rewriting. {@code HandlerInterceptor} are
- * usually created and managed by a {@link NamespaceDispatcher} or
- * {@link DomainDispatcher}.
+ * created and managed by a {@link NamespaceDispatchInterceptor} or a
+ * {@link DomainDispatchInterceptor}.
  * <p><b>
  * This API is a Sun internal API and is subject to changes without notice.
  * </b></p>
@@ -90,6 +90,12 @@
         this.handler = handler;
     }
 
+    //
+    // The {@code source} connection is a connection to the MBeanServer
+    // that contains the actual MBeans.
+    // In the case of cascading, that would be a connection to the sub
+    // agent. Practically, this is JMXNamespace.getSourceServer();
+    //
     @Override
     protected MBeanServer source() {
          return handler.getSourceServer();
@@ -105,7 +111,9 @@
          return source();
     }
 
-    T getNamespace() {
+    // The namespace or domain handler - this either a JMXNamespace or a
+    // a JMXDomain
+    T getHandlerInterceptorMBean() {
         return handler;
     }
 
@@ -122,12 +130,16 @@
                     Util.newRuntimeIOException(x));
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public AttributeList getAttributes(ObjectName name, String[] attributes)
         throws InstanceNotFoundException, ReflectionException {
         try {
-            return super.getAttributes(name, attributes);
+            final String[] authorized =
+                    checkAttributes(name,attributes,"getAttribute");
+            final AttributeList attrList =
+                    super.getAttributes(name,authorized);
+            return attrList;
         } catch (IOException ex) {
             throw handleIOException(ex,"getAttributes",name,attributes);
         }
@@ -172,18 +184,19 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void removeNotificationListener(ObjectName name, ObjectName listener)
         throws InstanceNotFoundException, ListenerNotFoundException {
         try {
-            super.removeNotificationListener(name, listener);
+            check(name,null,"removeNotificationListener");
+            super.removeNotificationListener(name,listener);
         } catch (IOException ex) {
             throw handleIOException(ex,"removeNotificationListener",name,listener);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public String getDefaultDomain() {
         try {
@@ -193,17 +206,19 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public String[] getDomains() {
         try {
-            return super.getDomains();
+            check(null,null,"getDomains");
+            final String[] domains = super.getDomains();
+            return checkDomains(domains,"getDomains");
         } catch (IOException ex) {
             throw handleIOException(ex,"getDomains");
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public Integer getMBeanCount() {
         try {
@@ -213,64 +228,74 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void setAttribute(ObjectName name, Attribute attribute)
         throws InstanceNotFoundException, AttributeNotFoundException,
             InvalidAttributeValueException, MBeanException,
             ReflectionException {
         try {
-            super.setAttribute(name, attribute);
+            check(name,
+                  (attribute==null?null:attribute.getName()),
+                  "setAttribute");
+            super.setAttribute(name,attribute);
         } catch (IOException ex) {
             throw handleIOException(ex,"setAttribute",name, attribute);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        if (name == null) name=ObjectName.WILDCARD;
         try {
-            return super.queryNames(name, query);
+            checkPattern(name,null,"queryNames");
+            return super.queryNames(name,query);
         } catch (IOException ex) {
             throw handleIOException(ex,"queryNames",name, query);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        if (name == null) name=ObjectName.WILDCARD;
         try {
-            return super.queryMBeans(name, query);
+            checkPattern(name,null,"queryMBeans");
+            return super.queryMBeans(name,query);
         } catch (IOException ex) {
             throw handleIOException(ex,"queryMBeans",name, query);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public boolean isInstanceOf(ObjectName name, String className)
         throws InstanceNotFoundException {
         try {
+            check(name, null, "isInstanceOf");
             return super.isInstanceOf(name, className);
         } catch (IOException ex) {
             throw handleIOException(ex,"isInstanceOf",name, className);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public ObjectInstance createMBean(String className, ObjectName name)
         throws ReflectionException, InstanceAlreadyExistsException,
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException {
         try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
             return super.createMBean(className, name);
         } catch (IOException ex) {
             throw handleIOException(ex,"createMBean",className, name);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public ObjectInstance createMBean(String className, ObjectName name,
                         ObjectName loaderName)
@@ -278,30 +303,34 @@
                 MBeanRegistrationException, MBeanException,
                 NotCompliantMBeanException, InstanceNotFoundException {
         try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
             return super.createMBean(className, name, loaderName);
         } catch (IOException ex) {
             throw handleIOException(ex,"createMBean",className, name, loaderName);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public Object getAttribute(ObjectName name, String attribute)
         throws MBeanException, AttributeNotFoundException,
             InstanceNotFoundException, ReflectionException {
         try {
+            check(name, attribute, "getAttribute");
             return super.getAttribute(name, attribute);
         } catch (IOException ex) {
             throw handleIOException(ex,"getAttribute",name, attribute);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void removeNotificationListener(ObjectName name, ObjectName listener,
                             NotificationFilter filter, Object handback)
         throws InstanceNotFoundException, ListenerNotFoundException {
         try {
+            check(name,null,"removeNotificationListener");
             super.removeNotificationListener(name, listener, filter, handback);
         } catch (IOException ex) {
             throw handleIOException(ex,"removeNotificationListener",name,
@@ -309,13 +338,14 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void removeNotificationListener(ObjectName name,
                       NotificationListener listener, NotificationFilter filter,
                       Object handback)
         throws InstanceNotFoundException, ListenerNotFoundException {
         try {
+            check(name,null,"removeNotificationListener");
             super.removeNotificationListener(name, listener, filter, handback);
         } catch (IOException ex) {
             throw handleIOException(ex,"removeNotificationListener",name,
@@ -323,12 +353,13 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void removeNotificationListener(ObjectName name,
                 NotificationListener listener)
         throws InstanceNotFoundException, ListenerNotFoundException {
         try {
+            check(name,null,"removeNotificationListener");
             super.removeNotificationListener(name, listener);
         } catch (IOException ex) {
             throw handleIOException(ex,"removeNotificationListener",name,
@@ -336,12 +367,13 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void addNotificationListener(ObjectName name,
                     NotificationListener listener, NotificationFilter filter,
                     Object handback) throws InstanceNotFoundException {
         try {
+            check(name,null,"addNotificationListener");
             super.addNotificationListener(name, listener, filter, handback);
         } catch (IOException ex) {
             throw handleIOException(ex,"addNotificationListener",name,
@@ -349,12 +381,13 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void addNotificationListener(ObjectName name, ObjectName listener,
                 NotificationFilter filter, Object handback)
         throws InstanceNotFoundException {
         try {
+            check(name,null,"addNotificationListener");
             super.addNotificationListener(name, listener, filter, handback);
         } catch (IOException ex) {
             throw handleIOException(ex,"addNotificationListener",name,
@@ -362,7 +395,7 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public boolean isRegistered(ObjectName name) {
         try {
@@ -372,41 +405,44 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public void unregisterMBean(ObjectName name)
         throws InstanceNotFoundException, MBeanRegistrationException {
         try {
+            check(name, null, "unregisterMBean");
             super.unregisterMBean(name);
         } catch (IOException ex) {
             throw handleIOException(ex,"unregisterMBean",name);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public MBeanInfo getMBeanInfo(ObjectName name)
         throws InstanceNotFoundException, IntrospectionException,
             ReflectionException {
         try {
+            check(name, null, "getMBeanInfo");
             return super.getMBeanInfo(name);
         } catch (IOException ex) {
             throw handleIOException(ex,"getMBeanInfo",name);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public ObjectInstance getObjectInstance(ObjectName name)
         throws InstanceNotFoundException {
         try {
+            check(name, null, "getObjectInstance");
             return super.getObjectInstance(name);
         } catch (IOException ex) {
             throw handleIOException(ex,"getObjectInstance",name);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public ObjectInstance createMBean(String className, ObjectName name,
                 Object[] params, String[] signature)
@@ -414,6 +450,8 @@
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException {
         try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
             return super.createMBean(className, name, params, signature);
         } catch (IOException ex) {
             throw handleIOException(ex,"createMBean",className, name,
@@ -421,7 +459,7 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public ObjectInstance createMBean(String className, ObjectName name,
                 ObjectName loaderName, Object[] params, String[] signature)
@@ -429,6 +467,8 @@
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException, InstanceNotFoundException {
         try {
+            checkCreate(name, className, "instantiate");
+            checkCreate(name, className, "registerMBean");
             return super.createMBean(className, name, loaderName, params,
                     signature);
         } catch (IOException ex) {
@@ -437,23 +477,26 @@
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public AttributeList setAttributes(ObjectName name,AttributeList attributes)
     throws InstanceNotFoundException, ReflectionException {
         try {
-            return super.setAttributes(name, attributes);
+            final AttributeList authorized =
+                    checkAttributes(name, attributes, "setAttribute");
+            return super.setAttributes(name, authorized);
         } catch (IOException ex) {
             throw handleIOException(ex,"setAttributes",name, attributes);
         }
     }
 
-    // From MBeanServer: catch & handles IOException
+    // From MBeanServerConnection: catch & handles IOException
     @Override
     public Object invoke(ObjectName name, String operationName, Object[] params,
                 String[] signature)
         throws InstanceNotFoundException, MBeanException, ReflectionException {
         try {
+            check(name, operationName, "invoke");
             return super.invoke(name, operationName, params, signature);
         } catch (IOException ex) {
             throw handleIOException(ex,"invoke",name, operationName,
@@ -574,4 +617,118 @@
                 "Not supported in this namespace: "+namespace));
     }
 
+    /**
+     * A result might be excluded for security reasons.
+     */
+    @Override
+    boolean excludesFromResult(ObjectName targetName, String queryMethod) {
+        return !checkQuery(targetName, queryMethod);
+    }
+
+
+    //----------------------------------------------------------------------
+    // Hooks for checking permissions
+    //----------------------------------------------------------------------
+
+   /**
+     * This method is a hook to implement permission checking in subclasses.
+     * 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.
+     * @throws SecurityException if the caller doesn't have the permission
+     *         to perform the given action on the MBean pointed to
+     *         by routingName.
+     */
+    abstract void check(ObjectName routingName,
+                        String member, String action);
+
+    // called in createMBean and registerMBean
+    abstract void checkCreate(ObjectName routingName, String className,
+                                String action);
+
+    /**
+     * 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}.
+     *
+     * 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.
+     */
+    abstract boolean checkQuery(ObjectName routingName, String action);
+
+    /**
+     * This method is a hook to implement permission checking in subclasses.
+     *
+     * @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}.
+     * @throws SecurityException if the caller doesn't have the permission
+     *         to perform {@code action} on the MBean pointed to by routingName.
+     */
+    abstract String[] checkAttributes(ObjectName routingName,
+            String[] attributes, String action);
+
+    /**
+     * This method is a hook to implement permission checking in subclasses.
+     *
+     * @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}.
+     * @throws SecurityException if the caller doesn't have the permission
+     *         to perform {@code action} on the MBean pointed to by routingName.
+     */
+    abstract AttributeList checkAttributes(ObjectName routingName,
+            AttributeList attributes, String action);
+
+    /**
+     * 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;
+    }
+
+    // A priori check for queryNames/queryMBeans/
+    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.
+        // We only check that we have the permission requested for 'action'.
+        check(null,null,action);
+    }
+
+
+
 }
--- a/jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java	Fri Sep 12 23:31:43 2008 -0700
@@ -29,7 +29,6 @@
 
 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;
@@ -40,6 +39,8 @@
 import javax.management.NotificationFilter;
 import javax.management.NotificationListener;
 import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.namespace.JMXNamespace;
 import javax.management.namespace.JMXNamespaces;
 import javax.management.remote.JMXAddressable;
 import javax.management.remote.JMXConnector;
@@ -66,26 +67,10 @@
         return new WeakHashMap<K,V>();
     }
 
-    /** Creates a new instance of JMXNamespaces */
+    /** There are no instances of this class */
     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())
--- a/jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,22 +25,15 @@
 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;
 
@@ -54,12 +47,6 @@
  */
 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;
@@ -69,21 +56,6 @@
     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(
@@ -104,164 +76,6 @@
                 ", 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
@@ -281,29 +95,9 @@
      * (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;
-        }
+        final MBeanServer c = super.source();
+        if (c != null) return c;
+        // should not come here
         throw new NullPointerException("getMBeanServerConnection");
     }
 
@@ -319,24 +113,6 @@
         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 {
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java	Fri Sep 12 23:31:43 2008 -0700
@@ -45,6 +45,9 @@
  * </b></p>
  * @since 1.7
  */
+// See class hierarchy and detailled explanations in RoutingProxy in this
+// package.
+//
 public class RoutingConnectionProxy
         extends RoutingProxy<MBeanServerConnection> {
 
@@ -93,40 +96,28 @@
                targetNs+"\", "+forwardsContext+")";
     }
 
+    static final RoutingProxyFactory
+            <MBeanServerConnection,RoutingConnectionProxy>
+        FACTORY = new RoutingProxyFactory
+        <MBeanServerConnection,RoutingConnectionProxy>() {
+
+        public RoutingConnectionProxy newInstance(MBeanServerConnection source,
+                String sourcePath, String targetPath,
+                boolean forwardsContext) {
+            return new RoutingConnectionProxy(source,sourcePath,
+                    targetPath,forwardsContext);
+        }
+
+        public RoutingConnectionProxy newInstance(
+                MBeanServerConnection source, String sourcePath) {
+            return new RoutingConnectionProxy(source,sourcePath);
+        }
+    };
+
     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);
+        return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY,
+                source, sourcePath);
     }
 
 }
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java	Fri Sep 12 23:31:43 2008 -0700
@@ -83,18 +83,32 @@
     }
 
     /**
-     * Returns the wrapped source connection.
+     * Returns the wrapped source connection. The {@code source} connection
+     * is a connection to the MBeanServer that contains the actual MBean.
+     * In the case of cascading, that would be a connection to the sub
+     * agent.
      **/
     protected abstract T source() throws IOException;
 
     /**
      * Converts a target ObjectName to a source ObjectName.
+     * The target ObjectName is the name of the MBean in the mount point
+     * target. In the case of cascading, that would be the name of the
+     * MBean in the master agent. So if a subagent S containing an MBean
+     * named "X" is mounted in the target namespace "foo//" of a master agent M,
+     * the source is S, the target is "foo//" in M, the source name is "X", and
+     * the target name is "foo//X".
+     * In the case of cascading - such as in NamespaceInterceptor, this method
+     * will convert "foo//X" (the targetName) into "X", the source name.
      **/
     protected abstract ObjectName toSource(ObjectName targetName)
         throws MalformedObjectNameException;
 
     /**
      * Converts a source ObjectName to a target ObjectName.
+     * (see description of toSource above for explanations)
+     * In the case of cascading - such as in NamespaceInterceptor, this method
+     * will convert "X" (the sourceName) into "foo//X", the target name.
      **/
     protected abstract ObjectName toTarget(ObjectName sourceName)
         throws MalformedObjectNameException;
@@ -142,90 +156,17 @@
         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;
+            return source().getAttributes(sourceName, attributes);
         } 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)
@@ -233,7 +174,6 @@
             IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name, operationName, "invoke");
             final Object result =
                     source().invoke(sourceName,operationName,params,
                                    signature);
@@ -249,7 +189,6 @@
             IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name, null, "unregisterMBean");
             source().unregisterMBean(sourceName);
         } catch (RuntimeException ex) {
             throw makeCompliantRuntimeException(ex);
@@ -262,7 +201,6 @@
             ReflectionException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name, null, "getMBeanInfo");
             return source().getMBeanInfo(sourceName);
         } catch (RuntimeException ex) {
             throw makeCompliantRuntimeException(ex);
@@ -274,7 +212,6 @@
         throws InstanceNotFoundException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name, null, "getObjectInstance");
             return processOutputInstance(
                     source().getObjectInstance(sourceName));
         } catch (RuntimeException ex) {
@@ -301,9 +238,6 @@
             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);
@@ -321,8 +255,6 @@
         // 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,
@@ -341,8 +273,6 @@
             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) {
@@ -360,8 +290,6 @@
         // 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) {
@@ -376,8 +304,6 @@
             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) {
@@ -391,7 +317,6 @@
             InstanceNotFoundException, ReflectionException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name, attribute, "getAttribute");
             return source().getAttribute(sourceName,attribute);
         } catch (RuntimeException ex) {
             throw makeCompliantRuntimeException(ex);
@@ -403,7 +328,6 @@
         throws InstanceNotFoundException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name, null, "isInstanceOf");
             return source().isInstanceOf(sourceName,className);
         } catch (RuntimeException ex) {
             throw makeCompliantRuntimeException(ex);
@@ -415,10 +339,8 @@
         throws InstanceNotFoundException, ReflectionException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            final AttributeList authorized =
-                    checkAttributes(name, attributes, "setAttribute");
             return source().
-                    setAttributes(sourceName,authorized);
+                    setAttributes(sourceName,attributes);
         } catch (RuntimeException ex) {
             throw makeCompliantRuntimeException(ex);
         }
@@ -431,7 +353,7 @@
         for (ObjectInstance i : sources) {
             try {
                 final ObjectInstance target = processOutputInstance(i);
-                if (!checkQuery(target.getObjectName(), "queryMBeans"))
+                if (excludesFromResult(target.getObjectName(), "queryMBeans"))
                     continue;
                 result.add(target);
             } catch (Exception x) {
@@ -446,24 +368,6 @@
         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) {
@@ -488,7 +392,7 @@
         for (ObjectName n : sourceNames) {
             try {
                 final ObjectName targetName = toTarget(n);
-                if (!checkQuery(targetName, "queryNames")) continue;
+                if (excludesFromResult(targetName, "queryNames")) continue;
                 names.add(targetName);
             } catch (Exception x) {
                 if (LOG.isLoggable(Level.FINE)) {
@@ -508,7 +412,6 @@
         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) {
@@ -523,7 +426,6 @@
         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);
@@ -540,7 +442,6 @@
         ListenerNotFoundException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name,null,"removeNotificationListener");
             source().removeNotificationListener(sourceName,listener);
         } catch (RuntimeException ex) {
             throw makeCompliantRuntimeException(ex);
@@ -554,7 +455,6 @@
         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) {
@@ -568,7 +468,6 @@
                 Object handback) throws InstanceNotFoundException, IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name,null,"addNotificationListener");
             source().addNotificationListener(sourceName, listener, filter,
                     handback);
         } catch (RuntimeException ex) {
@@ -585,7 +484,6 @@
                 IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name,null,"removeNotificationListener");
             source().removeNotificationListener(sourceName,listener,filter,
                     handback);
         } catch (RuntimeException ex) {
@@ -600,7 +498,6 @@
             IOException {
         final ObjectName sourceName = toSourceOrRuntime(name);
         try {
-            check(name,null,"removeNotificationListener");
             source().removeNotificationListener(sourceName,listener,
                     filter,handback);
         } catch (RuntimeException ex) {
@@ -616,7 +513,6 @@
         // 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);
@@ -635,30 +531,12 @@
     // from MBeanServerConnection
     public String[] getDomains() throws IOException {
         try {
-            check(null,null,"getDomains");
-            final String[] domains = source().getDomains();
-            return checkDomains(domains,"getDomains");
+            return source().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 {
@@ -668,4 +546,22 @@
         }
     }
 
+    /**
+     * Returns true if the given targetName must be excluded from the
+     * query result.
+     * In this base class, always return {@code false}.
+     * By default all object names returned by the sources are
+     * transmitted to the caller - there is no filtering.
+     *
+     * @param name         A target object name expressed in the caller's
+     *                     context. In the case of cascading, where the source
+     *                     is a sub agent mounted on e.g. namespace "foo",
+     *                     that would be a name prefixed by "foo//"...
+     * @param queryMethod  either "queryNames" or "queryMBeans".
+     * @return true if the name must be excluded.
+     */
+    boolean excludesFromResult(ObjectName targetName, String queryMethod) {
+        return false;
+    }
+
 }
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java	Fri Sep 12 23:31:43 2008 -0700
@@ -30,31 +30,110 @@
 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
+ * A 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>{@link RoutingConnectionProxy}: to narrow down into an
+ *    MBeanServerConnection.</p>
+ * <p>{@link RoutingServerProxy}: to narrow down into an MBeanServer.</p>
+ *
+ * <p>This class can also be used to "broaden" from a namespace.  The same
+ * class is used for both purposes because in both cases all that happens
+ * is that ObjectNames are rewritten in one way on the way in (e.g. the
+ * parameter of getMBeanInfo) and another way on the way out (e.g. the
+ * return value of queryNames).</p>
+ *
+ * <p>Specifically, if you narrow into "a//" then you want to add the
+ * "a//" prefix to ObjectNames on the way in and subtract it on the way
+ * out.  But ClientContext uses this class to subtract the
+ * "jmx.context//foo=bar//" prefix on the way in and add it back on the
+ * way out.</p>
+ *
  * <p><b>
  * This API is a Sun internal API and is subject to changes without notice.
  * </b></p>
  * @since 1.7
  */
+//
+// RoutingProxies are client side objects which are used to narrow down
+// into a namespace. They are used to perform ObjectName translation,
+// adding the namespace to the routing ObjectName before sending it over
+// to the source connection, and removing that prefix from results of
+// queries, createMBean, registerMBean, and getObjectInstance.
+// This translation is the opposite to that which is performed by
+// NamespaceInterceptors.
+//
+// There is however a special case where routing proxies are used on the
+// 'server' side to remove a namespace - rather than to add it:
+// This the case of ClientContext.
+// When an ObjectName like "jmx.context//c1=v1,c2=v2//D:k=v" reaches the
+// jmx.context namespace, a routing proxy is used to remove the prefix
+// c1=v1,c2=v2// from the routing objectname.
+//
+// For a RoutingProxy used in a narrowDownToNamespace operation, we have:
+//     targetNs="" // targetNS is the namespace 'to remove'
+//     sourceNS=<namespace-we-narrow-down-to> // namespace 'to add'
+//
+// For a RoutingProxy used in a ClientContext operation, we have:
+//     targetNs=<encoded-context> // context must be removed from object name
+//     sourceNs="" // nothing to add...
+//
+// RoutingProxies can also be used on the client side to implement
+// "withClientContext" operations. In that case, the boolean parameter
+// 'forwards context' is set to true, targetNs is "", and sourceNS may
+// also be "". When forwardsContext is true, the RoutingProxy dynamically
+// creates an ObjectNameRouter for each operation - in order to dynamically add
+// the context attached to the thread to the routing ObjectName. This is
+// performed in the getObjectNameRouter() method.
+//
+// Finally, in order to avoid too many layers of wrapping,
+// RoutingConnectionProxy and RoutingServerProxy can be created through a
+// factory method that can concatenate namespace pathes in order to
+// return a single RoutingProxy - rather than wrapping a RoutingProxy inside
+// another RoutingProxy. See RoutingConnectionProxy.cd and
+// RoutingServerProxy.cd
+//
+// The class hierarchy is as follows:
+//
+//                           RoutingMBeanServerConnection
+//                   [abstract class for all routing interceptors,
+//                    such as RoutingProxies and HandlerInterceptors]
+//                            /                          \
+//                           /                            \
+//                    RoutingProxy                HandlerInterceptor
+//          [base class for                   [base class for server side
+//           client-side objects used          objects, created by
+//           in narrowDownTo]                  DispatchInterceptors]
+//           /                  \                   |          \
+//  RoutingConnectionProxy       \                  |      NamespaceInterceptor
+//  [wraps MBeanServerConnection  \                 |     [used to remove
+//   objects]                      \                |      namespace prefix and
+//                        RoutingServerProxy        |      wrap  JMXNamespace]
+//                        [wraps MBeanServer        |
+//                         Objects]                 |
+//                                            DomainInterceptor
+//                                            [used to wrap JMXDomain]
+//
+// RoutingProxies also differ from HandlerInterceptors in that they transform
+// calls to MBeanServerConnection operations that do not have any parameters
+// into a call to the underlying JMXNamespace MBean.
+// So for instance a call to:
+//    JMXNamespaces.narrowDownToNamespace(conn,"foo").getDomains()
+// is transformed into
+//    conn.getAttribute("foo//type=JMXNamespace","Domains");
+//
 public abstract class RoutingProxy<T extends MBeanServerConnection>
         extends RoutingMBeanServerConnection<T> {
 
@@ -179,17 +258,11 @@
              throw x;
          } catch (MBeanException ex) {
              throw new IOException("Failed to get "+attributeName+": "+
-                     ex.getMessage(),
-                     ex.getTargetException());
-         } catch (AttributeNotFoundException ex) {
+                     ex.getCause(),
+                     ex.getCause());
+         } catch (Exception 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);
+                     ex,ex);
          }
     }
 
@@ -279,4 +352,62 @@
                     (" mounted on targetNs="+targetNs));
     }
 
+    // Creates an instance of a subclass 'R' of RoutingProxy<T>
+    // RoutingServerProxy and RoutingConnectionProxy have their own factory
+    // instance.
+    static interface RoutingProxyFactory<T extends MBeanServerConnection,
+            R extends RoutingProxy<T>> {
+            R newInstance(T source,
+                    String sourcePath, String targetPath,
+                    boolean forwardsContext);
+            R newInstance(T source,
+                    String sourcePath);
+    }
+
+    // Performs a narrowDownToNamespace operation.
+    // This method will attempt to merge two RoutingProxies in a single
+    // one if they are of the same class.
+    //
+    // This method is never called directly - it should be called only by
+    // subclasses of RoutingProxy.
+    //
+    // As for now it is called by:
+    // RoutingServerProxy.cd and RoutingConnectionProxy.cd.
+    //
+    static <T extends MBeanServerConnection, R extends RoutingProxy<T>>
+           R cd(Class<R> routingProxyClass,
+              RoutingProxyFactory<T,R> factory,
+              T source, String sourcePath) {
+        if (source == null) throw new IllegalArgumentException("null");
+        if (source.getClass().equals(routingProxyClass)) {
+            // cast is OK here, but findbugs complains unless we use class.cast
+            final R other = routingProxyClass.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
+            //    RoutingServerProxy.
+            //
+            if (target == null || target.equals("")) {
+                final String path =
+                    JMXNamespaces.concat(other.getSourceNamespace(),
+                    sourcePath);
+                return factory.newInstance(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 factory.newInstance(source,sourcePath);
+    }
 }
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java	Fri Sep 12 23:31:43 2008 -0700
@@ -69,6 +69,9 @@
  *
  * @since 1.7
  */
+// See class hierarchy and detailled explanations in RoutingProxy in this
+// package.
+//
 public class RoutingServerProxy
         extends RoutingProxy<MBeanServer>
         implements MBeanServer {
@@ -564,39 +567,24 @@
         }
     }
 
+    static final RoutingProxyFactory<MBeanServer,RoutingServerProxy>
+        FACTORY = new RoutingProxyFactory<MBeanServer,RoutingServerProxy>() {
+
+        public RoutingServerProxy newInstance(MBeanServer source,
+                String sourcePath, String targetPath,
+                boolean forwardsContext) {
+            return new RoutingServerProxy(source,sourcePath,
+                    targetPath,forwardsContext);
+        }
+
+        public RoutingServerProxy newInstance(
+                MBeanServer source, String sourcePath) {
+            return new RoutingServerProxy(source,sourcePath);
+        }
+    };
 
     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);
+        return RoutingProxy.cd(RoutingServerProxy.class, FACTORY,
+                source, sourcePath);
     }
 }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java	Fri Sep 12 23:31:43 2008 -0700
@@ -32,13 +32,15 @@
 import com.sun.jmx.remote.util.EnvHelp;
 
 public abstract class ClientCommunicatorAdmin {
+    private static volatile long threadNo = 1;
+
     public ClientCommunicatorAdmin(long period) {
         this.period = period;
 
         if (period > 0) {
             checker = new Checker();
 
-            Thread t = new Thread(checker);
+            Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo);
             t.setDaemon(true);
             t.start();
         } else
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java	Fri Sep 12 23:31:43 2008 -0700
@@ -42,7 +42,7 @@
     /**
      * The value is used for character storage.
      */
-    char value[];
+    char[] value;
 
     /**
      * The count is the number of characters used.
@@ -333,8 +333,7 @@
      *             <code>dst.length</code>
      *             </ul>
      */
-    public void getChars(int srcBegin, int srcEnd, char dst[],
-                                      int dstBegin)
+    public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
     {
         if (srcBegin < 0)
             throw new StringIndexOutOfBoundsException(srcBegin);
@@ -366,14 +365,14 @@
     }
 
     /**
-     * Appends the string representation of the <code>Object</code>
-     * argument.
+     * Appends the string representation of the {@code Object} argument.
      * <p>
-     * The argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then appended to this sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(Object)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   obj   an <code>Object</code>.
+     * @param   obj   an {@code Object}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(Object obj) {
@@ -383,17 +382,17 @@
     /**
      * Appends the specified string to this character sequence.
      * <p>
-     * The characters of the <code>String</code> argument are appended, in
+     * The characters of the {@code String} argument are appended, in
      * order, increasing the length of this sequence by the length of the
-     * argument. If <code>str</code> is <code>null</code>, then the four
-     * characters <code>"null"</code> are appended.
+     * argument. If {@code str} is {@code null}, then the four
+     * characters {@code "null"} are appended.
      * <p>
      * Let <i>n</i> be the length of this character sequence just prior to
-     * execution of the <code>append</code> method. Then the character at
+     * execution of the {@code append} method. Then the character at
      * index <i>k</i> in the new character sequence is equal to the character
      * at index <i>k</i> in the old character sequence, if <i>k</i> is less
      * than <i>n</i>; otherwise, it is equal to the character at index
-     * <i>k-n</i> in the argument <code>str</code>.
+     * <i>k-n</i> in the argument {@code str}.
      *
      * @param   str   a string.
      * @return  a reference to this object.
@@ -435,33 +434,33 @@
     }
 
     /**
-     * Appends a subsequence of the specified <code>CharSequence</code> to this
+     * Appends a subsequence of the specified {@code CharSequence} to this
      * sequence.
      * <p>
-     * Characters of the argument <code>s</code>, starting at
-     * index <code>start</code>, are appended, in order, to the contents of
-     * this sequence up to the (exclusive) index <code>end</code>. The length
-     * of this sequence is increased by the value of <code>end - start</code>.
+     * Characters of the argument {@code s}, starting at
+     * index {@code start}, are appended, in order, to the contents of
+     * this sequence up to the (exclusive) index {@code end}. The length
+     * of this sequence is increased by the value of {@code end - start}.
      * <p>
      * Let <i>n</i> be the length of this character sequence just prior to
-     * execution of the <code>append</code> method. Then the character at
+     * execution of the {@code append} method. Then the character at
      * index <i>k</i> in this character sequence becomes equal to the
      * character at index <i>k</i> in this sequence, if <i>k</i> is less than
      * <i>n</i>; otherwise, it is equal to the character at index
-     * <i>k+start-n</i> in the argument <code>s</code>.
+     * <i>k+start-n</i> in the argument {@code s}.
      * <p>
-     * If <code>s</code> is <code>null</code>, then this method appends
+     * If {@code s} is {@code null}, then this method appends
      * characters as if the s parameter was a sequence containing the four
-     * characters <code>"null"</code>.
+     * characters {@code "null"}.
      *
      * @param   s the sequence to append.
      * @param   start   the starting index of the subsequence to be appended.
      * @param   end     the end index of the subsequence to be appended.
      * @return  a reference to this object.
      * @throws     IndexOutOfBoundsException if
-     *                  <code>start</code> or <code>end</code> are negative, or
-     *             <code>start</code> is greater than <code>end</code> or
-     *             <code>end</code> is greater than <code>s.length()</code>
+     *             {@code start} is negative, or
+     *             {@code start} is greater than {@code end} or
+     *             {@code end} is greater than {@code s.length()}
      */
     public AbstractStringBuilder append(CharSequence s, int start, int end) {
         if (s == null)
@@ -483,22 +482,22 @@
     }
 
     /**
-     * Appends the string representation of the <code>char</code> array
+     * Appends the string representation of the {@code char} array
      * argument to this sequence.
      * <p>
      * The characters of the array argument are appended, in order, to
      * the contents of this sequence. The length of this sequence
      * increases by the length of the argument.
      * <p>
-     * The overall effect is exactly as if the argument were converted to
-     * a string by the method {@link String#valueOf(char[])} and the
-     * characters of that string were then {@link #append(String) appended}
-     * to this character sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(char[])},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
      * @param   str   the characters to be appended.
      * @return  a reference to this object.
      */
-    public AbstractStringBuilder append(char str[]) {
+    public AbstractStringBuilder append(char[] str) {
         int newCount = count + str.length;
         if (newCount > value.length)
             expandCapacity(newCount);
@@ -509,22 +508,25 @@
 
     /**
      * Appends the string representation of a subarray of the
-     * <code>char</code> array argument to this sequence.
+     * {@code char} array argument to this sequence.
      * <p>
-     * Characters of the <code>char</code> array <code>str</code>, starting at
-     * index <code>offset</code>, are appended, in order, to the contents
+     * Characters of the {@code char} array {@code str}, starting at
+     * index {@code offset}, are appended, in order, to the contents
      * of this sequence. The length of this sequence increases
-     * by the value of <code>len</code>.
+     * by the value of {@code len}.
      * <p>
-     * The overall effect is exactly as if the arguments were converted to
-     * a string by the method {@link String#valueOf(char[],int,int)} and the
-     * characters of that string were then {@link #append(String) appended}
-     * to this character sequence.
+     * The overall effect is exactly as if the arguments were converted
+     * to a string by the method {@link String#valueOf(char[],int,int)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
      * @param   str      the characters to be appended.
-     * @param   offset   the index of the first <code>char</code> to append.
-     * @param   len      the number of <code>char</code>s to append.
+     * @param   offset   the index of the first {@code char} to append.
+     * @param   len      the number of {@code char}s to append.
      * @return  a reference to this object.
+     * @throws IndexOutOfBoundsException
+     *         if {@code offset < 0} or {@code len < 0}
+     *         or {@code offset+len > str.length}
      */
     public AbstractStringBuilder append(char str[], int offset, int len) {
         int newCount = count + len;
@@ -536,14 +538,15 @@
     }
 
     /**
-     * Appends the string representation of the <code>boolean</code>
+     * Appends the string representation of the {@code boolean}
      * argument to the sequence.
      * <p>
-     * The argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then appended to this sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(boolean)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   b   a <code>boolean</code>.
+     * @param   b   a {@code boolean}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(boolean b) {
@@ -569,18 +572,18 @@
     }
 
     /**
-     * Appends the string representation of the <code>char</code>
+     * Appends the string representation of the {@code char}
      * argument to this sequence.
      * <p>
      * The argument is appended to the contents of this sequence.
-     * The length of this sequence increases by <code>1</code>.
+     * The length of this sequence increases by {@code 1}.
      * <p>
-     * The overall effect is exactly as if the argument were converted to
-     * a string by the method {@link String#valueOf(char)} and the character
-     * in that string were then {@link #append(String) appended} to this
-     * character sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(char)},
+     * and the character in that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   c   a <code>char</code>.
+     * @param   c   a {@code char}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(char c) {
@@ -592,14 +595,15 @@
     }
 
     /**
-     * Appends the string representation of the <code>int</code>
+     * Appends the string representation of the {@code int}
      * argument to this sequence.
      * <p>
-     * The argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then appended to this sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(int)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   i   an <code>int</code>.
+     * @param   i   an {@code int}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(int i) {
@@ -618,14 +622,15 @@
     }
 
     /**
-     * Appends the string representation of the <code>long</code>
+     * Appends the string representation of the {@code long}
      * argument to this sequence.
      * <p>
-     * The argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then appended to this sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(long)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   l   a <code>long</code>.
+     * @param   l   a {@code long}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(long l) {
@@ -644,14 +649,15 @@
     }
 
     /**
-     * Appends the string representation of the <code>float</code>
+     * Appends the string representation of the {@code float}
      * argument to this sequence.
      * <p>
-     * The argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then appended to this string sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(float)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   f   a <code>float</code>.
+     * @param   f   a {@code float}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(float f) {
@@ -660,14 +666,15 @@
     }
 
     /**
-     * Appends the string representation of the <code>double</code>
+     * Appends the string representation of the {@code double}
      * argument to this sequence.
      * <p>
-     * The argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then appended to this sequence.
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(double)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
      *
-     * @param   d   a <code>double</code>.
+     * @param   d   a {@code double}.
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(double d) {
@@ -677,17 +684,17 @@
 
     /**
      * Removes the characters in a substring of this sequence.
-     * The substring begins at the specified <code>start</code> and extends to
-     * the character at index <code>end - 1</code> or to the end of the
+     * The substring begins at the specified {@code start} and extends to
+     * the character at index {@code end - 1} or to the end of the
      * sequence if no such character exists. If
-     * <code>start</code> is equal to <code>end</code>, no changes are made.
+     * {@code start} is equal to {@code end}, no changes are made.
      *
      * @param      start  The beginning index, inclusive.
      * @param      end    The ending index, exclusive.
      * @return     This object.
-     * @throws     StringIndexOutOfBoundsException  if <code>start</code>
-     *             is negative, greater than <code>length()</code>, or
-     *             greater than <code>end</code>.
+     * @throws     StringIndexOutOfBoundsException  if {@code start}
+     *             is negative, greater than {@code length()}, or
+     *             greater than {@code end}.
      */
     public AbstractStringBuilder delete(int start, int end) {
         if (start < 0)
@@ -705,7 +712,7 @@
     }
 
     /**
-     * Appends the string representation of the <code>codePoint</code>
+     * Appends the string representation of the {@code codePoint}
      * argument to this sequence.
      *
      * <p> The argument is appended to the contents of this sequence.
@@ -713,15 +720,15 @@
      * {@link Character#charCount(int) Character.charCount(codePoint)}.
      *
      * <p> The overall effect is exactly as if the argument were
-     * converted to a <code>char</code> array by the method {@link
-     * Character#toChars(int)} and the character in that array were
-     * then {@link #append(char[]) appended} to this character
+     * converted to a {@code char} array by the method
+     * {@link Character#toChars(int)} and the character in that array
+     * were then {@link #append(char[]) appended} to this character
      * sequence.
      *
      * @param   codePoint   a Unicode code point
      * @return  a reference to this object.
      * @exception IllegalArgumentException if the specified
-     * <code>codePoint</code> isn't a valid Unicode code point
+     * {@code codePoint} isn't a valid Unicode code point
      */
     public AbstractStringBuilder appendCodePoint(int codePoint) {
         if (!Character.isValidCodePoint(codePoint)) {
@@ -879,27 +886,27 @@
     }
 
     /**
-     * Inserts the string representation of a subarray of the <code>str</code>
+     * Inserts the string representation of a subarray of the {@code str}
      * array argument into this sequence. The subarray begins at the
-     * specified <code>offset</code> and extends <code>len</code> <code>char</code>s.
+     * specified {@code offset} and extends {@code len} {@code char}s.
      * The characters of the subarray are inserted into this sequence at
-     * the position indicated by <code>index</code>. The length of this
-     * sequence increases by <code>len</code> <code>char</code>s.
+     * the position indicated by {@code index}. The length of this
+     * sequence increases by {@code len} {@code char}s.
      *
      * @param      index    position at which to insert subarray.
-     * @param      str       A <code>char</code> array.
-     * @param      offset   the index of the first <code>char</code> in subarray to
+     * @param      str       A {@code char} array.
+     * @param      offset   the index of the first {@code char} in subarray to
      *             be inserted.
-     * @param      len      the number of <code>char</code>s in the subarray to
+     * @param      len      the number of {@code char}s in the subarray to
      *             be inserted.
      * @return     This object
-     * @throws     StringIndexOutOfBoundsException  if <code>index</code>
-     *             is negative or greater than <code>length()</code>, or
-     *             <code>offset</code> or <code>len</code> are negative, or
-     *             <code>(offset+len)</code> is greater than
-     *             <code>str.length</code>.
+     * @throws     StringIndexOutOfBoundsException  if {@code index}
+     *             is negative or greater than {@code length()}, or
+     *             {@code offset} or {@code len} are negative, or
+     *             {@code (offset+len)} is greater than
+     *             {@code str.length}.
      */
-    public AbstractStringBuilder insert(int index, char str[], int offset,
+    public AbstractStringBuilder insert(int index, char[] str, int offset,
                                         int len)
     {
         if ((index < 0) || (index > length()))
@@ -918,20 +925,21 @@
     }
 
     /**
-     * Inserts the string representation of the <code>Object</code>
+     * Inserts the string representation of the {@code Object}
      * argument into this character sequence.
      * <p>
-     * The second argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then inserted into this sequence at the indicated
-     * offset.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(Object)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      obj      an <code>Object</code>.
+     * @param      obj      an {@code Object}.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
@@ -942,28 +950,28 @@
     /**
      * Inserts the string into this character sequence.
      * <p>
-     * The characters of the <code>String</code> argument are inserted, in
+     * The characters of the {@code String} argument are inserted, in
      * order, into this sequence at the indicated offset, moving up any
      * characters originally above that position and increasing the length
      * of this sequence by the length of the argument. If
-     * <code>str</code> is <code>null</code>, then the four characters
-     * <code>"null"</code> are inserted into this sequence.
+     * {@code str} is {@code null}, then the four characters
+     * {@code "null"} are inserted into this sequence.
      * <p>
      * The character at index <i>k</i> in the new character sequence is
      * equal to:
      * <ul>
      * <li>the character at index <i>k</i> in the old character sequence, if
-     * <i>k</i> is less than <code>offset</code>
-     * <li>the character at index <i>k</i><code>-offset</code> in the
-     * argument <code>str</code>, if <i>k</i> is not less than
-     * <code>offset</code> but is less than <code>offset+str.length()</code>
-     * <li>the character at index <i>k</i><code>-str.length()</code> in the
+     * <i>k</i> is less than {@code offset}
+     * <li>the character at index <i>k</i>{@code -offset} in the
+     * argument {@code str}, if <i>k</i> is not less than
+     * {@code offset} but is less than {@code offset+str.length()}
+     * <li>the character at index <i>k</i>{@code -str.length()} in the
      * old character sequence, if <i>k</i> is not less than
-     * <code>offset+str.length()</code>
+     * {@code offset+str.length()}
      * </ul><p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
      * @param      str      a string.
@@ -986,27 +994,30 @@
     }
 
     /**
-     * Inserts the string representation of the <code>char</code> array
+     * Inserts the string representation of the {@code char} array
      * argument into this sequence.
      * <p>
      * The characters of the array argument are inserted into the
      * contents of this sequence at the position indicated by
-     * <code>offset</code>. The length of this sequence increases by
+     * {@code offset}. The length of this sequence increases by
      * the length of the argument.
      * <p>
-     * The overall effect is exactly as if the argument were converted to
-     * a string by the method {@link String#valueOf(char[])} and the
-     * characters of that string were then
-     * {@link #insert(int,String) inserted} into this
-     * character sequence at the position indicated by
-     * <code>offset</code>.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(char[])},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
      * @param      str      a character array.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
-    public AbstractStringBuilder insert(int offset, char str[]) {
+    public AbstractStringBuilder insert(int offset, char[] str) {
         if ((offset < 0) || (offset > length()))
             throw new StringIndexOutOfBoundsException(offset);
         int len = str.length;
@@ -1020,18 +1031,20 @@
     }
 
     /**
-     * Inserts the specified <code>CharSequence</code> into this sequence.
+     * Inserts the specified {@code CharSequence} into this sequence.
      * <p>
-     * The characters of the <code>CharSequence</code> argument are inserted,
+     * The characters of the {@code CharSequence} argument are inserted,
      * in order, into this sequence at the indicated offset, moving up
      * any characters originally above that position and increasing the length
      * of this sequence by the length of the argument s.
      * <p>
      * The result of this method is exactly the same as if it were an
-     * invocation of this object's insert(dstOffset, s, 0, s.length()) method.
+     * invocation of this object's
+     * {@link #insert(int,CharSequence,int,int) insert}(dstOffset, s, 0, s.length())
+     * method.
      *
-     * <p>If <code>s</code> is <code>null</code>, then the four characters
-     * <code>"null"</code> are inserted into this sequence.
+     * <p>If {@code s} is {@code null}, then the four characters
+     * {@code "null"} are inserted into this sequence.
      *
      * @param      dstOffset   the offset.
      * @param      s the sequence to be inserted
@@ -1047,51 +1060,51 @@
     }
 
     /**
-     * Inserts a subsequence of the specified <code>CharSequence</code> into
+     * Inserts a subsequence of the specified {@code CharSequence} into
      * this sequence.
      * <p>
-     * The subsequence of the argument <code>s</code> specified by
-     * <code>start</code> and <code>end</code> are inserted,
+     * The subsequence of the argument {@code s} specified by
+     * {@code start} and {@code end} are inserted,
      * in order, into this sequence at the specified destination offset, moving
      * up any characters originally above that position. The length of this
-     * sequence is increased by <code>end - start</code>.
+     * sequence is increased by {@code end - start}.
      * <p>
      * The character at index <i>k</i> in this sequence becomes equal to:
      * <ul>
      * <li>the character at index <i>k</i> in this sequence, if
-     * <i>k</i> is less than <code>dstOffset</code>
-     * <li>the character at index <i>k</i><code>+start-dstOffset</code> in
-     * the argument <code>s</code>, if <i>k</i> is greater than or equal to
-     * <code>dstOffset</code> but is less than <code>dstOffset+end-start</code>
-     * <li>the character at index <i>k</i><code>-(end-start)</code> in this
+     * <i>k</i> is less than {@code dstOffset}
+     * <li>the character at index <i>k</i>{@code +start-dstOffset} in
+     * the argument {@code s}, if <i>k</i> is greater than or equal to
+     * {@code dstOffset} but is less than {@code dstOffset+end-start}
+     * <li>the character at index <i>k</i>{@code -(end-start)} in this
      * sequence, if <i>k</i> is greater than or equal to
-     * <code>dstOffset+end-start</code>
+     * {@code dstOffset+end-start}
      * </ul><p>
-     * The dstOffset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code dstOffset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      * <p>The start argument must be nonnegative, and not greater than
-     * <code>end</code>.
+     * {@code end}.
      * <p>The end argument must be greater than or equal to
-     * <code>start</code>, and less than or equal to the length of s.
+     * {@code start}, and less than or equal to the length of s.
      *
-     * <p>If <code>s</code> is <code>null</code>, then this method inserts
+     * <p>If {@code s} is {@code null}, then this method inserts
      * characters as if the s parameter was a sequence containing the four
-     * characters <code>"null"</code>.
+     * characters {@code "null"}.
      *
      * @param      dstOffset   the offset in this sequence.
      * @param      s       the sequence to be inserted.
      * @param      start   the starting index of the subsequence to be inserted.
      * @param      end     the end index of the subsequence to be inserted.
      * @return     a reference to this object.
-     * @throws     IndexOutOfBoundsException  if <code>dstOffset</code>
-     *             is negative or greater than <code>this.length()</code>, or
-     *              <code>start</code> or <code>end</code> are negative, or
-     *              <code>start</code> is greater than <code>end</code> or
-     *              <code>end</code> is greater than <code>s.length()</code>
+     * @throws     IndexOutOfBoundsException  if {@code dstOffset}
+     *             is negative or greater than {@code this.length()}, or
+     *              {@code start} or {@code end} are negative, or
+     *              {@code start} is greater than {@code end} or
+     *              {@code end} is greater than {@code s.length()}
      */
      public AbstractStringBuilder insert(int dstOffset, CharSequence s,
-                                           int start, int end) {
+                                         int start, int end) {
         if (s == null)
             s = "null";
         if ((dstOffset < 0) || (dstOffset > this.length()))
@@ -1115,20 +1128,21 @@
     }
 
     /**
-     * Inserts the string representation of the <code>boolean</code>
+     * Inserts the string representation of the {@code boolean}
      * argument into this sequence.
      * <p>
-     * The second argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then inserted into this sequence at the indicated
-     * offset.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(boolean)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      b        a <code>boolean</code>.
+     * @param      b        a {@code boolean}.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
@@ -1137,25 +1151,21 @@
     }
 
     /**
-     * Inserts the string representation of the <code>char</code>
+     * Inserts the string representation of the {@code char}
      * argument into this sequence.
      * <p>
-     * The second argument is inserted into the contents of this sequence
-     * at the position indicated by <code>offset</code>. The length
-     * of this sequence increases by one.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(char)},
+     * and the character in that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The overall effect is exactly as if the argument were converted to
-     * a string by the method {@link String#valueOf(char)} and the character
-     * in that string were then {@link #insert(int, String) inserted} into
-     * this character sequence at the position indicated by
-     * <code>offset</code>.
-     * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      c        a <code>char</code>.
+     * @param      c        a {@code char}.
      * @return     a reference to this object.
      * @throws     IndexOutOfBoundsException  if the offset is invalid.
      */
@@ -1170,20 +1180,21 @@
     }
 
     /**
-     * Inserts the string representation of the second <code>int</code>
+     * Inserts the string representation of the second {@code int}
      * argument into this sequence.
      * <p>
-     * The second argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then inserted into this sequence at the indicated
-     * offset.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(int)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      i        an <code>int</code>.
+     * @param      i        an {@code int}.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
@@ -1192,20 +1203,21 @@
     }
 
     /**
-     * Inserts the string representation of the <code>long</code>
+     * Inserts the string representation of the {@code long}
      * argument into this sequence.
      * <p>
-     * The second argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then inserted into this sequence at the position
-     * indicated by <code>offset</code>.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(long)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      l        a <code>long</code>.
+     * @param      l        a {@code long}.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
@@ -1214,20 +1226,21 @@
     }
 
     /**
-     * Inserts the string representation of the <code>float</code>
+     * Inserts the string representation of the {@code float}
      * argument into this sequence.
      * <p>
-     * The second argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then inserted into this sequence at the indicated
-     * offset.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(float)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      f        a <code>float</code>.
+     * @param      f        a {@code float}.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
@@ -1236,20 +1249,21 @@
     }
 
     /**
-     * Inserts the string representation of the <code>double</code>
+     * Inserts the string representation of the {@code double}
      * argument into this sequence.
      * <p>
-     * The second argument is converted to a string as if by the method
-     * <code>String.valueOf</code>, and the characters of that
-     * string are then inserted into this sequence at the indicated
-     * offset.
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(double)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
      * <p>
-     * The offset argument must be greater than or equal to
-     * <code>0</code>, and less than or equal to the length of this
-     * sequence.
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
      *
      * @param      offset   the offset.
-     * @param      d        a <code>double</code>.
+     * @param      d        a {@code double}.
      * @return     a reference to this object.
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
--- a/jdk/src/share/classes/java/lang/StringBuffer.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/lang/StringBuffer.java	Fri Sep 12 23:31:43 2008 -0700
@@ -212,7 +212,7 @@
      * @throws NullPointerException {@inheritDoc}
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
-    public synchronized void getChars(int srcBegin, int srcEnd, char dst[],
+    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                       int dstBegin)
     {
         super.getChars(srcBegin, srcEnd, dst, dstBegin);
@@ -228,10 +228,6 @@
         value[index] = ch;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(java.lang.Object)
-     * @see     #append(java.lang.String)
-     */
     public synchronized StringBuffer append(Object obj) {
         super.append(String.valueOf(obj));
         return this;
@@ -314,20 +310,19 @@
         return this;
     }
 
-    public synchronized StringBuffer append(char str[]) {
+    public synchronized StringBuffer append(char[] str) {
         super.append(str);
         return this;
     }
 
-    public synchronized StringBuffer append(char str[], int offset, int len) {
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public synchronized StringBuffer append(char[] str, int offset, int len) {
         super.append(str, offset, len);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(boolean)
-     * @see     #append(java.lang.String)
-     */
     public synchronized StringBuffer append(boolean b) {
         super.append(b);
         return this;
@@ -338,10 +333,6 @@
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(int)
-     * @see     #append(java.lang.String)
-     */
     public synchronized StringBuffer append(int i) {
         super.append(i);
         return this;
@@ -355,28 +346,16 @@
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(long)
-     * @see     #append(java.lang.String)
-     */
     public synchronized StringBuffer append(long lng) {
         super.append(lng);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(float)
-     * @see     #append(java.lang.String)
-     */
     public synchronized StringBuffer append(float f) {
         super.append(f);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(double)
-     * @see     #append(java.lang.String)
-     */
     public synchronized StringBuffer append(double d) {
         super.append(d);
         return this;
@@ -437,7 +416,7 @@
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      * @since      1.2
      */
-    public synchronized StringBuffer insert(int index, char str[], int offset,
+    public synchronized StringBuffer insert(int index, char[] str, int offset,
                                             int len)
     {
         super.insert(index, str, offset, len);
@@ -446,9 +425,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(java.lang.Object)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public synchronized StringBuffer insert(int offset, Object obj) {
         super.insert(offset, String.valueOf(obj));
@@ -457,7 +433,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        #length()
      */
     public synchronized StringBuffer insert(int offset, String str) {
         super.insert(offset, str);
@@ -467,7 +442,7 @@
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
-    public synchronized StringBuffer insert(int offset, char str[]) {
+    public synchronized StringBuffer insert(int offset, char[] str) {
         super.insert(offset, str);
         return this;
     }
@@ -498,9 +473,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(boolean)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuffer insert(int offset, boolean b) {
         return insert(offset, String.valueOf(b));
@@ -508,7 +480,6 @@
 
     /**
      * @throws IndexOutOfBoundsException {@inheritDoc}
-     * @see        #length()
      */
     public synchronized StringBuffer insert(int offset, char c) {
         super.insert(offset, c);
@@ -517,9 +488,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(int)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuffer insert(int offset, int i) {
         return insert(offset, String.valueOf(i));
@@ -527,9 +495,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(long)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuffer insert(int offset, long l) {
         return insert(offset, String.valueOf(l));
@@ -537,9 +502,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(float)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuffer insert(int offset, float f) {
         return insert(offset, String.valueOf(f));
@@ -547,9 +509,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(double)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuffer insert(int offset, double d) {
         return insert(offset, String.valueOf(d));
--- a/jdk/src/share/classes/java/lang/StringBuilder.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/lang/StringBuilder.java	Fri Sep 12 23:31:43 2008 -0700
@@ -124,10 +124,6 @@
         append(seq);
     }
 
-    /**
-     * @see     java.lang.String#valueOf(java.lang.Object)
-     * @see     #append(java.lang.String)
-     */
     public StringBuilder append(Object obj) {
         return append(String.valueOf(obj));
     }
@@ -175,7 +171,6 @@
     }
 
     /**
-     * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public StringBuilder append(CharSequence s) {
         if (s == null)
@@ -197,20 +192,19 @@
         return this;
     }
 
-    public StringBuilder append(char str[]) {
+    public StringBuilder append(char[] str) {
         super.append(str);
         return this;
     }
 
-    public StringBuilder append(char str[], int offset, int len) {
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public StringBuilder append(char[] str, int offset, int len) {
         super.append(str, offset, len);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(boolean)
-     * @see     #append(java.lang.String)
-     */
     public StringBuilder append(boolean b) {
         super.append(b);
         return this;
@@ -221,37 +215,21 @@
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(int)
-     * @see     #append(java.lang.String)
-     */
     public StringBuilder append(int i) {
         super.append(i);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(long)
-     * @see     #append(java.lang.String)
-     */
     public StringBuilder append(long lng) {
         super.append(lng);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(float)
-     * @see     #append(java.lang.String)
-     */
     public StringBuilder append(float f) {
         super.append(f);
         return this;
     }
 
-    /**
-     * @see     java.lang.String#valueOf(double)
-     * @see     #append(java.lang.String)
-     */
     public StringBuilder append(double d) {
         super.append(d);
         return this;
@@ -292,7 +270,7 @@
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
-    public StringBuilder insert(int index, char str[], int offset,
+    public StringBuilder insert(int index, char[] str, int offset,
                                 int len)
     {
         super.insert(index, str, offset, len);
@@ -301,9 +279,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(java.lang.Object)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuilder insert(int offset, Object obj) {
         return insert(offset, String.valueOf(obj));
@@ -311,7 +286,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        #length()
      */
     public StringBuilder insert(int offset, String str) {
         super.insert(offset, str);
@@ -321,7 +295,7 @@
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
-    public StringBuilder insert(int offset, char str[]) {
+    public StringBuilder insert(int offset, char[] str) {
         super.insert(offset, str);
         return this;
     }
@@ -349,9 +323,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(boolean)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuilder insert(int offset, boolean b) {
         super.insert(offset, b);
@@ -360,7 +331,6 @@
 
     /**
      * @throws IndexOutOfBoundsException {@inheritDoc}
-     * @see        #length()
      */
     public StringBuilder insert(int offset, char c) {
         super.insert(offset, c);
@@ -369,9 +339,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(int)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuilder insert(int offset, int i) {
         return insert(offset, String.valueOf(i));
@@ -379,9 +346,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(long)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuilder insert(int offset, long l) {
         return insert(offset, String.valueOf(l));
@@ -389,9 +353,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(float)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuilder insert(int offset, float f) {
         return insert(offset, String.valueOf(f));
@@ -399,9 +360,6 @@
 
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
-     * @see        java.lang.String#valueOf(double)
-     * @see        #insert(int, java.lang.String)
-     * @see        #length()
      */
     public StringBuilder insert(int offset, double d) {
         return insert(offset, String.valueOf(d));
--- a/jdk/src/share/classes/java/lang/management/PlatformComponent.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/lang/management/PlatformComponent.java	Fri Sep 12 23:31:43 2008 -0700
@@ -388,7 +388,7 @@
             // if there are more than 1 key properties (i.e. other than "type")
             domainAndType += ",*";
         }
-        ObjectName on = com.sun.jmx.mbeanserver.Util.newObjectName(domainAndType);
+        ObjectName on = ObjectName.valueOf(domainAndType);
         Set<ObjectName> set =  mbs.queryNames(on, null);
         for (PlatformComponent pc : subComponents) {
             set.addAll(pc.getObjectNames(mbs));
--- a/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java	Fri Sep 12 23:31:43 2008 -0700
@@ -186,7 +186,7 @@
 
     // --- Methods to support CharSequence ---
 
-    public CharSequence subSequence(int start, int end) {
+    public CharBuffer subSequence(int start, int end) {
         int pos = position();
         int lim = limit();
         assert (pos <= lim);
--- a/jdk/src/share/classes/java/nio/Direct-X-Buffer.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/nio/Direct-X-Buffer.java	Fri Sep 12 23:31:43 2008 -0700
@@ -402,7 +402,7 @@
 
     // --- Methods to support CharSequence ---
 
-    public CharSequence subSequence(int start, int end) {
+    public CharBuffer subSequence(int start, int end) {
         int pos = position();
         int lim = limit();
         assert (pos <= lim);
--- a/jdk/src/share/classes/java/nio/Heap-X-Buffer.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/nio/Heap-X-Buffer.java	Fri Sep 12 23:31:43 2008 -0700
@@ -566,7 +566,7 @@
 
     // --- Methods to support CharSequence ---
 
-    public CharSequence subSequence(int start, int end) {
+    public CharBuffer subSequence(int start, int end) {
         if ((start < 0)
             || (end > length())
             || (start > end))
--- a/jdk/src/share/classes/java/nio/StringCharBuffer.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/nio/StringCharBuffer.java	Fri Sep 12 23:31:43 2008 -0700
@@ -99,7 +99,7 @@
         return str.toString().substring(start + offset, end + offset);
     }
 
-    public final CharSequence subSequence(int start, int end) {
+    public final CharBuffer subSequence(int start, int end) {
         try {
             int pos = position();
             return new StringCharBuffer(str, -1,
--- a/jdk/src/share/classes/java/nio/X-Buffer.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/nio/X-Buffer.java	Fri Sep 12 23:31:43 2008 -0700
@@ -1239,13 +1239,13 @@
      *         smaller than <tt>start</tt> and no larger than
      *         <tt>remaining()</tt>
      *
-     * @return  The new character sequence
+     * @return  The new character buffer
      *
      * @throws  IndexOutOfBoundsException
      *          If the preconditions on <tt>start</tt> and <tt>end</tt>
      *          do not hold
      */
-    public abstract CharSequence subSequence(int start, int end);
+    public abstract CharBuffer subSequence(int start, int end);
 
 
     // --- Methods to support Appendable ---
--- a/jdk/src/share/classes/java/util/logging/Logging.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/util/logging/Logging.java	Fri Sep 12 23:31:43 2008 -0700
@@ -118,6 +118,6 @@
     }
 
     public ObjectName getObjectName() {
-        return com.sun.jmx.mbeanserver.Util.newObjectName(LogManager.LOGGING_MXBEAN_NAME);
+        return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME);
     }
 }
--- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java	Fri Sep 12 23:31:43 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-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
@@ -317,9 +317,6 @@
         if (current != null) {
             closeEntry();
         }
-        if (xentries.size() < 1) {
-            throw new ZipException("ZIP file must have at least one entry");
-        }
         // write central directory
         long off = written;
         for (XEntry xentry : xentries)
--- a/jdk/src/share/classes/javax/management/InstanceNotFoundException.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/InstanceNotFoundException.java	Fri Sep 12 23:31:43 2008 -0700
@@ -61,6 +61,6 @@
      * @since 1.7
      */
     public InstanceNotFoundException(ObjectName name) {
-        this(name.toString());
+        this(String.valueOf(name));
     }
 }
--- a/jdk/src/share/classes/javax/management/MBeanServerDelegate.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanServerDelegate.java	Fri Sep 12 23:31:43 2008 -0700
@@ -304,7 +304,7 @@
      * @since 1.6
      */
     public static final ObjectName DELEGATE_NAME =
-            Util.newObjectName("JMImplementation:type=MBeanServerDelegate");
+            ObjectName.valueOf("JMImplementation:type=MBeanServerDelegate");
 
     /* Return a timestamp that is monotonically increasing even if
        System.currentTimeMillis() isn't (for example, if you call this
--- a/jdk/src/share/classes/javax/management/ObjectName.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/ObjectName.java	Fri Sep 12 23:31:43 2008 -0700
@@ -413,7 +413,7 @@
     }
 
     private void copyToOtherDomain(String domain, ObjectName aname)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
 
         // The domain cannot be null
         if (domain == null)
@@ -467,7 +467,7 @@
      * is null.
      */
     private void construct(String name)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
 
         // The name cannot be null
         if (name == null)
@@ -729,7 +729,7 @@
      * @exception NullPointerException One of the parameters is null.
      */
     private void construct(String domain, Map<String,String> props)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
 
         // The domain cannot be null
         if (domain == null)
@@ -1071,7 +1071,7 @@
      * Check if the supplied key is a valid key.
      */
     private static void checkKey(String key)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
 
         if (key == null) throw new
             NullPointerException("Invalid key (null)");
@@ -1359,9 +1359,10 @@
      * @exception NullPointerException The <code>name</code> parameter
      * is null.
      *
+     * @see #valueOf(String)
      */
     public static ObjectName getInstance(String name)
-            throws MalformedObjectNameException, NullPointerException {
+            throws MalformedObjectNameException {
         return new ObjectName(name);
     }
 
@@ -1386,10 +1387,11 @@
      * follow the rules for quoting.
      * @exception NullPointerException One of the parameters is null.
      *
+     * @see #valueOf(String, String, String)
      */
     public static ObjectName getInstance(String domain, String key,
                                          String value)
-            throws MalformedObjectNameException, NullPointerException {
+            throws MalformedObjectNameException {
         return new ObjectName(domain, key, value);
     }
 
@@ -1417,10 +1419,11 @@
      * quoting.
      * @exception NullPointerException One of the parameters is null.
      *
+     * @see #valueOf(String, Hashtable)
      */
     public static ObjectName getInstance(String domain,
                                          Hashtable<String,String> table)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
         return new ObjectName(domain, table);
     }
 
@@ -1453,11 +1456,120 @@
      * @exception NullPointerException The <code>name</code> is null.
      *
      */
-    public static ObjectName getInstance(ObjectName name)
-            throws NullPointerException {
+    public static ObjectName getInstance(ObjectName name) {
         if (name.getClass().equals(ObjectName.class))
             return name;
-        return Util.newObjectName(name.getSerializedNameString());
+        return valueOf(name.getSerializedNameString());
+    }
+
+    /**
+     * <p>Return an instance of ObjectName that can be used anywhere
+     * an object obtained with {@link #ObjectName(String) new
+     * ObjectName(name)} can be used.  The returned object may be of
+     * a subclass of ObjectName.  Calling this method twice with the
+     * same parameters may return the same object or two equal but
+     * not identical objects.</p>
+     *
+     * <p>This method is equivalent to {@link #getInstance(String)} except that
+     * it does not throw any checked exceptions.</p>
+     *
+     * @param name  A string representation of the object name.
+     *
+     * @return an ObjectName corresponding to the given String.
+     *
+     * @exception IllegalArgumentException The string passed as a
+     * parameter does not have the right format.  The {@linkplain
+     * Throwable#getCause() cause} of this exception will be a
+     * {@link MalformedObjectNameException}.
+     * @exception NullPointerException The <code>name</code> parameter
+     * is null.
+     *
+     * @since 1.7
+     */
+    public static ObjectName valueOf(String name) {
+        try {
+            return getInstance(name);
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+            // Just plain IllegalArgumentException(e) produces an exception
+            // message "javax.management.MalformedObjectNameException: ..."
+            // which is distracting.
+        }
+    }
+
+    /**
+     * <p>Return an instance of ObjectName that can be used anywhere
+     * an object obtained with {@link #ObjectName(String, String,
+     * String) new ObjectName(domain, key, value)} can be used.  The
+     * returned object may be of a subclass of ObjectName.  Calling
+     * this method twice with the same parameters may return the same
+     * object or two equal but not identical objects.</p>
+     *
+     * <p>This method is equivalent to {@link #getInstance(String, String,
+     * String)} except that it does not throw any checked exceptions.</p>
+     *
+     * @param domain  The domain part of the object name.
+     * @param key  The attribute in the key property of the object name.
+     * @param value The value in the key property of the object name.
+     *
+     * @return an ObjectName corresponding to the given domain,
+     * key, and value.
+     *
+     * @exception IllegalArgumentException The
+     * <code>domain</code>, <code>key</code>, or <code>value</code>
+     * contains an illegal character, or <code>value</code> does not
+     * follow the rules for quoting.  The {@linkplain
+     * Throwable#getCause() cause} of this exception will be a
+     * {@link MalformedObjectNameException}.
+     * @exception NullPointerException One of the parameters is null.
+     *
+     * @since 1.7
+     */
+    public static ObjectName valueOf(String domain, String key, String value) {
+        try {
+            return getInstance(domain, key, value);
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * <p>Return an instance of ObjectName that can be used anywhere
+     * an object obtained with {@link #ObjectName(String, Hashtable)
+     * new ObjectName(domain, table)} can be used.  The returned
+     * object may be of a subclass of ObjectName.  Calling this method
+     * twice with the same parameters may return the same object or
+     * two equal but not identical objects.</p>
+     *
+     * <p>This method is equivalent to {@link #getInstance(String, Hashtable)}
+     * except that it does not throw any checked exceptions.</p>
+     *
+     * @param domain  The domain part of the object name.
+     * @param table A hash table containing one or more key
+     * properties.  The key of each entry in the table is the key of a
+     * key property in the object name.  The associated value in the
+     * table is the associated value in the object name.
+     *
+     * @return an ObjectName corresponding to the given domain and
+     * key mappings.
+     *
+     * @exception IllegalArgumentException The <code>domain</code>
+     * contains an illegal character, or one of the keys or values in
+     * <code>table</code> contains an illegal character, or one of the
+     * values in <code>table</code> does not follow the rules for
+     * quoting.  The {@linkplain Throwable#getCause() cause} of this exception
+     * will be a {@link MalformedObjectNameException}.
+     * @exception NullPointerException One of the parameters is null.
+     *
+     * @since 1.7
+     */
+    public static ObjectName valueOf(String domain,
+                                     Hashtable<String,String> table) {
+        try {
+            return new ObjectName(domain, table);
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
     }
 
     /**
@@ -1477,7 +1589,7 @@
      * @since 1.7
      **/
     public final ObjectName withDomain(String newDomain)
-            throws NullPointerException, MalformedObjectNameException {
+            throws MalformedObjectNameException {
         return new ObjectName(newDomain, this);
     }
 
@@ -1490,9 +1602,11 @@
      * parameter does not have the right format.
      * @exception NullPointerException The <code>name</code> parameter
      * is null.
+     *
+     * @see #valueOf(String)
      */
     public ObjectName(String name)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
         construct(name);
     }
 
@@ -1508,9 +1622,11 @@
      * contains an illegal character, or <code>value</code> does not
      * follow the rules for quoting.
      * @exception NullPointerException One of the parameters is null.
+     *
+     * @see #valueOf(String, String, String)
      */
     public ObjectName(String domain, String key, String value)
-        throws MalformedObjectNameException, NullPointerException {
+        throws MalformedObjectNameException {
         // If key or value are null a NullPointerException
         // will be thrown by the put method in Hashtable.
         //
@@ -1533,9 +1649,11 @@
      * values in <code>table</code> does not follow the rules for
      * quoting.
      * @exception NullPointerException One of the parameters is null.
+     *
+     * @see #valueOf(String, Hashtable)
      */
     public ObjectName(String domain, Hashtable<String,String> table)
-            throws MalformedObjectNameException, NullPointerException {
+            throws MalformedObjectNameException {
         construct(domain, table);
         /* The exception for when a key or value in the table is not a
            String is now ClassCastException rather than
@@ -1629,8 +1747,7 @@
      *
      * @since 1.6
      */
-    public boolean isPropertyValuePattern(String property)
-        throws NullPointerException, IllegalArgumentException {
+    public boolean isPropertyValuePattern(String property) {
         if (property == null)
             throw new NullPointerException("key property can't be null");
         for (int i = 0; i < _ca_array.length; i++) {
@@ -1691,7 +1808,7 @@
      *
      * @exception NullPointerException If <code>property</code> is null.
      */
-    public String getKeyProperty(String property) throws NullPointerException {
+    public String getKeyProperty(String property) {
         return _getKeyPropertyList().get(property);
     }
 
@@ -1950,8 +2067,7 @@
      * @exception NullPointerException if <code>s</code> is null.
      *
      */
-    public static String quote(String s)
-            throws NullPointerException {
+    public static String quote(String s) {
         final StringBuilder buf = new StringBuilder("\"");
         final int len = s.length();
         for (int i = 0; i < len; i++) {
@@ -1995,8 +2111,7 @@
      * @exception NullPointerException if <code>q</code> is null.
      *
      */
-    public static String unquote(String q)
-            throws IllegalArgumentException, NullPointerException {
+    public static String unquote(String q) {
         final StringBuilder buf = new StringBuilder();
         final int len = q.length();
         if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"')
@@ -2041,7 +2156,7 @@
      *
      * @since 1.6
      */
-    public static final ObjectName WILDCARD = Util.newObjectName("*:*");
+    public static final ObjectName WILDCARD = valueOf("*:*");
 
     // Category : Utilities <===================================
 
@@ -2064,7 +2179,7 @@
      * @exception NullPointerException if <code>name</code> is null.
      *
      */
-    public boolean apply(ObjectName name) throws NullPointerException {
+    public boolean apply(ObjectName name) {
 
         if (name == null) throw new NullPointerException();
 
--- a/jdk/src/share/classes/javax/management/QueryNotificationFilter.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/QueryNotificationFilter.java	Fri Sep 12 23:31:43 2008 -0700
@@ -170,7 +170,7 @@
     private static final long serialVersionUID = -8408613922660635231L;
 
     private static final ObjectName DEFAULT_NAME =
-            Util.newObjectName(":type=Notification");
+            ObjectName.valueOf(":type=Notification");
     private static final QueryExp trueQuery;
     static {
         ValueExp zero = Query.value(0);
--- a/jdk/src/share/classes/javax/management/event/EventClient.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/EventClient.java	Fri Sep 12 23:31:43 2008 -0700
@@ -264,11 +264,12 @@
                 new PerThreadGroupPool.Create<ScheduledThreadPoolExecutor>() {
             public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) {
                 ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
-                        "EventClient lease renewer %d");
+                        "JMX EventClient lease renewer %d");
                 ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(
                         20, daemonThreadFactory);
-                exec.setKeepAliveTime(3, TimeUnit.SECONDS);
+                exec.setKeepAliveTime(1, TimeUnit.SECONDS);
                 exec.allowCoreThreadTimeOut(true);
+                exec.setRemoveOnCancelPolicy(true);
                 return exec;
             }
         };
--- a/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java	Fri Sep 12 23:31:43 2008 -0700
@@ -96,7 +96,7 @@
      * <code>{@value #OBJECT_NAME_STRING}</code>.
      */
     public final static ObjectName OBJECT_NAME =
-            Util.newObjectName(OBJECT_NAME_STRING);
+            ObjectName.valueOf(OBJECT_NAME_STRING);
 
     /**
      * A unique listener identifier specified for an EventClient.
--- a/jdk/src/share/classes/javax/management/event/EventSubscriber.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/EventSubscriber.java	Fri Sep 12 23:31:43 2008 -0700
@@ -149,10 +149,10 @@
         if (listener == null)
             throw new IllegalArgumentException("Null listener");
 
-        final ListenerInfo li = new ListenerInfo(listener, filter, handback);
-        List<ListenerInfo> list;
+        final MyListenerInfo li = new MyListenerInfo(listener, filter, handback);
+        List<MyListenerInfo> list;
 
-        Map<ObjectName, List<ListenerInfo>> map;
+        Map<ObjectName, List<MyListenerInfo>> map;
         Set<ObjectName> names;
         if (name.isPattern()) {
             map = patternSubscriptionMap;
@@ -165,7 +165,7 @@
         synchronized (map) {
             list = map.get(name);
             if (list == null) {
-                list = new ArrayList<ListenerInfo>();
+                list = new ArrayList<MyListenerInfo>();
                 map.put(name, list);
             }
             list.add(li);
@@ -186,7 +186,6 @@
     public void unsubscribe(ObjectName name,
             NotificationListener listener)
             throws ListenerNotFoundException, IOException {
-
         if (logger.traceOn())
             logger.trace("unsubscribe", "" + name);
 
@@ -196,7 +195,7 @@
         if (listener == null)
             throw new ListenerNotFoundException();
 
-        Map<ObjectName, List<ListenerInfo>> map;
+        Map<ObjectName, List<MyListenerInfo>> map;
         Set<ObjectName> names;
 
         if (name.isPattern()) {
@@ -207,22 +206,39 @@
             names = Collections.singleton(name);
         }
 
-        final ListenerInfo li = new ListenerInfo(listener, null, null);
-        List<ListenerInfo> list;
+        List<MyListenerInfo> toRemove = new ArrayList<MyListenerInfo>();
         synchronized (map) {
-            list = map.get(name);
-            if (list == null || !list.remove(li))
+            List<MyListenerInfo> list = map.get(name);
+            if (list == null) {
                 throw new ListenerNotFoundException();
+            }
+
+            for (MyListenerInfo info : list) {
+                if (info.listener == listener) {
+                    toRemove.add(info);
+                }
+            }
+
+            if (toRemove.isEmpty()) {
+                throw new ListenerNotFoundException();
+            }
+
+            for (MyListenerInfo info : toRemove) {
+                list.remove(info);
+            }
 
             if (list.isEmpty())
                 map.remove(name);
         }
 
         for (ObjectName mbeanName : names) {
-            try {
-                mbeanServer.removeNotificationListener(mbeanName, li.listener);
-            } catch (Exception e) {
-                logger.fine("unsubscribe", "removeNotificationListener", e);
+            for (MyListenerInfo i : toRemove) {
+                try {
+                    mbeanServer.removeNotificationListener(mbeanName,
+                        i.listener, i.filter, i.handback);
+                } catch (Exception e) {
+                    logger.fine("unsubscribe", "removeNotificationListener", e);
+                }
             }
         }
     }
@@ -256,12 +272,12 @@
                 return;
             }
 
-            final List<ListenerInfo> listeners = new ArrayList<ListenerInfo>();
+            final List<MyListenerInfo> listeners = new ArrayList<MyListenerInfo>();
 
             // If there are subscribers for the exact name that has just arrived
             // then add their listeners to the list.
             synchronized (exactSubscriptionMap) {
-                List<ListenerInfo> exactListeners = exactSubscriptionMap.get(name);
+                List<MyListenerInfo> exactListeners = exactSubscriptionMap.get(name);
                 if (exactListeners != null)
                     listeners.addAll(exactListeners);
             }
@@ -277,7 +293,7 @@
             }
 
             // Add all the listeners just found to the new MBean.
-            for (ListenerInfo li : listeners) {
+            for (MyListenerInfo li : listeners) {
                 try {
                     mbeanServer.addNotificationListener(
                             name,
@@ -292,12 +308,12 @@
         }
     };
 
-    private static class ListenerInfo {
+    private static class MyListenerInfo {
         public final NotificationListener listener;
         public final NotificationFilter filter;
         public final Object handback;
 
-        public ListenerInfo(NotificationListener listener,
+        public MyListenerInfo(NotificationListener listener,
                 NotificationFilter filter,
                 Object handback) {
 
@@ -308,26 +324,6 @@
             this.filter = filter;
             this.handback = handback;
         }
-
-        /* Two ListenerInfo instances are equal if they have the same
-         * NotificationListener.  This means that we can use List.remove
-         * to implement the two-argument removeNotificationListener.
-         */
-        @Override
-        public boolean equals(Object o) {
-            if (o == this)
-                return true;
-
-            if (!(o instanceof ListenerInfo))
-                return false;
-
-            return listener.equals(((ListenerInfo)o).listener);
-        }
-
-        @Override
-        public int hashCode() {
-            return listener.hashCode();
-        }
     }
 
     // ---------------------------------
@@ -338,10 +334,10 @@
     // ---------------------------------
     private final MBeanServer mbeanServer;
 
-    private final Map<ObjectName, List<ListenerInfo>> exactSubscriptionMap =
-            new HashMap<ObjectName, List<ListenerInfo>>();
-    private final Map<ObjectName, List<ListenerInfo>> patternSubscriptionMap =
-            new HashMap<ObjectName, List<ListenerInfo>>();
+    private final Map<ObjectName, List<MyListenerInfo>> exactSubscriptionMap =
+            new HashMap<ObjectName, List<MyListenerInfo>>();
+    private final Map<ObjectName, List<MyListenerInfo>> patternSubscriptionMap =
+            new HashMap<ObjectName, List<MyListenerInfo>>();
 
 
 
--- a/jdk/src/share/classes/javax/management/event/FetchingEventRelay.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/FetchingEventRelay.java	Fri Sep 12 23:31:43 2008 -0700
@@ -31,10 +31,8 @@
 import java.io.IOException;
 import java.io.NotSerializableException;
 import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import javax.management.MBeanException;
@@ -215,50 +213,47 @@
         this.maxNotifs = maxNotifs;
 
         if (executor == null) {
-            executor = Executors.newSingleThreadScheduledExecutor(
+            ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1,
                     daemonThreadFactory);
-        }
+            stpe.setKeepAliveTime(1, TimeUnit.SECONDS);
+            stpe.allowCoreThreadTimeOut(true);
+            executor = stpe;
+            this.defaultExecutor = stpe;
+        } else
+            this.defaultExecutor = null;
         this.executor = executor;
-        if (executor instanceof ScheduledExecutorService)
-            leaseScheduler = (ScheduledExecutorService) executor;
-        else {
-            leaseScheduler = Executors.newSingleThreadScheduledExecutor(
-                    daemonThreadFactory);
-        }
 
         startSequenceNumber = 0;
         fetchingJob = new MyJob();
     }
 
-    public void setEventReceiver(EventReceiver eventReceiver) {
+    public synchronized void setEventReceiver(EventReceiver eventReceiver) {
         if (logger.traceOn()) {
             logger.trace("setEventReceiver", ""+eventReceiver);
         }
 
         EventReceiver old = this.eventReceiver;
-        synchronized(fetchingJob) {
-            this.eventReceiver = eventReceiver;
-            if (old == null && eventReceiver != null)
-                fetchingJob.resume();
-        }
+        this.eventReceiver = eventReceiver;
+        if (old == null && eventReceiver != null)
+            fetchingJob.resume();
     }
 
     public String getClientId() {
         return clientId;
     }
 
-    public void stop() {
+    public synchronized void stop() {
         if (logger.traceOn()) {
             logger.trace("stop", "");
         }
-        synchronized(fetchingJob) {
-            if (stopped) {
-                return;
-            }
+        if (stopped) {
+            return;
+        }
 
-            stopped = true;
-            clientId = null;
-        }
+        stopped = true;
+        clientId = null;
+        if (defaultExecutor != null)
+            defaultExecutor.shutdown();
     }
 
     private class MyJob extends RepeatedSingletonJob {
@@ -372,10 +367,9 @@
     private final EventClientDelegateMBean delegate;
     private String clientId;
     private boolean stopped = false;
-    private volatile ScheduledFuture<?> leaseRenewalFuture;
 
     private final Executor executor;
-    private final ScheduledExecutorService leaseScheduler;
+    private final ExecutorService defaultExecutor;
     private final MyJob fetchingJob;
 
     private final long timeout;
@@ -385,5 +379,5 @@
             new ClassLogger("javax.management.event",
             "FetchingEventRelay");
     private static final ThreadFactory daemonThreadFactory =
-                    new DaemonThreadFactory("FetchingEventRelay-executor");
+                    new DaemonThreadFactory("JMX FetchingEventRelay executor %d");
 }
--- a/jdk/src/share/classes/javax/management/event/RMIPushEventForwarder.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/RMIPushEventForwarder.java	Fri Sep 12 23:31:43 2008 -0700
@@ -185,7 +185,7 @@
 
     private static final ExecutorService executor =
             Executors.newCachedThreadPool(
-            new DaemonThreadFactory("RMIEventForwarder Executor"));
+            new DaemonThreadFactory("JMX RMIEventForwarder Executor"));
     private final SendingJob sendingJob = new SendingJob();
 
     private final BlockingQueue<TargetedNotification> buffer;
--- a/jdk/src/share/classes/javax/management/namespace/JMXDomain.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/namespace/JMXDomain.java	Fri Sep 12 23:31:43 2008 -0700
@@ -308,17 +308,17 @@
      * It is however only available for subclasses in this package.
      **/
     @Override
-    ObjectName validateHandlerName(ObjectName supliedName) {
-        if (supliedName == null)
+    ObjectName validateHandlerName(ObjectName suppliedName) {
+        if (suppliedName == null)
             throw new IllegalArgumentException("Must supply a valid name");
         final String dirName = JMXNamespaces.
-                normalizeNamespaceName(supliedName.getDomain());
+                normalizeNamespaceName(suppliedName.getDomain());
         final ObjectName handlerName = getDomainObjectName(dirName);
-        if (!supliedName.equals(handlerName))
+        if (!suppliedName.equals(handlerName))
             throw new IllegalArgumentException("invalid name space name: "+
-                        supliedName);
+                        suppliedName);
 
-        return supliedName;
+        return suppliedName;
     }
 
     /**
--- a/jdk/src/share/classes/javax/management/namespace/JMXNamespace.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespace.java	Fri Sep 12 23:31:43 2008 -0700
@@ -482,8 +482,8 @@
     /**
      * This method is part of the {@link MBeanRegistration} interface.
      * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
-     * interface in order to get a handle to the MBean server in which it is
-     * registered. It also check the validity of its own ObjectName.
+     * interface in order to get a reference to the MBean server in which it is
+     * registered. It also checks the validity of its own ObjectName.
      * <p>
      * This method is called by the MBean server.
      * Application classes should never call this method directly.
@@ -502,11 +502,14 @@
      */
     public ObjectName preRegister(MBeanServer server, ObjectName name)
         throws Exception {
-        if (objectName != null && ! objectName.equals(name))
-            throw new IllegalStateException(
+        // need to synchronize to protect against multiple registration.
+        synchronized(this) {
+            if (objectName != null && ! objectName.equals(name))
+                throw new IllegalStateException(
                     "Already registered under another name: " + objectName);
-        objectName = validateHandlerName(name);
-        mbeanServer = server;
+            objectName = validateHandlerName(name);
+            mbeanServer = server;
+        }
         return name;
     }
 
@@ -517,23 +520,23 @@
      * reuse JMXNamespace in order to implement sessions...
      * It is however only available for subclasses in this package.
      **/
-    ObjectName validateHandlerName(ObjectName supliedName) {
-        if (supliedName == null)
+    ObjectName validateHandlerName(ObjectName suppliedName) {
+        if (suppliedName == null)
             throw new IllegalArgumentException("Must supply a valid name");
         final String dirName = JMXNamespaces.
-                normalizeNamespaceName(supliedName.getDomain());
+                normalizeNamespaceName(suppliedName.getDomain());
         final ObjectName handlerName =
                 JMXNamespaces.getNamespaceObjectName(dirName);
-        if (!supliedName.equals(handlerName))
+        if (!suppliedName.equals(handlerName))
             throw new IllegalArgumentException("invalid name space name: "+
-                        supliedName);
-        return supliedName;
+                        suppliedName);
+        return suppliedName;
     }
 
     /**
      * This method is part of the {@link MBeanRegistration} interface.
      * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
-     * interface in order to get a handle to the MBean server in which it is
+     * interface in order to get a reference to the MBean server in which it is
      * registered.
      * <p>
      * This method is called by the MBean server. Application classes should
@@ -549,7 +552,7 @@
     /**
      * This method is part of the {@link MBeanRegistration} interface.
      * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
-     * interface in order to get a handle to the MBean server in which it is
+     * interface in order to get a reference to the MBean server in which it is
      * registered.
      * <p>
      * This method is called by the MBean server. Application classes should
@@ -573,8 +576,11 @@
      * @see MBeanRegistration#postDeregister MBeanRegistration
      */
     public void postDeregister() {
-        mbeanServer = null;
-        objectName  = null;
+        // need to synchronize to protect against multiple registration.
+        synchronized(this) {
+            mbeanServer = null;
+            objectName  = null;
+        }
     }
 
 
--- a/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java	Fri Sep 12 23:31:43 2008 -0700
@@ -266,11 +266,15 @@
                 ObjectNameRouter.normalizeNamespacePath(namespace,false,
                             true,false);
         try {
+            // We could use Util.newObjectName here - but throwing an
+            // IllegalArgumentException that contains just the supplied
+            // namespace instead of the whole ObjectName seems preferable.
             return ObjectName.getInstance(sourcePath+
                     NAMESPACE_SEPARATOR+":"+
                     JMXNamespace.TYPE_ASSIGNMENT);
         } catch (MalformedObjectNameException x) {
-            throw new IllegalArgumentException(namespace,x);
+            throw new IllegalArgumentException("Invalid namespace: " +
+                                               namespace,x);
         }
     }
 
--- a/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java	Fri Sep 12 23:31:43 2008 -0700
@@ -28,13 +28,12 @@
 import com.sun.jmx.defaults.JmxProperties;
 import com.sun.jmx.mbeanserver.Util;
 import com.sun.jmx.namespace.JMXNamespaceUtils;
-import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe;
 import com.sun.jmx.remote.util.EnvHelp;
 
 import java.io.IOException;
-import java.security.AccessControlException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -43,9 +42,7 @@
 import javax.management.InstanceNotFoundException;
 import javax.management.ListenerNotFoundException;
 import javax.management.MBeanNotificationInfo;
-import javax.management.MBeanPermission;
 import javax.management.MBeanServerConnection;
-import javax.management.MalformedObjectNameException;
 import javax.management.Notification;
 import javax.management.NotificationBroadcasterSupport;
 import javax.management.NotificationEmitter;
@@ -117,18 +114,13 @@
      */
     private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
 
-    private static final Logger PROBE_LOG = Logger.getLogger(
-            JmxProperties.NAMESPACE_LOGGER_NAME+".probe");
-
 
     // This connection listener is used to listen for connection events from
     // the underlying JMXConnector. It is used in particular to maintain the
     // "connected" state in this MBean.
     //
-    private static class ConnectionListener implements NotificationListener {
-        private final JMXRemoteNamespace handler;
-        private ConnectionListener(JMXRemoteNamespace handler) {
-            this.handler = handler;
+    private class ConnectionListener implements NotificationListener {
+        private ConnectionListener() {
         }
         public void handleNotification(Notification notification,
                 Object handback) {
@@ -136,7 +128,11 @@
                 return;
             final JMXConnectionNotification cn =
                     (JMXConnectionNotification)notification;
-            handler.checkState(this,cn,(JMXConnector)handback);
+            final String type = cn.getType();
+            if (JMXConnectionNotification.CLOSED.equals(type)
+                    || JMXConnectionNotification.FAILED.equals(type)) {
+                checkState(this,cn,(JMXConnector)handback);
+            }
         }
     }
 
@@ -150,8 +146,7 @@
     // because the one that is actually used is the one supplied by the
     // override of getMBeanServerConnection().
     private static class JMXRemoteNamespaceDelegate
-            extends MBeanServerConnectionWrapper
-            implements DynamicProbe {
+            extends MBeanServerConnectionWrapper {
         private volatile JMXRemoteNamespace parent=null;
 
         JMXRemoteNamespaceDelegate() {
@@ -177,9 +172,6 @@
 
         }
 
-        public boolean isProbeRequested() {
-            return this.parent.isProbeRequested();
-        }
     }
 
     private static final MBeanNotificationInfo connectNotification =
@@ -188,7 +180,7 @@
             "Connected",
             "Emitted when the Connected state of this object changes");
 
-    private static long seqNumber=0;
+    private static AtomicLong seqNumber = new AtomicLong(0);
 
     private final NotificationBroadcasterSupport broadcaster;
     private final ConnectionListener listener;
@@ -198,7 +190,6 @@
     private volatile MBeanServerConnection server = null;
     private volatile JMXConnector conn = null;
     private volatile ClassLoader defaultClassLoader = null;
-    private volatile boolean probed;
 
     /**
      * Creates a new instance of {@code JMXRemoteNamespace}.
@@ -237,10 +228,7 @@
         this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap);
 
         // handles (dis)connection events
-        this.listener = new ConnectionListener(this);
-
-        // XXX TODO: remove the probe, or simplify it.
-        this.probed = false;
+        this.listener = new ConnectionListener();
     }
 
    /**
@@ -271,10 +259,6 @@
         return optionsMap;
     }
 
-    boolean isProbeRequested() {
-        return probed==false;
-    }
-
     public void addNotificationListener(NotificationListener listener,
             NotificationFilter filter, Object handback) {
         broadcaster.addNotificationListener(listener, filter, handback);
@@ -313,8 +297,8 @@
         broadcaster.removeNotificationListener(listener, filter, handback);
     }
 
-    private static synchronized long getNextSeqNumber() {
-        return seqNumber++;
+    private static long getNextSeqNumber() {
+        return seqNumber.getAndIncrement();
     }
 
 
@@ -362,14 +346,18 @@
         // lock while evaluating the true value of the connected state,
         // while anyone might also call close() or connect() from a
         // different thread.
-        //
         // The method switchConnection() (called from here too) also has the
-        // same kind of complex logic.
+        // same kind of complex logic:
         //
         // We use the JMXConnector has a handback to the notification listener
         // (emittingConnector) in order to be able to determine whether the
         // notification concerns the current connector in use, or an older
-        // one.
+        // one. The 'emittingConnector' is the connector from which the
+        // notification originated. This could be an 'old' connector - as
+        // closed() and connect() could already have been called before the
+        // notification arrived. So what we do is to compare the
+        // 'emittingConnector' with the current connector, to see if the
+        // notification actually comes from the curent connector.
         //
         boolean remove = false;
 
@@ -486,14 +474,12 @@
         }
     }
 
-    private void closeall(JMXConnector... a) {
-        for (JMXConnector c : a) {
-            try {
-                if (c != null) c.close();
-            } catch (Exception x) {
-                // OK: we're gonna throw the original exception later.
-                LOG.finest("Ignoring exception when closing connector: "+x);
-            }
+    private void close(JMXConnector c) {
+        try {
+            if (c != null) c.close();
+        } catch (Exception x) {
+            // OK: we're gonna throw the original exception later.
+            LOG.finest("Ignoring exception when closing connector: "+x);
         }
     }
 
@@ -598,26 +584,7 @@
     }
 
     public void connect() throws IOException {
-        if (conn != null) {
-            try {
-               // This is much too fragile. It must go away!
-               PROBE_LOG.finest("Probing again...");
-               triggerProbe(getMBeanServerConnection());
-            } catch(Exception x) {
-                close();
-                Throwable cause = x;
-                // if the cause is a security exception - rethrows it...
-                while (cause != null) {
-                    if (cause instanceof SecurityException)
-                        throw (SecurityException) cause;
-                    cause = cause.getCause();
-                }
-                throw new IOException("connection failed: cycle?",x);
-            }
-        }
         LOG.fine("connecting...");
-        // TODO remove these traces
-        // System.err.println(getInitParameter()+" connecting");
         final Map<String,Object> env =
                 new HashMap<String,Object>(getEnvMap());
         try {
@@ -640,86 +607,16 @@
             msc = aconn.getMBeanServerConnection();
             aconn.addConnectionNotificationListener(listener,null,aconn);
         } catch (IOException io) {
-            closeall(aconn);
+            close(aconn);
             throw io;
         } catch (RuntimeException x) {
-            closeall(aconn);
+            close(aconn);
             throw x;
         }
 
-
-        // XXX Revisit here
-        // Note from the author: This business of switching connection is
-        // incredibly complex. Isn't there any means to simplify it?
-        //
         switchConnection(conn,aconn,msc);
-        try {
-           triggerProbe(msc);
-        } catch(Exception x) {
-            close();
-            Throwable cause = x;
-            // if the cause is a security exception - rethrows it...
-            while (cause != null) {
-                if (cause instanceof SecurityException)
-                    throw (SecurityException) cause;
-                cause = cause.getCause();
-            }
-            throw new IOException("connection failed: cycle?",x);
-        }
-        LOG.fine("connected.");
-    }
 
-    // If this is a self-linking namespace, this method should trigger
-    // the emission of a probe in the wrapping NamespaceInterceptor.
-    // The first call to source() in the wrapping NamespaceInterceptor
-    // causes the emission of the probe.
-    //
-    // Note: the MBeanServer returned by getSourceServer
-    //       (our private JMXRemoteNamespaceDelegate inner class)
-    //       implements a sun private interface (DynamicProbe) which is
-    //       used by the NamespaceInterceptor to determine whether it should
-    //       send a probe or not.
-    //       We needed this interface here because the NamespaceInterceptor
-    //       has otherwise no means to knows that this object has just
-    //       connected, and that a new probe should be sent.
-    //
-    // 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 JMXNamespace (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 queryNames() it knows that it has been looping back on
-    // itslef and throws an Exception - which will be raised through this
-    // method, thus preventing the connection to be established...
-    //
-    // More info in the com.sun.jmx.namespace.NamespaceInterceptor class
-    //
-    // 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 void triggerProbe(final MBeanServerConnection msc)
-            throws MalformedObjectNameException, IOException {
-        // Query Pattern that we will send through the source server in order
-        // to detect self-linking namespaces.
-        //
-        //
-        final ObjectName pattern;
-        pattern = ObjectName.getInstance("*" +
-                JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
-                JMXNamespace.TYPE_ASSIGNMENT);
-        probed = false;
-        try {
-            msc.queryNames(pattern, null);
-            probed = true;
-        } catch (AccessControlException x) {
-            // if we have an MBeanPermission missing then do nothing...
-            if (!(x.getPermission() instanceof MBeanPermission))
-                throw x;
-            PROBE_LOG.finer("Can't check for cycles: " + x);
-            probed = false; // no need to do it again...
-        }
+        LOG.fine("connected.");
     }
 
     public void close() throws IOException {
--- a/jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java	Fri Sep 12 23:31:43 2008 -0700
@@ -28,7 +28,6 @@
 import com.sun.jmx.mbeanserver.Util;
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import java.security.AccessController;
 import java.util.Set;
 
 import javax.management.Attribute;
--- a/jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java	Fri Sep 12 23:31:43 2008 -0700
@@ -193,14 +193,6 @@
  * }
  *
  * <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;
  *
@@ -219,7 +211,7 @@
  *             throws InstanceNotFoundException {
  *
  *         // Check that the name is a legal one for a Property MBean
- *         ObjectName namePattern = newObjectName(
+ *         ObjectName namePattern = ObjectName.valueOf(
  *                     "com.example:type=Property,name=\"*\"");
  *         if (!namePattern.apply(name))
  *             throw new InstanceNotFoundException(name);
@@ -239,7 +231,7 @@
  *         {@code Set<ObjectName> names = new TreeSet<ObjectName>();}
  *         Properties props = System.getProperties();
  *         for (String propName : props.stringPropertyNames()) {
- *             ObjectName objectName = newObjectName(
+ *             ObjectName objectName = ObjectName.valueOf(
  *                     "com.example:type=Property,name=" +
  *                     ObjectName.quote(propName));
  *             names.add(objectName);
@@ -278,7 +270,7 @@
  *     }
  *
  *     public void propertyChanged(String name, String newValue) {
- *         ObjectName objectName = newObjectName(
+ *         ObjectName objectName = ObjectName.valueOf(
  *                 "com.example:type=Property,name=" + ObjectName.quote(name));
  *         Notification n = new Notification(
  *                 "com.example.property.changed", objectName, 0L,
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Fri Sep 12 23:31:43 2008 -0700
@@ -420,7 +420,7 @@
                 new PerThreadGroupPool.Create<ThreadPoolExecutor>() {
             public ThreadPoolExecutor createThreadPool(ThreadGroup group) {
                 ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
-                        "RMIConnector listener dispatch %d");
+                        "JMX RMIConnector listener dispatch %d");
                 ThreadPoolExecutor exec = new ThreadPoolExecutor(
                         1, 10, 1, TimeUnit.SECONDS,
                         new LinkedBlockingDeque<Runnable>(),
--- a/jdk/src/share/classes/sun/management/ClassLoadingImpl.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/ClassLoadingImpl.java	Fri Sep 12 23:31:43 2008 -0700
@@ -71,6 +71,6 @@
     native static void setVerboseClass(boolean value);
 
     public ObjectName getObjectName() {
-        return Util.newObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME);
+        return ObjectName.valueOf(ManagementFactory.CLASS_LOADING_MXBEAN_NAME);
     }
 }
--- a/jdk/src/share/classes/sun/management/CompilationImpl.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/CompilationImpl.java	Fri Sep 12 23:31:43 2008 -0700
@@ -70,7 +70,7 @@
     }
 
     public ObjectName getObjectName() {
-        return Util.newObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME);
+        return ObjectName.valueOf(ManagementFactory.COMPILATION_MXBEAN_NAME);
     }
 
 
--- a/jdk/src/share/classes/sun/management/HotSpotDiagnostic.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/HotSpotDiagnostic.java	Fri Sep 12 23:31:43 2008 -0700
@@ -117,6 +117,6 @@
     }
 
     public ObjectName getObjectName() {
-        return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic");
+        return ObjectName.valueOf("com.sun.management:type=HotSpotDiagnostic");
     }
 }
--- a/jdk/src/share/classes/sun/management/HotspotInternal.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/HotspotInternal.java	Fri Sep 12 23:31:43 2008 -0700
@@ -41,7 +41,7 @@
 
     private final static String HOTSPOT_INTERNAL_MBEAN_NAME =
         "sun.management:type=HotspotInternal";
-    private static ObjectName objName = Util.newObjectName(HOTSPOT_INTERNAL_MBEAN_NAME);
+    private static ObjectName objName = ObjectName.valueOf(HOTSPOT_INTERNAL_MBEAN_NAME);
     private MBeanServer server = null;
 
     /**
--- a/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java	Fri Sep 12 23:31:43 2008 -0700
@@ -220,7 +220,7 @@
      */
     private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) {
         try {
-            final ObjectName objName = Util.newObjectName(mbeanName);
+            final ObjectName objName = ObjectName.valueOf(mbeanName);
 
             // inner class requires these fields to be final
             final MBeanServer mbs0 = mbs;
@@ -280,7 +280,7 @@
 
     private static void unregisterMBean(MBeanServer mbs, String mbeanName) {
         try {
-            final ObjectName objName = Util.newObjectName(mbeanName);
+            final ObjectName objName = ObjectName.valueOf(mbeanName);
 
             // inner class requires these fields to be final
             final MBeanServer mbs0 = mbs;
--- a/jdk/src/share/classes/sun/management/MemoryImpl.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/MemoryImpl.java	Fri Sep 12 23:31:43 2008 -0700
@@ -177,7 +177,7 @@
     }
 
     public ObjectName getObjectName() {
-        return Util.newObjectName(ManagementFactory.MEMORY_MXBEAN_NAME);
+        return ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME);
     }
 
 }
--- a/jdk/src/share/classes/sun/management/OperatingSystemImpl.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/OperatingSystemImpl.java	Fri Sep 12 23:31:43 2008 -0700
@@ -74,7 +74,7 @@
         }
     }
     public ObjectName getObjectName() {
-        return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+        return ObjectName.valueOf(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
     }
 
 }
--- a/jdk/src/share/classes/sun/management/RuntimeImpl.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/RuntimeImpl.java	Fri Sep 12 23:31:43 2008 -0700
@@ -149,7 +149,7 @@
     }
 
     public ObjectName getObjectName() {
-        return Util.newObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);
+        return ObjectName.valueOf(ManagementFactory.RUNTIME_MXBEAN_NAME);
     }
 
 }
--- a/jdk/src/share/classes/sun/management/ThreadImpl.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/ThreadImpl.java	Fri Sep 12 23:31:43 2008 -0700
@@ -415,7 +415,7 @@
     private static native void resetContentionTimes0(long tid);
 
     public ObjectName getObjectName() {
-        return Util.newObjectName(ManagementFactory.THREAD_MXBEAN_NAME);
+        return ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME);
     }
 
 }
--- a/jdk/src/share/classes/sun/management/Util.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/classes/sun/management/Util.java	Fri Sep 12 23:31:43 2008 -0700
@@ -43,12 +43,8 @@
         return (String[]) list.toArray(EMPTY_STRING_ARRAY);
     }
 
-    static ObjectName newObjectName(String name) {
-        return com.sun.jmx.mbeanserver.Util.newObjectName(name);
-    }
-
     public static ObjectName newObjectName(String domainAndType, String name) {
-        return newObjectName(domainAndType + ",name=" + name);
+        return ObjectName.valueOf(domainAndType + ",name=" + name);
     }
 
     private static ManagementPermission monitorPermission =
--- a/jdk/src/share/native/java/util/zip/zip_util.c	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/src/share/native/java/util/zip/zip_util.c	Fri Sep 12 23:31:43 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1995-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
@@ -722,16 +722,22 @@
     }
 
     len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END);
-    if (len == -1) {
-        if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
-            *pmsg = errbuf;
+    if (len <= 0) {
+        if (len == 0) { /* zip file is empty */
+            if (pmsg) {
+                *pmsg = "zip file is empty";
+            }
+        } else { /* error */
+            if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
+                *pmsg = errbuf;
+        }
         ZFILE_Close(zfd);
         freeZip(zip);
         return NULL;
     }
 
     zip->zfd = zfd;
-    if (readCEN(zip, -1) <= 0) {
+    if (readCEN(zip, -1) < 0) {
         /* An error occurred while trying to read the zip file */
         if (pmsg != 0) {
             /* Set the zip error message */
@@ -947,10 +953,15 @@
 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
 {
     unsigned int hsh = hash(name);
-    jint idx = zip->table[hsh % zip->tablelen];
-    jzentry *ze;
+    jint idx;
+    jzentry *ze = 0;
 
     ZIP_Lock(zip);
+    if (zip->total == 0) {
+        goto Finally;
+    }
+
+    idx = zip->table[hsh % zip->tablelen];
 
     /*
      * This while loop is an optimization where a double lookup
@@ -1025,6 +1036,7 @@
         ulen = 0;
     }
 
+Finally:
     ZIP_Unlock(zip);
     return ze;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/zip/TestEmptyZip.java	Fri Sep 12 23:31:43 2008 -0700
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 6334003 6440786
+ * @summary Test ability to write and read zip files that have no entries.
+ * @author Dave Bristor
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+public class TestEmptyZip {
+    public static void realMain(String[] args) throws Throwable {
+        String zipName = "foo.zip";
+        File f = new File(System.getProperty("test.scratch", "."), zipName);
+        if (f.exists() && !f.delete()) {
+            throw new Exception("failed to delete " + zipName);
+        }
+
+        // Verify 0-length file cannot be read
+        f.createNewFile();
+        ZipFile zf = null;
+        try {
+            zf = new ZipFile(f);
+            fail();
+        } catch (Exception ex) {
+            check(ex.getMessage().contains("zip file is empty"));
+        } finally {
+            if (zf != null) {
+                zf.close();
+            }
+        }
+
+        ZipInputStream zis = null;
+        try {
+            zis = new ZipInputStream(new FileInputStream(f));
+            ZipEntry ze = zis.getNextEntry();
+            check(ze == null);
+        } catch (Exception ex) {
+            unexpected(ex);
+        } finally {
+            if (zis != null) {
+                zis.close();
+            }
+        }
+
+        f.delete();
+
+        // Verify 0-entries file can be written
+        write(f);
+
+        // Verify 0-entries file can be read
+        readFile(f);
+        readStream(f);
+
+        f.delete();
+    }
+
+    static void write(File f) throws Exception {
+        ZipOutputStream zos = null;
+        try {
+            zos = new ZipOutputStream(new FileOutputStream(f));
+            zos.finish();
+            zos.close();
+            pass();
+        } catch (Exception ex) {
+            unexpected(ex);
+        } finally {
+            if (zos != null) {
+                zos.close();
+            }
+        }
+    }
+
+    static void readFile(File f) throws Exception {
+        ZipFile zf = null;
+        try {
+            zf = new ZipFile(f);
+
+            Enumeration e = zf.entries();
+            while (e.hasMoreElements()) {
+                ZipEntry entry = (ZipEntry) e.nextElement();
+                fail();
+            }
+            zf.close();
+            pass();
+        } catch (Exception ex) {
+            unexpected(ex);
+        } finally {
+            if (zf != null) {
+                zf.close();
+            }
+        }
+    }
+
+    static void readStream(File f) throws Exception {
+        ZipInputStream zis = null;
+        try {
+            zis = new ZipInputStream(new FileInputStream(f));
+            ZipEntry ze = zis.getNextEntry();
+            check(ze == null);
+            byte[] buf = new byte[1024];
+            check(zis.read(buf, 0, 1024) == -1);
+        } finally {
+            if (zis != null) {
+                zis.close();
+            }
+        }
+    }
+
+    //--------------------- Infrastructure ---------------------------
+    static volatile int passed = 0, failed = 0;
+    static boolean pass() {passed++; return true;}
+    static boolean fail() {failed++; Thread.dumpStack(); return false;}
+    static boolean fail(String msg) {System.out.println(msg); return fail();}
+    static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+    static boolean equal(Object x, Object y) {
+        if (x == null ? y == null : x.equals(y)) return pass();
+        else return fail(x + " not equal to " + y);}
+    public static void main(String[] args) throws Throwable {
+        try {realMain(args);} catch (Throwable t) {unexpected(t);}
+        System.out.println("\nPassed = " + passed + " failed = " + failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6669137
+ * @summary Test the constructors of InstanceNotFoundExceptionTest.
+ * @author Daniel Fuchs
+ * @compile InstanceNotFoundExceptionTest.java
+ * @run main InstanceNotFoundExceptionTest
+ */
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+public class InstanceNotFoundExceptionTest {
+    public static void main(String[] args) throws Exception {
+        final InstanceNotFoundException x =
+                new InstanceNotFoundException();
+        System.out.println("InstanceNotFoundException(): "+x.getMessage());
+
+        final String msg = "who is toto?";
+        final InstanceNotFoundException x2 =
+                new InstanceNotFoundException(msg);
+        if (!msg.equals(x2.getMessage()))
+            throw new Exception("Bad message: expected "+msg+
+                    ", got "+x2.getMessage());
+        System.out.println("InstanceNotFoundException(" +
+                msg+"): "+x2.getMessage());
+
+        final InstanceNotFoundException x3 =
+                new InstanceNotFoundException((String)null);
+        if (x3.getMessage() != null)
+            throw new Exception("Bad message: expected "+null+
+                    ", got "+x3.getMessage());
+        System.out.println("InstanceNotFoundException((String)null): "+
+                x3.getMessage());
+
+        final ObjectName n = new ObjectName("who is toto?:type=msg");
+        final InstanceNotFoundException x4 =
+                new InstanceNotFoundException(n);
+        if (!String.valueOf(n).equals(x4.getMessage()))
+            throw new Exception("Bad message: expected "+n+
+                    ", got "+x4.getMessage());
+        System.out.println("InstanceNotFoundException(" +
+                n+"): "+x4.getMessage());
+
+        final InstanceNotFoundException x5 =
+                new InstanceNotFoundException((ObjectName)null);
+        if (!String.valueOf((ObjectName)null).equals(x5.getMessage()))
+            throw new Exception("Bad message: expected " +
+                    String.valueOf((ObjectName)null)+" got "+x5.getMessage());
+        System.out.println("InstanceNotFoundException((ObjectName)null): "+
+                x5.getMessage());
+    }
+}
--- a/jdk/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test
  * @summary Test named MBeanServers.
  * @author Daniel Fuchs
+ * @bug 6299231
  * @run clean NamedMBeanServerTest
  * @run build NamedMBeanServerTest
  * @run main NamedMBeanServerTest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/ObjectName/ValueOfTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6734813
+ * @summary Test the ObjectName.valueOf methods
+ * @author Eamonn McManus
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Hashtable;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+public class ValueOfTest {
+    public static void main(String[] args) throws Exception {
+        // Calls that should work
+        testPositive("d:foo=bar,baz=buh");
+        testPositive("foo", "bar", "baz");
+        Hashtable<String, String> h = new Hashtable<String, String>();
+        h.put("foo", "bar");
+        h.put("baz", "buh");
+        testPositive("domain", h);
+
+        // Calls that should not work
+        testNegative("d");
+        testNegative("d:");
+        testNegative("d::foo=bar");
+        testNegative("d:", "foo", "bar");
+        testNegative("d", "foo=", "bar");
+        testNegative("d:", h);
+        testNegative("d", new Hashtable<String, String>());
+    }
+
+    private static void testPositive(Object... args) throws Exception {
+        Method valueOf = valueOfMethod(args);
+        Method getInstance = getInstanceMethod(args);
+        Constructor<?> constructor = constructor(args);
+
+        Object valueOfValue = valueOf.invoke(null, args);
+        Object getInstanceValue = getInstance.invoke(null, args);
+        Object constructorValue = constructor.newInstance(args);
+
+        String argString =
+                Arrays.toString(args).replace('[', '(').replace(']', ')');
+
+        if (!valueOfValue.equals(getInstanceValue)) {
+            throw new Exception(
+                    "valueOf" + argString + " differs from getInstance" +
+                    argString);
+        }
+
+        if (!valueOfValue.equals(constructorValue)) {
+            throw new Exception(
+                    "valueOf" + argString + " differs from new ObjectName " +
+                    argString);
+        }
+
+        System.out.println("OK: valueOf" + argString);
+    }
+
+    private static void testNegative(Object... args) throws Exception {
+        Method valueOf = valueOfMethod(args);
+        Method getInstance = getInstanceMethod(args);
+
+        String argString =
+                Arrays.toString(args).replace('[', '(').replace(']', ')');
+
+        final Throwable valueOfException;
+        try {
+            valueOf.invoke(null, args);
+            throw new Exception("valueOf" + argString + " did not fail but should");
+        } catch (InvocationTargetException e) {
+            valueOfException = e.getCause();
+        }
+        if (!(valueOfException instanceof IllegalArgumentException)) {
+            throw new Exception(
+                    "valueOf" + argString + " threw " +
+                    valueOfException.getClass().getName() + " instead of " +
+                    "IllegalArgumentException", valueOfException);
+        }
+
+        final Throwable valueOfCause = valueOfException.getCause();
+        if (!(valueOfCause instanceof MalformedObjectNameException)) {
+            throw new Exception(
+                    "valueOf" + argString + " threw exception with wrong " +
+                    "type of cause", valueOfCause);
+        }
+
+        if (!valueOfException.getMessage().equals(valueOfCause.getMessage())) {
+            // The IllegalArgumentException should have the same message as
+            // the MalformedObjectNameException it wraps.
+            // This isn't specified but is desirable.
+            throw new Exception(
+                    "valueOf" + argString + ": message in wrapping " +
+                    "IllegalArgumentException (" + valueOfException.getMessage() +
+                    ") differs from message in wrapped " +
+                    "MalformedObjectNameException (" + valueOfCause.getMessage() +
+                    ")");
+        }
+
+        final Throwable getInstanceException;
+        try {
+            getInstance.invoke(null, args);
+            throw new Exception("getInstance" + argString + " did not fail but should");
+        } catch (InvocationTargetException e) {
+            getInstanceException = e.getCause();
+        }
+        if (!(getInstanceException instanceof MalformedObjectNameException)) {
+            throw new Exception(
+                    "getInstance" + argString + " threw wrong exception",
+                    getInstanceException);
+        }
+
+        if (!valueOfException.getMessage().equals(getInstanceException.getMessage())) {
+            // Again this is not specified.
+            throw new Exception(
+                    "Exception message from valueOf" + argString + " (" +
+                    valueOfException.getMessage() + ") differs from message " +
+                    "from getInstance" + argString + " (" +
+                    getInstanceException.getMessage() + ")");
+        }
+
+        System.out.println("OK (correct exception): valueOf" + argString);
+    }
+
+    private static Method valueOfMethod(Object[] args) throws Exception {
+        return method("valueOf", args);
+    }
+
+    private static Method getInstanceMethod(Object[] args) throws Exception {
+        return method("getInstance", args);
+    }
+
+    private static Method method(String name, Object[] args) throws Exception {
+        Class<?>[] argTypes = argTypes(args);
+        return ObjectName.class.getMethod(name, argTypes);
+    }
+
+    private static Constructor<?> constructor(Object[] args) throws Exception {
+        Class<?>[] argTypes = argTypes(args);
+        return ObjectName.class.getConstructor(argTypes);
+    }
+
+    private static Class<?>[] argTypes(Object[] args) {
+        Class<?>[] argTypes = new Class<?>[args.length];
+        for (int i = 0; i < args.length; i++)
+            argTypes[i] = args[i].getClass();
+        return argTypes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/EventClientThreadTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6747411
+ * @summary Check that EventClient instances don't leak threads.
+ * @author Eamonn McManus
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class EventClientThreadTest {
+    private static final int MAX_TIME_SECONDS = 20;
+
+    private static final BlockingQueue<Notification> queue =
+            new ArrayBlockingQueue(100);
+
+    private static final NotificationListener queueListener =
+            new NotificationListener() {
+        public void handleNotification(Notification notification,
+                                       Object handback) {
+            queue.add(notification);
+        }
+    };
+
+    private static final NotificationFilter dummyFilter =
+            new NotificationFilter() {
+        public boolean isNotificationEnabled(Notification notification) {
+            return true;
+        }
+    };
+
+    public static void main(String[] args) throws Exception {
+        long start = System.currentTimeMillis();
+        long deadline = start + MAX_TIME_SECONDS * 1000;
+
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
+        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+                url, null, mbs);
+        cs.start();
+        JMXServiceURL addr = cs.getAddress();
+        JMXConnector cc = JMXConnectorFactory.connect(addr);
+        MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+        ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+
+        System.out.println("Opening and closing some EventClients...");
+        // If we create a connection, then create and destroy EventClients
+        // over it, then close it, there should be no "JMX *" threads left.
+        for (int i = 0; i < 5; i++)
+            test(mbsc);
+
+        cc.close();
+
+        showTime("opening and closing initial EventClients", start);
+
+        Set<String> jmxThreads = threadsMatching("JMX .*");
+        while (!jmxThreads.isEmpty() && System.currentTimeMillis() < deadline) {
+            Set<String> jmxThreadsNow = threadsMatching("JMX .*");
+            Set<String> gone = new TreeSet<String>(jmxThreads);
+            gone.removeAll(jmxThreadsNow);
+            for (String s : gone)
+                showTime("expiry of \"" + s + "\"", start);
+            jmxThreads = jmxThreadsNow;
+            Thread.sleep(10);
+        }
+        if (System.currentTimeMillis() >= deadline) {
+            showThreads(threads);
+            throw new Exception("Timed out waiting for JMX threads to expire");
+        }
+
+        showTime("waiting for JMX threads to expire", start);
+
+        System.out.println("TEST PASSED");
+    }
+
+    static void showThreads(ThreadMXBean threads) throws Exception {
+        long[] ids = threads.getAllThreadIds();
+        for (long id : ids) {
+            ThreadInfo ti = threads.getThreadInfo(id);
+            String name = (ti == null) ? "(defunct)" : ti.getThreadName();
+            System.out.printf("%4d %s\n", id, name);
+        }
+    }
+
+    static void showTime(String what, long start) {
+        long elapsed = System.currentTimeMillis() - start;
+        System.out.printf("Time after %s: %.3f s\n", what, elapsed / 1000.0);
+    }
+
+    static Set<String> threadsMatching(String pattern) {
+        Set<String> matching = new TreeSet<String>();
+        ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+        long[] ids = threads.getAllThreadIds();
+        for (long id : ids) {
+            ThreadInfo ti = threads.getThreadInfo(id);
+            String name = (ti == null) ? "(defunct)" : ti.getThreadName();
+            if (name.matches(pattern))
+                matching.add(name);
+        }
+        return matching;
+    }
+
+    static void test(MBeanServerConnection mbsc) throws Exception {
+        final ObjectName delegateName = MBeanServerDelegate.DELEGATE_NAME;
+        final ObjectName testName = new ObjectName("test:type=Test");
+        EventClient ec = new EventClient(mbsc);
+        ec.addNotificationListener(delegateName, queueListener, null, null);
+        mbsc.createMBean(MBeanServerDelegate.class.getName(), testName);
+        mbsc.unregisterMBean(testName);
+        final String[] expectedTypes = {
+            MBeanServerNotification.REGISTRATION_NOTIFICATION,
+            MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
+        };
+        for (String s : expectedTypes) {
+            Notification n = queue.poll(3, TimeUnit.SECONDS);
+            if (n == null)
+                throw new Exception("Timed out waiting for notif: " + s);
+            if (!(n instanceof MBeanServerNotification))
+                throw new Exception("Got notif of wrong class: " + n.getClass());
+            if (!n.getType().equals(s)) {
+                throw new Exception("Got notif of wrong type: " + n.getType() +
+                        " (expecting " + s + ")");
+            }
+        }
+        ec.removeNotificationListener(delegateName, queueListener);
+
+        ec.addNotificationListener(delegateName, queueListener, dummyFilter, "foo");
+        ec.removeNotificationListener(delegateName, queueListener, dummyFilter, "foo");
+
+        ec.close();
+    }
+}
\ No newline at end of file
--- a/jdk/test/javax/management/eventService/LeaseManagerDeadlockTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/eventService/LeaseManagerDeadlockTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -27,6 +27,7 @@
  * @summary Check that a lock is not held when a LeaseManager expires.
  * @author Eamonn McManus
  * @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java
+ * @run main LeaseManagerDeadlockTest
  */
 
 import com.sun.jmx.event.LeaseManager;
--- a/jdk/test/javax/management/eventService/SharingThreadTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/eventService/SharingThreadTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -1,4 +1,4 @@
-/*/*
+/*
  * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/SubUnsubTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test SubUnsubTest
+ * @bug 6736611
+ * @summary Test not to remove other listeners when calling unsubscribe
+ * @author Shanliang JIANG
+ * @run clean SubUnsubTest
+ * @run build SubUnsubTest
+ * @run main SubUnsubTest
+ */
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventSubscriber;
+import javax.management.event.EventClient;
+public class SubUnsubTest {
+    private static class CountListener implements NotificationListener {
+        volatile int count;
+
+        public void handleNotification(Notification n, Object h) {
+            count++;
+        }
+    }
+
+    public static interface SenderMBean {}
+
+    public static class Sender extends NotificationBroadcasterSupport
+            implements SenderMBean {
+        void send() {
+            Notification n = new Notification("type", this, 1L);
+            sendNotification(n);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Testing EventSubscriber-unsubscribe method.");
+
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        ObjectName name1 = new ObjectName("d:type=Sender,id=1");
+        ObjectName name2 = new ObjectName("d:type=Sender,id=2");
+        ObjectName pattern = new ObjectName("d:type=Sender,*");
+        Sender sender1 = new Sender();
+        Sender sender2 = new Sender();
+        mbs.registerMBean(sender1, name1);
+        mbs.registerMBean(sender2, name2);
+
+        EventSubscriber sub = EventSubscriber.getEventSubscriber(mbs);
+
+        System.out.println("Single subscribe covering both MBeans");
+        CountListener listener = new CountListener();
+
+        System.out.println("Subscribing and adding listeners ...");
+        sub.subscribe(pattern, listener, null, null);
+        sub.subscribe(name2, listener, null, null);
+        mbs.addNotificationListener(name2, listener, null, null);
+
+        sender1.send();
+        sender2.send();
+        if (listener.count != 4) {
+            throw new RuntimeException("Do not receive all notifications: "+
+                    "Expect 4, got "+listener.count);
+        }
+
+        System.out.println("Unsubscribe the listener with the pattern.");
+        sub.unsubscribe(pattern, listener);
+        listener.count = 0;
+        sender1.send();
+        sender2.send();
+        if (listener.count != 2) {
+            throw new RuntimeException("The method unsubscribe removes wrong listeners.");
+        }
+
+        System.out.println("Unsubscribe the listener with the ObjectName.");
+        sub.unsubscribe(name2, listener);
+        listener.count = 0;
+        sender1.send();
+        sender2.send();
+        if (listener.count != 1) {
+            throw new RuntimeException("The method unsubscribe removes wrong listeners.");
+        }
+
+        System.out.println("Subscribe twice to same MBean with same listener " +
+                "but different handback.");
+        sub.subscribe(name1, listener, null, new Object());
+        sub.subscribe(name1, listener, null, new Object());
+        listener.count = 0;
+
+        sub.unsubscribe(name1, listener);
+        sender1.send();
+        if (listener.count > 0) {
+            throw new RuntimeException("EventSubscriber: the method unsubscribe" +
+                    " does not remove a listener which was subscribed 2 times.");
+        }
+
+        System.out.println("Bye bye!");
+        return;
+    }
+}
\ No newline at end of file
--- a/jdk/test/javax/management/namespace/DomainCreationTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/DomainCreationTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -23,6 +23,7 @@
 /*
  *
  * @test DomainCreationTest.java
+ * @bug 5072476
  * @summary Test the creation and registration of JMXDomain instances.
  * @author Daniel Fuchs
  * @run clean DomainCreationTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -27,6 +27,7 @@
  * @summary Check -Djmx.remote.use.event.service=true and
  *                -Djmx.remote.delegate.event.service
  * @author Daniel Fuchs
+ * @bug 5072476 5108776
  * @run clean EventWithNamespaceTest EventWithNamespaceControlTest
  *            Wombat WombatMBean JMXRemoteTargetNamespace
  *            NamespaceController NamespaceControllerMBean
--- a/jdk/test/javax/management/namespace/EventWithNamespaceTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/EventWithNamespaceTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -24,7 +24,7 @@
 /*
  *
  * @test EventWithNamespaceTest.java 1.8
- * @bug 6539857
+ * @bug 6539857 5072476 5108776
  * @summary General Namespace & Notifications test.
  * @author Daniel Fuchs
  * @run clean EventWithNamespaceTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/ExportNamespaceTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/ExportNamespaceTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -26,6 +26,7 @@
  * @summary Test that you can export a single namespace through a
  *          JMXConnectorServer.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean ExportNamespaceTest Wombat WombatMBean
  * @run build ExportNamespaceTest Wombat WombatMBean
  * @run main ExportNamespaceTest
--- a/jdk/test/javax/management/namespace/JMXDomainTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/JMXDomainTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -23,6 +23,7 @@
 /*
  *
  * @test JMXDomainTest.java
+ * @bug 5072476
  * @summary Basic test for JMXDomain.
  * @author Daniel Fuchs
  * @run clean JMXDomainTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -26,6 +26,7 @@
  * @test JMXNamespaceSecurityTest.java
  * @summary General JMXNamespaceSecurityTest test.
  * @author Daniel Fuchs
+ * @bug 5072476 6299231
  * @run clean JMXNamespaceViewTest JMXNamespaceSecurityTest Wombat WombatMBean
  *            LazyDomainTest
  * @run build JMXNamespaceSecurityTest JMXNamespaceViewTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/JMXNamespaceTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/JMXNamespaceTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  *
  * @test JMXNamespaceTest.java
  * @summary General JMXNamespace test.
+ * @bug 5072476
  * @author Daniel Fuchs
  * @run clean JMXNamespaceTest
  *            Wombat WombatMBean JMXRemoteTargetNamespace
@@ -34,7 +35,6 @@
  *            NamespaceController.java NamespaceControllerMBean.java
  * @run main/othervm JMXNamespaceTest
  */
-import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
 import java.lang.reflect.InvocationTargetException;
@@ -51,10 +51,10 @@
 import javax.management.JMX;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
 import javax.management.NotificationEmitter;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
-import javax.management.RuntimeOperationsException;
 import javax.management.StandardMBean;
 import javax.management.namespace.JMXNamespaces;
 import javax.management.namespace.JMXNamespace;
@@ -154,7 +154,7 @@
             }
     }
 
-    private static class SimpleTestConf {
+    public static class SimpleTestConf {
         public final  Wombat wombat;
         public final  StandardMBean mbean;
         public final  String dirname;
@@ -456,259 +456,56 @@
         }
     }
 
-    /**
-     * Test cycle detection.
-     * mkdir test ; cd test ; ln -s . kanga ; ln -s kanga/kanga/roo/kanga roo
-     * touch kanga/roo/wombat
-     **/
-    public static void probeKangaRooTest(String[] args) {
-        final SimpleTestConf conf;
+    public static void verySimpleTest(String[] args) {
+        System.err.println("verySimpleTest: starting");
         try {
-            conf = new SimpleTestConf(args);
-            try {
-                final JMXServiceURL url =
-                        new JMXServiceURL("rmi","localHost",0);
-                final Map<String,Object> empty = Collections.emptyMap();
-                final JMXConnectorServer server =
-                        JMXConnectorServerFactory.newJMXConnectorServer(url,
-                        empty,conf.server);
-                server.start();
-                final JMXServiceURL address = server.getAddress();
-                final JMXConnector client =
-                        JMXConnectorFactory.connect(address,
-                        empty);
-                final String[] signature = {
-                    JMXServiceURL.class.getName(),
-                    Map.class.getName(),
-                };
-
-                final Object[] params = {
-                    address,
-                    null,
-                };
-                final MBeanServerConnection c =
-                        client.getMBeanServerConnection();
-
-                // ln -s . kanga
-                final ObjectName dirName1 =
-                        new ObjectName("kanga//:type=JMXNamespace");
-                c.createMBean(JMXRemoteTargetNamespace.class.getName(),
-                              dirName1, params,signature);
-                c.invoke(dirName1, "connect", null, null);
-                try {
-                    // ln -s kanga//kanga//roo//kanga roo
-                    final JMXNamespace local = new JMXNamespace(
-                            new MBeanServerConnectionWrapper(null,
-                            JMXNamespaceTest.class.getClassLoader()){
-
-                        @Override
-                        protected MBeanServerConnection getMBeanServerConnection() {
-                            return JMXNamespaces.narrowToNamespace(c,
-                                    "kanga//kanga//roo//kanga"
-                                    );
-                        }
-
-                    });
-                    final ObjectName dirName2 =
-                            new ObjectName("roo//:type=JMXNamespace");
-                    conf.server.registerMBean(local,dirName2);
-                    System.out.println(dirName2 + " created!");
-                    try {
-                        // touch kanga/roo/wombat
-                        final ObjectName wombatName1 =
-                                new ObjectName("kanga//roo//"+conf.wombatName);
-                        final WombatMBean wombat1 =
-                                JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
-                        final String newCaption="I am still the same old wombat";
-                        Exception x = null;
-                        try {
-                            wombat1.setCaption(newCaption);
-                        } catch (RuntimeOperationsException r) {
-                            x=r.getTargetException();
-                            System.out.println("Got expected exception: " + x);
-                            // r.printStackTrace();
-                        }
-                        if (x == null)
-                            throw new RuntimeException("cycle not detected!");
-                    } finally {
-                        c.unregisterMBean(dirName2);
-                    }
-                } finally {
-                    c.unregisterMBean(dirName1);
-                    client.close();
-                    server.stop();
-                }
-            } finally {
-                conf.close();
-            }
-            System.err.println("probeKangaRooTest PASSED");
+            final MBeanServer srv = MBeanServerFactory.createMBeanServer();
+            srv.registerMBean(new JMXNamespace(
+                    JMXNamespaces.narrowToNamespace(srv, "foo")),
+                    JMXNamespaces.getNamespaceObjectName("foo"));
+            throw new Exception("Excpected IllegalArgumentException not raised.");
+        } catch (IllegalArgumentException x) {
+            System.err.println("verySimpleTest: got expected exception: "+x);
         } catch (Exception x) {
-            System.err.println("probeKangaRooTest FAILED: " +x);
+            System.err.println("verySimpleTest FAILED: " +x);
             x.printStackTrace();
             throw new RuntimeException(x);
         }
+        System.err.println("verySimpleTest: PASSED");
     }
-    /**
-     * Test cycle detection 2.
-     * mkdir test ; cd test ; ln -s . roo ; ln -s roo/roo kanga
-     * touch kanga/roo/wombat ; rm roo ; ln -s kanga roo ;
-     * touch kanga/roo/wombat
-     *
-     **/
-    public static void probeKangaRooCycleTest(String[] args) {
-        final SimpleTestConf conf;
-        try {
-            conf = new SimpleTestConf(args);
-            Exception failed = null;
-            try {
-                final JMXServiceURL url =
-                        new JMXServiceURL("rmi","localHost",0);
-                final Map<String,Object> empty = Collections.emptyMap();
-                final JMXConnectorServer server =
-                        JMXConnectorServerFactory.newJMXConnectorServer(url,
-                        empty,conf.server);
-                server.start();
-                final JMXServiceURL address = server.getAddress();
-                final JMXConnector client =
-                        JMXConnectorFactory.connect(address,
-                        empty);
-                final String[] signature = {
-                    JMXServiceURL.class.getName(),
-                    Map.class.getName(),
-                };
-                final String[] signature2 = {
-                    JMXServiceURL.class.getName(),
-                    Map.class.getName(),
-                    String.class.getName()
-                };
-                final Object[] params = {
-                    address,
-                    Collections.emptyMap(),
-                };
-                final Object[] params2 = {
-                    address,
-                    null,
-                    "kanga",
-                };
-                final MBeanServerConnection c =
-                        client.getMBeanServerConnection();
 
-                // ln -s . roo
-                final ObjectName dirName1 =
-                        new ObjectName("roo//:type=JMXNamespace");
-                c.createMBean(JMXRemoteTargetNamespace.class.getName(),
-                              dirName1, params,signature);
-                c.invoke(dirName1, "connect",null,null);
-                try {
-                    final Map<String,Object> emptyMap =
-                            Collections.emptyMap();
-                    final JMXNamespace local = new JMXNamespace(
-                            new MBeanServerConnectionWrapper(
-                            JMXNamespaces.narrowToNamespace(c,
-                            "roo//roo//"),
-                            JMXNamespaceTest.class.getClassLoader())) {
-                    };
-                    // ln -s roo/roo kanga
-                    final ObjectName dirName2 =
-                            new ObjectName("kanga//:type=JMXNamespace");
-                    conf.server.registerMBean(local,dirName2);
-                    System.out.println(dirName2 + " created!");
-                    try {
-                        // touch kanga/roo/wombat
-                        final ObjectName wombatName1 =
-                                new ObjectName("kanga//roo//"+conf.wombatName);
-                        final WombatMBean wombat1 =
-                                JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
-                        final String newCaption="I am still the same old wombat";
-                        wombat1.setCaption(newCaption);
-                        // rm roo
-                        c.unregisterMBean(dirName1);
-                        // ln -s kanga roo
-                        System.err.println("**** Creating " + dirName1 +
-                                " ****");
-                        c.createMBean(JMXRemoteTargetNamespace.class.getName(),
-                              dirName1, params2,signature2);
-                        System.err.println("**** Created " + dirName1 +
-                                " ****");
-                        Exception x = null;
-                        try {
-                            // touch kanga/roo/wombat
-                            wombat1.setCaption(newCaption+" I hope");
-                        } catch (RuntimeOperationsException r) {
-                            x=(Exception)r.getCause();
-                            System.out.println("Got expected exception: " + x);
-                            //r.printStackTrace();
-                        }
-                        if (x == null)
-                            throw new RuntimeException("should have failed!");
-                        x = null;
-                        try {
-                            // ls kanga/roo/wombat
-                            System.err.println("**** Connecting " + dirName1 +
-                                    " ****");
-                            JMX.newMBeanProxy(c,dirName1,
-                                    JMXRemoteNamespaceMBean.class).connect();
-                            System.err.println("**** Connected " + dirName1 +
-                                    " ****");
-                        } catch (IOException r) {
-                            x=r;
-                            System.out.println("Got expected exception: " + x);
-                            //r.printStackTrace();
-                        }
-                        System.err.println("**** Expected Exception Not Raised ****");
-                        if (x == null) {
-                            System.out.println(dirName1+" contains: "+
-                                    c.queryNames(new ObjectName(
-                                    dirName1.getDomain()+"*:*"),null));
-                            throw new RuntimeException("cycle not detected!");
-                        }
-                    } catch (Exception t) {
-                        if (failed == null) failed = t;
-                    } finally {
-                            c.unregisterMBean(dirName2);
-                    }
-                } finally {
-                    try {
-                        c.unregisterMBean(dirName1);
-                    } catch (Exception t) {
-                        if (failed == null) failed = t;
-                        System.err.println("Failed to unregister "+dirName1+
-                                ": "+t);
-                    }
-                    try {
-                        client.close();
-                    } catch (Exception t) {
-                        if (failed == null) failed = t;
-                        System.err.println("Failed to close client: "+t);
-                    }
-                    try {
-                        server.stop();
-                    } catch (Exception t) {
-                        if (failed == null) failed = t;
-                        System.err.println("Failed to stop server: "+t);
-                    }
-                }
-            } finally {
-                try {
-                    conf.close();
-                } catch (Exception t) {
-                    if (failed == null) failed = t;
-                    System.err.println("Failed to stop server: "+t);
-                }
-            }
-            if (failed != null) throw failed;
-            System.err.println("probeKangaRooCycleTest PASSED");
+    public static void verySimpleTest2(String[] args) {
+        System.err.println("verySimpleTest2: starting");
+        try {
+            final MBeanServer srv = MBeanServerFactory.createMBeanServer();
+            final JMXConnectorServer cs = JMXConnectorServerFactory.
+                    newJMXConnectorServer(new JMXServiceURL("rmi",null,0),
+                    null, srv);
+            cs.start();
+            final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
+
+            srv.registerMBean(new JMXNamespace(
+                    new MBeanServerConnectionWrapper(
+                            JMXNamespaces.narrowToNamespace(
+                                cc.getMBeanServerConnection(),
+                                "foo"))),
+                    JMXNamespaces.getNamespaceObjectName("foo"));
+            throw new Exception("Excpected IllegalArgumentException not raised.");
+        } catch (IllegalArgumentException x) {
+            System.err.println("verySimpleTest2: got expected exception: "+x);
         } catch (Exception x) {
-            System.err.println("probeKangaRooCycleTest FAILED: " +x);
+            System.err.println("verySimpleTest2 FAILED: " +x);
             x.printStackTrace();
             throw new RuntimeException(x);
         }
+        System.err.println("verySimpleTest2: PASSED");
     }
+
     public static void main(String[] args) {
         simpleTest(args);
         recursiveTest(args);
-        probeKangaRooTest(args);
-        probeKangaRooCycleTest(args);
+        verySimpleTest(args);
+        verySimpleTest2(args);
     }
 
 }
--- a/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -24,6 +24,7 @@
  *
  * @test JMXNamespaceViewTest.java
  * @summary Test the JMXNamespaceView class.
+ * @bug 5072476
  * @author Daniel Fuchs
  * @run clean JMXNamespaceViewTest Wombat WombatMBean
  * @run build JMXNamespaceViewTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/JMXNamespacesTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/JMXNamespacesTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -24,6 +24,7 @@
  * @test JMXNamespacesTest.java
  * @summary Test the static method that rewrite ObjectNames in JMXNamespacesTest
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean JMXNamespacesTest
  * @compile -XDignore.symbol.file=true JMXNamespacesTest.java
  * @run main JMXNamespacesTest
--- a/jdk/test/javax/management/namespace/JMXRemoteNamespaceTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/JMXRemoteNamespaceTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test JMXRemoteNamespaceTest.java
  * @summary Basic tests on a JMXRemoteNamespace.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean JMXRemoteNamespaceTest Wombat WombatMBean
  * @run build JMXRemoteNamespaceTest Wombat WombatMBean
  * @run main JMXRemoteNamespaceTest
--- a/jdk/test/javax/management/namespace/LazyDomainTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/LazyDomainTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -23,6 +23,7 @@
 /*
  *
  * @test LazyDomainTest.java
+ * @bug 5072476
  * @summary Basic test for Lazy Domains.
  * @author Daniel Fuchs
  * @run clean LazyDomainTest Wombat WombatMBean
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/namespace/LeadingSeparatorsTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+/*
+ * @test LeadingSeparatorsTest.java
+ * @summary Test that the semantics of a leading // in ObjectName is respected.
+ * @author Daniel Fuchs
+ * @bug 5072476
+ * @run clean LeadingSeparatorsTest Wombat WombatMBean
+ * @compile -XDignore.symbol.file=true  LeadingSeparatorsTest.java
+ * @run build LeadingSeparatorsTest Wombat WombatMBean
+ * @run main LeadingSeparatorsTest
+ */
+
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.logging.Logger;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXRemoteNamespace;
+import javax.management.namespace.JMXNamespace;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * Class LeadingSeparatorsTest
+ * @author Sun Microsystems, 2005 - All rights reserved.
+ */
+public class LeadingSeparatorsTest {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG =
+            Logger.getLogger(LeadingSeparatorsTest.class.getName());
+
+    /** Creates a new instance of NullObjectNameTest */
+    public LeadingSeparatorsTest() {
+    }
+
+    public static interface MyWombatMBean extends WombatMBean {
+        public Set<ObjectName> untrue(ObjectName pat) throws Exception;
+    }
+    public static class MyWombat
+            extends Wombat implements MyWombatMBean {
+        public MyWombat() throws NotCompliantMBeanException {
+            super(MyWombatMBean.class);
+        }
+
+        public Set<ObjectName> untrue(ObjectName pat) throws Exception {
+            final Set<ObjectName> res=listMatching(pat.withDomain("*"));
+            final Set<ObjectName> untrue = new HashSet<ObjectName>();
+            for (ObjectName a:res) {
+                untrue.add(a.withDomain(pat.getDomain()+"//"+a.getDomain()));
+            }
+            return untrue;
+        }
+    }
+
+    static String failure=null;
+
+    public static void testRegister() throws Exception {
+        final MBeanServer top = ManagementFactory.getPlatformMBeanServer();
+        final MBeanServer sub = MBeanServerFactory.createMBeanServer();
+        final JMXServiceURL url = new JMXServiceURL("rmi",null,0);
+        final JMXConnectorServer srv =
+                JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub);
+        srv.start();
+
+        try {
+
+            // Create a namespace rmi// that points to 'sub' and flows through
+            // a JMXRemoteNamespace connected to 'srv'
+            // The namespace rmi// will accept createMBean, but not registerMBean.
+            //
+            final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace.
+                    newJMXRemoteNamespace(srv.getAddress(),null);
+            top.registerMBean(rmiHandler,
+                    JMXNamespaces.getNamespaceObjectName("rmi"));
+            top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"),
+                    "connect", null, null);
+
+            // Create a namespace direct// that points to 'sub' and flows
+            // through a direct reference to 'sub'.
+            // The namespace direct// will accept createMBean, and registerMBean.
+            //
+            final JMXNamespace directHandler = new JMXNamespace(sub);
+            top.registerMBean(directHandler,
+                    JMXNamespaces.getNamespaceObjectName("direct"));
+
+            final ObjectName n1 = new ObjectName("//direct//w:type=Wombat");
+            final ObjectName n2 = new ObjectName("direct//w:type=Wombat");
+            final ObjectName n3 = new ObjectName("//rmi//w:type=Wombat");
+            final ObjectName n4 = new ObjectName("rmi//w:type=Wombat");
+
+            // register wombat using an object name with a leading //
+            final Object     obj = new MyWombat();
+            // check that returned object name doesn't have the leading //
+            assertEquals(n2,top.registerMBean(obj, n1).getObjectName());
+            System.out.println(n1+" registered");
+
+            // check that the registered Wombat can be accessed with all its
+            // names.
+            System.out.println(n2+" mood is: "+top.getAttribute(n2, "Mood"));
+            System.out.println(n1+" mood is: "+top.getAttribute(n1, "Mood"));
+            System.out.println(n4+" mood is: "+top.getAttribute(n4, "Mood"));
+            System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood"));
+
+            // call listMatching. The result should not contain any prefix.
+            final Set<ObjectName> res = (Set<ObjectName>)
+                    top.invoke(n3, "listMatching",
+                    // remove rmi// from rmi//*:*
+                    JMXNamespaces.deepReplaceHeadNamespace(
+                    new Object[] {ObjectName.WILDCARD.withDomain("rmi//*")},
+                    "rmi", ""), new String[] {ObjectName.class.getName()});
+
+            // add rmi// prefix to all names in res.
+            final Set<ObjectName> res1 =
+                   JMXNamespaces.deepReplaceHeadNamespace(res, "", "rmi");
+            System.out.println("got: "+res1);
+
+            // compute expected result
+            final Set<ObjectName> res2 = sub.queryNames(null,null);
+            final Set<ObjectName> res3 = new HashSet<ObjectName>();
+            for (ObjectName o:res2) {
+               res3.add(o.withDomain("rmi//"+o.getDomain()));
+            }
+            System.out.println("expected: "+res3);
+            assertEquals(res1, res3);
+
+            // invoke "untrue(//niark//niark:*)"
+            // should return a set were all ObjectNames begin with
+            // //niark//niark//
+            //
+            final Set<ObjectName> res4 = (Set<ObjectName>)
+                    top.invoke(n3, "untrue",
+                    // remove niark//niark : should remove nothing since
+                    // our ObjectName begins with a leading //
+                    JMXNamespaces.deepReplaceHeadNamespace(
+                    new Object[] {
+                       ObjectName.WILDCARD.withDomain("//niark//niark")},
+                    "niark//niark", ""),
+                    new String[] {ObjectName.class.getName()});
+            System.out.println("got: "+res4);
+
+            // add rmi// should add nothing since the returned names have a
+            // leading //
+            //
+            final Set<ObjectName> res5 =
+                   JMXNamespaces.deepReplaceHeadNamespace(res4, "", "rmi");
+            System.out.println("got#2: "+res5);
+
+            // compute expected result
+            final Set<ObjectName> res6 = new HashSet<ObjectName>();
+            for (ObjectName o:res2) {
+               res6.add(o.withDomain("//niark//niark//"+o.getDomain()));
+            }
+            System.out.println("expected: "+res6);
+
+            // both res4 and res5 should be equals to the expected result.
+            assertEquals(res4, res6);
+            assertEquals(res5, res6);
+
+        } finally {
+            srv.stop();
+        }
+
+        if (failure != null)
+            throw new Exception(failure);
+
+
+    }
+    private static void assertEquals(Object x, Object y) {
+        if (!equal(x, y))
+            failed("expected " + string(x) + "; got " + string(y));
+    }
+
+    private static boolean equal(Object x, Object y) {
+        if (x == y)
+            return true;
+        if (x == null || y == null)
+            return false;
+        if (x.getClass().isArray())
+            return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
+        return x.equals(y);
+    }
+
+    private static String string(Object x) {
+        String s = Arrays.deepToString(new Object[] {x});
+        return s.substring(1, s.length() - 1);
+    }
+
+
+    private static void failed(String why) {
+        failure = why;
+        new Throwable("FAILED: " + why).printStackTrace(System.out);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testRegister();
+    }
+}
--- a/jdk/test/javax/management/namespace/NamespaceCreationTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/NamespaceCreationTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test NamespaceCreationTest.java
  * @summary General JMXNamespace test.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean NamespaceCreationTest Wombat WombatMBean
  * @run build NamespaceCreationTest Wombat WombatMBean
  * @run main NamespaceCreationTest
--- a/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  *
  * @test NamespaceNotificationsTest.java 1.12
  * @summary General Namespace & Notifications test.
+ * @bug 5072476
  * @author Daniel Fuchs
  * @run clean NamespaceNotificationsTest
  *            Wombat WombatMBean JMXRemoteTargetNamespace
--- a/jdk/test/javax/management/namespace/NullObjectNameTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/NullObjectNameTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -24,6 +24,7 @@
  * @test NullObjectNameTest.java
  * @summary Test that null ObjectName are correctly handled in namespaces.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean NullObjectNameTest Wombat WombatMBean
  * @compile -XDignore.symbol.file=true  NullObjectNameTest.java
  * @run build NullObjectNameTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/QueryNamesTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/QueryNamesTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test QueryNamesTest.java 1.4
  * @summary Test how queryNames works with Namespaces.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean QueryNamesTest Wombat WombatMBean
  * @run build QueryNamesTest Wombat WombatMBean
  * @run main QueryNamesTest
--- a/jdk/test/javax/management/namespace/RemoveNotificationListenerTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/RemoveNotificationListenerTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test RemoveNotificationListenerTest.java 1.8
  * @summary General RemoveNotificationListenerTest test.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean RemoveNotificationListenerTest JMXRemoteTargetNamespace
  * @compile -XDignore.symbol.file=true  JMXRemoteTargetNamespace.java
  * @run build RemoveNotificationListenerTest JMXRemoteTargetNamespace
--- a/jdk/test/javax/management/namespace/RoutingServerProxyTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/RoutingServerProxyTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test RoutingServerProxyTest.java 1.6
  * @summary General RoutingServerProxyTest test.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean RoutingServerProxyTest Wombat WombatMBean
  * @compile -XDignore.symbol.file=true RoutingServerProxyTest.java
  * @run build RoutingServerProxyTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/SerialParamProcessorTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/SerialParamProcessorTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -26,6 +26,7 @@
  * @test SerialParamProcessorTest.java 1.8
  * @summary General SerialParamProcessorTest test.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean SerialParamProcessorTest Wombat WombatMBean
  * @compile -XDignore.symbol.file=true  SerialParamProcessorTest.java
  * @run build SerialParamProcessorTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/SourceNamespaceTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/SourceNamespaceTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -24,6 +24,7 @@
  *
  * @test SourceNamespaceTest.java
  * @summary Test how queryNames works with Namespaces.
+ * @bug 5072476
  * @author Daniel Fuchs
  * @run clean SourceNamespaceTest Wombat WombatMBean
  * @run build SourceNamespaceTest Wombat WombatMBean
--- a/jdk/test/javax/management/namespace/VirtualMBeanNotifTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/VirtualMBeanNotifTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -25,6 +25,7 @@
  * @test VirtualMBeanNotifTest.java
  * @bug 5108776
  * @build VirtualMBeanNotifTest Wombat WombatMBean
+ * @run main VirtualMBeanNotifTest
  * @summary Test that Virtual MBeans can be implemented and emit notifs.
  * @author  Daniel Fuchs
  */
--- a/jdk/test/javax/management/namespace/VirtualMBeanTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/VirtualMBeanTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test VirtualMBeanTest.java
- * @bug 5108776
+ * @bug 5108776 5072476
  * @summary Test that Virtual MBeans can be implemented and emit notifs.
  * @author Eamonn McManus
  */
--- a/jdk/test/javax/management/namespace/VirtualNamespaceQueryTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/VirtualNamespaceQueryTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -26,6 +26,7 @@
  * @test VirtualNamespaceQueryTest.java
  * @summary General VirtualNamespaceQueryTest test.
  * @author Daniel Fuchs
+ * @bug 5072476
  * @run clean VirtualNamespaceQueryTest Wombat WombatMBean
  *            NamespaceController NamespaceControllerMBean
  *            JMXRemoteTargetNamespace
--- a/jdk/test/javax/management/namespace/VirtualPropsTest.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/VirtualPropsTest.java	Fri Sep 12 23:31:43 2008 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 5108776
+ * @bug 5108776 5072476
  * @summary Test the properties use case for Virtual MBeans that is documented
  * in MBeanServerSupport.
  * @author Eamonn McManus
--- a/jdk/test/javax/management/namespace/Wombat.java	Fri Sep 12 14:34:23 2008 -0700
+++ b/jdk/test/javax/management/namespace/Wombat.java	Fri Sep 12 23:31:43 2008 -0700
@@ -68,7 +68,12 @@
     }
 
     public Wombat() throws NotCompliantMBeanException {
-        super(WombatMBean.class);
+        this(WombatMBean.class);
+    }
+
+    public Wombat(Class<? extends WombatMBean> clazz)
+            throws NotCompliantMBeanException {
+        super(clazz);
         final Random r = new Random();
         seed = ((r.nextLong() % MAX_SEED) + MAX_SEED)%MAX_SEED;
         period = 200 + (((r.nextLong()%80)+80)%80)*10;