changeset 702:e81b47f0b40f

Merge
author alanb
date Tue, 11 Nov 2008 09:07:58 +0000
parents 275fa248e808 2410a0b48d06
children d2f96992b77b a85ef87f9eaa
files src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java
diffstat 151 files changed, 7976 insertions(+), 2560 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Nov 11 08:59:43 2008 +0000
+++ b/.hgtags	Tue Nov 11 09:07:58 2008 +0000
@@ -12,3 +12,4 @@
 cf4894b78ceb966326e93bf221db0c2d14d59218 jdk7-b35
 134fd1a656ea85acd1f97f6700f75029b9b472a0 jdk7-b36
 14f50aee4989b75934d385c56a83da0c23d2f68b jdk7-b37
+cc5f810b5af8a3a83b0df5a29d9e24d7a0ff8086 jdk7-b38
--- a/make/netbeans/jmx/build.xml	Tue Nov 11 08:59:43 2008 +0000
+++ b/make/netbeans/jmx/build.xml	Tue Nov 11 09:07:58 2008 +0000
@@ -44,13 +44,13 @@
         <!-- because they depend on the values of BUILD_DATE and BUILD_DATE_SIMPLE  -->
         <!-- At this time, ./build.properties has not been loaded yet. -->
         <property name="project.build.name" value="openjdk-bXX"/>
-	<property name="project.build.fulltag" 
+	<property name="project.build.fulltag"
                   value="${ant.project.name}-${project.build.name}-${BUILD_DATE}" />
 
         <!-- unchecked warnings will be fixed in JMX 2.0 as part of the work
              being done on JSR 255 new features                              -->
-        <property name="javac.options" 
-                  value="-Xlint -Xlint:-unchecked -Xlint:-deprecation"/>
+        <property name="javac.options"
+                  value="-Xlint -Xlint:-deprecation"/>
     </target>
 
 
@@ -58,13 +58,13 @@
 	<!-- Dir to keep generated stub source -->
         <mkdir dir="${gensrc.dir}" />
     </target>
-    
+
 
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~ -->
     <!-- Call rmic-jmx subtargets -->
 
     <target name="-rmic-jmx" depends="-init,-rmic-jmx-jrmp,-rmic-jmx-iiop"
-	    description="Calls -init,-rmic-jmx-jrmp,-rmic-jmx-iiop" 
+	    description="Calls -init,-rmic-jmx-jrmp,-rmic-jmx-iiop"
     />
 
 
@@ -96,7 +96,7 @@
 
     <target name="-rmic-jmx-iiop" depends="-init,-check-jmx-iiop-uptodate" unless="jmx-iiop-uptodate"
             description="Generate RMI IIOP stub class files for remote objects. Do not keep generated java files." >
- 
+
 	<rmic 	base="${classes.dir}"
 		includeAntRuntime="no"
 		includeJavaRuntime="no"
@@ -115,11 +115,11 @@
 
     <target name="-check-jmx-iiop-uptodate" depends="-init">
 
-	<uptodate property="jmx-iiop-uptodate" 
+	<uptodate property="jmx-iiop-uptodate"
 		   srcfile="${classes.dir}/javax/management/remote/rmi/RMIConnectionImpl.class"
 		targetfile="${classes.dir}/org/omg/stub/javax/management/remote/rmi/_RMIConnectionImpl_Tie.class"
 	/>
-	<uptodate property="jmx-iiop-uptodate" 
+	<uptodate property="jmx-iiop-uptodate"
 		   srcfile="${classes.dir}/javax/management/remote/rmi/RMIServerImpl.class"
 		targetfile="${classes.dir}/org/omg/stub/javax/management/remote/rmi/_RMIServerImpl_Tie.class"
 	/>
@@ -131,7 +131,7 @@
     <target name="-post-compile" depends="-init,-rmic-jmx"
             description="Jar JMX class files (including RMI stubs)" >
        <mkdir dir="${dist.dir}/lib"/>
-       <jar jarfile="${dist.dir}/lib/${jar.jmx.name}" 
+       <jar jarfile="${dist.dir}/lib/${jar.jmx.name}"
 	    update="true"
 	    index="false"
 	    duplicate="fail">
@@ -144,7 +144,7 @@
 		    <attribute name="Specification-Version"  value="${jar.jmx.spec.version}" />
 		    <attribute name="Specification-Vendor"   value="${jar.jmx.spec.vendor}" />
 		    <attribute name="Implementation-Title"   value="${jar.jmx.impl.title}" />
-		    <attribute name="Implementation-Version" value="${project.build.fulltag}" /> 
+		    <attribute name="Implementation-Version" value="${project.build.fulltag}" />
 		    <attribute name="Implementation-Vendor"  value="${jar.jmx.impl.vendor}" />
 		</section>
 	    </manifest>
--- a/src/share/classes/com/sun/jmx/defaults/ServiceName.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/defaults/ServiceName.java	Tue Nov 11 09:07:58 2008 +0000
@@ -69,9 +69,9 @@
     /**
      * The version of the JMX specification implemented by this product.
      * <BR>
-     * The value is <CODE>1.4</CODE>.
+     * The value is <CODE>2.0</CODE>.
      */
-    public static final String JMX_SPEC_VERSION = "1.4";
+    public static final String JMX_SPEC_VERSION = "2.0";
 
     /**
      * The vendor of the JMX specification implemented by this product.
--- a/src/share/classes/com/sun/jmx/event/EventParams.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/event/EventParams.java	Tue Nov 11 09:07:58 2008 +0000
@@ -41,7 +41,7 @@
 
     @SuppressWarnings("cast") // cast for jdk 1.5
     public static long getLeaseTimeout() {
-        long timeout = EventClient.DEFAULT_LEASE_TIMEOUT;
+        long timeout = EventClient.DEFAULT_REQUESTED_LEASE_TIME;
         try {
             final GetPropertyAction act =
                   new GetPropertyAction(DEFAULT_LEASE_TIMEOUT);
--- a/src/share/classes/com/sun/jmx/event/LeaseManager.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/event/LeaseManager.java	Tue Nov 11 09:07:58 2008 +0000
@@ -29,6 +29,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -141,11 +142,12 @@
     }
 
     private final Runnable callback;
-    private ScheduledFuture scheduled;  // If null, the lease has expired.
+    private ScheduledFuture<?> scheduled;  // If null, the lease has expired.
 
+    private static final ThreadFactory threadFactory =
+            new DaemonThreadFactory("JMX LeaseManager %d");
     private final ScheduledExecutorService executor
-            = Executors.newScheduledThreadPool(1,
-            new DaemonThreadFactory("JMX LeaseManager %d"));
+            = Executors.newScheduledThreadPool(1, threadFactory);
 
     private static final ClassLogger logger =
             new ClassLogger("javax.management.event", "LeaseManager");
--- a/src/share/classes/com/sun/jmx/event/LeaseRenewer.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/event/LeaseRenewer.java	Tue Nov 11 09:07:58 2008 +0000
@@ -128,7 +128,7 @@
     };
 
     private final Callable<Long> doRenew;
-    private ScheduledFuture future;
+    private ScheduledFuture<?> future;
     private boolean closed = false;
     private long nextRenewTime;
 
--- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Tue Nov 11 09:07:58 2008 +0000
@@ -247,7 +247,7 @@
                MBeanRegistrationException, MBeanException,
                NotCompliantMBeanException, InstanceNotFoundException {
 
-        Class theClass;
+        Class<?> theClass;
 
         if (className == null) {
             final RuntimeException wrapped =
@@ -327,7 +327,7 @@
 
         // ------------------------------
         // ------------------------------
-        Class theClass = object.getClass();
+        Class<?> theClass = object.getClass();
 
         Introspector.checkCompliance(theClass);
 
@@ -808,9 +808,8 @@
             // on each specific attribute
             //
             allowedAttributes = new AttributeList(attributes.size());
-            for (Iterator i = attributes.iterator(); i.hasNext();) {
+            for (Attribute attribute : attributes.asList()) {
                 try {
-                    Attribute attribute = (Attribute) i.next();
                     checkMBeanPermission(mbeanServerName, classname, attribute.getName(),
                                          name, "setAttribute");
                     allowedAttributes.add(attribute);
@@ -1857,7 +1856,7 @@
         }
     }
 
-    private static void checkMBeanTrustPermission(final Class theClass)
+    private static void checkMBeanTrustPermission(final Class<?> theClass)
         throws SecurityException {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
--- a/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java	Tue Nov 11 09:07:58 2008 +0000
@@ -55,9 +55,19 @@
 import javax.management.namespace.MBeanServerSupport;
 import javax.management.remote.IdentityMBeanServerForwarder;
 
+/**
+ * <p>An {@link MBeanServerForwarder} that simulates the existence of a
+ * given MBean.  Requests for that MBean, call it X, are intercepted by the
+ * forwarder, and requests for any other MBean are forwarded to the next
+ * forwarder in the chain.  Requests such as queryNames which can span both the
+ * X and other MBeans are handled by merging the results for X with the results
+ * from the next forwarder, unless the "visible" parameter is false, in which
+ * case X is invisible to such requests.</p>
+ */
 public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
 
     private final ObjectName mbeanName;
+    private final boolean visible;
     private DynamicMBean mbean;
 
     private MBeanServer mbeanMBS = new MBeanServerSupport() {
@@ -85,10 +95,20 @@
             return null;
         }
 
+        // This will only be called if mbeanName has an empty domain.
+        // In that case a getAttribute (e.g.) of that name will have the
+        // domain replaced by MBeanServerSupport with the default domain,
+        // so we must be sure that the default domain is empty too.
+        @Override
+        public String getDefaultDomain() {
+            return mbeanName.getDomain();
+        }
     };
 
-    public SingleMBeanForwarder(ObjectName mbeanName, DynamicMBean mbean) {
+    public SingleMBeanForwarder(
+            ObjectName mbeanName, DynamicMBean mbean, boolean visible) {
         this.mbeanName = mbeanName;
+        this.visible = visible;
         setSingleMBean(mbean);
     }
 
@@ -213,8 +233,10 @@
 
     @Override
     public String[] getDomains() {
-        TreeSet<String> domainSet =
-                new TreeSet<String>(Arrays.asList(super.getDomains()));
+        String[] domains = super.getDomains();
+        if (!visible)
+            return domains;
+        TreeSet<String> domainSet = new TreeSet<String>(Arrays.asList(domains));
         domainSet.add(mbeanName.getDomain());
         return domainSet.toArray(new String[domainSet.size()]);
     }
@@ -222,7 +244,7 @@
     @Override
     public Integer getMBeanCount() {
         Integer count = super.getMBeanCount();
-        if (!super.isRegistered(mbeanName))
+        if (visible && !super.isRegistered(mbeanName))
             count++;
         return count;
     }
@@ -284,7 +306,7 @@
      */
     private boolean applies(ObjectName pattern) {
         // we know pattern is not null.
-        if (!pattern.apply(mbeanName))
+        if (!visible || !pattern.apply(mbeanName))
             return false;
 
         final String dompat = pattern.getDomain();
@@ -306,10 +328,12 @@
     @Override
     public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
         Set<ObjectInstance> names = super.queryMBeans(name, query);
-        if (name == null || applies(name) ) {
-            // Don't assume mbs.queryNames returns a writable set.
-            names = Util.cloneSet(names);
-            names.addAll(mbeanMBS.queryMBeans(name, query));
+        if (visible) {
+            if (name == null || applies(name) ) {
+                // Don't assume mbs.queryNames returns a writable set.
+                names = Util.cloneSet(names);
+                names.addAll(mbeanMBS.queryMBeans(name, query));
+            }
         }
         return names;
     }
@@ -317,10 +341,12 @@
     @Override
     public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
         Set<ObjectName> names = super.queryNames(name, query);
-        if (name == null || applies(name)) {
-            // Don't assume mbs.queryNames returns a writable set.
-            names = Util.cloneSet(names);
-            names.addAll(mbeanMBS.queryNames(name, query));
+        if (visible) {
+            if (name == null || applies(name)) {
+                // Don't assume mbs.queryNames returns a writable set.
+                names = Util.cloneSet(names);
+                names.addAll(mbeanMBS.queryNames(name, query));
+            }
         }
         return names;
     }
--- a/src/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -136,14 +136,14 @@
         new Hashtable<ObjectName,ClassLoader>(10);
 
     // from javax.management.loading.DefaultLoaderRepository
-    public final Class loadClass(String className)
+    public final Class<?> loadClass(String className)
         throws ClassNotFoundException {
         return  loadClass(loaders, className, null, null);
     }
 
 
     // from javax.management.loading.DefaultLoaderRepository
-    public final Class loadClassWithout(ClassLoader without, String className)
+    public final Class<?> loadClassWithout(ClassLoader without, String className)
             throws ClassNotFoundException {
         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
             MBEANSERVER_LOGGER.logp(Level.FINER,
@@ -167,7 +167,7 @@
     }
 
 
-    public final Class loadClassBefore(ClassLoader stop, String className)
+    public final Class<?> loadClassBefore(ClassLoader stop, String className)
             throws ClassNotFoundException {
         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
             MBEANSERVER_LOGGER.logp(Level.FINER,
@@ -187,10 +187,10 @@
     }
 
 
-    private Class loadClass(final LoaderEntry list[],
-                            final String className,
-                            final ClassLoader without,
-                            final ClassLoader stop)
+    private Class<?> loadClass(final LoaderEntry list[],
+                               final String className,
+                               final ClassLoader without,
+                               final ClassLoader stop)
             throws ClassNotFoundException {
         final int size = list.length;
         for(int i=0; i<size; i++) {
--- a/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java	Tue Nov 11 09:07:58 2008 +0000
@@ -68,12 +68,12 @@
         return method.getName();
     }
 
-    OpenType getOpenReturnType() {
+    OpenType<?> getOpenReturnType() {
         return returnMapping.getOpenType();
     }
 
-    OpenType[] getOpenParameterTypes() {
-        final OpenType[] types = new OpenType[paramMappings.length];
+    OpenType<?>[] getOpenParameterTypes() {
+        final OpenType<?>[] types = new OpenType<?>[paramMappings.length];
         for (int i = 0; i < paramMappings.length; i++)
             types[i] = paramMappings[i].getOpenType();
         return types;
--- a/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Tue Nov 11 09:07:58 2008 +0000
@@ -26,7 +26,8 @@
 package com.sun.jmx.mbeanserver;
 
 import static com.sun.jmx.mbeanserver.Util.*;
-import java.lang.annotation.ElementType;
+import static com.sun.jmx.mbeanserver.MXBeanIntrospector.typeName;
+
 import javax.management.openmbean.MXBeanMappingClass;
 
 import static javax.management.openmbean.SimpleType.*;
@@ -120,7 +121,7 @@
  */
 public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
     static abstract class NonNullMXBeanMapping extends MXBeanMapping {
-        NonNullMXBeanMapping(Type javaType, OpenType openType) {
+        NonNullMXBeanMapping(Type javaType, OpenType<?> openType) {
             super(javaType, openType);
         }
 
@@ -195,15 +196,15 @@
     static {
         /* Set up the mappings for Java types that map to SimpleType.  */
 
-        final OpenType[] simpleTypes = {
+        final OpenType<?>[] simpleTypes = {
             BIGDECIMAL, BIGINTEGER, BOOLEAN, BYTE, CHARACTER, DATE,
             DOUBLE, FLOAT, INTEGER, LONG, OBJECTNAME, SHORT, STRING,
             VOID,
         };
 
         for (int i = 0; i < simpleTypes.length; i++) {
-            final OpenType t = simpleTypes[i];
-            Class c;
+            final OpenType<?> t = simpleTypes[i];
+            Class<?> c;
             try {
                 c = Class.forName(t.getClassName(), false,
                                   ObjectName.class.getClassLoader());
@@ -224,7 +225,7 @@
                     if (primitiveType != void.class) {
                         final Class<?> primitiveArrayType =
                             Array.newInstance(primitiveType, 0).getClass();
-                        final OpenType primitiveArrayOpenType =
+                        final OpenType<?> primitiveArrayOpenType =
                             ArrayType.getPrimitiveArrayType(primitiveArrayType);
                         final MXBeanMapping primitiveArrayMapping =
                             new IdentityMapping(primitiveArrayType,
@@ -247,8 +248,10 @@
     public synchronized MXBeanMapping mappingForType(Type objType,
                                                      MXBeanMappingFactory factory)
             throws OpenDataException {
-        if (inProgress.containsKey(objType))
-            throw new OpenDataException("Recursive data structure");
+        if (inProgress.containsKey(objType)) {
+            throw new OpenDataException(
+                    "Recursive data structure, including " + typeName(objType));
+        }
 
         MXBeanMapping mapping;
 
@@ -259,6 +262,8 @@
         inProgress.put(objType, objType);
         try {
             mapping = makeMapping(objType, factory);
+        } catch (OpenDataException e) {
+            throw openDataException("Cannot convert type: " + typeName(objType), e);
         } finally {
             inProgress.remove(objType);
         }
@@ -285,13 +290,13 @@
             Type componentType =
                 ((GenericArrayType) objType).getGenericComponentType();
             return makeArrayOrCollectionMapping(objType, componentType, factory);
-        } else if (objType instanceof Class) {
+        } else if (objType instanceof Class<?>) {
             Class<?> objClass = (Class<?>) objType;
             if (objClass.isEnum()) {
                 // Huge hack to avoid compiler warnings here.  The ElementType
                 // parameter is ignored but allows us to obtain a type variable
                 // T that matches <T extends Enum<T>>.
-                return makeEnumMapping((Class) objClass, ElementType.class);
+                return makeEnumMapping((Class<?>) objClass, ElementType.class);
             } else if (objClass.isArray()) {
                 Type componentType = objClass.getComponentType();
                 return makeArrayOrCollectionMapping(objClass, componentType,
@@ -354,7 +359,7 @@
     }
 
     private static <T extends Enum<T>> MXBeanMapping
-            makeEnumMapping(Class enumClass, Class<T> fake) {
+            makeEnumMapping(Class<?> enumClass, Class<T> fake) {
         return new EnumMapping<T>(Util.<Class<T>>cast(enumClass));
     }
 
@@ -411,17 +416,17 @@
                            MXBeanMappingFactory factory)
             throws OpenDataException {
 
-        final String objTypeName = objType.toString();
+        final String objTypeName = typeName(objType);
         final MXBeanMapping keyMapping = factory.mappingForType(keyType, factory);
         final MXBeanMapping valueMapping = factory.mappingForType(valueType, factory);
-        final OpenType keyOpenType = keyMapping.getOpenType();
-        final OpenType valueOpenType = valueMapping.getOpenType();
+        final OpenType<?> keyOpenType = keyMapping.getOpenType();
+        final OpenType<?> valueOpenType = valueMapping.getOpenType();
         final CompositeType rowType =
             new CompositeType(objTypeName,
                               objTypeName,
                               keyValueArray,
                               keyValueArray,
-                              new OpenType[] {keyOpenType, valueOpenType});
+                              new OpenType<?>[] {keyOpenType, valueOpenType});
         final TabularType tabularType =
             new TabularType(objTypeName, objTypeName, rowType, keyArray);
         return new TabularMapping(objType, sortedMap, tabularType,
@@ -440,8 +445,8 @@
 
         final Type rawType = objType.getRawType();
 
-        if (rawType instanceof Class) {
-            Class c = (Class<?>) rawType;
+        if (rawType instanceof Class<?>) {
+            Class<?> c = (Class<?>) rawType;
             if (c == List.class || c == Set.class || c == SortedSet.class) {
                 Type[] actuals = objType.getActualTypeArguments();
                 assert(actuals.length == 1);
@@ -468,7 +473,7 @@
         return new MXBeanRefMapping(t);
     }
 
-    private MXBeanMapping makeCompositeMapping(Class c,
+    private MXBeanMapping makeCompositeMapping(Class<?> c,
                                                MXBeanMappingFactory factory)
             throws OpenDataException {
 
@@ -514,7 +519,7 @@
 
         final Method[] getters = new Method[nitems];
         final String[] itemNames = new String[nitems];
-        final OpenType[] openTypes = new OpenType[nitems];
+        final OpenType<?>[] openTypes = new OpenType<?>[nitems];
         int i = 0;
         for (Map.Entry<String,Method> entry : getterMap.entrySet()) {
             itemNames[i] = entry.getKey();
@@ -546,7 +551,7 @@
        can be directly represented by an ArrayType, and an int needs no mapping
        because reflection takes care of it.  */
     private static final class IdentityMapping extends NonNullMXBeanMapping {
-        IdentityMapping(Type targetType, OpenType openType) {
+        IdentityMapping(Type targetType, OpenType<?> openType) {
             super(targetType, openType);
         }
 
@@ -576,7 +581,7 @@
 
         @Override
         final Object toNonNullOpenValue(Object value) {
-            return ((Enum) value).name();
+            return ((Enum<?>) value).name();
         }
 
         @Override
@@ -595,7 +600,7 @@
 
     private static final class ArrayMapping extends NonNullMXBeanMapping {
         ArrayMapping(Type targetType,
-                     ArrayType openArrayType, Class openArrayClass,
+                     ArrayType<?> openArrayType, Class<?> openArrayClass,
                      MXBeanMapping elementMapping) {
             super(targetType, openArrayType);
             this.elementMapping = elementMapping;
@@ -623,7 +628,7 @@
             if (javaType instanceof GenericArrayType) {
                 componentType =
                     ((GenericArrayType) javaType).getGenericComponentType();
-            } else if (javaType instanceof Class &&
+            } else if (javaType instanceof Class<?> &&
                        ((Class<?>) javaType).isArray()) {
                 componentType = ((Class<?>) javaType).getComponentType();
             } else {
@@ -651,8 +656,8 @@
 
     private static final class CollectionMapping extends NonNullMXBeanMapping {
         CollectionMapping(Type targetType,
-                          ArrayType openArrayType,
-                          Class openArrayClass,
+                          ArrayType<?> openArrayType,
+                          Class<?> openArrayClass,
                           MXBeanMapping elementMapping) {
             super(targetType, openArrayType);
             this.elementMapping = elementMapping;
@@ -662,26 +667,28 @@
                and all Sets to TreeSet.  (TreeSet because it is a SortedSet,
                so works for both Set and SortedSet.)  */
             Type raw = ((ParameterizedType) targetType).getRawType();
-            Class c = (Class<?>) raw;
+            Class<?> c = (Class<?>) raw;
+            final Class<?> collC;
             if (c == List.class)
-                collectionClass = ArrayList.class;
+                collC = ArrayList.class;
             else if (c == Set.class)
-                collectionClass = HashSet.class;
+                collC = HashSet.class;
             else if (c == SortedSet.class)
-                collectionClass = TreeSet.class;
+                collC = TreeSet.class;
             else { // can't happen
                 assert(false);
-                collectionClass = null;
+                collC = null;
             }
+            collectionClass = Util.cast(collC);
         }
 
         @Override
         final Object toNonNullOpenValue(Object value)
                 throws OpenDataException {
-            final Collection valueCollection = (Collection) value;
-            if (valueCollection instanceof SortedSet) {
-                Comparator comparator =
-                    ((SortedSet) valueCollection).comparator();
+            final Collection<?> valueCollection = (Collection<?>) value;
+            if (valueCollection instanceof SortedSet<?>) {
+                Comparator<?> comparator =
+                    ((SortedSet<?>) valueCollection).comparator();
                 if (comparator != null) {
                     final String msg =
                         "Cannot convert SortedSet with non-null comparator: " +
@@ -725,7 +732,7 @@
             elementMapping.checkReconstructible();
         }
 
-        private final Class<? extends Collection> collectionClass;
+        private final Class<? extends Collection<?>> collectionClass;
         private final MXBeanMapping elementMapping;
     }
 
@@ -794,8 +801,8 @@
         @Override
         final Object toNonNullOpenValue(Object value) throws OpenDataException {
             final Map<Object, Object> valueMap = cast(value);
-            if (valueMap instanceof SortedMap) {
-                Comparator comparator = ((SortedMap) valueMap).comparator();
+            if (valueMap instanceof SortedMap<?,?>) {
+                Comparator<?> comparator = ((SortedMap<?,?>) valueMap).comparator();
                 if (comparator != null) {
                     final String msg =
                         "Cannot convert SortedMap with non-null comparator: " +
@@ -806,7 +813,7 @@
             final TabularType tabularType = (TabularType) getOpenType();
             final TabularData table = new TabularDataSupport(tabularType);
             final CompositeType rowType = tabularType.getRowType();
-            for (Map.Entry entry : valueMap.entrySet()) {
+            for (Map.Entry<Object, Object> entry : valueMap.entrySet()) {
                 final Object openKey = keyMapping.toOpenValue(entry.getKey());
                 final Object openValue = valueMapping.toOpenValue(entry.getValue());
                 final CompositeData row;
@@ -852,7 +859,7 @@
     }
 
     private final class CompositeMapping extends NonNullMXBeanMapping {
-        CompositeMapping(Class targetClass,
+        CompositeMapping(Class<?> targetClass,
                          CompositeType compositeType,
                          String[] itemNames,
                          Method[] getters,
@@ -901,7 +908,7 @@
             if (compositeBuilder != null)
                 return;
 
-            Class targetClass = (Class<?>) getJavaType();
+            Class<?> targetClass = (Class<?>) getJavaType();
             /* In this 2D array, each subarray is a set of builders where
                there is no point in consulting the ones after the first if
                the first refuses.  */
@@ -924,6 +931,7 @@
                concatenating each Builder's explanation of why it
                isn't applicable.  */
             final StringBuilder whyNots = new StringBuilder();
+            Throwable possibleCause = null;
         find:
             for (CompositeBuilder[] relatedBuilders : builders) {
                 for (int i = 0; i < relatedBuilders.length; i++) {
@@ -933,6 +941,9 @@
                         foundBuilder = builder;
                         break find;
                     }
+                    Throwable cause = builder.possibleCause();
+                    if (cause != null)
+                        possibleCause = cause;
                     if (whyNot.length() > 0) {
                         if (whyNots.length() > 0)
                             whyNots.append("; ");
@@ -943,10 +954,12 @@
                 }
             }
             if (foundBuilder == null) {
-                final String msg =
+                String msg =
                     "Do not know how to make a " + targetClass.getName() +
                     " from a CompositeData: " + whyNots;
-                throw new InvalidObjectException(msg);
+                if (possibleCause != null)
+                    msg += ". Remaining exceptions show a POSSIBLE cause.";
+                throw invalidObjectException(msg, possibleCause);
             }
             compositeBuilder = foundBuilder;
         }
@@ -973,7 +986,7 @@
 
     /** Converts from a CompositeData to an instance of the targetClass.  */
     private static abstract class CompositeBuilder {
-        CompositeBuilder(Class targetClass, String[] itemNames) {
+        CompositeBuilder(Class<?> targetClass, String[] itemNames) {
             this.targetClass = targetClass;
             this.itemNames = itemNames;
         }
@@ -994,6 +1007,16 @@
         abstract String applicable(Method[] getters)
                 throws InvalidObjectException;
 
+        /** If the subclass returns an explanation of why it is not applicable,
+            it can additionally indicate an exception with details.  This is
+            potentially confusing, because the real problem could be that one
+            of the other subclasses is supposed to be applicable but isn't.
+            But the advantage of less information loss probably outweighs the
+            disadvantage of possible confusion.  */
+        Throwable possibleCause() {
+            return null;
+        }
+
         abstract Object fromCompositeData(CompositeData cd,
                                           String[] itemNames,
                                           MXBeanMapping[] converters)
@@ -1008,7 +1031,7 @@
     private static final class CompositeBuilderViaFrom
             extends CompositeBuilder {
 
-        CompositeBuilderViaFrom(Class targetClass, String[] itemNames) {
+        CompositeBuilderViaFrom(Class<?> targetClass, String[] itemNames) {
             super(targetClass, itemNames);
         }
 
@@ -1018,8 +1041,7 @@
             Class<?> targetClass = getTargetClass();
             try {
                 Method fromMethod =
-                    targetClass.getMethod("from",
-                                          new Class[] {CompositeData.class});
+                    targetClass.getMethod("from", CompositeData.class);
 
                 if (!Modifier.isStatic(fromMethod.getModifiers())) {
                     final String msg =
@@ -1030,8 +1052,8 @@
                 if (fromMethod.getReturnType() != getTargetClass()) {
                     final String msg =
                         "Method from(CompositeData) returns " +
-                        fromMethod.getReturnType().getName() +
-                        " not " + targetClass.getName();
+                        typeName(fromMethod.getReturnType()) +
+                        " not " + typeName(targetClass);
                     throw new InvalidObjectException(msg);
                 }
 
@@ -1071,7 +1093,7 @@
         If all the getters are OK, then the "applicable" method will return
         an empty string and the other builders will be tried.  */
     private static class CompositeBuilderCheckGetters extends CompositeBuilder {
-        CompositeBuilderCheckGetters(Class targetClass, String[] itemNames,
+        CompositeBuilderCheckGetters(Class<?> targetClass, String[] itemNames,
                                      MXBeanMapping[] getterConverters) {
             super(targetClass, itemNames);
             this.getterConverters = getterConverters;
@@ -1082,6 +1104,7 @@
                 try {
                     getterConverters[i].checkReconstructible();
                 } catch (InvalidObjectException e) {
+                    possibleCause = e;
                     return "method " + getters[i].getName() + " returns type " +
                         "that cannot be mapped back from OpenData";
                 }
@@ -1089,6 +1112,11 @@
             return "";
         }
 
+        @Override
+        Throwable possibleCause() {
+            return possibleCause;
+        }
+
         final Object fromCompositeData(CompositeData cd,
                                        String[] itemNames,
                                        MXBeanMapping[] converters) {
@@ -1096,6 +1124,7 @@
         }
 
         private final MXBeanMapping[] getterConverters;
+        private Throwable possibleCause;
     }
 
     /** Builder for when the target class has a setter for every getter. */
@@ -1115,7 +1144,7 @@
             Method[] setters = new Method[getters.length];
             for (int i = 0; i < getters.length; i++) {
                 Method getter = getters[i];
-                Class returnType = getter.getReturnType();
+                Class<?> returnType = getter.getReturnType();
                 String name = propertyName(getter);
                 String setterName = "set" + name;
                 Method setter;
@@ -1163,7 +1192,7 @@
     private static final class CompositeBuilderViaConstructor
             extends CompositeBuilder {
 
-        CompositeBuilderViaConstructor(Class targetClass, String[] itemNames) {
+        CompositeBuilderViaConstructor(Class<?> targetClass, String[] itemNames) {
             super(targetClass, itemNames);
         }
 
@@ -1171,7 +1200,7 @@
 
             final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class;
 
-            Class targetClass = getTargetClass();
+            Class<?> targetClass = getTargetClass();
             Constructor<?>[] constrs = targetClass.getConstructors();
 
             // Applicable if and only if there are any annotated constructors
@@ -1226,10 +1255,16 @@
                 for (int i = 0; i < propertyNames.length; i++) {
                     String propertyName = propertyNames[i];
                     if (!getterMap.containsKey(propertyName)) {
-                        final String msg =
+                        String msg =
                             "@ConstructorProperties includes name " + propertyName +
-                            " which does not correspond to a property: " +
-                            constr;
+                            " which does not correspond to a property";
+                        for (String getterName : getterMap.keySet()) {
+                            if (getterName.equalsIgnoreCase(propertyName)) {
+                                msg += " (differs only in case from property " +
+                                        getterName + ")";
+                            }
+                        }
+                        msg += ": " + constr;
                         throw new InvalidObjectException(msg);
                     }
                     int getterIndex = getterMap.get(propertyName);
@@ -1384,12 +1419,12 @@
     private static final class CompositeBuilderViaProxy
             extends CompositeBuilder {
 
-        CompositeBuilderViaProxy(Class targetClass, String[] itemNames) {
+        CompositeBuilderViaProxy(Class<?> targetClass, String[] itemNames) {
             super(targetClass, itemNames);
         }
 
         String applicable(Method[] getters) {
-            Class targetClass = getTargetClass();
+            Class<?> targetClass = getTargetClass();
             if (!targetClass.isInterface())
                 return "not an interface";
             Set<Method> methods =
@@ -1401,7 +1436,7 @@
             String bad = null;
             for (Method m : methods) {
                 String mname = m.getName();
-                Class[] mparams = m.getParameterTypes();
+                Class<?>[] mparams = m.getParameterTypes();
                 try {
                     Method om = Object.class.getMethod(mname, mparams);
                     if (!Modifier.isPublic(om.getModifiers()))
@@ -1422,10 +1457,10 @@
         final Object fromCompositeData(CompositeData cd,
                                        String[] itemNames,
                                        MXBeanMapping[] converters) {
-            final Class targetClass = getTargetClass();
+            final Class<?> targetClass = getTargetClass();
             return
                 Proxy.newProxyInstance(targetClass.getClassLoader(),
-                                       new Class[] {targetClass},
+                                       new Class<?>[] {targetClass},
                                        new CompositeDataInvocationHandler(cd));
         }
     }
@@ -1447,9 +1482,9 @@
         return openDataException(cause.getMessage(), cause);
     }
 
-    static void mustBeComparable(Class collection, Type element)
+    static void mustBeComparable(Class<?> collection, Type element)
             throws OpenDataException {
-        if (!(element instanceof Class)
+        if (!(element instanceof Class<?>)
             || !Comparable.class.isAssignableFrom((Class<?>) element)) {
             final String msg =
                 "Parameter class " + element + " of " +
--- a/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Tue Nov 11 09:07:58 2008 +0000
@@ -115,7 +115,7 @@
      *         Dynamic MBeans, <code>false</code> otherwise.
      *
      **/
-    public static final boolean isDynamic(final Class c) {
+    public static final boolean isDynamic(final Class<?> c) {
         // Check if the MBean implements the DynamicMBean interface
         return javax.management.DynamicMBean.class.isAssignableFrom(c);
     }
@@ -134,7 +134,7 @@
      *            MBeanServer.
      *
      **/
-    public static void testCreation(Class c)
+    public static void testCreation(Class<?> c)
         throws NotCompliantMBeanException {
         // Check if the class is a concrete class
         final int mods = c.getModifiers();
@@ -143,7 +143,7 @@
         }
 
         // Check if the MBean has a public constructor
-        final Constructor[] consList = c.getConstructors();
+        final Constructor<?>[] consList = c.getConstructors();
         if (consList.length == 0) {
             throw new NotCompliantMBeanException("MBean class must have public constructor");
         }
@@ -253,7 +253,7 @@
      * @exception NotCompliantMBeanException The specified class is not a
      *            JMX compliant MBean
      */
-    public static MBeanInfo testCompliance(Class baseClass)
+    public static MBeanInfo testCompliance(Class<?> baseClass)
         throws NotCompliantMBeanException {
 
         // ------------------------------
@@ -267,7 +267,7 @@
         return testCompliance(baseClass, null);
     }
 
-    public static void testComplianceMXBeanInterface(Class interfaceClass,
+    public static void testComplianceMXBeanInterface(Class<?> interfaceClass,
                                                      MXBeanMappingFactory factory)
             throws NotCompliantMBeanException {
         MXBeanIntrospector.getInstance(factory).getAnalyzer(interfaceClass);
@@ -596,10 +596,10 @@
                 ss[i] = (String) annotationToField(xx[i]);
             return ss;
         }
-        if (x instanceof Class)
+        if (x instanceof Class<?>)
             return ((Class<?>) x).getName();
-        if (x instanceof Enum)
-            return ((Enum) x).name();
+        if (x instanceof Enum<?>)
+            return ((Enum<?>) x).name();
         // The only other possibility is that the value is another
         // annotation, or that the language has evolved since this code
         // was written.  We don't allow for either of those currently.
--- a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java	Tue Nov 11 09:07:58 2008 +0000
@@ -33,6 +33,7 @@
 import java.security.Permission;
 import java.security.PrivilegedExceptionAction;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
 import java.util.logging.Level;
 
@@ -121,7 +122,7 @@
      *     {@link javax.management.MBeanServerFactory#newMBeanServer(java.lang.String)}
      *     instead.
      *     <p>
-     *     By default, {@link MBeanServerInterceptor} are disabled. Use
+     *     By default, interceptors are disabled. Use
      *     {@link #JmxMBeanServer(java.lang.String,javax.management.MBeanServer,javax.management.MBeanServerDelegate,boolean)} to enable them.
      * </ul>
      * @param domain The default domain name used by this MBeanServer.
@@ -238,7 +239,7 @@
         this.mBeanServerDelegateObject = delegate;
         this.outerShell   = outer;
 
-        final Repository repository = new Repository(domain,fairLock);
+        final Repository repository = new Repository(domain);
         this.mbsInterceptor =
             new NamespaceDispatchInterceptor(outer, delegate, instantiator,
                                               repository);
@@ -1144,7 +1145,7 @@
         // This call requires MBeanPermission 'getClassLoaderRepository'
         final ClassLoaderRepository clr = getClassLoaderRepository();
 
-        Class theClass;
+        Class<?> theClass;
         try {
             if (clr == null) throw new ClassNotFoundException(className);
             theClass = clr.loadClass(className);
@@ -1457,23 +1458,22 @@
      */
     private AttributeList cloneAttributeList(AttributeList list) {
         if (list != null) {
+            List<Attribute> alist = list.asList();
             if (!list.getClass().equals(AttributeList.class)) {
                 // Create new attribute list
                 //
-                AttributeList newList = new AttributeList(list.size());
+                AttributeList newList = new AttributeList(alist.size());
 
                 // Iterate through list and replace non JMX attributes
                 //
-                for (Iterator i = list.iterator(); i.hasNext(); ) {
-                    Attribute attribute = (Attribute) i.next();
+                for (Attribute attribute : alist)
                     newList.add(cloneAttribute(attribute));
-                }
                 return newList;
             } else {
                 // Iterate through list and replace non JMX attributes
                 //
-                for (int i = 0; i < list.size(); i++) {
-                    Attribute attribute = (Attribute) list.get(i);
+                for (int i = 0; i < alist.size(); i++) {
+                    Attribute attribute = alist.get(i);
                     if (!attribute.getClass().equals(Attribute.class)) {
                         list.set(i, cloneAttribute(attribute));
                     }
--- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java	Tue Nov 11 09:07:58 2008 +0000
@@ -70,7 +70,7 @@
      * instantiate an MBean of this class in the MBeanServer.
      * e.g. it must have a public constructor, be a concrete class...
      */
-    public void testCreation(Class c) throws NotCompliantMBeanException {
+    public void testCreation(Class<?> c) throws NotCompliantMBeanException {
         Introspector.testCreation(c);
     }
 
@@ -78,10 +78,10 @@
      * Loads the class with the specified name using this object's
      * Default Loader Repository.
      **/
-    public Class findClassWithDefaultLoaderRepository(String className)
+    public Class<?> findClassWithDefaultLoaderRepository(String className)
         throws ReflectionException {
 
-        Class theClass;
+        Class<?> theClass;
         if (className == null) {
             throw new RuntimeOperationsException(new
                 IllegalArgumentException("The class name cannot be null"),
@@ -105,7 +105,7 @@
      * Gets the class for the specified class name using the MBean
      * Interceptor's classloader
      */
-    public Class findClass(String className, ClassLoader loader)
+    public Class<?> findClass(String className, ClassLoader loader)
         throws ReflectionException {
 
         return loadClass(className,loader);
@@ -115,7 +115,7 @@
      * Gets the class for the specified class name using the specified
      * class loader
      */
-    public Class findClass(String className, ObjectName aLoader)
+    public Class<?> findClass(String className, ObjectName aLoader)
         throws ReflectionException, InstanceNotFoundException  {
 
         if (aLoader == null)
@@ -140,14 +140,14 @@
      * Return an array of Class corresponding to the given signature, using
      * the specified class loader.
      */
-    public Class[] findSignatureClasses(String signature[],
-                                        ClassLoader loader)
-        throws  ReflectionException {
+    public Class<?>[] findSignatureClasses(String signature[],
+                                           ClassLoader loader)
+        throws ReflectionException {
 
         if (signature == null) return null;
         final ClassLoader aLoader = loader;
         final int length= signature.length;
-        final Class tab[]=new Class[length];
+        final Class<?> tab[]=new Class<?>[length];
 
         if (length == 0) return tab;
         try {
@@ -156,7 +156,7 @@
                 // forth)
                 //
 
-                final Class primCla = primitiveClasses.get(signature[i]);
+                final Class<?> primCla = primitiveClasses.get(signature[i]);
                 if (primCla != null) {
                     tab[i] = primCla;
                     continue;
@@ -203,14 +203,14 @@
      * Instantiates an object given its class, using its empty constructor.
      * The call returns a reference to the newly created object.
      */
-    public Object instantiate(Class theClass)
+    public Object instantiate(Class<?> theClass)
         throws ReflectionException, MBeanException {
         Object moi;
 
 
         // ------------------------------
         // ------------------------------
-        Constructor cons = findConstructor(theClass, null);
+        Constructor<?> cons = findConstructor(theClass, null);
         if (cons == null) {
             throw new ReflectionException(new
                 NoSuchMethodException("No such constructor"));
@@ -257,14 +257,14 @@
      * signature of its constructor The call returns a reference to
      * the newly created object.
      */
-    public Object instantiate(Class theClass, Object params[],
+    public Object instantiate(Class<?> theClass, Object params[],
                               String signature[], ClassLoader loader)
         throws ReflectionException, MBeanException {
         // Instantiate the new object
 
         // ------------------------------
         // ------------------------------
-        final Class[] tab;
+        final Class<?>[] tab;
         Object moi;
         try {
             // Build the signature of the method
@@ -283,7 +283,7 @@
         }
 
         // Query the metadata service to get the right constructor
-        Constructor cons = findConstructor(theClass, tab);
+        Constructor<?> cons = findConstructor(theClass, tab);
 
         if (cons == null) {
             throw new ReflectionException(new
@@ -407,7 +407,7 @@
             throw new  RuntimeOperationsException(new
              IllegalArgumentException(), "Null className passed in parameter");
         }
-        Class theClass;
+        Class<?> theClass;
         if (loaderName == null) {
             // Load the class using the agent class loader
             theClass = findClass(className, loader);
@@ -547,7 +547,7 @@
         throws ReflectionException,
         MBeanException {
 
-        Class theClass = findClassWithDefaultLoaderRepository(className);
+        Class<?> theClass = findClassWithDefaultLoaderRepository(className);
         return instantiate(theClass, params, signature, loader);
     }
 
@@ -595,7 +595,7 @@
 
         // ------------------------------
         // ------------------------------
-        Class theClass;
+        Class<?> theClass;
 
         if (loaderName == null) {
             theClass = findClass(className, loader);
@@ -617,10 +617,10 @@
      * Load a class with the specified loader, or with this object
      * class loader if the specified loader is null.
      **/
-    static Class loadClass(String className, ClassLoader loader)
+    static Class<?> loadClass(String className, ClassLoader loader)
         throws ReflectionException {
 
-        Class theClass;
+        Class<?> theClass;
         if (className == null) {
             throw new RuntimeOperationsException(new
                 IllegalArgumentException("The class name cannot be null"),
@@ -647,15 +647,15 @@
      * Load the classes specified in the signature with the given loader,
      * or with this object class loader.
      **/
-    static Class[] loadSignatureClasses(String signature[],
-                                        ClassLoader loader)
+    static Class<?>[] loadSignatureClasses(String signature[],
+                                           ClassLoader loader)
         throws  ReflectionException {
 
         if (signature == null) return null;
         final ClassLoader aLoader =
            (loader==null?MBeanInstantiator.class.getClassLoader():loader);
         final int length= signature.length;
-        final Class tab[]=new Class[length];
+        final Class<?> tab[]=new Class<?>[length];
 
         if (length == 0) return tab;
         try {
@@ -664,7 +664,7 @@
                 // forth)
                 //
 
-                final Class primCla = primitiveClasses.get(signature[i]);
+                final Class<?> primCla = primitiveClasses.get(signature[i]);
                 if (primCla != null) {
                     tab[i] = primCla;
                     continue;
@@ -710,9 +710,9 @@
 
     private static final Map<String, Class<?>> primitiveClasses = Util.newMap();
     static {
-        for (Class<?> c : new Class[] {byte.class, short.class, int.class,
-                                       long.class, float.class, double.class,
-                                       char.class, boolean.class})
+        for (Class<?> c : new Class<?>[] {byte.class, short.class, int.class,
+                                          long.class, float.class, double.class,
+                                          char.class, boolean.class})
             primitiveClasses.put(c.getName(), c);
     }
 }
--- a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java	Tue Nov 11 09:07:58 2008 +0000
@@ -160,7 +160,7 @@
             // matched to the corresponding Java type, except when that
             // type is primitive.
             Type t = m.getGenericParameterTypes()[paramNo];
-            return (!(t instanceof Class) || !((Class) t).isPrimitive());
+            return (!(t instanceof Class<?>) || !((Class<?>) t).isPrimitive());
         } else {
             Object v;
             try {
@@ -354,7 +354,7 @@
         }
     }
 
-    private static Descriptor typeDescriptor(OpenType openType,
+    private static Descriptor typeDescriptor(OpenType<?> openType,
                                              Type originalType) {
         return new ImmutableDescriptor(
             new String[] {"openType",
@@ -380,37 +380,37 @@
         if (type instanceof GenericArrayType) {
             return canUseOpenInfo(
                 ((GenericArrayType) type).getGenericComponentType());
-        } else if (type instanceof Class && ((Class<?>) type).isArray()) {
+        } else if (type instanceof Class<?> && ((Class<?>) type).isArray()) {
             return canUseOpenInfo(
                 ((Class<?>) type).getComponentType());
         }
-        return (!(type instanceof Class && ((Class<?>) type).isPrimitive()));
+        return (!(type instanceof Class<?> && ((Class<?>) type).isPrimitive()));
     }
 
     private static String originalTypeString(Type type) {
-        if (type instanceof Class)
-            return ((Class) type).getName();
+        if (type instanceof Class<?>)
+            return ((Class<?>) type).getName();
         else
-            return genericTypeString(type);
+            return typeName(type);
     }
 
-    private static String genericTypeString(Type type) {
+    static String typeName(Type type) {
         if (type instanceof Class<?>) {
             Class<?> c = (Class<?>) type;
             if (c.isArray())
-                return genericTypeString(c.getComponentType()) + "[]";
+                return typeName(c.getComponentType()) + "[]";
             else
                 return c.getName();
         } else if (type instanceof GenericArrayType) {
             GenericArrayType gat = (GenericArrayType) type;
-            return genericTypeString(gat.getGenericComponentType()) + "[]";
+            return typeName(gat.getGenericComponentType()) + "[]";
         } else if (type instanceof ParameterizedType) {
             ParameterizedType pt = (ParameterizedType) type;
             StringBuilder sb = new StringBuilder();
-            sb.append(genericTypeString(pt.getRawType())).append("<");
+            sb.append(typeName(pt.getRawType())).append("<");
             String sep = "";
             for (Type t : pt.getActualTypeArguments()) {
-                sb.append(sep).append(genericTypeString(t));
+                sb.append(sep).append(typeName(t));
                 sep = ", ";
             }
             return sb.append(">").toString();
--- a/src/share/classes/com/sun/jmx/mbeanserver/ObjectInputStreamWithLoader.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/ObjectInputStreamWithLoader.java	Tue Nov 11 09:07:58 2008 +0000
@@ -54,7 +54,8 @@
         this.loader = theLoader;
     }
 
-    protected Class resolveClass(ObjectStreamClass aClass)
+    @Override
+    protected Class<?> resolveClass(ObjectStreamClass aClass)
             throws IOException, ClassNotFoundException {
         if (loader == null) {
             return super.resolveClass(aClass);
--- a/src/share/classes/com/sun/jmx/mbeanserver/SecureClassLoaderRepository.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/SecureClassLoaderRepository.java	Tue Nov 11 09:07:58 2008 +0000
@@ -47,16 +47,16 @@
     public SecureClassLoaderRepository(ClassLoaderRepository clr) {
         this.clr=clr;
     }
-    public final Class loadClass(String className)
+    public final Class<?> loadClass(String className)
         throws ClassNotFoundException {
         return clr.loadClass(className);
     }
-    public final Class loadClassWithout(ClassLoader loader,
+    public final Class<?> loadClassWithout(ClassLoader loader,
                                   String className)
         throws ClassNotFoundException {
         return clr.loadClassWithout(loader,className);
     }
-    public final Class loadClassBefore(ClassLoader loader,
+    public final Class<?> loadClassBefore(ClassLoader loader,
                                  String className)
         throws ClassNotFoundException {
         return clr.loadClassBefore(loader,className);
--- a/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Tue Nov 11 09:07:58 2008 +0000
@@ -669,7 +669,7 @@
     }
 
     public static <T> Set<T> cloneSet(Set<T> set) {
-        if (set instanceof SortedSet) {
+        if (set instanceof SortedSet<?>) {
             @SuppressWarnings("unchecked")
             SortedSet<T> sset = (SortedSet<T>) set;
             set = new TreeSet<T>(sset.comparator());
@@ -680,7 +680,7 @@
     }
 
     public static <T> Set<T> equivalentEmptySet(Set<T> set) {
-        if (set instanceof SortedSet) {
+        if (set instanceof SortedSet<?>) {
             @SuppressWarnings("unchecked")
             SortedSet<T> sset = (SortedSet<T>) set;
             set = new TreeSet<T>(sset.comparator());
--- a/src/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java	Tue Nov 11 09:07:58 2008 +0000
@@ -118,9 +118,9 @@
         public boolean equals(Object o) {
             if (this == o)
                 return true;
-            if (!(o instanceof IdentityWeakReference))
+            if (!(o instanceof IdentityWeakReference<?>))
                 return false;
-            IdentityWeakReference wr = (IdentityWeakReference) o;
+            IdentityWeakReference<?> wr = (IdentityWeakReference<?>) o;
             Object got = get();
             return (got != null && got == wr.get());
         }
--- a/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java	Tue Nov 11 08:59:43 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package com.sun.jmx.namespace;
-
-import com.sun.jmx.defaults.JmxProperties;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.event.EventClient;
-import javax.management.event.EventClientDelegateMBean;
-import javax.management.namespace.JMXNamespace;
-import javax.management.namespace.JMXNamespaces;
-import javax.management.remote.JMXAddressable;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXServiceURL;
-import javax.security.auth.Subject;
-
-/**
- * A collection of methods that provide JMXConnector wrappers for
- * JMXRemoteNamepaces underlying connectors.
- * <p><b>
- * This API is a Sun internal API and is subject to changes without notice.
- * </b></p>
- * @since 1.7
- */
-public final class JMXNamespaceUtils {
-
-    /**
-     * A logger for this class.
-     **/
-    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
-
-
-    private static <K,V> Map<K,V> newWeakHashMap() {
-        return new WeakHashMap<K,V>();
-    }
-
-    /** There are no instances of this class */
-    private JMXNamespaceUtils() {
-    }
-
-    // returns un unmodifiable view of a map.
-    public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) {
-        if (aMap == null || aMap.isEmpty())
-            return Collections.emptyMap();
-        return Collections.unmodifiableMap(aMap);
-    }
-
-
-    /**
-     * A base class that helps writing JMXConnectors that return
-     * MBeanServerConnection wrappers.
-     * This base class wraps an inner JMXConnector (the source), and preserve
-     * its caching policy. If a connection is cached in the source, its wrapper
-     * will be cached in this connector too.
-     * Author's note: rewriting this with java.lang.reflect.Proxy could be
-     * envisaged. It would avoid the combinatory sub-classing introduced by
-     * JMXAddressable.
-     * <p>
-     * Note: all the standard JMXConnector implementations are serializable.
-     *       This implementation here is not. Should it be?
-     *       I believe it must not be serializable unless it becomes
-     *       part of a public API (either standard or officially exposed
-     *       and supported in a documented com.sun package)
-     **/
-     static class JMXCachingConnector
-            implements JMXConnector  {
-
-        // private static final long serialVersionUID = -2279076110599707875L;
-
-        final JMXConnector source;
-
-        // if this object is made serializable, then the variable below
-        // needs to become volatile transient and be lazyly-created...
-        private final
-                Map<MBeanServerConnection,MBeanServerConnection> connectionMap;
-
-
-        public JMXCachingConnector(JMXConnector source) {
-            this.source = checkNonNull(source, "source");
-            connectionMap = newWeakHashMap();
-        }
-
-        private MBeanServerConnection
-                getCached(MBeanServerConnection inner) {
-            return connectionMap.get(inner);
-        }
-
-        private MBeanServerConnection putCached(final MBeanServerConnection inner,
-                final MBeanServerConnection wrapper) {
-            if (inner == wrapper) return wrapper;
-            synchronized (this) {
-                final MBeanServerConnection concurrent =
-                        connectionMap.get(inner);
-                if (concurrent != null) return concurrent;
-                connectionMap.put(inner,wrapper);
-            }
-            return wrapper;
-        }
-
-        public void addConnectionNotificationListener(NotificationListener
-                listener, NotificationFilter filter, Object handback) {
-            source.addConnectionNotificationListener(listener,filter,handback);
-        }
-
-        public void close() throws IOException {
-            source.close();
-        }
-
-        public void connect() throws IOException {
-            source.connect();
-        }
-
-        public void connect(Map<String,?> env) throws IOException {
-            source.connect(env);
-        }
-
-        public String getConnectionId() throws IOException {
-            return source.getConnectionId();
-        }
-
-        /**
-         * Preserve caching policy of the underlying connector.
-         **/
-        public MBeanServerConnection
-                getMBeanServerConnection() throws IOException {
-            final MBeanServerConnection inner =
-                    source.getMBeanServerConnection();
-            final MBeanServerConnection cached = getCached(inner);
-            if (cached != null) return cached;
-            final MBeanServerConnection wrapper = wrap(inner);
-            return putCached(inner,wrapper);
-        }
-
-        public MBeanServerConnection
-                getMBeanServerConnection(Subject delegationSubject)
-                throws IOException {
-            final MBeanServerConnection wrapped =
-                    source.getMBeanServerConnection(delegationSubject);
-            synchronized (this) {
-                final MBeanServerConnection cached = getCached(wrapped);
-                if (cached != null) return cached;
-                final MBeanServerConnection wrapper =
-                    wrapWithSubject(wrapped,delegationSubject);
-                return putCached(wrapped,wrapper);
-            }
-        }
-
-        public void removeConnectionNotificationListener(
-                NotificationListener listener)
-                throws ListenerNotFoundException {
-            source.removeConnectionNotificationListener(listener);
-        }
-
-        public void removeConnectionNotificationListener(
-                NotificationListener l, NotificationFilter f,
-                Object handback) throws ListenerNotFoundException {
-            source.removeConnectionNotificationListener(l,f,handback);
-        }
-
-        /**
-         * This is the method that subclass will redefine. This method
-         * is called by {@code this.getMBeanServerConnection()}.
-         * {@code inner} is the connection returned by
-         * {@code source.getMBeanServerConnection()}.
-         **/
-        protected MBeanServerConnection wrap(MBeanServerConnection inner)
-            throws IOException {
-            return inner;
-        }
-
-        /**
-         * Subclass may also want to redefine this method.
-         * By default it calls wrap(inner). This method
-         * is called by {@code this.getMBeanServerConnection(Subject)}.
-         * {@code inner} is the connection returned by
-         * {@code source.getMBeanServerConnection(Subject)}.
-         **/
-        protected MBeanServerConnection wrapWithSubject(
-                MBeanServerConnection inner, Subject delegationSubject)
-            throws IOException {
-                return wrap(inner);
-        }
-
-        @Override
-        public String toString() {
-            if (source instanceof JMXAddressable) {
-                final JMXServiceURL address =
-                        ((JMXAddressable)source).getAddress();
-                if (address != null)
-                    return address.toString();
-            }
-            return source.toString();
-        }
-
-    }
-
-
-    /**
-     * The name space connector can do 'cd'
-     **/
-    static class JMXNamespaceConnector extends JMXCachingConnector {
-
-        // private static final long serialVersionUID = -4813611540843020867L;
-
-        private final String toDir;
-        private final boolean closeable;
-
-        public JMXNamespaceConnector(JMXConnector source, String toDir,
-                boolean closeable) {
-            super(source);
-            this.toDir = toDir;
-            this.closeable = closeable;
-        }
-
-        @Override
-        public void close() throws IOException {
-            if (!closeable)
-                throw new UnsupportedOperationException("close");
-            else super.close();
-        }
-
-        @Override
-        protected MBeanServerConnection wrap(MBeanServerConnection wrapped)
-               throws IOException {
-            if (LOG.isLoggable(Level.FINER))
-                LOG.finer("Creating name space proxy connection for source: "+
-                        "namespace="+toDir);
-            return JMXNamespaces.narrowToNamespace(wrapped,toDir);
-        }
-
-        @Override
-        public String toString() {
-            return "JMXNamespaces.narrowToNamespace("+
-                    super.toString()+
-                    ", \""+toDir+"\")";
-        }
-
-    }
-
-    static class JMXEventConnector extends JMXCachingConnector {
-
-        // private static final long serialVersionUID = 4742659236340242785L;
-
-        JMXEventConnector(JMXConnector wrapped) {
-            super(wrapped);
-        }
-
-        @Override
-        protected MBeanServerConnection wrap(MBeanServerConnection inner)
-                throws IOException {
-            return EventClient.getEventClientConnection(inner);
-        }
-
-
-        @Override
-        public String toString() {
-            return "EventClient.withEventClient("+super.toString()+")";
-        }
-    }
-
-    static class JMXAddressableEventConnector extends JMXEventConnector
-        implements JMXAddressable {
-
-        // private static final long serialVersionUID = -9128520234812124712L;
-
-        JMXAddressableEventConnector(JMXConnector wrapped) {
-            super(wrapped);
-        }
-
-        public JMXServiceURL getAddress() {
-            return ((JMXAddressable)source).getAddress();
-        }
-    }
-
-    /**
-     * Creates a connector whose MBeamServerConnection will point to the
-     * given sub name space inside the source connector.
-     * @see JMXNamespace
-     **/
-    public static JMXConnector cd(final JMXConnector source,
-                                  final String toNamespace,
-                                  final boolean closeable)
-        throws IOException {
-
-        checkNonNull(source, "JMXConnector");
-
-        if (toNamespace == null || toNamespace.equals(""))
-            return source;
-
-        return new JMXNamespaceConnector(source,toNamespace,closeable);
-    }
-
-
-    /**
-     * Returns a JMX Connector that will use an {@link EventClient}
-     * to subscribe for notifications. If the server doesn't have
-     * an {@link EventClientDelegateMBean}, then the connector will
-     * use the legacy notification mechanism instead.
-     *
-     * @param source The underlying JMX Connector wrapped by the returned
-     *               connector.
-     * @return A JMX Connector that will uses an {@link EventClient}, if
-     *         available.
-     * @see EventClient#getEventClientConnection(MBeanServerConnection)
-     */
-    public static JMXConnector withEventClient(final JMXConnector source) {
-        checkNonNull(source, "JMXConnector");
-        if (source instanceof JMXAddressable)
-            return new JMXAddressableEventConnector(source);
-        else
-            return new JMXEventConnector(source);
-    }
-
-    public static <T> T checkNonNull(T parameter, String name) {
-        if (parameter == null)
-            throw new IllegalArgumentException(name+" must not be null");
-         return parameter;
-    }
-
-
-}
--- a/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java	Tue Nov 11 09:07:58 2008 +0000
@@ -49,11 +49,6 @@
     final int tlen;
     final boolean identity;
 
-
-    public ObjectNameRouter(String targetDirName) {
-        this(targetDirName,null);
-    }
-
     /** Creates a new instance of ObjectNameRouter */
     public ObjectNameRouter(final String remove, final String add) {
         this.targetPrefix = (remove==null?"":remove);
@@ -186,6 +181,4 @@
             b.append(NAMESPACE_SEPARATOR);
         return b.toString();
     }
-
-
 }
--- a/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java	Tue Nov 11 09:07:58 2008 +0000
@@ -31,7 +31,6 @@
 import java.util.logging.Logger;
 
 import javax.management.MBeanServerConnection;
-import javax.management.namespace.JMXNamespaces;
 
 
 /**
@@ -61,18 +60,10 @@
      * Creates a new instance of RoutingConnectionProxy
      */
     public RoutingConnectionProxy(MBeanServerConnection source,
-                               String sourceDir) {
-        this(source,sourceDir,"",false);
-    }
-
-    /**
-     * Creates a new instance of RoutingConnectionProxy
-     */
-    public RoutingConnectionProxy(MBeanServerConnection source,
                                String sourceDir,
                                String targetDir,
-                               boolean forwardsContext) {
-        super(source,sourceDir,targetDir,forwardsContext);
+                               boolean probe) {
+        super(source, sourceDir, targetDir, probe);
 
         if (LOG.isLoggable(Level.FINER))
             LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
@@ -85,15 +76,13 @@
         final String sourceNs = getSourceNamespace();
         String wrapped = String.valueOf(source());
         if ("".equals(targetNs)) {
-            if (forwardsContext)
-                wrapped = "ClientContext.withDynamicContext("+wrapped+")";
             return "JMXNamespaces.narrowToNamespace("+
                     wrapped+", \""+
                     sourceNs+"\")";
         }
         return this.getClass().getSimpleName()+"("+wrapped+", \""+
                sourceNs+"\", \""+
-               targetNs+"\", "+forwardsContext+")";
+               targetNs+"\")";
     }
 
     static final RoutingProxyFactory
@@ -102,22 +91,16 @@
         <MBeanServerConnection,RoutingConnectionProxy>() {
 
         public RoutingConnectionProxy newInstance(MBeanServerConnection source,
-                String sourcePath, String targetPath,
-                boolean forwardsContext) {
+                String sourcePath, String targetPath, boolean probe) {
             return new RoutingConnectionProxy(source,sourcePath,
-                    targetPath,forwardsContext);
-        }
-
-        public RoutingConnectionProxy newInstance(
-                MBeanServerConnection source, String sourcePath) {
-            return new RoutingConnectionProxy(source,sourcePath);
+                    targetPath, probe);
         }
     };
 
-    public static MBeanServerConnection cd(MBeanServerConnection source,
-            String sourcePath) {
+    public static MBeanServerConnection cd(
+            MBeanServerConnection source, String sourcePath, boolean probe) {
         return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY,
-                source, sourcePath);
+                source, sourcePath, probe);
     }
 
 }
--- a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java	Tue Nov 11 09:07:58 2008 +0000
@@ -30,6 +30,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.management.InstanceNotFoundException;
 import javax.management.MBeanException;
 import javax.management.MBeanRegistrationException;
 
@@ -90,17 +91,9 @@
 //     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
+// factory method that can concatenate namespace paths in order to
 // return a single RoutingProxy - rather than wrapping a RoutingProxy inside
 // another RoutingProxy. See RoutingConnectionProxy.cd and
 // RoutingServerProxy.cd
@@ -146,25 +139,27 @@
     private final T source;
 
     // The name space we're narrowing to (usually some name space in
-    // the source MBeanServerConnection
+    // the source MBeanServerConnection), e.g. "a" for the namespace
+    // "a//".  This is empty in the case of ClientContext described above.
     private final String                sourceNs;
 
-    // The name space we pretend to be mounted in (usually "")
+    // The name space we pretend to be mounted in.  This is empty except
+    // in the case of ClientContext described above (where it will be
+    // something like "jmx.context//foo=bar".
     private final String                targetNs;
 
     // The name of the JMXNamespace that handles the source name space
     private final ObjectName            handlerName;
     private final ObjectNameRouter      router;
-    final boolean forwardsContext;
     private volatile String             defaultDomain = null;
 
     /**
      * Creates a new instance of RoutingProxy
      */
     protected RoutingProxy(T source,
-                          String sourceNs,
-                          String targetNs,
-                          boolean forwardsContext) {
+                           String sourceNs,
+                           String targetNs,
+                           boolean probe) {
         if (source == null) throw new IllegalArgumentException("null");
         this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs);
 
@@ -177,13 +172,17 @@
             // System.err.println("sourceNs: "+sourceNs);
             this.handlerName =
                 JMXNamespaces.getNamespaceObjectName(this.sourceNs);
-            try {
-                // System.err.println("handlerName: "+handlerName);
-                if (!source.isRegistered(handlerName))
-                    throw new IllegalArgumentException(sourceNs +
-                            ": no such name space");
-            } catch (IOException x) {
-                throw new IllegalArgumentException("source stale: "+x,x);
+            if (probe) {
+                try {
+                    if (!source.isRegistered(handlerName)) {
+                        InstanceNotFoundException infe =
+                                new InstanceNotFoundException(handlerName);
+                        throw new IllegalArgumentException(sourceNs +
+                                ": no such name space", infe);
+                    }
+                } catch (IOException x) {
+                    throw new IllegalArgumentException("source stale: "+x,x);
+                }
             }
         }
         this.source = source;
@@ -191,7 +190,6 @@
             JMXNamespaces.normalizeNamespaceName(targetNs));
         this.router =
                 new ObjectNameRouter(this.targetNs,this.sourceNs);
-        this.forwardsContext = forwardsContext;
 
         if (LOG.isLoggable(Level.FINER))
             LOG.finer("RoutingProxy for " + this.sourceNs + " created");
@@ -200,14 +198,6 @@
     @Override
     public T source() { return source; }
 
-    ObjectNameRouter getObjectNameRouter() {
-// TODO: uncomment this when contexts are added
-//        if (forwardsContext)
-//            return ObjectNameRouter.wrapWithContext(router);
-//        else
-            return router;
-    }
-
     @Override
     public ObjectName toSource(ObjectName targetName)
         throws MalformedObjectNameException {
@@ -222,8 +212,7 @@
             if (defaultDomain != null)
                 targetName = targetName.withDomain(defaultDomain);
         }
-        final ObjectNameRouter r = getObjectNameRouter();
-        return r.toSourceContext(targetName,true);
+        return router.toSourceContext(targetName,true);
     }
 
     @Override
@@ -243,8 +232,7 @@
     public ObjectName toTarget(ObjectName sourceName)
         throws MalformedObjectNameException {
         if (sourceName == null) return null;
-        final ObjectNameRouter r = getObjectNameRouter();
-        return r.toTargetContext(sourceName,false);
+        return router.toTargetContext(sourceName,false);
     }
 
     private Object getAttributeFromHandler(String attributeName)
@@ -357,11 +345,8 @@
     // 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);
+            public R newInstance(
+                    T source, String sourcePath, String targetPath, boolean probe);
     }
 
     // Performs a narrowDownToNamespace operation.
@@ -377,7 +362,7 @@
     static <T extends MBeanServerConnection, R extends RoutingProxy<T>>
            R cd(Class<R> routingProxyClass,
               RoutingProxyFactory<T,R> factory,
-              T source, String sourcePath) {
+              T source, String sourcePath, boolean probe) {
         if (source == null) throw new IllegalArgumentException("null");
         if (source.getClass().equals(routingProxyClass)) {
             // cast is OK here, but findbugs complains unless we use class.cast
@@ -400,14 +385,13 @@
                 final String path =
                     JMXNamespaces.concat(other.getSourceNamespace(),
                     sourcePath);
-                return factory.newInstance(other.source(),path,"",
-                                           other.forwardsContext);
+                return factory.newInstance(other.source(), path, "", probe);
             }
             // 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);
+        return factory.newInstance(source, sourcePath, "", probe);
     }
 }
--- a/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java	Tue Nov 11 09:07:58 2008 +0000
@@ -54,7 +54,6 @@
 import javax.management.QueryExp;
 import javax.management.ReflectionException;
 import javax.management.loading.ClassLoaderRepository;
-import javax.management.namespace.JMXNamespaces;
 
 /**
  * A RoutingServerProxy is an MBeanServer proxy that proxies a
@@ -76,19 +75,11 @@
         extends RoutingProxy<MBeanServer>
         implements MBeanServer {
 
-    /**
-     * Creates a new instance of RoutingServerProxy
-     */
-    public RoutingServerProxy(MBeanServer source,
-                           String sourceNs) {
-        this(source,sourceNs,"",false);
-    }
-
     public RoutingServerProxy(MBeanServer source,
                                 String sourceNs,
                                 String targetNs,
-                                boolean forwardsContext) {
-        super(source,sourceNs,targetNs,forwardsContext);
+                                boolean probe) {
+        super(source, sourceNs, targetNs, probe);
     }
 
     /**
@@ -571,20 +562,15 @@
         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);
+                String sourcePath, String targetPath, boolean probe) {
+            return new RoutingServerProxy(
+                    source, sourcePath, targetPath, probe);
         }
     };
 
-    public static MBeanServer cd(MBeanServer source, String sourcePath) {
+    public static MBeanServer cd(
+            MBeanServer source, String sourcePath, boolean probe) {
         return RoutingProxy.cd(RoutingServerProxy.class, FACTORY,
-                source, sourcePath);
+                source, sourcePath, probe);
     }
 }
--- a/src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java	Tue Nov 11 09:07:58 2008 +0000
@@ -120,7 +120,7 @@
     private final Collection<ShareBuffer> sharers = new HashSet<ShareBuffer>(1);
 
     public static NotificationBuffer getNotificationBuffer(
-            MBeanServer mbs, Map env) {
+            MBeanServer mbs, Map<String, ?> env) {
 
         if (env == null)
             env = Collections.emptyMap();
--- a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Tue Nov 11 09:07:58 2008 +0000
@@ -54,7 +54,7 @@
 
 
 public abstract class ClientNotifForwarder {
-    public ClientNotifForwarder(Map env) {
+    public ClientNotifForwarder(Map<String, ?> env) {
         this(null, env);
     }
 
@@ -113,7 +113,7 @@
         private Thread thread;
     }
 
-    public ClientNotifForwarder(ClassLoader defaultClassLoader, Map env) {
+    public ClientNotifForwarder(ClassLoader defaultClassLoader, Map<String, ?> env) {
         maxNotifications = EnvHelp.getMaxFetchNotifNumber(env);
         timeout = EnvHelp.getFetchTimeout(env);
 
--- a/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java	Tue Nov 11 09:07:58 2008 +0000
@@ -36,7 +36,7 @@
 import org.omg.CORBA.TypeCode;
 import org.omg.CORBA.portable.BoxedValueHelper;
 
-@SuppressWarnings("deprecation")
+@SuppressWarnings({"deprecation", "rawtypes"})
 public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream {
     public ProxyInputStream(org.omg.CORBA.portable.InputStream in) {
         this.in = in;
--- a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Tue Nov 11 09:07:58 2008 +0000
@@ -59,7 +59,7 @@
 
 
     public ServerNotifForwarder(MBeanServer mbeanServer,
-                                Map env,
+                                Map<String, ?> env,
                                 NotificationBuffer notifBuffer,
                                 String connectionId) {
         this.mbeanServer = mbeanServer;
--- a/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java	Tue Nov 11 09:07:58 2008 +0000
@@ -29,6 +29,6 @@
 import java.rmi.MarshalledObject;
 
 public interface Unmarshal {
-    public Object get(MarshalledObject mo)
+    public Object get(MarshalledObject<?> mo)
             throws IOException, ClassNotFoundException;
 }
--- a/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java	Tue Nov 11 09:07:58 2008 +0000
@@ -26,6 +26,7 @@
 package com.sun.jmx.remote.security;
 
 import com.sun.jmx.mbeanserver.GetPropertyAction;
+import com.sun.jmx.mbeanserver.Util;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -146,8 +147,8 @@
     // Initial state
     private Subject subject;
     private CallbackHandler callbackHandler;
-    private Map<String, ?> sharedState;
-    private Map options;
+    private Map<String, Object> sharedState;
+    private Map<String, ?> options;
     private String passwordFile;
     private String passwordFileDisplayName;
     private boolean userSuppliedPasswordFile;
@@ -172,7 +173,7 @@
 
         this.subject = subject;
         this.callbackHandler = callbackHandler;
-        this.sharedState = sharedState;
+        this.sharedState = Util.cast(sharedState);
         this.options = options;
 
         // initialize any configured options
@@ -454,8 +455,8 @@
         if (storePass &&
             !sharedState.containsKey(USERNAME_KEY) &&
             !sharedState.containsKey(PASSWORD_KEY)) {
-            ((Map) sharedState).put(USERNAME_KEY, username);
-            ((Map) sharedState).put(PASSWORD_KEY, password);
+            sharedState.put(USERNAME_KEY, username);
+            sharedState.put(PASSWORD_KEY, password);
         }
 
         // Create a new user principal
--- a/src/share/classes/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java	Tue Nov 11 09:07:58 2008 +0000
@@ -87,7 +87,7 @@
      * @exception SecurityException if the authentication mechanism cannot be
      *            initialized.
      */
-    public JMXPluggableAuthenticator(Map env) {
+    public JMXPluggableAuthenticator(Map<?, ?> env) {
 
         String loginConfigName = null;
         String passwordFile = null;
--- a/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java	Tue Nov 11 09:07:58 2008 +0000
@@ -249,9 +249,8 @@
                     }
                 });
         if (s == null) return; /* security has not been enabled */
-        final Set principals = s.getPrincipals();
-        for (Iterator i = principals.iterator(); i.hasNext(); ) {
-            final Principal p = (Principal) i.next();
+        final Set<Principal> principals = s.getPrincipals();
+        for (Principal p : principals) {
             String grantedAccessLevel;
             synchronized (props) {
                 grantedAccessLevel = props.getProperty(p.getName());
@@ -271,8 +270,8 @@
     }
 
     private void checkValues(Properties props) {
-        Collection c = props.values();
-        for (Iterator i = c.iterator(); i.hasNext(); ) {
+        Collection<?> c = props.values();
+        for (Iterator<?> i = c.iterator(); i.hasNext(); ) {
             final String accessLevel = (String) i.next();
             if (!accessLevel.equals(READONLY) &&
                 !accessLevel.equals(READWRITE)) {
--- a/src/share/classes/com/sun/jmx/remote/util/ClassLoaderWithRepository.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/util/ClassLoaderWithRepository.java	Tue Nov 11 09:07:58 2008 +0000
@@ -38,7 +38,7 @@
         this.cl2 = cl2;
    }
 
-    protected Class findClass(String name) throws ClassNotFoundException {
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
         try {
             return repository.loadClass(name);
         } catch (ClassNotFoundException cne) {
--- a/src/share/classes/com/sun/jmx/remote/util/ClassLogger.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/util/ClassLogger.java	Tue Nov 11 09:07:58 2008 +0000
@@ -41,7 +41,7 @@
            people to use at least J2SE 1.4.  */
         boolean loaded = false;
         try {
-            Class c = java.util.logging.Logger.class;
+            Class<?> c = java.util.logging.Logger.class;
             loaded = true;
         } catch (Error e) {
             // OK.
--- a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Tue Nov 11 09:07:58 2008 +0000
@@ -117,7 +117,7 @@
      * <code>jmx.remote.default.class.loader.name</code> is specified
      * and the ClassLoader MBean is not found in <var>mbs</var>.
      */
-    public static ClassLoader resolveServerClassLoader(Map env,
+    public static ClassLoader resolveServerClassLoader(Map<String, ?> env,
                                                        MBeanServer mbs)
         throws InstanceNotFoundException {
 
@@ -194,7 +194,7 @@
      * <code>jmx.remote.default.class.loader</code> is specified
      * and is not an instance of {@link ClassLoader}.
      */
-    public static ClassLoader resolveClientClassLoader(Map env) {
+    public static ClassLoader resolveClientClassLoader(Map<String, ?> env) {
 
         if (env == null)
             return Thread.currentThread().getContextClassLoader();
@@ -241,7 +241,7 @@
 
         try {
             java.lang.reflect.Method getCause =
-                t.getClass().getMethod("getCause", (Class[]) null);
+                t.getClass().getMethod("getCause", (Class<?>[]) null);
             ret = (Throwable)getCause.invoke(t, (Object[]) null);
 
         } catch (Exception e) {
@@ -264,7 +264,7 @@
      * Returns the size of a notification buffer for a connector server.
      * The default value is 1000.
      */
-    public static int getNotifBufferSize(Map env) {
+    public static int getNotifBufferSize(Map<String, ?> env) {
         int defaultQueueSize = 1000; // default value
 
         // keep it for the compability for the fix:
@@ -327,7 +327,7 @@
      * Returns the maximum notification number which a client will
      * fetch every time.
      */
-    public static int getMaxFetchNotifNumber(Map env) {
+    public static int getMaxFetchNotifNumber(Map<String, ?> env) {
         return (int) getIntegerAttribute(env, MAX_FETCH_NOTIFS, 1000, 1,
                                          Integer.MAX_VALUE);
     }
@@ -344,7 +344,7 @@
     /**
      * Returns the timeout for a client to fetch notifications.
      */
-    public static long getFetchTimeout(Map env) {
+    public static long getFetchTimeout(Map<String, ?> env) {
         return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
                 Long.MAX_VALUE);
     }
@@ -361,7 +361,7 @@
             "com.sun.jmx.remote.notification.access.controller";
 
     public static NotificationAccessController getNotificationAccessController(
-            Map env) {
+            Map<String, ?> env) {
         return (env == null) ? null :
             (NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
     }
@@ -378,7 +378,7 @@
      * an entry for <code>name</code> but it does not meet the
      * constraints above.
      */
-    public static long getIntegerAttribute(Map env, String name,
+    public static long getIntegerAttribute(Map<String, ?> env, String name,
                                            long defaultValue, long minValue,
                                            long maxValue) {
         final Object o;
@@ -421,9 +421,8 @@
 
     /* Check that all attributes have a key that is a String.
        Could make further checks, e.g. appropriate types for attributes.  */
-    public static void checkAttributes(Map attributes) {
-        for (Iterator it = attributes.keySet().iterator(); it.hasNext(); ) {
-            Object key = it.next();
+    public static void checkAttributes(Map<?, ?> attributes) {
+        for (Object key : attributes.keySet()) {
             if (!(key instanceof String)) {
                 final String msg =
                     "Attributes contain key that is not a string: " + key;
@@ -455,7 +454,7 @@
         logger.trace("purgeUnserializable", "starts");
         ObjectOutputStream oos = null;
         int i = 0;
-        for (Iterator it = objects.iterator(); it.hasNext(); i++) {
+        for (Iterator<?> it = objects.iterator(); it.hasNext(); i++) {
             Object v = it.next();
 
             if (v == null || v instanceof String) {
@@ -564,18 +563,18 @@
            guarantees that we will never call next() on the corresponding
            iterator.  */
         String sentinelKey = map.lastKey() + "X";
-        Iterator keyIterator = map.keySet().iterator();
-        Iterator stringIterator = hiddenStrings.iterator();
-        Iterator prefixIterator = hiddenPrefixes.iterator();
+        Iterator<String> keyIterator = map.keySet().iterator();
+        Iterator<String> stringIterator = hiddenStrings.iterator();
+        Iterator<String> prefixIterator = hiddenPrefixes.iterator();
 
         String nextString;
         if (stringIterator.hasNext())
-            nextString = (String) stringIterator.next();
+            nextString = stringIterator.next();
         else
             nextString = sentinelKey;
         String nextPrefix;
         if (prefixIterator.hasNext())
-            nextPrefix = (String) prefixIterator.next();
+            nextPrefix = prefixIterator.next();
         else
             nextPrefix = sentinelKey;
 
@@ -583,7 +582,7 @@
            or prefix, remove it. */
     keys:
         while (keyIterator.hasNext()) {
-            String key = (String) keyIterator.next();
+            String key = keyIterator.next();
 
             /* Continue through string-match values until we find one
                that is either greater than the current key, or equal
@@ -591,7 +590,7 @@
             int cmp = +1;
             while ((cmp = nextString.compareTo(key)) < 0) {
                 if (stringIterator.hasNext())
-                    nextString = (String) stringIterator.next();
+                    nextString = stringIterator.next();
                 else
                     nextString = sentinelKey;
             }
@@ -609,7 +608,7 @@
                     continue keys;
                 }
                 if (prefixIterator.hasNext())
-                    nextPrefix = (String) prefixIterator.next();
+                    nextPrefix = prefixIterator.next();
                 else
                     nextPrefix = sentinelKey;
             }
@@ -640,7 +639,7 @@
     /**
      * Returns the server side connection timeout.
      */
-    public static long getServerConnectionTimeout(Map env) {
+    public static long getServerConnectionTimeout(Map<String, ?> env) {
         return getIntegerAttribute(env, SERVER_CONNECTION_TIMEOUT, 120000L,
                                    0, Long.MAX_VALUE);
     }
@@ -656,7 +655,7 @@
     /**
      * Returns the client connection check period.
      */
-    public static long getConnectionCheckPeriod(Map env) {
+    public static long getConnectionCheckPeriod(Map<String, ?> env) {
         return getIntegerAttribute(env, CLIENT_CONNECTION_CHECK_PERIOD, 60000L,
                                    0, Long.MAX_VALUE);
     }
@@ -691,7 +690,7 @@
      * to {@code String}.
      */
     public static boolean computeBooleanFromString(
-            Map env, String prop, boolean systemProperty) {
+            Map<String, ?> env, String prop, boolean systemProperty) {
 
         if (env == null)
             throw new IllegalArgumentException("env map cannot be null");
@@ -744,7 +743,8 @@
      * to {@code String}.
      */
     public static boolean computeBooleanFromString(
-            Map env, String prop, boolean systemProperty, boolean defaultValue) {
+            Map<String, ?> env, String prop,
+            boolean systemProperty, boolean defaultValue) {
 
         if (env == null)
             throw new IllegalArgumentException("env map cannot be null");
@@ -774,7 +774,7 @@
     public static <K, V> Hashtable<K, V> mapToHashtable(Map<K, V> map) {
         HashMap<K, V> m = new HashMap<K, V>(map);
         if (m.containsKey(null)) m.remove(null);
-        for (Iterator i = m.values().iterator(); i.hasNext(); )
+        for (Iterator<?> i = m.values().iterator(); i.hasNext(); )
             if (i.next() == null) i.remove();
         return new Hashtable<K, V>(m);
     }
@@ -783,7 +783,7 @@
      * Returns true if the parameter JMXConnector.USE_EVENT_SERVICE is set to a
      * String equals "true" by ignoring case in the map or in the System.
      */
-    public static boolean eventServiceEnabled(Map env) {
+    public static boolean eventServiceEnabled(Map<String, ?> env) {
         return computeBooleanFromString(env, JMXConnector.USE_EVENT_SERVICE, true);
     }
 
@@ -793,7 +793,7 @@
      * If the property DELEGATE_TO_EVENT_SERVICE is not set, returns
      * a default value of "true".
      */
-    public static boolean delegateToEventService(Map env) {
+    public static boolean delegateToEventService(Map<String, ?> env) {
         return computeBooleanFromString(env,
                 JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true);
     }
--- a/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java	Tue Nov 11 09:07:58 2008 +0000
@@ -138,8 +138,8 @@
             Class<T> interfaceClass, Callable<EventClient> eventClientFactory) {
         final InvocationHandler handler =
                 new EventClientConnection(connection,eventClientFactory);
-        final Class[] interfaces =
-                new Class[] {interfaceClass, EventClientFactory.class};
+        final Class<?>[] interfaces =
+                new Class<?>[] {interfaceClass, EventClientFactory.class};
 
         Object proxy =
                 Proxy.newProxyInstance(interfaceClass.getClassLoader(),
@@ -156,7 +156,7 @@
         // add/remove notification listener are routed to the EventClient
         if (methodName.equals("addNotificationListener")
             || methodName.equals("removeNotificationListener")) {
-            final Class[] sig = method.getParameterTypes();
+            final Class<?>[] sig = method.getParameterTypes();
             if (sig.length>1 &&
                     NotificationListener.class.isAssignableFrom(sig[1])) {
                 return invokeBroadcasterMethod(proxy,method,args);
@@ -164,7 +164,7 @@
         }
 
         // subscribe/unsubscribe are also routed to the EventClient.
-        final Class clazz = method.getDeclaringClass();
+        final Class<?> clazz = method.getDeclaringClass();
         if (clazz.equals(EventClientFactory.class)) {
             return invokeEventClientSubscriberMethod(proxy,method,args);
         }
@@ -319,7 +319,7 @@
             return true;
         if (methodName.equals("equals")
             && Arrays.equals(method.getParameterTypes(),
-                new Class[] {Object.class})
+                new Class<?>[] {Object.class})
                 && isLocal(proxy, method))
             return true;
         return false;
@@ -430,13 +430,11 @@
      *        The {@code EventClient} is created lazily, when it is needed
      *        for the first time. If null, a default factory will be used
      *        (see {@link #createEventClient}).
-     * @return the
+     * @return the MBeanServerConnection.
      **/
     public static MBeanServerConnection getEventConnectionFor(
                     MBeanServerConnection connection,
                     Callable<EventClient> eventClientFactory) {
-        // if c already uses an EventClient no need to create a new one.
-        //
         if (connection instanceof EventClientFactory
             && eventClientFactory != null)
             throw new IllegalArgumentException("connection already uses EventClient");
--- a/src/share/classes/com/sun/jmx/remote/util/OrderClassLoaders.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/jmx/remote/util/OrderClassLoaders.java	Tue Nov 11 09:07:58 2008 +0000
@@ -32,7 +32,7 @@
         this.cl2 = cl2;
     }
 
-    protected Class findClass(String name) throws ClassNotFoundException {
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
         try {
             return super.findClass(name);
         } catch (ClassNotFoundException cne) {
--- a/src/share/classes/com/sun/org/apache/xml/internal/security/utils/IdResolver.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/com/sun/org/apache/xml/internal/security/utils/IdResolver.java	Tue Nov 11 09:07:58 2008 +0000
@@ -70,10 +70,13 @@
      */
     public static void registerElementById(Element element, String idValue) {
         Document doc = element.getOwnerDocument();
-        WeakHashMap elementMap = (WeakHashMap) docMap.get(doc);
-        if(elementMap == null) {
-            elementMap = new WeakHashMap();
-            docMap.put(doc, elementMap);
+        WeakHashMap elementMap;
+        synchronized (docMap) {
+            elementMap = (WeakHashMap) docMap.get(doc);
+            if (elementMap == null) {
+                elementMap = new WeakHashMap();
+                docMap.put(doc, elementMap);
+            }
         }
         elementMap.put(idValue, new WeakReference(element));
     }
@@ -153,7 +156,10 @@
     private static Element getElementByIdType(Document doc, String id) {
         if (log.isLoggable(java.util.logging.Level.FINE))
             log.log(java.util.logging.Level.FINE, "getElementByIdType() Search for ID " + id);
-        WeakHashMap elementMap = (WeakHashMap) docMap.get(doc);
+        WeakHashMap elementMap;
+        synchronized (docMap) {
+            elementMap = (WeakHashMap) docMap.get(doc);
+        }
         if (elementMap != null) {
             WeakReference weakReference = (WeakReference) elementMap.get(id);
             if (weakReference != null) {
--- a/src/share/classes/java/security/cert/CertPathValidatorException.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/java/security/cert/CertPathValidatorException.java	Tue Nov 11 09:07:58 2008 +0000
@@ -113,7 +113,7 @@
      * permitted, and indicates that the cause is nonexistent or unknown.)
      */
     public CertPathValidatorException(Throwable cause) {
-        this(null, cause);
+        this((cause == null ? null : cause.toString()), cause);
     }
 
     /**
--- a/src/share/classes/javax/management/AttributeList.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/AttributeList.java	Tue Nov 11 09:07:58 2008 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,23 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
- * Represents a list of values for attributes of an MBean. The methods
- * used for the insertion of {@link javax.management.Attribute
- * Attribute} objects in the <CODE>AttributeList</CODE> overrides the
- * corresponding methods in the superclass
- * <CODE>ArrayList</CODE>. This is needed in order to insure that the
- * objects contained in the <CODE>AttributeList</CODE> are only
- * <CODE>Attribute</CODE> objects. This avoids getting an exception
- * when retrieving elements from the <CODE>AttributeList</CODE>.
+ * <p>Represents a list of values for attributes of an MBean.  See the
+ * {@link MBeanServerConnection#getAttributes getAttributes} and
+ * {@link MBeanServerConnection#setAttributes setAttributes} methods of
+ * {@link MBeanServer} and {@link MBeanServerConnection}.</p>
+ *
+ * <p id="type-safe">For compatibility reasons, it is possible, though
+ * highly discouraged, to add objects to an {@code AttributeList} that are
+ * not instances of {@code Attribute}.  However, an {@code AttributeList}
+ * can be made <em>type-safe</em>, which means that an attempt to add
+ * an object that is not an {@code Attribute} will produce an {@code
+ * IllegalArgumentException}.  An {@code AttributeList} becomes type-safe
+ * when the method {@link #asList()} is called on it.</p>
  *
  * @since 1.5
  */
@@ -58,8 +64,8 @@
 */
 public class AttributeList extends ArrayList<Object> {
 
-    private transient boolean typeSafe;
-    private transient boolean tainted;
+    private transient volatile boolean typeSafe;
+    private transient volatile boolean tainted;
 
     /* Serial version */
     private static final long serialVersionUID = -4077085769279709076L;
@@ -124,7 +130,7 @@
 
         // Check for non-Attribute objects
         //
-        checkTypeSafe(list);
+        adding(list);
 
         // Build the List<Attribute>
         //
@@ -132,6 +138,56 @@
     }
 
     /**
+     * <p>Constructs an {@code AttributeList} containing the elements of
+     * the {@code Map} specified, in the order in which they appear in the
+     * {@code Map}'s {@link Map#entrySet entrySet}.  For each <em>{@code
+     * key}</em> and <em>{@code value}</em> in the {@code Map}, the constructed
+     * {@code AttributeList} will contain {@link Attribute#Attribute
+     * Attribute(<em>key</em>, <em>value</em>)}.</p>
+     *
+     * @param map the {@code Map} defining the elements of the new
+     * {@code AttributeList}.
+     */
+    public AttributeList(Map<String, ?> map) {
+        for (Map.Entry<String, ?> entry : map.entrySet())
+            add(new Attribute(entry.getKey(), entry.getValue()));
+        typeSafe = true;
+    }
+
+    /**
+     * <p>Return a {@code Map} that is a snapshot of the values in this
+     * {@code AttributeList}.  Each key in the {@code Map} is the {@linkplain
+     * Attribute#getName() name} of an {@code Attribute} in the list, and each
+     * value is the corresponding {@linkplain Attribute#getValue() value} of
+     * that {@code Attribute}.  The {@code AttributeList} and the {@code Map}
+     * are unrelated after the call, that is, changes to one do not affect the
+     * other.</p>
+     *
+     * <p>If the {@code AttributeList} contains more than one {@code Attribute}
+     * with the same name, then the {@code Map} will contain an entry
+     * for that name where the value is that of the last of those {@code
+     * Attribute}s.</p>
+     *
+     * @return the new {@code Map}.
+     *
+     * @throws IllegalArgumentException if this {@code AttributeList} contains
+     * an element that is not an {@code Attribute}.
+     */
+    public Map<String, Object> toMap() {
+        Map<String, Object> map = new LinkedHashMap<String, Object>();
+
+        // We can't call adding(this) because we're not necessarily typeSafe
+        if (tainted)
+            throw new IllegalArgumentException("AttributeList contains non-Attribute");
+
+        for (Object x : this) {
+            Attribute a = (Attribute) x;
+            map.put(a.getName(), a.getValue());
+        }
+        return map;
+    }
+
+    /**
      * Return a view of this list as a {@code List<Attribute>}.
      * Changes to the returned value are reflected by changes
      * to the original {@code AttributeList} and vice versa.
@@ -154,12 +210,10 @@
      */
     @SuppressWarnings("unchecked")
     public List<Attribute> asList() {
-        if (!typeSafe) {
-            if (tainted)
-                checkTypeSafe(this);
-            typeSafe = true;
-        }
-        return (List<Attribute>) (List) this;
+        typeSafe = true;
+        if (tainted)
+            adding((Collection<?>) this);  // will throw IllegalArgumentException
+        return (List<Attribute>) (List<?>) this;
     }
 
     /**
@@ -175,7 +229,7 @@
      * Inserts the attribute specified as an element at the position specified.
      * Elements with an index greater than or equal to the current position are
      * shifted up. If the index is out of range (index < 0 || index >
-     * size() a RuntimeOperationsException should be raised, wrapping the
+     * size()) a RuntimeOperationsException should be raised, wrapping the
      * java.lang.IndexOutOfBoundsException thrown.
      *
      * @param object  The <CODE>Attribute</CODE> object to be inserted.
@@ -245,8 +299,7 @@
     public boolean addAll(int index, AttributeList list)  {
         try {
             return super.addAll(index, list);
-        }
-        catch (IndexOutOfBoundsException e) {
+        } catch (IndexOutOfBoundsException e) {
             throw new RuntimeOperationsException(e,
                 "The specified index is out of range");
         }
@@ -258,96 +311,77 @@
      * been called on this instance.
      */
 
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException if this {@code AttributeList} is
+     * <a href="#type-safe">type-safe</a> and {@code element} is not an
+     * {@code Attribute}.
+     */
     @Override
-    public boolean add(Object o) {
-        if (!tainted)
-            tainted = isTainted(o);
-        if (typeSafe)
-            checkTypeSafe(o);
-        return super.add(o);
+    public boolean add(Object element) {
+        adding(element);
+        return super.add(element);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException if this {@code AttributeList} is
+     * <a href="#type-safe">type-safe</a> and {@code element} is not an
+     * {@code Attribute}.
+     */
     @Override
     public void add(int index, Object element) {
-        if (!tainted)
-            tainted = isTainted(element);
-        if (typeSafe)
-            checkTypeSafe(element);
+        adding(element);
         super.add(index, element);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException if this {@code AttributeList} is
+     * <a href="#type-safe">type-safe</a> and {@code c} contains an
+     * element that is not an {@code Attribute}.
+     */
     @Override
     public boolean addAll(Collection<?> c) {
-        if (!tainted)
-            tainted = isTainted(c);
-        if (typeSafe)
-            checkTypeSafe(c);
+        adding(c);
         return super.addAll(c);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException if this {@code AttributeList} is
+     * <a href="#type-safe">type-safe</a> and {@code c} contains an
+     * element that is not an {@code Attribute}.
+     */
     @Override
     public boolean addAll(int index, Collection<?> c) {
-        if (!tainted)
-            tainted = isTainted(c);
-        if (typeSafe)
-            checkTypeSafe(c);
+        adding(c);
         return super.addAll(index, c);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException if this {@code AttributeList} is
+     * <a href="#type-safe">type-safe</a> and {@code element} is not an
+     * {@code Attribute}.
+     */
     @Override
     public Object set(int index, Object element) {
-        if (!tainted)
-            tainted = isTainted(element);
-        if (typeSafe)
-            checkTypeSafe(element);
+        adding(element);
         return super.set(index, element);
     }
 
-    /**
-     * IllegalArgumentException if o is a non-Attribute object.
-     */
-    private static void checkTypeSafe(Object o) {
-        try {
-            o = (Attribute) o;
-        } catch (ClassCastException e) {
-            throw new IllegalArgumentException(e);
-        }
+    private void adding(Object x) {
+        if (x == null || x instanceof Attribute)
+            return;
+        if (typeSafe)
+            throw new IllegalArgumentException("Not an Attribute: " + x);
+        else
+            tainted = true;
     }
 
-    /**
-     * IllegalArgumentException if c contains any non-Attribute objects.
-     */
-    private static void checkTypeSafe(Collection<?> c) {
-        try {
-            Attribute a;
-            for (Object o : c)
-                a = (Attribute) o;
-        } catch (ClassCastException e) {
-            throw new IllegalArgumentException(e);
-        }
-    }
-
-    /**
-     * Returns true if o is a non-Attribute object.
-     */
-    private static boolean isTainted(Object o) {
-        try {
-            checkTypeSafe(o);
-        } catch (IllegalArgumentException e) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if c contains any non-Attribute objects.
-     */
-    private static boolean isTainted(Collection<?> c) {
-        try {
-            checkTypeSafe(c);
-        } catch (IllegalArgumentException e) {
-            return true;
-        }
-        return false;
+    private void adding(Collection<?> c) {
+        for (Object x : c)
+            adding(x);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/management/ClientContext.java	Tue Nov 11 09:07:58 2008 +0000
@@ -0,0 +1,1091 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management;
+
+import com.sun.jmx.interceptor.SingleMBeanForwarder;
+import com.sun.jmx.namespace.RoutingConnectionProxy;
+import com.sun.jmx.namespace.RoutingProxy;
+import com.sun.jmx.namespace.RoutingServerProxy;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXNamespace;
+import javax.management.namespace.JMXNamespaceMBean;
+import javax.management.namespace.MBeanServerSupport;
+import javax.management.remote.IdentityMBeanServerForwarder;
+import javax.management.remote.MBeanServerForwarder;
+
+/**
+ * <p>Methods to communicate a client context to MBeans.  A context is
+ * a {@literal Map<String, String>} that is provided by the client and
+ * that an MBean can consult using the {@link #getContext()} method.
+ * The context is set on a per-thread basis and can be consulted by any
+ * code that the target MBean calls within the thread.</p>
+ *
+ * <p>One common usage of client context is to communicate the client's
+ * {@link Locale} to MBeans.  For example, if an MBean has a String attribute
+ * {@code LastProblemDescription}, the value of that attribute could be
+ * a description of the last problem encountered by the MBean, translated
+ * into the client's locale.  Different clients accessing this attribute
+ * from different locales would each see the appropriate version for their
+ * locale.</p>
+ *
+ * <p>The locale case is sufficiently important that it has a special
+ * shorthand, the {@link #getLocale()} method.  This method calls
+ * <code>{@link #getContext()}.get({@link #LOCALE_KEY})</code> and converts the
+ * resultant String into a Locale object.</p>
+ *
+ * <p>Here is what an MBean with a localized {@code LastProblemDescription}
+ * attribute might look like:</p>
+ *
+ * <pre>
+ * public class LocaleSensitive implements LocaleSensitiveMBean {
+ *     ...
+ *     public String getLastProblemDescription() {
+ *         Locale loc = {@link #getLocale() ClientContext.getLocale()};
+ *         ResourceBundle rb = ResourceBundle.getBundle("MyResources", loc);
+ *         String resourceKey = getLastProblemResourceKey();
+ *         return rb.getString(resourceKey);
+ *     }
+ *     ...
+ * }
+ * </pre>
+ *
+ * <p>Here is how a client can communicate its locale to the target
+ * MBean:</p>
+ *
+ * <pre>
+ * JMXConnector connector = JMXConnectorFactory.connect(url);
+ * MBeanServerConnection connection = connector.getMBeanServerConnection();
+ * <b>MBeanServerConnection localizedConnection =
+ *     {@link #withLocale(MBeanServerConnection, Locale)
+ *      ClientContext.withLocale}(connection, Locale.getDefault());</b>
+ * String problem = localizedConnection.getAttribute(
+ *          objectName, "LastProblemDescription");
+ * </pre>
+ *
+ * <p>In the more general case where the client wants to communicate context
+ * other than the locale, it can use {@link #withContext(MBeanServerConnection,
+ * String, String) withContext} instead of {@code withLocale}, and the target
+ * MBean can retrieve the context using {@link #getContext()}.</p>
+ *
+ *
+ * <h3 id="remote-use">Remote use of contexts</h3>
+ *
+ * <p>The various {@code with*} methods, for example {@link
+ * #withLocale(javax.management.MBeanServer, java.util.Locale) withLocale},
+ * transmit the context of each request by encoding it in the ObjectName of
+ * the request.  For example, if a client creates a connection in the
+ * French locale like this...</p>
+ *
+ * <pre>
+ * MBeanServerConnection mbsc = ...;
+ * Locale french = new Locale("fr");
+ * MBeanServerConnection localizedConnection = ClientContext.withLocale(mbsc, french);
+ * </pre>
+ *
+ * <p>...or, equivalently, like this...</p>
+ *
+ * <pre>
+ * MBeanServerConnection localizedConnection =
+ *     ClientContext.withContext(mbsc, {@link #LOCALE_KEY "jmx.locale"}, "fr");
+ * </pre>
+ *
+ * <p>...then the context associates {@code "jmx.locale"} with {@code "fr"}
+ * and a request such as<br>
+ * {@code localizedConnection.getAttribute("java.lang:type=Runtime", "Name")}<br>
+ * is translated into<br>
+ * {@code mbsc.getAttribute("jmx.context//jmx.locale=fr//java.lang:Runtime", "Name")}.<br>
+ * A special {@linkplain javax.management.namespace namespace} {@code jmx.context//}
+ * extracts the context from the string {@code jmx.locale=fr} and establishes
+ * it in the thread that will do<br>
+ * {@code getAttribute("java.lang:Runtime", "Name")}.</p>
+ *
+ * <p>The details of how contexts are encoded into ObjectNames are explained
+ * in the {@link #encode encode} method.</p>
+ *
+ * <p>The namespace {@code jmx.context//} just mentioned is only needed by
+ * remote clients, since local clients can set the context directly using
+ * {@link #doWithContext doWithContext}.  Accordingly, this namespace is not
+ * present by default in the {@code MBeanServer}.  Instead, it is
+ * <em>simulated</em> by the standard RMI connector using a special
+ * {@link MBeanServerForwarder}.  If you are using this connector, you do not
+ * need to do anything special.  Other connectors may or may not simulate this
+ * namespace in the same way.  If the connector server returns true from the
+ * method {@link
+ * javax.management.remote.JMXConnectorServer#supportsSystemMBeanServerForwarder()
+ * supportsSystemMBeanServerForwarder} then it does simulate the namespace.
+ * If you are using another connector, or if you want to be able to use the
+ * {@code with*} methods locally, then you can install the {@code
+ * MBeanServerForwarder} yourself as described in the method {@link
+ * #newContextForwarder newContextForwarder}.</p>
+ */
+public class ClientContext {
+    /**
+     * <p>The context key for the client locale.  The string associated with
+     * this key is an encoded locale such as {@code en_US} which could be
+     * returned by {@link Locale#toString()}.</p>
+     */
+    public static final String LOCALE_KEY = "jmx.locale";
+
+    private static final Logger LOG =
+            Logger.getLogger("javax.management.context");
+
+    /**
+     * <p>The namespace that implements contexts, {@value}.</p>
+     */
+    public static final String
+            NAMESPACE = "jmx.context";
+    private static final String NAMESPACE_PLUS_SEP =
+            NAMESPACE + NAMESPACE_SEPARATOR;
+    static final ObjectName CLIENT_CONTEXT_NAMESPACE_HANDLER =
+            ObjectName.valueOf(NAMESPACE_PLUS_SEP + ":" +
+                    JMXNamespace.TYPE_ASSIGNMENT);
+    private static final ObjectName NAMESPACE_HANDLER_WITHOUT_NAMESPACE =
+            ObjectName.valueOf(":" + JMXNamespace.TYPE_ASSIGNMENT);
+
+    private static final ThreadLocal<Map<String, String>> contextThreadLocal =
+            new InheritableThreadLocal<Map<String, String>>() {
+        @Override
+        protected Map<String, String> initialValue() {
+            return Collections.emptyMap();
+        }
+    };
+
+    /** There are no instances of this class. */
+    private ClientContext() {
+    }
+
+    /**
+     * <p>Get the client context associated with the current thread.
+     *
+     * @return the client context associated with the current thread.
+     * This may be an empty Map, but it cannot be null.  The returned
+     * Map cannot be modified.
+     */
+    public static Map<String, String> getContext() {
+        return Collections.unmodifiableMap(contextThreadLocal.get());
+    }
+
+    /**
+     * <p>Get the client locale associated with the current thread.
+     * If the client context includes the {@value #LOCALE_KEY} key
+     * then the returned value is the Locale encoded in that key.
+     * Otherwise the returned value is the {@linkplain Locale#getDefault()
+     * default locale}.
+     *
+     * @return the client locale.
+     */
+    public static Locale getLocale() {
+        String localeS = getContext().get(LOCALE_KEY);
+        if (localeS == null)
+            return Locale.getDefault();
+        // Parse the locale string.  Why isn't there a method in Locale for this?
+        String language, country, variant;
+        int ui = localeS.indexOf('_');
+        if (ui < 0) {
+            language = localeS;
+            country = variant = "";
+        } else {
+            language = localeS.substring(0, ui);
+            localeS = localeS.substring(ui + 1);
+            ui = localeS.indexOf('_');
+            if (ui < 0) {
+                country = localeS;
+                variant = "";
+            } else {
+                country = localeS.substring(0, ui);
+                variant = localeS.substring(ui + 1);
+            }
+        }
+        return new Locale(language, country, variant);
+    }
+
+    /**
+     * <p>Execute the given {@code task} with the client context set to
+     * the given Map.  This Map will be the result of {@link #getContext()}
+     * within the {@code task}.</p>
+     *
+     * <p>The {@code task} may include nested calls to {@code doWithContext}.
+     * The value returned by {@link #getContext} at any point is the Map
+     * provided to the most recent {@code doWithContext} (in the current thread)
+     * that has not yet returned.</p>
+     *
+     * <p>The {@link #getContext()} method returns the same value immediately
+     * after a call to this method as immediately before.  In other words,
+     * {@code doWithContext} only affects the context during the execution of
+     * the {@code task}.</p>
+     *
+     * <p>As an example, suppose you want to get an attribute with whatever
+     * context has already been set, plus the locale set to "fr".  You could
+     * write this:</p>
+     *
+     * <pre>
+     * {@code Map<String, String>} context =
+     *     new {@code HashMap<String, String>}(ClientContext.getContext());
+     * context.put(ClientContext.LOCALE_KEY, "fr");
+     * String lastProblemDescription =
+     *     ClientContext.doWithContext(context, new {@code Callable<String>}() {
+     *         public String call() {
+     *             return (String) mbeanServer.getAttribute(mbean, "LastProblemDescription");
+     *         }
+     *     });
+     * </pre>
+     *
+     * @param <T> the type of value that the task will return.  This type
+     * parameter is usually inferred from the type of the {@code task}
+     * parameter.  For example, if {@code task} is a {@code Callable<String>}
+     * then {@code T} is {@code String}.  If the task does not return a value,
+     * use a {@code Callable<Void>} and return null from its
+     * {@link Callable#call call} method.
+     * @param context the context to use while executing {@code task}.
+     * @param task the task to run with the {@code key}={@code value}
+     * binding.
+     * @return the result of {@link Callable#call() task.call()}.
+     * @throws IllegalArgumentException if either parameter is null, or
+     * if any key in {@code context} is null or empty, or if any value
+     * in {@code context} is null.
+     * @throws Exception If {@link Callable#call() task.call()} throws an
+     * exception, {@code doWithContext} throws the same exception.
+     */
+    public static <T> T doWithContext(Map<String, String> context, Callable<T> task)
+    throws Exception {
+        if (context == null || task == null)
+            throw new IllegalArgumentException("Null parameter");
+        Map<String, String> contextCopy = new TreeMap<String, String>(context);
+        validateContext(contextCopy);
+        Map<String, String> oldContextMap = contextThreadLocal.get();
+        try {
+            contextThreadLocal.set(contextCopy);
+            return task.call();
+        } finally {
+            contextThreadLocal.set(oldContextMap);
+        }
+    }
+
+    private static void validateContext(Map<String, String> context) {
+        for (Map.Entry<String, String> entry : context.entrySet()) {
+            // If the user passes a raw Map rather than a Map<String, String>,
+            // entries could contain objects other than Strings.  If so,
+            // we'll get a ClassCastException here.
+            String key = entry.getKey();
+            String value = entry.getValue();
+            if (key == null || value == null)
+                throw new IllegalArgumentException("Null key or value in context");
+            if (key.equals(""))
+                throw new IllegalArgumentException("Empty key in context");
+        }
+    }
+
+    /**
+     * <p>Return an MBeanServer object that is equivalent to the given
+     * MBeanServer object except that operations on MBeans run with
+     * the given Locale in their {@linkplain #getContext() thread context}.
+     * Note that this will only work if the given MBeanServer supports
+     * contexts, as described <a href="#remote-use">above</a>.</p>
+     *
+     * <p>This method is equivalent to {@link #withContext(MBeanServer,
+     * String, String) withContext}<code>(mbs, {@value LOCALE_KEY},
+     * locale.toString())</code>.</p>
+     *
+     * @throws IllegalArgumentException if either parameter is null, or if
+     * {@code mbs} does not support contexts.  In the second case only,
+     * the cause of the {@code IllegalArgumentException} will be an {@link
+     * InstanceNotFoundException}.
+     */
+    public static MBeanServer withLocale(MBeanServer mbs, Locale locale) {
+        return withLocale(mbs, MBeanServer.class, locale);
+    }
+
+    /**
+     * <p>Return an MBeanServerConnection object that is equivalent to the given
+     * MBeanServerConnection object except that operations on MBeans run with
+     * the given Locale in their {@linkplain #getContext() thread context}.
+     * Note that this will only work if the given MBeanServerConnection supports
+     * contexts, as described <a href="#remote-use">above</a>.</p>
+     *
+     * <p>This method is equivalent to {@link #withContext(MBeanServerConnection,
+     * String, String) withContext}<code>(mbs, {@value LOCALE_KEY},
+     * locale.toString())</code>.</p>
+     *
+     * @throws IllegalArgumentException if either parameter is null, or if
+     * the communication with {@code mbsc} fails, or if {@code mbsc} does not
+     * support contexts.  If the communication with {@code mbsc} fails, the
+     * {@linkplain Throwable#getCause() cause} of this exception will be an
+     * {@code IOException}.  If {@code mbsc} does not support contexts, the
+     * cause will be an {@link InstanceNotFoundException}.
+     */
+    public static MBeanServerConnection withLocale(
+            MBeanServerConnection mbsc, Locale locale) {
+        return withLocale(mbsc, MBeanServerConnection.class, locale);
+    }
+
+    private static <T extends MBeanServerConnection> T withLocale(
+            T mbsc, Class<T> mbscClass, Locale locale) {
+        if (locale == null)
+            throw new IllegalArgumentException("Null locale");
+        return withContext(mbsc, mbscClass, LOCALE_KEY, locale.toString());
+    }
+
+    /**
+     * <p>Return an MBeanServer object that is equivalent to the given
+     * MBeanServer object except that operations on MBeans run with
+     * the given key bound to the given value in their {@linkplain
+     * #getContext() thread context}.
+     * Note that this will only work if the given MBeanServer supports
+     * contexts, as described <a href="#remote-use">above</a>.</p>
+     *
+     * @param mbs the original MBeanServer.
+     * @param key the key to bind in the context of MBean operations
+     * in the returned MBeanServer object.
+     * @param value the value to bind to the key in the context of MBean
+     * operations in the returned MBeanServer object.
+     * @throws IllegalArgumentException if any parameter is null, or
+     * if {@code key} is the empty string, or if {@code mbs} does not support
+     * contexts.  In the last case only, the cause of the {@code
+     * IllegalArgumentException} will be an {@link InstanceNotFoundException}.
+     */
+    public static MBeanServer withContext(
+            MBeanServer mbs, String key, String value) {
+        return withContext(mbs, MBeanServer.class, key, value);
+    }
+
+    /**
+     * <p>Return an MBeanServerConnection object that is equivalent to the given
+     * MBeanServerConnection object except that operations on MBeans run with
+     * the given key bound to the given value in their {@linkplain
+     * #getContext() thread context}.
+     * Note that this will only work if the given MBeanServerConnection supports
+     * contexts, as described <a href="#remote-use">above</a>.</p>
+     *
+     * @param mbsc the original MBeanServerConnection.
+     * @param key the key to bind in the context of MBean operations
+     * in the returned MBeanServerConnection object.
+     * @param value the value to bind to the key in the context of MBean
+     * operations in the returned MBeanServerConnection object.
+     * @throws IllegalArgumentException if any parameter is null, or
+     * if {@code key} is the empty string, or if the communication with {@code
+     * mbsc} fails, or if {@code mbsc} does not support contexts.  If
+     * the communication with {@code mbsc} fails, the {@linkplain
+     * Throwable#getCause() cause} of this exception will be an {@code
+     * IOException}.  If {@code mbsc} does not support contexts, the cause will
+     * be an {@link InstanceNotFoundException}.
+     */
+    public static MBeanServerConnection withContext(
+            MBeanServerConnection mbsc, String key, String value) {
+        return withContext(mbsc, MBeanServerConnection.class, key, value);
+    }
+
+
+    /**
+     * <p>Returns an MBeanServerConnection object that is equivalent to the
+     * given MBeanServerConnection object except that remote operations on
+     * MBeans run with the context that has been established by the client
+     * using {@link #doWithContext doWithContext}.  Note that this will
+     * only work if the remote system supports contexts, as described <a
+     * href="#remote-use">above</a>.</p>
+     *
+     * <p>For example, suppose the remote system does support contexts, and you
+     * have created a {@code JMXConnector} like this:</p>
+     *
+     * <pre>
+     * JMXServiceURL url = ...;
+     * JMXConnector client = JMXConnectorFactory.connect(url);
+     * MBeanServerConnection mbsc = client.getMBeanServerConnection();
+     * <b>mbsc = ClientContext.withDynamicContext(mbsc);</b>
+     * </pre>
+     *
+     * <p>Then if you do this...</p>
+     *
+     * <pre>
+     * MBeanInfo mbi = ClientContext.doWithContext(
+     *     Collections.singletonMap(ClientContext.LOCALE_KEY, "fr"),
+     *     new {@code Callable<MBeanInfo>}() {
+     *         public MBeanInfo call() {
+     *             return mbsc.getMBeanInfo(objectName);
+     *         }
+     *     });
+     * </pre>
+     *
+     * <p>...then the context with the locale set to "fr" will be in place
+     * when the {@code getMBeanInfo} is executed on the remote MBean Server.</p>
+     *
+     * @param mbsc the original MBeanServerConnection.
+     *
+     * @throws IllegalArgumentException if the {@code mbsc} parameter is null,
+     * or if the communication with {@code mbsc} fails, or if {@code mbsc}
+     * does not support contexts.  If the communication with {@code mbsc}
+     * fails, the {@linkplain Throwable#getCause() cause} of this exception
+     * will be an {@code IOException}.  If {@code mbsc} does not support
+     * contexts, the cause will be an {@link InstanceNotFoundException}.
+     */
+    public static MBeanServerConnection withDynamicContext(
+            MBeanServerConnection mbsc) {
+        // Probe mbsc to get the right exception if it's incommunicado or
+        // doesn't support namespaces.
+        JMXNamespaces.narrowToNamespace(mbsc, NAMESPACE);
+        return (MBeanServerConnection) Proxy.newProxyInstance(
+                MBeanServerConnection.class.getClassLoader(),
+                new Class<?>[] {MBeanServerConnection.class},
+                new DynamicContextIH(mbsc));
+    }
+
+    private static class DynamicContextIH implements InvocationHandler {
+        private final MBeanServerConnection mbsc;
+
+        public DynamicContextIH(MBeanServerConnection mbsc) {
+            this.mbsc = mbsc;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args)
+                throws Throwable {
+            MBeanServerConnection dynMBSC = withContext(
+                    mbsc, MBeanServerConnection.class, getContext(), false);
+            try {
+                return method.invoke(dynMBSC, args);
+            } catch (InvocationTargetException e) {
+                throw e.getCause();
+            }
+        }
+    }
+
+    private static <T extends MBeanServerConnection> T withContext(
+            T mbsc, Class<T> mbscClass, String key, String value) {
+        return withContext(
+                mbsc, mbscClass, Collections.singletonMap(key, value), true);
+    }
+
+    private static <T extends MBeanServerConnection> T withContext(
+            T mbsc, Class<T> mbscClass, Map<String, String> context,
+            boolean probe) {
+        if (mbsc == null || context == null)
+            throw new IllegalArgumentException("Null parameter");
+        if (context.isEmpty())
+            return mbsc;
+        validateContext(context);
+        Map<String, String> contextMap = null;
+        if (mbsc.getClass() == RoutingServerProxy.class ||
+                mbsc.getClass() == RoutingProxy.class) {
+            RoutingProxy<?> nsp = (RoutingProxy<?>) mbsc;
+            String where = nsp.getSourceNamespace();
+            if (where.startsWith(NAMESPACE_PLUS_SEP)) {
+                /* Try to merge the existing context namespace with the
+                 * new one.  If it doesn't work, we fall back to just
+                 * prefixing jmx.context//key=value, which
+                 * might lead to a name like jmx.c//k1=v1//jmx.c//k2=v2//d:k=v.
+                 */
+                String encodedContext =
+                        where.substring(NAMESPACE_PLUS_SEP.length());
+                if (encodedContext.indexOf(NAMESPACE_SEPARATOR) < 0) {
+                    contextMap = stringToMapOrNull(encodedContext);
+                    if (contextMap != null) {
+                        contextMap.putAll(context);
+                        mbsc = mbscClass.cast(nsp.source());
+                    }
+                }
+            }
+        }
+        if (contextMap == null)
+            contextMap = context;
+        String contextDir = NAMESPACE_PLUS_SEP + mapToString(contextMap);
+        if (mbscClass == MBeanServer.class) {
+            return mbscClass.cast(RoutingServerProxy.cd(
+                    (MBeanServer) mbsc, contextDir, probe));
+        } else if (mbscClass == MBeanServerConnection.class) {
+            return mbscClass.cast(RoutingConnectionProxy.cd(
+                    mbsc, contextDir, probe));
+        } else
+            throw new AssertionError("Bad MBSC: " + mbscClass);
+    }
+
+    /**
+     * <p>Returns an encoded context prefix for ObjectNames.
+     * If the given context is empty, {@code ""} is returned.
+     * Otherwise, this method returns a string of the form
+     * {@code "jmx.context//key=value;key=value;..."}.
+     * For example, if the context has keys {@code "jmx.locale"}
+     * and {@code "xid"} with respective values {@code "fr"}
+     * and {@code "1234"}, this method will return
+     * {@code "jmx.context//jmx.locale=fr;xid=1234"} or
+     * {@code "jmx.context//xid=1234;jmx.locale=fr"}.</p>
+     *
+     * <p>Each key and each value in the encoded string is subject to
+     * encoding as if by the method {@link URLEncoder#encode(String, String)}
+     * with a character encoding of {@code "UTF-8"}, but with the additional
+     * encoding of any {@code *} character as {@code "%2A"}.  This ensures
+     * that keys and values can contain any character.  Without encoding,
+     * characters such as {@code =} and {@code :} would pose problems.</p>
+     *
+     * @param context the context to encode.
+     *
+     * @return the context in encoded form.
+     *
+     * @throws IllegalArgumentException if the {@code context} parameter
+     * is null or if it contains a null key or value.
+     **/
+    public static String encode(Map<String, String> context) {
+        if (context == null)
+            throw new IllegalArgumentException("Null context");
+        if (context.isEmpty())
+            return "";
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String, String> entry : context.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            if (key == null || value == null)
+                throw new IllegalArgumentException("Null key or value");
+            if (sb.length() > 0)
+                sb.append(";");
+            sb.append(encode(key)).append("=").append(encode(value));
+        }
+        sb.insert(0, NAMESPACE_PLUS_SEP);
+        return sb.toString();
+    }
+
+    /**
+     * <p>Create a new {@link MBeanServerForwarder} that applies the context
+     * received from a client to the current thread.  A client using
+     * one of the various {@code with*} methods (for example {@link
+     * #withContext(MBeanServerConnection, String, String) withContext}) will
+     * encode that context into the {@code ObjectName} of each
+     * {@code MBeanServer} request.  The object returned by this method
+     * decodes the context from that {@code ObjectName} and applies it
+     * as described for {@link #doWithContext doWithContext} while performing
+     * the {@code MBeanServer} request using the {@code ObjectName} without
+     * the encoded context.</p>
+     *
+     * <p>This forwarder can be used in a number of ways:</p>
+     *
+     * <ul>
+     * <li>
+     * <p>To add context decoding to a local {@code MBeanServer}, you can
+     * write:</p>
+     * <pre>
+     * MBeanServer mbs = {@link
+     * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+     * ManagementFactory.getPlatformMBeanServer()};  // for example
+     * mbs = ClientContext.newContextForwarder(mbs, null);
+     * </pre>
+     *
+     * <li>
+     * <p>To add context decoding to a {@linkplain
+     * javax.management.remote.JMXConnectorServer connector server}:</p>
+     * <pre>
+     * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(...);
+     * MBeanServer nextMBS = cs.getMBeanServer();
+     * MBeanServerForwarder mbsf = ClientContext.newContextForwarder(nextMBS, null);
+     * cs.{@link
+     * javax.management.remote.JMXConnectorServer#setMBeanServerForwarder
+     * setMBeanServerForwarder}(mbsf);
+     * </pre>
+     *
+     * <li>
+     * <p>For connectors, such as the standard RMI connector, that support
+     * a {@linkplain
+     * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder
+     * system chain} of {@code MBeanServerForwarder}s, this forwarder will
+     * be installed in that chain by default.  See
+     * {@link javax.management.remote.JMXConnectorServer#CONTEXT_FORWARDER
+     * JMXConnectorServer.CONTEXT_FORWARDER}.
+     * </p>
+     *
+     * </ul>
+     *
+     * @param nextMBS the next {@code MBeanServer} in the chain of
+     * forwarders, which might be another {@code MBeanServerForwarder} or
+     * a plain {@code MBeanServer}.  This is the object to which {@code
+     * MBeanServer} requests that do not include a context are sent.  It
+     * will be the value of {@link MBeanServerForwarder#getMBeanServer()
+     * getMBeanServer()} on the returned object, and can be changed with {@link
+     * MBeanServerForwarder#setMBeanServer setMBeanServer}.  It can be null but
+     * must be set to a non-null value before any {@code MBeanServer} requests
+     * arrive.
+     *
+     * @param loopMBS the {@code MBeanServer} to which requests that contain
+     * an encoded context should be sent once the context has been decoded.
+     * For example, if the request is {@link MBeanServer#getAttribute
+     * getAttribute}{@code ("jmx.context//jmx.locale=fr//java.lang:type=Runtime",
+     * "Name")}, then the {@linkplain #getContext() context} of the thread
+     * executing that request will have {@code "jmx.locale"} set to {@code "fr"}
+     * while executing {@code loopMBS.getAttribute("java.lang:type=Runtime",
+     * "Name")}.  If this parameter is null, then these requests will be
+     * sent to the newly-created {@code MBeanServerForwarder}.  Usually
+     * the parameter will either be null or will be the result of {@link
+     * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder
+     * getSystemMBeanServerForwarder()} for the connector server in which
+     * this forwarder will be installed.
+     *
+     * @return a new {@code MBeanServerForwarder} that decodes client context
+     * from {@code ObjectName}s.
+     */
+    /*
+     * What we're building here is confusing enough to need a diagram.
+     * The MBSF that we return is actually the composition of two forwarders:
+     * the first one simulates the existence of the MBean
+     * jmx.context//:type=JMXNamespace, and the second one simulates the
+     * existence of the namespace jmx.context//.  Furthermore, that namespace
+     * loops back to the composed forwarder, so that something like
+     * jmx.context//foo=bar//jmxcontext//baz=buh will work.  And the loopback
+     * goes through yet another forwarder, which simulates the existence of
+     * (e.g.) jmx.context//foo=bar//:type=JMXNamespace, which is needed
+     * notably so that narrowToNamespace will work.
+     *
+     *          |     +--------------------------------------------------+
+     *          v     v                                                  |
+     * +----------------+                                                |
+     * | Handler MBSF   |->accesses to jmx.context//:type=JMXNamespace   |
+     * +----------------+    (handled completely here)   +-------------------+
+     *          |                                        | 2nd Handler MBSF  |
+     *          v                                        +-------------------+
+     * +----------------+                                                ^
+     * | Namespace MBSF |->accesses to jmx.context//**-------------------+
+     * +----------------+    (after attaching context to thread)
+     *          |
+     *          v          accesses to anything else
+     *
+     * And finally, we need to ensure that from the outside the composed object
+     * looks like a single forwarder, so that its get/setMBeanServer methods
+     * will do the expected thing.  That's what the anonymous subclass is for.
+     */
+    public static MBeanServerForwarder newContextForwarder(
+            MBeanServer nextMBS, MBeanServer loopMBS) {
+        final MBeanServerForwarder mbsWrapper =
+                new IdentityMBeanServerForwarder(nextMBS);
+        DynamicMBean handlerMBean = new StandardMBean(
+                new JMXNamespace(mbsWrapper), JMXNamespaceMBean.class, false);
+        SingleMBeanForwarder handlerForwarder = new SingleMBeanForwarder(
+                CLIENT_CONTEXT_NAMESPACE_HANDLER, handlerMBean, true) {
+            @Override
+            public MBeanServer getMBeanServer() {
+                return ((MBeanServerForwarder) super.getMBeanServer()).getMBeanServer();
+            }
+
+            @Override
+            public void setMBeanServer(MBeanServer mbs1) {
+                MBeanServerForwarder mbsf1 = (MBeanServerForwarder)
+                        super.getMBeanServer();
+                if (mbsf1 != null)
+                    mbsf1.setMBeanServer(mbs1);
+                else
+                    super.setMBeanServer(mbs1);
+                mbsWrapper.setMBeanServer(mbs1);
+            }
+        };
+        if (loopMBS == null)
+            loopMBS = handlerForwarder;
+        ContextInvocationHandler contextIH =
+                new ContextInvocationHandler(nextMBS, loopMBS);
+        MBeanServerForwarder contextForwarder = newForwarderProxy(contextIH);
+        handlerForwarder.setMBeanServer(contextForwarder);
+        return handlerForwarder;
+    }
+
+    /**
+     * <p>Create a new {@link MBeanServerForwarder} that localizes
+     * descriptions in {@code MBeanInfo} instances returned by
+     * {@link MBeanServer#getMBeanInfo getMBeanInfo}.  The {@code
+     * MBeanServerForwarder} returned by this method passes all {@code
+     * MBeanServer} methods through unchanged to the supplied object, {@code
+     * mbs}, with the exception of {@code getMBeanInfo}.  To handle {@code
+     * getMBeanInfo(objectName)}, it calls {@code mbs.getMBeanInfo(objectName)}
+     * to get an {@code MBeanInfo}, {@code mbi}; it calls {@link
+     * MBeanServer#getClassLoaderFor mbs.getClassLoaderFor(objectName)} to
+     * get a {@code ClassLoader}, {@code cl}; and it calls {@link
+     * #getLocale} to get a {@code Locale}, {@code locale}.  The order
+     * of these three calls is not specified.  Then the result is {@code
+     * mbi.localizeDescriptions(locale, loader)}.</p>
+     *
+     * <p>This forwarder can be used in a number of ways:</p>
+     *
+     * <ul>
+     * <li>
+     * <p>To add description localization to a local {@code MBeanServer}, you
+     * can write:</p>
+     *
+     * <pre>
+     * MBeanServer mbs = {@link
+     * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+     * ManagementFactory.getPlatformMBeanServer()};  // for example
+     * mbs = ClientContext.newLocalizeMBeanInfoForwarder(mbs);
+     * </pre>
+     *
+     * <li>
+     * <p>To add description localization to a {@linkplain
+     * javax.management.remote.JMXConnectorServer connector server}, you will
+     * need to add both a {@linkplain #newContextForwarder context forwarder}
+     * and a localization forwarder, for example like this:</p>
+     *
+     * <pre>
+     * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(...);
+     * MBeanServer nextMBS = cs.getMBeanServer();
+     * MBeanServerForwarder localizeMBSF =
+     *     ClientContext.newLocalizeMBeanInfoForwarder(nextMBS);
+     * MBeanServerForwarder contextMBSF =
+     *     ClientContext.newContextForwarder(localizeMBSF, null);
+     * cs.{@link
+     * javax.management.remote.JMXConnectorServer#setMBeanServerForwarder
+     * setMBeanServerForwarder}(contextMBSF);
+     * </pre>
+     *
+     * <p>Notice that the context forwarder must run before the localization
+     * forwarder, so that the locale is correctly established when the latter
+     * runs.  So the {@code nextMBS} parameter of the context forwarder must
+     * be the localization forwarder, and not vice versa.</p>
+     *
+     * <li>
+     * <p>For connectors, such as the standard RMI connector, that support
+     * a {@linkplain
+     * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder
+     * system chain} of {@code MBeanServerForwarder}s, the context forwarder and
+     * the localization forwarder will be installed in that chain, in the right
+     * order, if you include
+     * {@link
+     * javax.management.remote.JMXConnectorServer#LOCALIZE_MBEAN_INFO_FORWARDER
+     * LOCALIZE_MBEAN_INFO_FORWARDER} in the environment {@code Map} with
+     * the value {@code "true"}, for example like this:</p>
+     * </p>
+     * <pre>
+     * MBeanServer mbs = ...;
+     * JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://...");
+     * {@code Map<String, Object>} env = new {@code HashMap<String, Object>}();
+     * env.put(JMXConnectorServer.LOCALIZE_MBEAN_INFO_FORWARDER, "true");
+     * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+     *     url, env, mbs);
+     * </pre>
+     *
+     * </ul>
+     *
+     * @param mbs the next {@code MBeanServer} in the chain of
+     * forwarders, which might be another {@code MBeanServerForwarder}
+     * or a plain {@code MBeanServer}.  It will be the value of
+     * {@link MBeanServerForwarder#getMBeanServer() getMBeanServer()}
+     * on the returned object, and can be changed with {@link
+     * MBeanServerForwarder#setMBeanServer setMBeanServer}.  It can be null but
+     * must be set to a non-null value before any {@code MBeanServer} requests
+     * arrive.
+     *
+     * @return a new {@code MBeanServerForwarder} that localizes descriptions
+     * in the result of {@code getMBeanInfo}.
+     */
+    public static MBeanServerForwarder newLocalizeMBeanInfoForwarder(
+            MBeanServer mbs) {
+        return new IdentityMBeanServerForwarder(mbs) {
+            @Override
+            public MBeanInfo getMBeanInfo(ObjectName name)
+                    throws InstanceNotFoundException, IntrospectionException,
+                           ReflectionException {
+                MBeanInfo mbi = super.getMBeanInfo(name);
+                Locale locale = getLocale();
+                ClassLoader loader = getClassLoaderFor(name);
+                return mbi.localizeDescriptions(locale, loader);
+            }
+        };
+    }
+
+    private static MBeanServerForwarder newForwarderProxy(InvocationHandler ih) {
+        return (MBeanServerForwarder) Proxy.newProxyInstance(
+                MBeanServerForwarder.class.getClassLoader(),
+                new Class<?>[] {MBeanServerForwarder.class},
+                ih);
+    }
+
+    // A proxy connection that will strip the 'contextDir' at input (routing),
+    // and put it back at output (createMBean / registerMBean / query* /
+    // getObjectInstance). Usually RoutingProxy / RoutingServerProxy are used
+    // the other way round (they are used for 'cd' - where they need to add
+    // something at input and remove it at output).
+    // For 'cd' operations we create RoutingProxys with a non empty sourceDir,
+    // and a possibly non-empty targetDir. This is the only case where we use
+    // RoutingProxies with an empty sourceDir (sourceDir is what we add at input
+    // and remove at output, targetDir is what we remove at input and add at
+    // output.
+    //
+    // Note that using a transient ContextRoutingConnection
+    // is possible only because RoutingProxys don't rewrite
+    // notifications sources - otherwise we would have to
+    // keep the ContextRoutingConnection - just to preserve
+    // the 'wrapping listeners'
+    //
+    private static final class ContextRoutingConnection
+            extends RoutingServerProxy {
+        public ContextRoutingConnection(MBeanServer source,
+                                 String contextDir) {
+            super(source, "", contextDir, false);
+        }
+
+        // Not really needed - but this is safer and more optimized.
+        // See RoutingProxy for more details.
+        //
+        @Override
+        public Integer getMBeanCount() {
+            return source().getMBeanCount();
+        }
+
+        // Not really needed - but this is safer and more optimized.
+        // See RoutingProxy for more details.
+        //
+        @Override
+        public String[] getDomains() {
+            return source().getDomains();
+        }
+
+        // Not really needed - but this is safer and more optimized.
+        // See RoutingProxy for more details.
+        //
+        @Override
+        public String getDefaultDomain() {
+            return source().getDefaultDomain();
+        }
+
+    }
+
+    private static class ContextInvocationHandler implements InvocationHandler {
+        /*
+         * MBeanServer requests that don't include jmx.context//foo=bar//
+         * are forwarded to forwardMBS, which is the unadorned MBeanServer
+         * that knows nothing about the context namespace.
+         * MBeanServer requests that do include this prefix will
+         * usually (depending on the value of the loopMBS parameter to
+         * newContextForwarder) loop back to the combined MBeanServerForwarder
+         * that first implements
+         * jmx.context//:type=JMXNamespace and then implements
+         * jmx.context//foo=bar//.  The reason is that it is valid
+         * to have jmx.context//foo=bar//jmx.context//baz=buh//, although
+         * usually that will be combined into jmx.context//foo=bar;baz=buh//.
+         *
+         * Before forwarding to loopMBS, we must check for :type=JMXNamespace
+         * so that jmx.context//foo=bar//:type=JMXNamespace will exist.  Its
+         * existence is partial because it must remain "invisible": it should
+         * not show up in queryNames or getMBeanCount even though it does
+         * accept getAttribute and isRegistered and all other methods that
+         * reference a single MBean.
+         */
+        private MBeanServer forwardMBS;
+        private final MBeanServer loopMBS;
+        private static final MBeanServer emptyMBS = new MBeanServerSupport() {
+            @Override
+            public DynamicMBean getDynamicMBeanFor(ObjectName name)
+                    throws InstanceNotFoundException {
+                throw new InstanceNotFoundException(name.toString());
+            }
+
+            @Override
+            protected Set<ObjectName> getNames() {
+                return Collections.emptySet();
+            }
+        };
+
+        ContextInvocationHandler(MBeanServer forwardMBS, MBeanServer loopMBS) {
+            this.forwardMBS = forwardMBS;
+            DynamicMBean handlerMBean = new StandardMBean(
+                    new JMXNamespace(loopMBS), JMXNamespaceMBean.class, false);
+            MBeanServerForwarder handlerMBS = new SingleMBeanForwarder(
+                    NAMESPACE_HANDLER_WITHOUT_NAMESPACE, handlerMBean, false);
+            handlerMBS.setMBeanServer(loopMBS);
+            this.loopMBS = handlerMBS;
+        }
+
+        public Object invoke(Object proxy, final Method method, final Object[] args)
+        throws Throwable {
+            String methodName = method.getName();
+            Class<?>[] paramTypes = method.getParameterTypes();
+
+            // If this is a method from MBeanServerForwarder, handle it here.
+            // There are only two such methods: getMBeanServer() and
+            // setMBeanServer(mbs).
+            if (methodName.equals("getMBeanServer"))
+                return forwardMBS;
+            else if (methodName.equals("setMBeanServer")) {
+                this.forwardMBS = (MBeanServer) args[0];
+                return null;
+            }
+
+            // It is a method from MBeanServer.
+            // Find the first parameter whose declared type is ObjectName,
+            // and see if it is in the context namespace.  If so we need to
+            // trigger the logic for that namespace.  If not, we simply
+            // forward to the next MBeanServer in the chain.  This logic
+            // depends on the fact that if a method in the MBeanServer interface
+            // has a "routing" ObjectName parameter, it is always the first
+            // parameter of that type.  Conversely, if a method has an
+            // ObjectName parameter, then it makes sense to "route" that
+            // method.  Except for deserialize and instantiate, but if we
+            // recognize a context namespace in those methods' ObjectName
+            // parameters it is pretty harmless.
+            int objectNameI = -1;
+            for (int i = 0; i < paramTypes.length; i++) {
+                if (paramTypes[i] == ObjectName.class) {
+                    objectNameI = i;
+                    break;
+                }
+            }
+
+            if (objectNameI < 0)
+                return invoke(method, forwardMBS, args);
+
+            ObjectName target = (ObjectName) args[objectNameI];
+            if (target == null ||
+                    !target.getDomain().startsWith(NAMESPACE_PLUS_SEP))
+                return invoke(method, forwardMBS, args);
+
+            String domain = target.getDomain().substring(NAMESPACE_PLUS_SEP.length());
+
+            // The method routes through the (simulated) context namespace.
+            // Decode the context after it, e.g. jmx.context//jmx.locale=fr//...
+            // If there is no context part, we can throw an exception,
+            // because a forwarder has already handled the unique MBean
+            // jmx.context//:type=JMXNamespace.
+            int sep = domain.indexOf(NAMESPACE_SEPARATOR);
+            if (sep < 0)
+                return invoke(method, emptyMBS, args);  // throw exception
+            final String encodedContext = domain.substring(0, sep);
+
+            if (method.getName().startsWith("query") &&
+                    (encodedContext.contains("*") || encodedContext.contains("?"))) {
+                // Queries like jmx.context//*//d:k=v return
+                // an empty set, consistent with "real" namespaces.
+                return Collections.EMPTY_SET;
+            }
+
+            Map<String, String> ctx = new TreeMap<String, String>(getContext());
+            ctx.putAll(stringToMap(encodedContext));
+
+            return doWithContext(ctx, new Callable<Object>() {
+                public Object call() throws Exception {
+                    // Create a proxy connection that will strip
+                    // "jmx.context//" + encodedContext + "//" on input,
+                    // and put it back on output.
+                    //
+                    // Note that using a transient ContextRoutingConnection
+                    // is possible only because it doesn't rewrite
+                    // notification sources - otherwise we would have to
+                    // keep the ContextRoutingConnection - just to preserve
+                    // the 'wrapping listeners'
+                    //
+                    String namespace = NAMESPACE_PLUS_SEP + encodedContext;
+                    final ContextRoutingConnection route =
+                              new ContextRoutingConnection(loopMBS, namespace);
+
+                    if (LOG.isLoggable(Level.FINE))
+                        LOG.fine("context="+encodedContext);
+                    if (LOG.isLoggable(Level.FINER))
+                        LOG.finer(method.getName()+""+
+                            ((args==null)?"()":(""+Arrays.asList(args))));
+
+                    return invoke(method, route, args);
+                }
+            });
+        }
+
+        private static Object invoke(Method method, Object target, Object[] args)
+                throws Exception {
+            try {
+                return method.invoke(target, args);
+            } catch (InvocationTargetException e) {
+                Throwable cause = e.getCause();
+                if (cause instanceof Error)
+                    throw (Error) cause;
+                throw (Exception) cause;
+            }
+        }
+    }
+
+    private static String mapToString(Map<String, String> map) {
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            String key = encode(entry.getKey());
+            String value = encode(entry.getValue());
+            if (sb.length() > 0)
+                sb.append(";");
+            sb.append(key).append("=").append(value);
+        }
+        return sb.toString();
+    }
+
+    private static Map<String, String> stringToMap(String encodedContext) {
+        Map<String, String> map = stringToMapOrNull(encodedContext);
+        if (map == null) {
+            throw new IllegalArgumentException(
+                    "Invalid encoded context: " + encodedContext);
+        }
+        return map;
+    }
+
+    private static Map<String, String> stringToMapOrNull(String encodedContext) {
+        Map<String, String> map = new LinkedHashMap<String, String>();
+        StringTokenizer stok = new StringTokenizer(encodedContext, ";");
+        while (stok.hasMoreTokens()) {
+            String tok = stok.nextToken();
+            int eq = tok.indexOf('=');
+            if (eq < 0)
+                return null;
+            String key = decode(tok.substring(0, eq));
+            if (key.equals(""))
+                return null;
+            String value = decode(tok.substring(eq + 1));
+            map.put(key, value);
+        }
+        return map;
+    }
+
+    private static String encode(String s) {
+        try {
+            s = URLEncoder.encode(s, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);  // Should not happen
+        }
+        return s.replace("*", "%2A");
+        // The * character is left intact in URL encodings, but for us it
+        // is special (an ObjectName wildcard) so we must map it.
+        // We are assuming that URLDecoder will decode it the same way as any
+        // other hex escape.
+    }
+
+    private static String decode(String s) {
+        try {
+            return URLDecoder.decode(s, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- a/src/share/classes/javax/management/DefaultLoaderRepository.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/DefaultLoaderRepository.java	Tue Nov 11 09:07:58 2008 +0000
@@ -62,7 +62,7 @@
      *
      * @exception ClassNotFoundException The specified class could not be found.
      */
-    public static Class loadClass(String className)
+    public static Class<?> loadClass(String className)
         throws ClassNotFoundException {
         return javax.management.loading.DefaultLoaderRepository.loadClass(className);
     }
@@ -82,7 +82,7 @@
      *
      * @exception ClassNotFoundException The specified class could not be found.
      */
-    public static Class loadClassWithout(ClassLoader loader,String className)
+    public static Class<?> loadClassWithout(ClassLoader loader,String className)
         throws ClassNotFoundException {
         return javax.management.loading.DefaultLoaderRepository.loadClassWithout(loader, className);
     }
--- a/src/share/classes/javax/management/Descriptor.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/Descriptor.java	Tue Nov 11 09:07:58 2008 +0000
@@ -35,8 +35,8 @@
 // Javadoc imports:
 import java.lang.management.MemoryUsage;
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.ResourceBundle;
-
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.MXBeanMappingFactory;
 import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
@@ -101,7 +101,7 @@
  *
  * <tr><th>Name</th><th>Type</th><th>Used in</th><th>Meaning</th></tr>
  *
- * <tr><td><a name="defaultValue"><i>defaultValue</i></a><td>Object</td>
+ * <tr id="defaultValue"><td><i>defaultValue</i><td>Object</td>
  * <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
  *
  * <td>Default value for an attribute or parameter.  See
@@ -118,19 +118,22 @@
  * deprecation, for example {@code "1.3 Replaced by the Capacity
  * attribute"}.</td>
  *
- * <tr id="descriptionResourceBundleBaseName">
- * <td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td>
+ * <tr><td id="descriptionResourceBundleBaseName"><i>descriptionResource<br>
+ * BundleBaseName</i></td><td>String</td><td>Any</td>
  *
  * <td>The base name for the {@link ResourceBundle} in which the key given in
  * the {@code descriptionResourceKey} field can be found, for example
- * {@code "com.example.myapp.MBeanResources"}.</td>
+ * {@code "com.example.myapp.MBeanResources"}.  See
+ * {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.</td>
  *
- * <tr id="descriptionResourceKey">
- * <td>descriptionResourceKey</td><td>String</td><td>Any</td>
+ * <tr><td id="descriptionResourceKey"><i>descriptionResourceKey</i></td>
+ * <td>String</td><td>Any</td>
  *
  * <td>A resource key for the description of this element.  In
  * conjunction with the {@code descriptionResourceBundleBaseName},
- * this can be used to find a localized version of the description.</td>
+ * this can be used to find a localized version of the description.
+ * See {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.
+ * </td>
  *
  * <tr><td>enabled</td><td>String</td>
  * <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td>
@@ -144,7 +147,7 @@
  * might be disabled if it cannot currently be emitted but could be in
  * other circumstances.</td>
  *
- * <tr><td><a name="immutableInfo"><i>immutableInfo</i></a><td>String</td>
+ * <tr id="immutableInfo"><td><i>immutableInfo</i><td>String</td>
  * <td>MBeanInfo</td>
  *
  * <td>The string {@code "true"} or {@code "false"} according as this
@@ -153,9 +156,11 @@
  * the lifetime of the MBean.  Hence, a client can read it once and
  * cache the read value.  When this field is false or absent, there is
  * no such guarantee, although that does not mean that the MBeanInfo
- * will necessarily change.</td>
+ * will necessarily change.  See also the <a
+ * href="MBeanInfo.html#info-changed">{@code "jmx.mbean.info.changed"}</a>
+ * notification.</td>
  *
- * <tr><td>infoTimeout</td><td>String<br>Long</td><td>MBeanInfo</td>
+ * <tr id="infoTimeout"><td>infoTimeout</td><td>String<br>Long</td><td>MBeanInfo</td>
  *
  * <td>The time in milli-seconds that the MBeanInfo can reasonably be
  * expected to be unchanged.  The value can be a {@code Long} or a
@@ -164,9 +169,11 @@
  * that the MBeanInfo is not likely to change within this period and
  * therefore can be cached.  When this field is missing or has the
  * value zero, it is not recommended to cache the MBeanInfo unless it
- * has the {@code immutableInfo} set to {@code true}.</td></tr>
+ * has the {@code immutableInfo} set to {@code true} or it has <a
+ * href="MBeanInfo.html#info-changed">{@code "jmx.mbean.info.changed"}</a> in
+ * its {@link MBeanNotificationInfo} array.</td></tr>
  *
- * <tr><td><a name="interfaceClassName"><i>interfaceClassName</i></a></td>
+ * <tr id="interfaceClassName"><td><i>interfaceClassName</i></td>
  * <td>String</td><td>MBeanInfo</td>
  *
  * <td>The Java interface name for a Standard MBean or MXBean, as
@@ -175,19 +182,26 @@
  * StandardMBean} class will have this field in its MBeanInfo
  * Descriptor.</td>
  *
- * <tr><td><a name="legalValues"><i>legalValues</i></a></td>
+ * <tr id="legalValues"><td><i>legalValues</i></td>
  * <td>{@literal Set<?>}</td><td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
  *
  * <td>Legal values for an attribute or parameter.  See
  * {@link javax.management.openmbean}.</td>
  *
- * <tr><td><a name="maxValue"><i>maxValue</i></a><td>Object</td>
+ * <tr id="locale"><td><i>locale</i></td>
+ * <td>String</td><td>Any</td>
+ *
+ * <td>The {@linkplain Locale locale} of the description in this
+ * {@code MBeanInfo}, {@code MBeanAttributeInfo}, etc, as returned
+ * by {@link Locale#toString()}.</td>
+ *
+ * <tr id="maxValue"><td><i>maxValue</i><td>Object</td>
  * <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
  *
  * <td>Maximum legal value for an attribute or parameter.  See
  * {@link javax.management.openmbean}.</td>
  *
- * <tr><td><a name="metricType">metricType</a><td>String</td>
+ * <tr id="metricType"><td>metricType</td><td>String</td>
  * <td>MBeanAttributeInfo<br>MBeanOperationInfo</td>
  *
  * <td>The type of a metric, one of the strings "counter" or "gauge".
@@ -200,13 +214,13 @@
  * that can increase or decrease.  Examples might be the number of
  * open connections or a cache hit rate or a temperature reading.
  *
- * <tr><td><a name="minValue"><i>minValue</i></a><td>Object</td>
+ * <tr id="minValue"><td><i>minValue</i><td>Object</td>
  * <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
  *
  * <td>Minimum legal value for an attribute or parameter.  See
  * {@link javax.management.openmbean}.</td>
  *
- * <tr><td><a name="mxbean"><i>mxbean</i></a><td>String</td>
+ * <tr id="mxbean"><td><i>mxbean</i><td>String</td>
  * <td>MBeanInfo</td>
  *
  * <td>The string {@code "true"} or {@code "false"} according as this
@@ -223,7 +237,7 @@
  * MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
  * one.</td>
  *
- * <tr><td><a name="openType"><i>openType</i></a><td>{@link OpenType}</td>
+ * <tr id="openType"><td><i>openType</i><td>{@link OpenType}</td>
  * <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
  *
  * <td><p>The Open Type of this element.  In the case of {@code
@@ -240,7 +254,7 @@
  * which case it indicates the Open Type that the {@link
  * Notification#getUserData() user data} will have.</td>
  *
- * <tr><td><a name="originalType"><i>originalType</i></a><td>String</td>
+ * <tr id="originalType"><td><i>originalType</i><td>String</td>
  * <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
  *
  * <td><p>The original Java type of this element as it appeared in the
@@ -282,11 +296,132 @@
  *
  * </table>
  *
- * <p>Some additional fields are defined by Model MBeans.  See
- * {@link javax.management.modelmbean.ModelMBeanInfo ModelMBeanInfo}
- * and related classes and the chapter "Model MBeans" of the
- * <a href="http://java.sun.com/products/JavaManagement/download.html">
- * JMX Specification</a>.</p>
+ * <p>Some additional fields are defined by Model MBeans.  See the
+ * information for <a href="modelmbean/ModelMBeanInfo.html#descriptor"><!--
+ * -->{@code ModelMBeanInfo}</a>,
+ * <a href="modelmbean/ModelMBeanAttributeInfo.html#descriptor"><!--
+ * -->{@code ModelMBeanAttributeInfo}</a>,
+ * <a href="modelmbean/ModelMBeanConstructorInfo.html#descriptor"><!--
+ * -->{@code ModelMBeanConstructorInfo}</a>,
+ * <a href="modelmbean/ModelMBeanNotificationInfo.html#descriptor"><!--
+ * -->{@code ModelMBeanNotificationInfo}</a>, and
+ * <a href="modelmbean/ModelMBeanOperationInfo.html#descriptor"><!--
+ * -->{@code ModelMBeanOperationInfo}</a>, as
+ * well as the chapter "Model MBeans" of the <a
+ * href="http://java.sun.com/products/JavaManagement/download.html">JMX
+ * Specification</a>.  The following table summarizes these fields.  Note
+ * that when the Type in this table is Number, a String that is the decimal
+ * representation of a Long can also be used.</p>
+ *
+ * <p>Nothing prevents the use of these fields in MBeans that are not Model
+ * MBeans.  The <a href="#displayName">displayName</a>, <a href="#severity"><!--
+ * -->severity</a>, and <a href="#visibility">visibility</a> fields are of
+ * interest outside Model MBeans, for example.  But only Model MBeans have
+ * a predefined behavior for these fields.</p>
+ *
+ * <table border="1" cellpadding="5">
+ *
+ * <tr><th>Name</th><th>Type</th><th>Used in</th><th>Meaning</th></tr>
+ *
+ * <tr><td>class</td><td>String</td><td>ModelMBeanOperationInfo</td>
+ *     <td>Class where method is defined (fully qualified).</td></tr>
+ *
+ * <tr><td>currencyTimeLimit</td><td>Number</td>
+ *     <td>ModelMBeanInfo<br>ModelMBeanAttributeInfo<br>ModelMBeanOperationInfo</td>
+ *     <td>How long cached value is valid: &lt;0 never, =0 always,
+ *         &gt;0 seconds.</td></tr>
+ *
+ * <tr><td>default</td><td>Object</td><td>ModelMBeanAttributeInfo</td>
+ *     <td>Default value for attribute.</td></tr>
+ *
+ * <tr><td>descriptorType</td><td>String</td><td>Any</td>
+ *     <td>Type of descriptor, "mbean", "attribute", "constructor", "operation",
+ *         or "notification".</td></tr>
+ *
+ * <tr id="displayName"><td>displayName</td><td>String</td><td>Any</td>
+ *     <td>Human readable name of this item.</td></tr>
+ *
+ * <tr><td>export</td><td>String</td><td>ModelMBeanInfo</td>
+ *     <td>Name to be used to export/expose this MBean so that it is
+ *         findable by other JMX Agents.</td></tr>
+ *
+ * <tr><td>getMethod</td><td>String</td><td>ModelMBeanAttributeInfo</td>
+ *     <td>Name of operation descriptor for get method.</td></tr>
+ *
+ * <tr><td>lastUpdatedTimeStamp</td><td>Number</td>
+ *     <td>ModelMBeanAttributeInfo<br>ModelMBeanOperationInfo</td>
+ *     <td>When <a href="#value-field">value</a> was set.</td></tr>
+ *
+ * <tr><td>log</td><td>String</td><td>ModelMBeanInfo<br>ModelMBeanNotificationInfo</td>
+ *     <td>t or T: log all notifications, f or F: log no notifications.</td></tr>
+ *
+ * <tr><td>logFile</td><td>String</td><td>ModelMBeanInfo<br>ModelMBeanNotificationInfo</td>
+ *     <td>Fully qualified filename to log events to.</td></tr>
+ *
+ * <tr><td>messageID</td><td>String</td><td>ModelMBeanNotificationInfo</td>
+ *     <td>Unique key for message text (to allow translation, analysis).</td></tr>
+ *
+ * <tr><td>messageText</td><td>String</td><td>ModelMBeanNotificationInfo</td>
+ *     <td>Text of notification.</td></tr>
+ *
+ * <tr><td>name</td><td>String</td><td>Any</td>
+ *     <td>Name of this item.</td></tr>
+ *
+ * <tr><td>persistFile</td><td>String</td><td>ModelMBeanInfo</td>
+ *     <td>File name into which the MBean should be persisted.</td></tr>
+ *
+ * <tr><td>persistLocation</td><td>String</td><td>ModelMBeanInfo</td>
+ *     <td>The fully qualified directory name where the MBean should be
+ *         persisted (if appropriate).</td></tr>
+ *
+ * <tr><td>persistPeriod</td><td>Number</td>
+ *     <td>ModelMBeanInfo<br>ModelMBeanAttributeInfo</td>
+ *     <td>Frequency of persist cycle in seconds. Used when persistPolicy is
+ *         "OnTimer" or "NoMoreOftenThan".</td></tr>
+ *
+ * <tr><td>persistPolicy</td><td>String</td>
+ *     <td>ModelMBeanInfo<br>ModelMBeanAttributeInfo</td>
+ *     <td>One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
+ *         See the section "MBean Descriptor Fields" in the JMX specification
+ *         document.</td></tr>
+ *
+ * <tr><td>presentationString</td><td>String</td><td>Any</td>
+ *     <td>XML formatted string to allow presentation of data.</td></tr>
+ *
+ * <tr><td>protocolMap</td><td>Descriptor</td><td>ModelMBeanAttributeInfo</td>
+ *     <td>See the section "Protocol Map Support" in the JMX specification
+ *         document.  Mappings must be appropriate for the attribute and entries
+ *         can be updated or augmented at runtime.</td></tr>
+ *
+ * <tr><td>role</td><td>String</td>
+ *     <td>ModelMBeanConstructorInfo<br>ModelMBeanOperationInfo</td>
+ *     <td>One of "constructor", "operation", "getter", or "setter".</td></tr>
+ *
+ * <tr><td>setMethod</td><td>String</td><td>ModelMBeanAttributeInfo</td>
+ *     <td>Name of operation descriptor for set method.</td></tr>
+ *
+ * <tr id="severity"><td>severity</td><td>Number</td>
+ *     <td>ModelMBeanNotificationInfo</td>
+ *     <td>0-6 where 0: unknown; 1: non-recoverable;
+ *         2: critical, failure; 3: major, severe;
+ *         4: minor, marginal, error; 5: warning;
+ *         6: normal, cleared, informative</td></tr>
+ *
+ * <tr><td>targetObject</td><td>Object</td><td>ModelMBeanOperationInfo</td>
+ *     <td>Object on which to execute this method.</td></tr>
+ *
+ * <tr><td>targetType</td><td>String</td><td>ModelMBeanOperationInfo</td>
+ *     <td>type of object reference for targetObject. Can be:
+ *         ObjectReference | Handle | EJBHandle | IOR | RMIReference.</td></tr>
+ *
+ * <tr id="value-field"><td>value</td><td>Object</td>
+ *     <td>ModelMBeanAttributeInfo<br>ModelMBeanOperationInfo</td>
+ *     <td>Current (cached) value for attribute or operation.</td></tr>
+ *
+ * <tr id="visibility"><td>visibility</td><td>Number</td><td>Any</td>
+ *     <td>1-4 where 1: always visible, 4: rarely visible.</td></tr>
+ *
+ * </table>
  *
  * @since 1.5
  */
@@ -439,7 +574,7 @@
     public boolean isValid() throws RuntimeOperationsException;
 
     /**
-     * Compares this descriptor to the given object.  The objects are equal if
+     * <p>Compares this descriptor to the given object.  The objects are equal if
      * the given object is also a Descriptor, and if the two Descriptors have
      * the same field names (possibly differing in case) and the same
      * associated values.  The respective values for a field in the two
--- a/src/share/classes/javax/management/JMRuntimeException.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/JMRuntimeException.java	Tue Nov 11 09:07:58 2008 +0000
@@ -70,7 +70,7 @@
         try {
             java.lang.reflect.Method initCause =
                 Throwable.class.getMethod("initCause",
-                                          new Class[] {Throwable.class});
+                                          new Class<?>[] {Throwable.class});
             initCause.invoke(this, new Object[] {cause});
         } catch (Exception e) {
             // OK: just means we won't have debugging info
--- a/src/share/classes/javax/management/JMX.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/JMX.java	Tue Nov 11 09:07:58 2008 +0000
@@ -30,6 +30,7 @@
 import com.sun.jmx.remote.util.ClassLogger;
 import java.beans.BeanInfo;
 import java.beans.PropertyDescriptor;
+import java.io.IOException;
 import java.io.Serializable;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
@@ -37,6 +38,7 @@
 import java.lang.reflect.Proxy;
 import java.util.Map;
 import java.util.TreeMap;
+import javax.management.namespace.JMXNamespaces;
 import javax.management.openmbean.MXBeanMappingFactory;
 
 /**
@@ -60,6 +62,21 @@
      */
     public static final String DEFAULT_VALUE_FIELD = "defaultValue";
 
+   /**
+     * The name of the <a
+     * href="Descriptor.html#descriptionResourceBundleBaseName">{@code
+     * descriptionResourceBundleBaseName}</a> field.
+     */
+    public static final String DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD =
+            "descriptionResourceBundleBaseName";
+
+    /**
+     * The name of the <a href="Descriptor.html#descriptionResourceKey">{@code
+     * descriptionResourceKey}</a> field.
+     */
+    public static final String DESCRIPTION_RESOURCE_KEY_FIELD =
+            "descriptionResourceKey";
+
     /**
      * The name of the <a href="Descriptor.html#immutableInfo">{@code
      * immutableInfo}</a> field.
@@ -79,6 +96,12 @@
     public static final String LEGAL_VALUES_FIELD = "legalValues";
 
     /**
+     * The name of the <a href="Descriptor.html#locale">{@code locale}</a>
+     * field.
+     */
+    public static final String LOCALE_FIELD = "locale";
+
+    /**
      * The name of the <a href="Descriptor.html#maxValue">{@code
      * maxValue}</a> field.
      */
@@ -120,13 +143,12 @@
      * <p>Options to apply to an MBean proxy or to an instance of {@link
      * StandardMBean}.</p>
      *
-     * <p>For example, to specify a custom {@link MXBeanMappingFactory}
-     * for a {@code StandardMBean}, you might write this:</p>
+     * <p>For example, to specify the "wrapped object visible" option for a
+     * {@code StandardMBean}, you might write this:</p>
      *
      * <pre>
-     * MXBeanMappingFactory factory = new MyMXBeanMappingFactory();
-     * JMX.MBeanOptions opts = new JMX.MBeanOptions();
-     * opts.setMXBeanMappingFactory(factory);
+     * StandardMBean.Options opts = new StandardMBean.Options();
+     * opts.setWrappedObjectVisible(true);
      * StandardMBean mbean = new StandardMBean(impl, intf, opts);
      * </pre>
      *
@@ -463,6 +485,12 @@
      * likewise for the other methods of {@link
      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
      *
+     * <p>This method is equivalent to {@link
+     * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions)
+     * newMBeanProxy(connection, objectName, interfaceClass, opts)}, where
+     * {@code opts} is a {@link JMX.ProxyOptions} representing the
+     * {@code notificationEmitter} parameter.</p>
+     *
      * @param connection the MBean server to forward to.
      * @param objectName the name of the MBean within
      * {@code connection} to forward to.
@@ -555,10 +583,6 @@
      *
      * </ul>
      *
-     * <p>The object returned by this method is a
-     * {@link Proxy} whose {@code InvocationHandler} is an
-     * {@link MBeanServerInvocationHandler}.</p>
-     *
      * <p>This method is equivalent to {@link
      * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
      * boolean) newMXBeanProxy(connection, objectName, interfaceClass,
@@ -601,6 +625,17 @@
      * likewise for the other methods of {@link
      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
      *
+     * <p>This method is equivalent to {@link
+     * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions)
+     * newMBeanProxy(connection, objectName, interfaceClass, opts)}, where
+     * {@code opts} is a {@link JMX.ProxyOptions} where the {@link
+     * JMX.ProxyOptions#getMXBeanMappingFactory() MXBeanMappingFactory}
+     * property is
+     * {@link MXBeanMappingFactory#forInterface(Class)
+     * MXBeanMappingFactory.forInterface(interfaceClass)} and the {@link
+     * JMX.ProxyOptions#isNotificationEmitter() notificationEmitter} property
+     * is equal to the {@code notificationEmitter} parameter.</p>
+     *
      * @param connection the MBean server to forward to.
      * @param objectName the name of the MBean within
      * {@code connection} to forward to.
@@ -655,6 +690,36 @@
      *     arbitrary Java types and Open Types.</li>
      * </ul>
      *
+     * <p>The object returned by this method is a
+     * {@link Proxy} whose {@code InvocationHandler} is an
+     * {@link MBeanServerInvocationHandler}.  This means that it is possible
+     * to retrieve the parameters that were used to produce the proxy.  If the
+     * proxy was produced as follows...</p>
+     *
+     * <pre>
+     * FooMBean proxy =
+     *     JMX.newMBeanProxy(connection, objectName, FooMBean.class, opts);
+     * </pre>
+     *
+     * <p>...then you can get the {@code MBeanServerInvocationHandler} like
+     * this...</p>
+     *
+     * <pre>
+     * MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
+     *     {@link Proxy#getInvocationHandler(Object)
+     *            Proxy.getInvocationHandler}(proxy);
+     * </pre>
+     *
+     * <p>...and you can retrieve {@code connection}, {@code
+     * objectName}, and {@code opts} using the {@link
+     * MBeanServerInvocationHandler#getMBeanServerConnection()
+     * getMBeanServerConnection()}, {@link
+     * MBeanServerInvocationHandler#getObjectName() getObjectName()}, and
+     * {@link MBeanServerInvocationHandler#getMBeanOptions() getMBeanOptions()}
+     * methods on {@code mbsih}.  You can retrieve {@code FooMBean.class}
+     * using {@code proxy.getClass().}{@link
+     * Class#getInterfaces() getInterfaces()}.</p>
+     *
      * @param connection the MBean server to forward to.
      * @param objectName the name of the MBean within
      * {@code connection} to forward to.
@@ -703,12 +768,12 @@
 
         InvocationHandler handler = new MBeanServerInvocationHandler(
                 connection, objectName, opts);
-        final Class[] interfaces;
+        final Class<?>[] interfaces;
         if (notificationEmitter) {
             interfaces =
                 new Class<?>[] {interfaceClass, NotificationEmitter.class};
         } else
-            interfaces = new Class[] {interfaceClass};
+            interfaces = new Class<?>[] {interfaceClass};
         Object proxy = Proxy.newProxyInstance(
                 interfaceClass.getClassLoader(),
                 interfaces,
@@ -765,4 +830,80 @@
             ((DynamicWrapperMBean) mbean).getWrappedObject() : mbean;
         return (MBeanInjector.injectsSendNotification(resource));
     }
+
+    /**
+     * <p>Return the version of the JMX specification that a (possibly remote)
+     * MBean Server is using.  The JMX specification described in this
+     * documentation is version 2.0.  The earlier versions that might be
+     * reported by this method are 1.0, 1.1, 1.2, and 1.4.  (There is no 1.3.)
+     * All of these versions and all future versions can be compared using
+     * {@link String#compareTo(String)}.  So, for example, to tell if
+     * {@code mbsc} is running at least version 2.0 you can write:</p>
+     *
+     * <pre>
+     * String version = JMX.getSpecificationVersion(mbsc, null);
+     * boolean atLeast2dot0 = (version.compareTo("2.0") >= 0);
+     * </pre>
+     *
+     * <p>A remote MBean Server might be running an earlier version of the
+     * JMX API, and in that case <a href="package-summary.html#interop">certain
+     * features</a> might not be available in it.</p>
+     *
+     * <p>The version of the MBean Server {@code mbsc} is not necessarily
+     * the version of all namespaces within that MBean Server, for example
+     * if some of them use {@link javax.management.namespace.JMXRemoteNamespace
+     * JMXRemoteNamespace}.  To determine the version of the namespace
+     * that a particular MBean is in, give its name as the {@code mbeanName}
+     * parameter.</p>
+     *
+     * @param mbsc a connection to an MBean Server.
+     *
+     * @param mbeanName the name of an MBean within that MBean Server, or null.
+     * If non-null, the namespace of this name, as determined by
+     * {@link JMXNamespaces#getContainingNamespace
+     * JMXNamespaces.getContainingNamespace}, is the one whose specification
+     * version will be returned.
+     *
+     * @return the JMX specification version reported by that MBean Server.
+     *
+     * @throws IllegalArgumentException if {@code mbsc} is null, or if
+     * {@code mbeanName} includes a wildcard character ({@code *} or {@code ?})
+     * in its namespace.
+     *
+     * @throws IOException if the version cannot be obtained, either because
+     * there is a communication problem or because the remote MBean Server
+     * does not have the appropriate {@linkplain
+     * MBeanServerDelegateMBean#getSpecificationVersion() attribute}.
+     *
+     * @see <a href="package-summary.html#interop">Interoperability between
+     * versions of the JMX specification</a>
+     * @see MBeanServerDelegateMBean#getSpecificationVersion
+     */
+    public static String getSpecificationVersion(
+            MBeanServerConnection mbsc, ObjectName mbeanName)
+            throws IOException {
+        if (mbsc == null)
+            throw new IllegalArgumentException("Null MBeanServerConnection");
+
+        String namespace;
+        if (mbeanName == null)
+            namespace = "";
+        else
+            namespace = JMXNamespaces.getContainingNamespace(mbeanName);
+        if (namespace.contains("*") || namespace.contains("?")) {
+            throw new IllegalArgumentException(
+                    "ObjectName contains namespace wildcard: " + mbeanName);
+        }
+
+        try {
+            if (namespace.length() > 0)
+                mbsc = JMXNamespaces.narrowToNamespace(mbsc, namespace);
+            return (String) mbsc.getAttribute(
+                    MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
+        } catch (IOException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
 }
--- a/src/share/classes/javax/management/MBeanAttributeInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanAttributeInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -316,7 +316,7 @@
      */
     private static String attributeType(Method getter, Method setter)
             throws IntrospectionException {
-        Class type = null;
+        Class<?> type = null;
 
         if (getter != null) {
             if (getter.getParameterTypes().length != 0) {
@@ -330,7 +330,7 @@
         }
 
         if (setter != null) {
-            Class params[] = setter.getParameterTypes();
+            Class<?> params[] = setter.getParameterTypes();
             if (params.length != 1) {
                 throw new IntrospectionException("bad setter arg count");
             }
--- a/src/share/classes/javax/management/MBeanConstructorInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanConstructorInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -64,7 +64,7 @@
      * @param constructor The <CODE>java.lang.reflect.Constructor</CODE>
      * object describing the MBean constructor.
      */
-    public MBeanConstructorInfo(String description, Constructor constructor) {
+    public MBeanConstructorInfo(String description, Constructor<?> constructor) {
         this(constructor.getName(), description,
              constructorSignature(constructor),
              Introspector.descriptorForElement(constructor));
@@ -210,8 +210,8 @@
         return hash;
     }
 
-    private static MBeanParameterInfo[] constructorSignature(Constructor cn) {
-        final Class[] classes = cn.getParameterTypes();
+    private static MBeanParameterInfo[] constructorSignature(Constructor<?> cn) {
+        final Class<?>[] classes = cn.getParameterTypes();
         final Annotation[][] annots = cn.getParameterAnnotations();
         return MBeanOperationInfo.parameters(classes, annots);
     }
--- a/src/share/classes/javax/management/MBeanInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -25,6 +25,7 @@
 
 package javax.management;
 
+import com.sun.jmx.mbeanserver.Util;
 import java.io.IOException;
 import java.io.StreamCorruptedException;
 import java.io.Serializable;
@@ -37,6 +38,12 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import static javax.management.ImmutableDescriptor.nonNullDescriptor;
 
 /**
@@ -45,6 +52,17 @@
  * management operations.  Instances of this class are immutable.
  * Subclasses may be mutable but this is not recommended.</p>
  *
+ * <p id="info-changed">Usually the {@code MBeanInfo} for any given MBean does
+ * not change over the lifetime of that MBean.  Dynamic MBeans can change their
+ * {@code MBeanInfo} and in that case it is recommended that they emit a {@link
+ * Notification} with a {@linkplain Notification#getType() type} of {@code
+ * "jmx.mbean.info.changed"} and a {@linkplain Notification#getUserData()
+ * userData} that is the new {@code MBeanInfo}.  This is not required, but
+ * provides a conventional way for clients of the MBean to discover the change.
+ * See also the <a href="Descriptor.html#immutableInfo">immutableInfo</a> and
+ * <a href="Descriptor.html#infoTimeout">infoTimeout</a> fields in the {@code
+ * MBeanInfo} {@link Descriptor}.</p>
+ *
  * <p>The contents of the <code>MBeanInfo</code> for a Dynamic MBean
  * are determined by its {@link DynamicMBean#getMBeanInfo
  * getMBeanInfo()} method.  This includes Open MBeans and Model
@@ -62,27 +80,49 @@
  * constructors in that object;
  *
  * <li>{@link #getAttributes()} returns the list of all attributes
- * whose existence is deduced from the presence in the MBean interface
- * of a <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
- * <code>set<i>Name</i></code> method that conforms to the conventions
+ * whose existence is deduced as follows:
+ * <ul>
+ * <li>if the Standard MBean is defined with an MBean interface,
+ * from <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
+ * <code>set<i>Name</i></code> methods that conform to the conventions
  * for Standard MBeans;
+ * <li>if the Standard MBean is defined with the {@link MBean &#64;MBean} or
+ * {@link MXBean &#64;MXBean} annotation on a class, from methods with the
+ * {@link ManagedAttribute &#64;ManagedAttribute} annotation;
+ * </ul>
  *
- * <li>{@link #getOperations()} returns the list of all methods in
+ * <li>{@link #getOperations()} returns the list of all operations whose
+ * existence is deduced as follows:
+ * <ul>
+ * <li>if the Standard MBean is defined with an MBean interface, from methods in
  * the MBean interface that do not represent attributes;
+ * <li>if the Standard MBean is defined with the {@link MBean &#64;MBean} or
+ * {@link MXBean &#64;MXBean} annotation on a class, from methods with the
+ * {@link ManagedOperation &#64;ManagedOperation} annotation;
+ * </ul>
  *
- * <li>{@link #getNotifications()} returns an empty array if the MBean
- * does not implement the {@link NotificationBroadcaster} interface,
- * otherwise the result of calling {@link
+ * <li>{@link #getNotifications()} returns:
+ * <ul>
+ * <li>if the MBean implements the {@link NotificationBroadcaster} interface,
+ * the result of calling {@link
  * NotificationBroadcaster#getNotificationInfo()} on it;
+ * <li>otherwise, if there is a {@link NotificationInfo &#64;NotificationInfo}
+ * or {@link NotificationInfos &#64;NotificationInfos} annotation on the
+ * MBean interface or <code>&#64;MBean</code> or <code>&#64;MXBean</code>
+ * class, the array implied by those annotations;
+ * <li>otherwise an empty array;
+ * </ul>
  *
  * <li>{@link #getDescriptor()} returns a descriptor containing the contents
- * of any descriptor annotations in the MBean interface.
+ * of any descriptor annotations in the MBean interface (see
+ * {@link DescriptorFields &#64;DescriptorFields} and
+ * {@link DescriptorKey &#64;DescriptorKey}).
  *
  * </ul>
  *
  * <p>The description returned by {@link #getDescription()} and the
  * descriptions of the contained attributes and operations are determined
- * by the corresponding <!-- link here --> Description annotations if any;
+ * by the corresponding {@link Description} annotations if any;
  * otherwise their contents are not specified.</p>
  *
  * <p>The remaining details of the <code>MBeanInfo</code> for a
@@ -257,6 +297,7 @@
      * <p>Since this class is immutable, the clone method is chiefly of
      * interest to subclasses.</p>
      */
+     @Override
      public Object clone () {
          try {
              return super.clone() ;
@@ -441,6 +482,7 @@
         return (Descriptor) nonNullDescriptor(descriptor).clone();
     }
 
+    @Override
     public String toString() {
         return
             getClass().getName() + "[" +
@@ -472,6 +514,7 @@
      * @return true if and only if <code>o</code> is an MBeanInfo that is equal
      * to this one according to the rules above.
      */
+    @Override
     public boolean equals(Object o) {
         if (o == this)
             return true;
@@ -491,6 +534,7 @@
              Arrays.equals(p.fastGetNotifications(), fastGetNotifications()));
     }
 
+    @Override
     public int hashCode() {
         /* Since computing the hashCode is quite expensive, we cache it.
            If by some terrible misfortune the computed value is 0, the
@@ -524,8 +568,8 @@
      * a WeakHashMap so that we don't prevent a class from being
      * garbage collected just because we know whether it's immutable.
      */
-    private static final Map<Class, Boolean> arrayGettersSafeMap =
-        new WeakHashMap<Class, Boolean>();
+    private static final Map<Class<?>, Boolean> arrayGettersSafeMap =
+        new WeakHashMap<Class<?>, Boolean>();
 
     /**
      * Return true if <code>subclass</code> is known to preserve the
@@ -537,7 +581,7 @@
      * This is obviously not an infallible test for immutability,
      * but it works for the public interfaces of the MBean*Info classes.
     */
-    static boolean arrayGettersSafe(Class subclass, Class immutableClass) {
+    static boolean arrayGettersSafe(Class<?> subclass, Class<?> immutableClass) {
         if (subclass == immutableClass)
             return true;
         synchronized (arrayGettersSafeMap) {
@@ -714,4 +758,377 @@
             throw new StreamCorruptedException("Got unexpected byte.");
         }
     }
+
+    /**
+     * <p>Return an {@code MBeanInfo} object that is the same as this one
+     * except that its descriptions are localized in the given locale.
+     * This means the text returned by {@link MBeanInfo#getDescription}
+     * (the description of the MBean itself), and the text returned by the
+     * {@link MBeanFeatureInfo#getDescription getDescription()} method
+     * for every {@linkplain MBeanAttributeInfo attribute}, {@linkplain
+     * MBeanOperationInfo operation}, {@linkplain MBeanConstructorInfo
+     * constructor}, and {@linkplain MBeanNotificationInfo notification}
+     * contained in the {@code MBeanInfo}.</p>
+     *
+     * <p>Here is how the description {@code this.getDescription()} is
+     * localized.</p>
+     *
+     * <p>First, if the {@linkplain #getDescriptor() descriptor}
+     * of this {@code MBeanInfo} contains a field <code><a
+     * href="Descriptor.html#locale">"locale"</a></code>, and the value of
+     * the field is the same as {@code locale.toString()}, then this {@code
+     * MBeanInfo} is returned. Otherwise, localization proceeds as follows,
+     * and the {@code "locale"} field in the returned {@code MBeanInfo} will
+     * be {@code locale.toString()}.
+     *
+     * <p>A <em>{@code className}</em> is determined. If this
+     * {@code MBeanInfo} contains a descriptor with the field
+     * <a href="Descriptor.html#interfaceClassName">{@code
+     * "interfaceClassName"}</a>, then the value of that field is the
+     * {@code className}. Otherwise, it is {@link #getClassName()}.
+     * Everything before the last period (.) in the {@code className} is
+     * the <em>{@code package}</em>, and everything after is the <em>{@code
+     * simpleClassName}</em>. (If there is no period, then the {@code package}
+     * is empty and the {@code simpleClassName} is the same as the {@code
+     * className}.)</p>
+     *
+     * <p>A <em>{@code resourceKey}</em> is determined. If this {@code
+     * MBeanInfo} contains a {@linkplain MBeanInfo#getDescriptor() descriptor}
+     * with a field {@link JMX#DESCRIPTION_RESOURCE_KEY_FIELD
+     * "descriptionResourceKey"}, the value of the field is
+     * the {@code resourceKey}. Otherwise, the {@code resourceKey} is {@code
+     * simpleClassName + ".mbean"}.</p>
+     *
+     * <p>A <em>{@code resourceBundleBaseName}</em> is determined. If
+     * this {@code MBeanInfo} contains a descriptor with a field {@link
+     * JMX#DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD
+     * "descriptionResourceBundleBaseName"}, the value of the field
+     * is the {@code resourceBundleBaseName}. Otherwise, the {@code
+     * resourceBundleBaseName} is {@code package + ".MBeanDescriptions"}.
+     *
+     * <p>Then, a {@link java.util.ResourceBundle ResourceBundle} is
+     * determined, using<br> {@link java.util.ResourceBundle#getBundle(String,
+     * Locale, ClassLoader) ResourceBundle.getBundle(resourceBundleBaseName,
+     * locale, loader)}. If this succeeds, and if {@link
+     * java.util.ResourceBundle#getString(String) getString(resourceKey)}
+     * returns a string, then that string is the localized description.
+     * Otherwise, the original description is unchanged.</p>
+     *
+     * <p>A localized description for an {@code MBeanAttributeInfo} is
+     * obtained similarly. The default {@code resourceBundleBaseName}
+     * is the same as above. The default description and the
+     * descriptor fields {@code "descriptionResourceKey"} and {@code
+     * "descriptionResourceBundleBaseName"} come from the {@code
+     * MBeanAttributeInfo} rather than the {@code MBeanInfo}. If the
+     * attribute's {@linkplain MBeanFeatureInfo#getName() name} is {@code
+     * Foo} then its default {@code resourceKey} is {@code simpleClassName +
+     * ".attribute.Foo"}.</p>
+     *
+     * <p>Similar rules apply for operations, constructors, and notifications.
+     * If the name of the operation, constructor, or notification is {@code
+     * Foo} then the default {@code resourceKey} is respectively {@code
+     * simpleClassName + ".operation.Foo"}, {@code simpleClassName +
+     * ".constructor.Foo"}, or {@code simpleClassName + ".notification.Foo"}.
+     * If two operations or constructors have the same name (overloading) then
+     * they have the same default {@code resourceKey}; if different localized
+     * descriptions are needed then a non-default key must be supplied using
+     * {@code "descriptionResourceKey"}.</p>
+     *
+     * <p>Similar rules also apply for descriptions of parameters ({@link
+     * MBeanParameterInfo}). The default {@code resourceKey} for a parameter
+     * whose {@linkplain MBeanFeatureInfo#getName() name} is {@code
+     * Bar} in an operation or constructor called {@code Foo} is {@code
+     * simpleClassName + ".operation.Foo.Bar"} or {@code simpleClassName +
+     * ".constructor.Foo.Bar"} respectively.</p>
+     *
+     * <h4>Example</h4>
+     *
+     * <p>Suppose you have an MBean defined by these two Java source files:</p>
+     *
+     * <pre>
+     * // ConfigurationMBean.java
+     * package com.example;
+     * public interface ConfigurationMBean {
+     *     public String getName();
+     *     public void save(String fileName);
+     * }
+     *
+     * // Configuration.java
+     * package com.example;
+     * public class Configuration implements ConfigurationMBean {
+     *     public Configuration(String defaultName) {
+     *         ...
+     *     }
+     *     ...
+     * }
+     * </pre>
+     *
+     * <p>Then you could define the default descriptions for the MBean, by
+     * including a resource bundle called {@code com/example/MBeanDescriptions}
+     * with the compiled classes. Most often this is done by creating a file
+     * {@code MBeanDescriptions.properties} in the same directory as {@code
+     * ConfigurationMBean.java}. Make sure that this file is copied into the
+     * same place as the compiled classes; in typical build environments that
+     * will be true by default.</p>
+     *
+     * <p>The file {@code com/example/MBeanDescriptions.properties} might
+     * look like this:</p>
+     *
+     * <pre>
+     * # Description of the MBean
+     * ConfigurationMBean.mbean = Configuration manager
+     *
+     * # Description of the Name attribute
+     * ConfigurationMBean.attribute.Name = The name of the configuration
+     *
+     * # Description of the save operation
+     * ConfigurationMBean.operation.save = Save the configuration to a file
+     *
+     * # Description of the parameter to the save operation.
+     * # Parameter names from the original Java source are not available,
+     * # so the default names are p1, p2, etc.  If the names were available,
+     * # this would be ConfigurationMBean.operation.save.fileName
+     * ConfigurationMBean.operation.save.p1 = The name of the file
+     *
+     * # Description of the constructor.  The default name of a constructor is
+     * # its fully-qualified class name.
+     * ConfigurationMBean.constructor.com.example.Configuration = <!--
+     * -->Constructor with name of default file
+     * # Description of the constructor parameter.
+     * ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
+     * -->Name of the default file
+     * </pre>
+     *
+     * <p>Starting with this file, you could create descriptions for the French
+     * locale by creating {@code com/example/MBeanDescriptions_fr.properties}.
+     * The keys in this file are the same as before but the text has been
+     * translated:
+     *
+     * <pre>
+     * ConfigurationMBean.mbean = Gestionnaire de configuration
+     *
+     * ConfigurationMBean.attribute.Name = Le nom de la configuration
+     *
+     * ConfigurationMBean.operation.save = Sauvegarder la configuration <!--
+     * -->dans un fichier
+     *
+     * ConfigurationMBean.operation.save.p1 = Le nom du fichier
+     *
+     * ConfigurationMBean.constructor.com.example.Configuration = <!--
+     * -->Constructeur avec nom du fichier par d&eacute;faut
+     * ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
+     * -->Nom du fichier par d&eacute;faut
+     * </pre>
+     *
+     * <p>The descriptions in {@code MBeanDescriptions.properties} and
+     * {@code MBeanDescriptions_fr.properties} will only be consulted if
+     * {@code localizeDescriptions} is called, perhaps because the
+     * MBean Server has been wrapped by {@link
+     * ClientContext#newLocalizeMBeanInfoForwarder} or because the
+     * connector server has been created with the {@link
+     * javax.management.remote.JMXConnectorServer#LOCALIZE_MBEAN_INFO_FORWARDER
+     * LOCALIZE_MBEAN_INFO_FORWARDER} option. If you want descriptions
+     * even when there is no localization step, then you should consider
+     * using {@link Description &#64;Description} annotations. Annotations
+     * provide descriptions by default but are overridden if {@code
+     * localizeDescriptions} is called.</p>
+     *
+     * @param locale the target locale for descriptions.  Cannot be null.
+     *
+     * @param loader the {@code ClassLoader} to use for looking up resource
+     * bundles.
+     *
+     * @return an {@code MBeanInfo} with descriptions appropriately localized.
+     *
+     * @throws NullPointerException if {@code locale} is null.
+     */
+    public MBeanInfo localizeDescriptions(Locale locale, ClassLoader loader) {
+        if (locale == null)
+            throw new NullPointerException("locale");
+        Descriptor d = getDescriptor();
+        String mbiLocaleString = (String) d.getFieldValue(JMX.LOCALE_FIELD);
+        if (locale.toString().equals(mbiLocaleString))
+            return this;
+        return new Rewriter(this, locale, loader).getMBeanInfo();
+    }
+
+    private static class Rewriter {
+        private final MBeanInfo mbi;
+        private final ClassLoader loader;
+        private final Locale locale;
+        private final String packageName;
+        private final String simpleClassNamePlusDot;
+        private ResourceBundle defaultBundle;
+        private boolean defaultBundleLoaded;
+
+        // ResourceBundle.getBundle throws NullPointerException
+        // if the loader is null, even though that is perfectly
+        // valid and means the bootstrap loader.  So we work
+        // around with a ClassLoader that is equivalent to the
+        // bootstrap loader but is not null.
+        private static final ClassLoader bootstrapLoader =
+                new ClassLoader(null) {};
+
+        Rewriter(MBeanInfo mbi, Locale locale, ClassLoader loader) {
+            this.mbi = mbi;
+            this.locale = locale;
+            if (loader == null)
+                loader = bootstrapLoader;
+            this.loader = loader;
+
+            String intfName = (String)
+                    mbi.getDescriptor().getFieldValue("interfaceClassName");
+            if (intfName == null)
+                intfName = mbi.getClassName();
+            int lastDot = intfName.lastIndexOf('.');
+            this.packageName = intfName.substring(0, lastDot + 1);
+            this.simpleClassNamePlusDot = intfName.substring(lastDot + 1) + ".";
+            // Inner classes show up as Outer$Inner so won't match the dot.
+            // When there is no dot, lastDot is -1,
+            // packageName is empty, and simpleClassNamePlusDot is intfName.
+        }
+
+        MBeanInfo getMBeanInfo() {
+            MBeanAttributeInfo[] mbais =
+                    rewrite(mbi.getAttributes(), "attribute.");
+            MBeanOperationInfo[] mbois =
+                    rewrite(mbi.getOperations(), "operation.");
+            MBeanConstructorInfo[] mbcis =
+                    rewrite(mbi.getConstructors(), "constructor.");
+            MBeanNotificationInfo[] mbnis =
+                    rewrite(mbi.getNotifications(), "notification.");
+            Descriptor d = mbi.getDescriptor();
+            d = changeLocale(d);
+            String description = getDescription(d, "mbean", "");
+            if (description == null)
+                description = mbi.getDescription();
+            return new MBeanInfo(
+                    mbi.getClassName(), description,
+                    mbais, mbcis, mbois, mbnis, d);
+        }
+
+        private Descriptor changeLocale(Descriptor d) {
+            if (d.getFieldValue(JMX.LOCALE_FIELD) != null) {
+                Map<String, Object> map = new HashMap<String, Object>();
+                for (String field : d.getFieldNames())
+                    map.put(field, d.getFieldValue(field));
+                map.remove(JMX.LOCALE_FIELD);
+                d = new ImmutableDescriptor(map);
+            }
+            return ImmutableDescriptor.union(
+                    d, new ImmutableDescriptor(JMX.LOCALE_FIELD + "=" + locale));
+        }
+
+        private String getDescription(
+                Descriptor d, String defaultPrefix, String defaultSuffix) {
+            ResourceBundle bundle = bundleFromDescriptor(d);
+            if (bundle == null)
+                return null;
+            String key =
+                    (String) d.getFieldValue(JMX.DESCRIPTION_RESOURCE_KEY_FIELD);
+            if (key == null)
+                key = simpleClassNamePlusDot + defaultPrefix + defaultSuffix;
+            return descriptionFromResource(bundle, key);
+        }
+
+        private <T extends MBeanFeatureInfo> T[] rewrite(
+                T[] features, String resourcePrefix) {
+            for (int i = 0; i < features.length; i++) {
+                T feature = features[i];
+                Descriptor d = feature.getDescriptor();
+                String description =
+                        getDescription(d, resourcePrefix, feature.getName());
+                if (description != null &&
+                        !description.equals(feature.getDescription())) {
+                    features[i] = setDescription(feature, description);
+                }
+            }
+            return features;
+        }
+
+        private <T extends MBeanFeatureInfo> T setDescription(
+                T feature, String description) {
+
+            Object newf;
+            String name = feature.getName();
+            Descriptor d = feature.getDescriptor();
+
+            if (feature instanceof MBeanAttributeInfo) {
+                MBeanAttributeInfo mbai = (MBeanAttributeInfo) feature;
+                newf = new MBeanAttributeInfo(
+                        name, mbai.getType(), description,
+                        mbai.isReadable(), mbai.isWritable(), mbai.isIs(),
+                        d);
+            } else if (feature instanceof MBeanOperationInfo) {
+                MBeanOperationInfo mboi = (MBeanOperationInfo) feature;
+                MBeanParameterInfo[] sig = rewrite(
+                        mboi.getSignature(), "operation." + name + ".");
+                newf = new MBeanOperationInfo(
+                        name, description, sig,
+                        mboi.getReturnType(), mboi.getImpact(), d);
+            } else if (feature instanceof MBeanConstructorInfo) {
+                MBeanConstructorInfo mbci = (MBeanConstructorInfo) feature;
+                MBeanParameterInfo[] sig = rewrite(
+                        mbci.getSignature(), "constructor." + name + ".");
+                newf = new MBeanConstructorInfo(
+                        name, description, sig, d);
+            } else if (feature instanceof MBeanNotificationInfo) {
+                MBeanNotificationInfo mbni = (MBeanNotificationInfo) feature;
+                newf = new MBeanNotificationInfo(
+                        mbni.getNotifTypes(), name, description, d);
+            } else if (feature instanceof MBeanParameterInfo) {
+                MBeanParameterInfo mbpi = (MBeanParameterInfo) feature;
+                newf = new MBeanParameterInfo(
+                        name, mbpi.getType(), description, d);
+            } else {
+                logger().log(Level.FINE, "Unknown feature type: " +
+                        feature.getClass());
+                newf = feature;
+            }
+
+            return Util.<T>cast(newf);
+        }
+
+        private ResourceBundle bundleFromDescriptor(Descriptor d) {
+            String bundleName = (String) d.getFieldValue(
+                    JMX.DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD);
+
+            if (bundleName != null)
+                return getBundle(bundleName);
+
+            if (defaultBundleLoaded)
+                return defaultBundle;
+
+            bundleName = packageName + "MBeanDescriptions";
+            defaultBundle = getBundle(bundleName);
+            defaultBundleLoaded = true;
+            return defaultBundle;
+        }
+
+        private String descriptionFromResource(
+                ResourceBundle bundle, String key) {
+            try {
+                return bundle.getString(key);
+            } catch (MissingResourceException e) {
+                logger().log(Level.FINEST, "No resource for " + key, e);
+            } catch (Exception e) {
+                logger().log(Level.FINE, "Bad resource for " + key, e);
+            }
+            return null;
+        }
+
+        private ResourceBundle getBundle(String name) {
+            try {
+                return ResourceBundle.getBundle(name, locale, loader);
+            } catch (Exception e) {
+                logger().log(Level.FINE,
+                           "Could not load ResourceBundle " + name, e);
+                return null;
+            }
+        }
+
+        private Logger logger() {
+            return Logger.getLogger("javax.management.locale");
+        }
+    }
 }
--- a/src/share/classes/javax/management/MBeanOperationInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanOperationInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -308,17 +308,18 @@
        wrong should be less than the penalty we would pay if it were
        right and we needlessly hashed in the description and the
        parameter array.  */
+    @Override
     public int hashCode() {
         return getName().hashCode() ^ getReturnType().hashCode();
     }
 
     private static MBeanParameterInfo[] methodSignature(Method method) {
-        final Class[] classes = method.getParameterTypes();
+        final Class<?>[] classes = method.getParameterTypes();
         final Annotation[][] annots = method.getParameterAnnotations();
         return parameters(classes, annots);
     }
 
-    static MBeanParameterInfo[] parameters(Class[] classes,
+    static MBeanParameterInfo[] parameters(Class<?>[] classes,
                                            Annotation[][] annots) {
         final MBeanParameterInfo[] params =
             new MBeanParameterInfo[classes.length];
--- a/src/share/classes/javax/management/MBeanServer.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanServer.java	Tue Nov 11 09:07:58 2008 +0000
@@ -377,19 +377,19 @@
      * MBean will not be registered.
      * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
      * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
-     * <CODE>RuntimeException</CODE>, the <CODE>registerMBean<CODE> method will
+     * <CODE>RuntimeException</CODE>, the <CODE>registerMBean</CODE> method will
      * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean
      * registration succeeded. In such a case, the MBean will be actually
-     * registered even though the <CODE>registerMBean<CODE> method
+     * registered even though the <CODE>registerMBean</CODE> method
      * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
      * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
      * will not be registered.
      * @exception RuntimeErrorException If the <CODE>postRegister</CODE>
      * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
-     * <CODE>Error</CODE>, the <CODE>registerMBean<CODE> method will
+     * <CODE>Error</CODE>, the <CODE>registerMBean</CODE> method will
      * throw a <CODE>RuntimeErrorException</CODE>, although the MBean
      * registration succeeded. In such a case, the MBean will be actually
-     * registered even though the <CODE>registerMBean<CODE> method
+     * registered even though the <CODE>registerMBean</CODE> method
      * threw an exception.  Note that <CODE>RuntimeErrorException</CODE> can
      * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
      * will not be registered.
@@ -411,6 +411,8 @@
      * is sent as described <a href="#notif">above</a>.</p>
      *
      * @throws RuntimeOperationsException {@inheritDoc}
+     * @throws RuntimeMBeanException {@inheritDoc}
+     * @throws RuntimeErrorException {@inheritDoc}
      */
     public void unregisterMBean(ObjectName name)
             throws InstanceNotFoundException, MBeanRegistrationException;
--- a/src/share/classes/javax/management/MBeanServerConnection.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanServerConnection.java	Tue Nov 11 09:07:58 2008 +0000
@@ -76,7 +76,9 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
-     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * @exception RuntimeMBeanException If the MBean's constructor or its
+     * {@code preRegister} or {@code postRegister} method threw
+     * a {@code RuntimeException}. If the <CODE>postRegister</CODE>
      * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
      * <CODE>RuntimeException</CODE>, the <CODE>createMBean</CODE> method will
      * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
@@ -148,7 +150,9 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
-     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * @exception RuntimeMBeanException If the MBean's constructor or its
+     * {@code preRegister} or {@code postRegister} method threw
+     * a {@code RuntimeException}. If the <CODE>postRegister</CODE>
      * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
      * <CODE>RuntimeException</CODE>, the <CODE>createMBean</CODE> method will
      * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
@@ -223,7 +227,9 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
-     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * @exception RuntimeMBeanException If the MBean's constructor or its
+     * {@code preRegister} or {@code postRegister} method threw
+     * a {@code RuntimeException}. If the <CODE>postRegister</CODE>
      * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
      * <CODE>RuntimeException</CODE>, the <CODE>createMBean</CODE> method will
      * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
@@ -295,7 +301,9 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
-     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * @exception RuntimeMBeanException The MBean's constructor or its
+     * {@code preRegister} or {@code postRegister} method threw
+     * a {@code RuntimeException}. If the <CODE>postRegister</CODE>
      * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
      * <CODE>RuntimeException</CODE>, the <CODE>createMBean</CODE> method will
      * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
@@ -524,8 +532,30 @@
 
 
     /**
-     * Enables the values of several attributes of a named MBean. The MBean
-     * is identified by its object name.
+     * <p>Retrieves the values of several attributes of a named MBean. The MBean
+     * is identified by its object name.</p>
+     *
+     * <p>If one or more attributes cannot be retrieved for some reason, they
+     * will be omitted from the returned {@code AttributeList}.  The caller
+     * should check that the list is the same size as the {@code attributes}
+     * array.  To discover what problem prevented a given attribute from being
+     * retrieved, call {@link #getAttribute getAttribute} for that attribute.</p>
+     *
+     * <p>Here is an example of calling this method and checking that it
+     * succeeded in retrieving all the requested attributes:</p>
+     *
+     * <pre>
+     * String[] attrNames = ...;
+     * AttributeList list = mbeanServerConnection.getAttributes(objectName, attrNames);
+     * if (list.size() == attrNames.length)
+     *     System.out.println("All attributes were retrieved successfully");
+     * else {
+     *     {@code List<String>} missing = new {@code ArrayList<String>}(<!--
+     * -->{@link java.util.Arrays#asList Arrays.asList}(attrNames));
+     *     missing.removeAll(list.toMap().keySet());
+     *     System.out.println("Did not retrieve: " + missing);
+     * }
+     * </pre>
      *
      * @param name The object name of the MBean from which the
      * attributes are retrieved.
@@ -549,6 +579,7 @@
             throws InstanceNotFoundException, ReflectionException,
                    IOException;
 
+
     /**
      * Sets the value of a specific attribute of a named MBean. The MBean
      * is identified by its object name.
@@ -584,10 +615,36 @@
                    ReflectionException, IOException;
 
 
-
     /**
-     * Sets the values of several attributes of a named MBean. The MBean is
-     * identified by its object name.
+     * <p>Sets the values of several attributes of a named MBean. The MBean is
+     * identified by its object name.</p>
+     *
+     * <p>If one or more attributes cannot be set for some reason, they will be
+     * omitted from the returned {@code AttributeList}.  The caller should check
+     * that the input {@code AttributeList} is the same size as the output one.
+     * To discover what problem prevented a given attribute from being retrieved,
+     * it will usually be possible to call {@link #setAttribute setAttribute}
+     * for that attribute, although this is not guaranteed to work.  (For
+     * example, the values of two attributes may have been rejected because
+     * they were inconsistent with each other.  Setting one of them alone might
+     * be allowed.)<p>
+     *
+     * <p>Here is an example of calling this method and checking that it
+     * succeeded in setting all the requested attributes:</p>
+     *
+     * <pre>
+     * AttributeList inputAttrs = ...;
+     * AttributeList outputAttrs = mbeanServerConnection.setAttributes(<!--
+     * -->objectName, inputAttrs);
+     * if (inputAttrs.size() == outputAttrs.size())
+     *     System.out.println("All attributes were set successfully");
+     * else {
+     *     {@code List<String>} missing = new {@code ArrayList<String>}(<!--
+     * -->inputAttrs.toMap().keySet());
+     *     missing.removeAll(outputAttrs.toMap().keySet());
+     *     System.out.println("Did not set: " + missing);
+     * }
+     * </pre>
      *
      * @param name The object name of the MBean within which the
      * attributes are to be set.
@@ -614,7 +671,39 @@
         throws InstanceNotFoundException, ReflectionException, IOException;
 
     /**
-     * Invokes an operation on an MBean.
+     * <p>Invokes an operation on an MBean.</p>
+     *
+     * <p>Because of the need for a {@code signature} to differentiate
+     * possibly-overloaded operations, it is much simpler to invoke operations
+     * through an {@linkplain JMX#newMBeanProxy(MBeanServerConnection, ObjectName,
+     * Class) MBean proxy} where possible.  For example, suppose you have a
+     * Standard MBean interface like this:</p>
+     *
+     * <pre>
+     * public interface FooMBean {
+     *     public int countMatches(String[] patterns, boolean ignoreCase);
+     * }
+     * </pre>
+     *
+     * <p>The {@code countMatches} operation can be invoked as follows:</p>
+     *
+     * <pre>
+     * String[] myPatterns = ...;
+     * int count = (Integer) mbeanServerConnection.invoke(
+     *         objectName,
+     *         "countMatches",
+     *         new Object[] {myPatterns, true},
+     *         new String[] {String[].class.getName(), boolean.class.getName()});
+     * </pre>
+     *
+     * <p>Alternatively, it can be invoked through a proxy as follows:</p>
+     *
+     * <pre>
+     * String[] myPatterns = ...;
+     * FooMBean fooProxy = JMX.newMBeanProxy(
+     *         mbeanServerConnection, objectName, FooMBean.class);
+     * int count = fooProxy.countMatches(myPatterns, true);
+     * </pre>
      *
      * @param name The object name of the MBean on which the method is
      * to be invoked.
@@ -622,7 +711,8 @@
      * @param params An array containing the parameters to be set when
      * the operation is invoked
      * @param signature An array containing the signature of the
-     * operation. The class objects will be loaded using the same
+     * operation, an array of class names in the format returned by
+     * {@link Class#getName()}. The class objects will be loaded using the same
      * class loader as the one used for loading the MBean on which the
      * operation was invoked.
      *
--- a/src/share/classes/javax/management/MBeanServerFactory.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanServerFactory.java	Tue Nov 11 09:07:58 2008 +0000
@@ -747,7 +747,7 @@
      * Load the builder class through the context class loader.
      * @param builderClassName The name of the builder class.
      **/
-    private static Class loadBuilderClass(String builderClassName)
+    private static Class<?> loadBuilderClass(String builderClassName)
     throws ClassNotFoundException {
         final ClassLoader loader =
                 Thread.currentThread().getContextClassLoader();
@@ -767,7 +767,7 @@
      * If any checked exception needs to be thrown, it is embedded in
      * a JMRuntimeException.
      **/
-    private static MBeanServerBuilder newBuilder(Class builderClass) {
+    private static MBeanServerBuilder newBuilder(Class<?> builderClass) {
         try {
             final Object abuilder = builderClass.newInstance();
             return (MBeanServerBuilder)abuilder;
@@ -792,7 +792,7 @@
             String builderClassName = AccessController.doPrivileged(act);
 
             try {
-                final Class newBuilderClass;
+                final Class<?> newBuilderClass;
                 if (builderClassName == null || builderClassName.length() == 0)
                     newBuilderClass = MBeanServerBuilder.class;
                 else
@@ -800,7 +800,7 @@
 
                 // Check whether a new builder needs to be created
                 if (builder != null) {
-                    final Class builderClass = builder.getClass();
+                    final Class<?> builderClass = builder.getClass();
                     if (newBuilderClass == builderClass)
                         return; // no need to create a new builder...
                 }
--- a/src/share/classes/javax/management/MBeanServerInvocationHandler.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanServerInvocationHandler.java	Tue Nov 11 09:07:58 2008 +0000
@@ -253,12 +253,12 @@
                                          boolean notificationBroadcaster) {
         final InvocationHandler handler =
             new MBeanServerInvocationHandler(connection, objectName);
-        final Class[] interfaces;
+        final Class<?>[] interfaces;
         if (notificationBroadcaster) {
             interfaces =
-                new Class[] {interfaceClass, NotificationEmitter.class};
+                new Class<?>[] {interfaceClass, NotificationEmitter.class};
         } else
-            interfaces = new Class[] {interfaceClass};
+            interfaces = new Class<?>[] {interfaceClass};
 
         Object proxy =
             Proxy.newProxyInstance(interfaceClass.getClassLoader(),
@@ -269,7 +269,7 @@
 
     public Object invoke(Object proxy, Method method, Object[] args)
             throws Throwable {
-        final Class methodClass = method.getDeclaringClass();
+        final Class<?> methodClass = method.getDeclaringClass();
 
         if (methodClass.equals(NotificationBroadcaster.class)
             || methodClass.equals(NotificationEmitter.class))
@@ -285,8 +285,8 @@
                 return p.invoke(connection, objectName, method, args);
             } else {
                 final String methodName = method.getName();
-                final Class[] paramTypes = method.getParameterTypes();
-                final Class returnType = method.getReturnType();
+                final Class<?>[] paramTypes = method.getParameterTypes();
+                final Class<?> returnType = method.getReturnType();
 
                 /* Inexplicably, InvocationHandler specifies that args is null
                    when the method takes no arguments rather than a
@@ -361,7 +361,13 @@
                 if (p != null)
                     return p;
             }
-            p = new MXBeanProxy(mxbeanInterface, mappingFactory);
+            try {
+                p = new MXBeanProxy(mxbeanInterface, mappingFactory);
+            } catch (IllegalArgumentException e) {
+                String msg = "Cannot make MXBean proxy for " +
+                        mxbeanInterface.getName() + ": " + e.getMessage();
+                throw new IllegalArgumentException(msg, e.getCause());
+            }
             classToProxy.put(mxbeanInterface, new WeakReference<MXBeanProxy>(p));
             return p;
         }
@@ -452,7 +458,7 @@
             return true;
         if (methodName.equals("equals")
             && Arrays.equals(method.getParameterTypes(),
-                             new Class[] {Object.class})
+                             new Class<?>[] {Object.class})
             && isLocal(proxy, method))
             return true;
         return false;
--- a/src/share/classes/javax/management/MBeanServerNotification.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/MBeanServerNotification.java	Tue Nov 11 09:07:58 2008 +0000
@@ -27,15 +27,70 @@
 
 
 /**
- * Represents a notification emitted by the MBean server through the MBeanServerDelegate MBean.
+ * Represents a notification emitted by the MBean Server through the MBeanServerDelegate MBean.
  * The MBean Server emits the following types of notifications: MBean registration, MBean
- * de-registration.
+ * unregistration.
  * <P>
- * To receive to MBeanServerNotifications, you need to be declared as listener to
- * the {@link javax.management.MBeanServerDelegate javax.management.MBeanServerDelegate} MBean
- * that represents the MBeanServer. The ObjectName of the MBeanServerDelegate is:
+ * To receive MBeanServerNotifications, you need to register a listener with
+ * the {@link MBeanServerDelegate MBeanServerDelegate} MBean
+ * that represents the MBeanServer. The ObjectName of the MBeanServerDelegate is
+ * {@link MBeanServerDelegate#DELEGATE_NAME}, which is
  * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.
  *
+ * <p>The following code prints a message every time an MBean is registered
+ * or unregistered in the MBean Server {@code mbeanServer}:</p>
+ *
+ * <pre>
+ * private static final NotificationListener printListener = new NotificationListener() {
+ *     public void handleNotification(Notification n, Object handback) {
+ *         if (!(n instanceof MBeanServerNotification)) {
+ *             System.out.println("Ignored notification of class " + n.getClass().getName());
+ *             return;
+ *         }
+ *         MBeanServerNotification mbsn = (MBeanServerNotification) n;
+ *         String what;
+ *         if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
+ *             what = "MBean registered";
+ *         else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
+ *             what = "MBean unregistered";
+ *         else
+ *             what = "Unknown type " + n.getType();
+ *         System.out.println("Received MBean Server notification: " + what + ": " +
+ *                 mbsn.getMBeanName());
+ * };
+ *
+ * ...
+ *     mbeanServer.addNotificationListener(
+ *             MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
+ * </pre>
+ *
+ * <p>The following code prints a message every time an MBean is registered
+ * or unregistered in the MBean Server {@code mbeanServer}:</p>
+ *
+ * <pre>
+ * private static final NotificationListener printListener = new NotificationListener() {
+ *     public void handleNotification(Notification n, Object handback) {
+ *         if (!(n instanceof MBeanServerNotification)) {
+ *             System.out.println("Ignored notification of class " + n.getClass().getName());
+ *             return;
+ *         }
+ *         MBeanServerNotification mbsn = (MBeanServerNotification) n;
+ *         String what;
+ *         if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
+ *             what = "MBean registered";
+ *         else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
+ *             what = "MBean unregistered";
+ *         else
+ *             what = "Unknown type " + n.getType();
+ *         System.out.println("Received MBean Server notification: " + what + ": " +
+ *                 mbsn.getMBeanName());
+ * };
+ *
+ * ...
+ *     mbeanServer.addNotificationListener(
+ *             MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
+ * </pre>
+ *
  * @since 1.5
  */
 public class MBeanServerNotification extends Notification {
--- a/src/share/classes/javax/management/Notification.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/Notification.java	Tue Nov 11 09:07:58 2008 +0000
@@ -54,7 +54,7 @@
  * @since 1.5
  */
 @SuppressWarnings("serial")  // serialVersionUID is not constant
-public class Notification extends EventObject {
+public class Notification extends EventObject implements Cloneable {
 
     // Serialization compatibility stuff:
     // Two serial forms are supported in this class. The selected form depends
@@ -244,6 +244,26 @@
     }
 
     /**
+     * <p>Creates and returns a copy of this object.  The copy is created as
+     * described for {@link Object#clone()}.  This means, first, that the
+     * class of the object will be the same as the class of this object, and,
+     * second, that the copy is a "shallow copy".  Fields of this notification
+     * are not themselves copied.  In particular, the {@linkplain
+     * #getUserData user data} of the copy is the same object as the
+     * original.</p>
+     *
+     * @return a copy of this object.
+     */
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
      * Sets the source.
      *
      * @param source the new source for this object.
@@ -285,8 +305,10 @@
     /**
      * Get the notification type.
      *
-     * @return The notification type. It's a string expressed in a dot notation similar
-     * to Java properties. An example of a notification type is network.alarm.router .
+     * @return The notification type. It's a string expressed in a dot notation
+     * similar to Java properties. It is recommended that the notification type
+     * should follow the reverse-domain-name convention used by Java package
+     * names.  An example of a notification type is com.example.alarm.router.
      */
     public String getType() {
         return type ;
@@ -317,15 +339,26 @@
     /**
      * Get the notification message.
      *
-     * @return The message string of this notification object. It contains in a string,
-     * which could be the explanation of the notification for displaying to a user
+     * @return The message string of this notification object.
      *
+     * @see #setMessage
      */
     public String getMessage() {
         return message ;
     }
 
     /**
+     * Set the notification message.
+     *
+     * @param message the new notification message.
+     *
+     * @see #getMessage
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    /**
      * Get the user data.
      *
      * @return The user data object. It is used for whatever data
@@ -355,6 +388,7 @@
      *
      * @return A String representation of this notification.
      */
+    @Override
     public String toString() {
         return super.toString()+"[type="+type+"][message="+message+"]";
     }
--- a/src/share/classes/javax/management/NotificationListener.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/NotificationListener.java	Tue Nov 11 09:07:58 2008 +0000
@@ -39,11 +39,10 @@
     * blocking its notification broadcaster.
     *
     * @param notification The notification.
-    * @param handback An opaque object which helps the listener to associate information
-    * regarding the MBean emitter. This object is passed to the MBean during the
-    * addListener call and resent, without modification, to the listener. The MBean object
-    * should not use or modify the object.
-    *
+    * @param handback An opaque object which helps the listener to associate
+    * information regarding the MBean emitter. This object is passed to the
+    * addNotificationListener call and resent, without modification, to the
+    * listener.
     */
-    public void handleNotification(Notification notification, Object handback) ;
+    public void handleNotification(Notification notification, Object handback);
 }
--- a/src/share/classes/javax/management/QueryNotificationFilter.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/QueryNotificationFilter.java	Tue Nov 11 09:07:58 2008 +0000
@@ -26,7 +26,6 @@
 package javax.management;
 
 import com.sun.jmx.mbeanserver.NotificationMBeanSupport;
-import com.sun.jmx.mbeanserver.Util;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -43,6 +42,11 @@
  * on both the client and the server in the remote case, so using this class
  * instead is recommended where possible.</p>
  *
+ * <p>Because this class was introduced in version 2.0 of the JMX API,
+ * it may not be present on a remote JMX agent that is running an earlier
+ * version.  The method {@link JMX#getSpecificationVersion
+ * JMX.getSpecificationVersion} can be used to determine the remote version.</p>
+ *
  * <p>This class uses the {@linkplain Query Query API} to specify the
  * filtering logic.  For example, to select only notifications where the
  * {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
--- a/src/share/classes/javax/management/StandardMBean.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/StandardMBean.java	Tue Nov 11 09:07:58 2008 +0000
@@ -689,7 +689,7 @@
                     getImplementationClass().getName());
         }
 
-        MBeanSupport msupport = mbean;
+        MBeanSupport<?> msupport = mbean;
         final MBeanInfo bi = msupport.getMBeanInfo();
         final Object impl = msupport.getWrappedObject();
 
@@ -1391,8 +1391,8 @@
      * garbage collected just because we know whether its MBeanInfo
      * is immutable.
      */
-    private static final Map<Class, Boolean> mbeanInfoSafeMap =
-        new WeakHashMap<Class, Boolean>();
+    private static final Map<Class<?>, Boolean> mbeanInfoSafeMap =
+        new WeakHashMap<Class<?>, Boolean>();
 
     /**
      * Return true if {@code subclass} is known to preserve the immutability
@@ -1438,9 +1438,9 @@
     private static class MBeanInfoSafeAction
             implements PrivilegedAction<Boolean> {
 
-        private final Class subclass;
+        private final Class<?> subclass;
 
-        MBeanInfoSafeAction(Class subclass) {
+        MBeanInfoSafeAction(Class<?> subclass) {
             this.subclass = subclass;
         }
 
@@ -1454,13 +1454,13 @@
             // Check for "MBeanInfo getCachedMBeanInfo()" method.
             //
             if (overrides(subclass, StandardMBean.class,
-                          "getCachedMBeanInfo", (Class[]) null))
+                          "getCachedMBeanInfo", (Class<?>[]) null))
                 return false;
 
             // Check for "MBeanInfo getMBeanInfo()" method.
             //
             if (overrides(subclass, StandardMBean.class,
-                          "getMBeanInfo", (Class[]) null))
+                          "getMBeanInfo", (Class<?>[]) null))
                 return false;
 
             // Check for "MBeanNotificationInfo[] getNotificationInfo()"
@@ -1473,7 +1473,7 @@
             //
             if (StandardEmitterMBean.class.isAssignableFrom(subclass))
                 if (overrides(subclass, StandardEmitterMBean.class,
-                              "getNotificationInfo", (Class[]) null))
+                              "getNotificationInfo", (Class<?>[]) null))
                     return false;
             return true;
         }
--- a/src/share/classes/javax/management/event/EventClient.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/event/EventClient.java	Tue Nov 11 09:07:58 2008 +0000
@@ -29,7 +29,6 @@
 import com.sun.jmx.event.LeaseRenewer;
 import com.sun.jmx.event.ReceiverBuffer;
 import com.sun.jmx.event.RepeatedSingletonJob;
-import com.sun.jmx.namespace.JMXNamespaceUtils;
 import com.sun.jmx.mbeanserver.PerThreadGroupPool;
 import com.sun.jmx.remote.util.ClassLogger;
 
@@ -58,7 +57,6 @@
 import javax.management.NotificationFilter;
 import javax.management.NotificationListener;
 import javax.management.ObjectName;
-import javax.management.remote.JMXConnector;
 import javax.management.remote.NotificationResult;
 import javax.management.remote.TargetedNotification;
 
@@ -117,23 +115,24 @@
     public static final String NONFATAL = "jmx.event.service.nonfatal";
 
     /**
-     * <p>A notification string type used by an {@code EventClient} object to
-     * inform a listener added by {@code #addEventClientListener} that it
-     * has detected that notifications have been lost.  The {@link
-     * Notification#getUserData() userData} of the notification is a Long which
-     * is an upper bound on the number of lost notifications that have just
-     * been detected.</p>
+     * <p>A notification string type used by an {@code EventClient} object
+     * to inform a listener added by {@link #addEventClientListener
+     * addEventClientListener} that it has detected that notifications have
+     * been lost.  The {@link Notification#getUserData() userData} of the
+     * notification is a Long which is an upper bound on the number of lost
+     * notifications that have just been detected.</p>
      *
      * @see #addEventClientListener
      */
     public static final String NOTIFS_LOST = "jmx.event.service.notifs.lost";
 
     /**
-     * The default lease time, {@value}, in milliseconds.
+     * The default lease time that EventClient instances will request, in
+     * milliseconds.  This value is {@value}.
      *
      * @see EventClientDelegateMBean#lease
      */
-    public static final long DEFAULT_LEASE_TIMEOUT = 300000;
+    public static final long DEFAULT_REQUESTED_LEASE_TIME = 300000;
 
     /**
      * <p>Constructs a default {@code EventClient} object.</p>
@@ -173,7 +172,7 @@
      */
     public EventClient(EventClientDelegateMBean delegate)
     throws IOException {
-        this(delegate, null, null, null, DEFAULT_LEASE_TIMEOUT);
+        this(delegate, null, null, null, DEFAULT_REQUESTED_LEASE_TIME);
     }
 
     /**
@@ -196,7 +195,7 @@
      * If {@code null}, a default scheduler will be used.
      * @param requestedLeaseTime The lease time used to keep this client alive
      * in the {@link EventClientDelegateMBean}.  A value of zero is equivalent
-     * to the {@linkplain #DEFAULT_LEASE_TIMEOUT default value}.
+     * to the {@linkplain #DEFAULT_REQUESTED_LEASE_TIME default value}.
      *
      * @throws IllegalArgumentException If {@code delegate} is null.
      * @throws IOException If an I/O error occurs when communicating with the
@@ -213,7 +212,7 @@
         }
 
         if (requestedLeaseTime == 0)
-            requestedLeaseTime = DEFAULT_LEASE_TIMEOUT;
+            requestedLeaseTime = DEFAULT_REQUESTED_LEASE_TIME;
         else if (requestedLeaseTime < 0) {
             throw new IllegalArgumentException(
                     "Negative lease time: " + requestedLeaseTime);
@@ -269,7 +268,13 @@
                         new ScheduledThreadPoolExecutor(20, daemonThreadFactory);
                 executor.setKeepAliveTime(1, TimeUnit.SECONDS);
                 executor.allowCoreThreadTimeOut(true);
-                executor.setRemoveOnCancelPolicy(true);
+                if (setRemoveOnCancelPolicy != null) {
+                    try {
+                        setRemoveOnCancelPolicy.invoke(executor, true);
+                    } catch (Exception e) {
+                        logger.trace("setRemoveOnCancelPolicy", e);
+                    }
+                }
                 // By default, a ScheduledThreadPoolExecutor will keep jobs
                 // in its queue even after they have been cancelled.  They
                 // will only be removed when their scheduled time arrives.
@@ -277,12 +282,25 @@
                 // this EventClient, this can lead to a moderately large number
                 // of objects remaining referenced until the renewal time
                 // arrives.  Hence the above call, which removes the job from
-                // the queue as soon as it is cancelled.
+                // the queue as soon as it is cancelled.  Since the call is
+                // new with JDK 7, we invoke it via reflection to make it
+                // easier to use this code on JDK 6.
                 return executor;
             }
         };
         return leaseRenewerThreadPool.getThreadPoolExecutor(create);
+    }
 
+    private static final Method setRemoveOnCancelPolicy;
+    static {
+        Method m;
+        try {
+            m = ScheduledThreadPoolExecutor.class.getMethod(
+                    "setRemoveOnCancelPolicy", boolean.class);
+        } catch (Exception e) {
+            m = null;
+        }
+        setRemoveOnCancelPolicy = m;
     }
 
     /**
@@ -577,8 +595,13 @@
     }
 
     /**
-     * Returns the set of listeners that have been added through
-     * this {@code EventClient} and not subsequently removed.
+     * <p>Returns the collection of listeners that have been added through
+     * this {@code EventClient} and not subsequently removed.  The returned
+     * collection contains one entry for every listener added with
+     * {@link #addNotificationListener addNotificationListener} or
+     * {@link #subscribe subscribe} and not subsequently removed with
+     * {@link #removeNotificationListener removeNotificationListener} or
+     * {@link #unsubscribe unsubscribe}, respectively.</p>
      *
      * @return A collection of listener information. Empty if there are no
      * current listeners or if this {@code EventClient} has been {@linkplain
@@ -927,8 +950,10 @@
     private final static MBeanNotificationInfo[] myInfo =
             new MBeanNotificationInfo[] {
         new MBeanNotificationInfo(
-                new String[] {FAILED, NOTIFS_LOST},
-                Notification.class.getName(), "")};
+                new String[] {FAILED, NONFATAL, NOTIFS_LOST},
+                Notification.class.getName(),
+                "Notifications that can be sent to a listener added with " +
+                "EventClient.addEventClientListener")};
 
     private final NotificationBroadcasterSupport broadcaster =
             new NotificationBroadcasterSupport();
@@ -1035,7 +1060,7 @@
             final public EventClient call() throws Exception {
                 EventClientDelegateMBean ecd = EventClientDelegate.getProxy(conn);
                 return new EventClient(ecd, eventRelay, null, null,
-                        DEFAULT_LEASE_TIMEOUT);
+                        DEFAULT_REQUESTED_LEASE_TIME);
             }
         };
 
@@ -1073,24 +1098,6 @@
         return clientId;
     }
 
-    /**
-     * Returns a JMX Connector that will use an {@link EventClient}
-     * to subscribe for notifications. If the server doesn't have
-     * an {@link EventClientDelegateMBean}, then the connector will
-     * use the legacy notification mechanism instead.
-     *
-     * @param wrapped The underlying JMX Connector wrapped by the returned
-     *               connector.
-     *
-     * @return A JMX Connector that will uses an {@link EventClient}, if
-     *         available.
-     *
-     * @see EventClient#getEventClientConnection(MBeanServerConnection)
-     */
-    public static JMXConnector withEventClient(final JMXConnector wrapped) {
-        return JMXNamespaceUtils.withEventClient(wrapped);
-    }
-
     private static final PerThreadGroupPool<ScheduledThreadPoolExecutor>
             leaseRenewerThreadPool = PerThreadGroupPool.make();
 }
--- a/src/share/classes/javax/management/event/EventClientDelegate.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/event/EventClientDelegate.java	Tue Nov 11 09:07:58 2008 +0000
@@ -104,8 +104,8 @@
     public static EventClientDelegate getEventClientDelegate(MBeanServer server) {
         EventClientDelegate delegate = null;
         synchronized(delegateMap) {
-            final WeakReference wrf = delegateMap.get(server);
-            delegate = (wrf == null) ? null : (EventClientDelegate)wrf.get();
+            final WeakReference<EventClientDelegate> wrf = delegateMap.get(server);
+            delegate = (wrf == null) ? null : wrf.get();
 
             if (delegate == null) {
                 delegate = new EventClientDelegate(server);
@@ -149,6 +149,7 @@
     // of a setMBeanServer on some other forwarder later in the chain.
 
     private static class Forwarder extends SingleMBeanForwarder {
+        private MBeanServer loopMBS;
 
         private static class UnsupportedInvocationHandler
                 implements InvocationHandler {
@@ -173,7 +174,11 @@
         private volatile boolean madeECD;
 
         Forwarder() {
-            super(OBJECT_NAME, makeUnsupportedECD());
+            super(OBJECT_NAME, makeUnsupportedECD(), true);
+        }
+
+        synchronized void setLoopMBS(MBeanServer loopMBS) {
+            this.loopMBS = loopMBS;
         }
 
         @Override
@@ -186,7 +191,7 @@
                         AccessController.doPrivileged(
                             new PrivilegedAction<EventClientDelegate>() {
                                 public EventClientDelegate run() {
-                                    return getEventClientDelegate(Forwarder.this);
+                                    return getEventClientDelegate(loopMBS);
                                 }
                             });
                     DynamicMBean mbean = new StandardMBean(
@@ -208,11 +213,46 @@
      * that are targeted for that MBean and handles them itself.  All other
      * requests are forwarded to the next element in the forwarder chain.</p>
      *
+     * @param nextMBS the next {@code MBeanServer} in the chain of forwarders,
+     * which might be another {@code MBeanServerForwarder} or a plain {@code
+     * MBeanServer}.  This is the object to which {@code MBeanServer} requests
+     * that do not concern the {@code EventClientDelegateMBean} are sent.
+     * It will be the value of {@link MBeanServerForwarder#getMBeanServer()
+     * getMBeanServer()} on the returned object, and can be changed with {@link
+     * MBeanServerForwarder#setMBeanServer setMBeanServer}.  It can be null but
+     * must be set to a non-null value before any {@code MBeanServer} requests
+     * arrive.
+     *
+     * @param loopMBS the {@code MBeanServer} to which requests from the
+     * {@code EventClientDelegateMBean} should be sent.  For example,
+     * when you invoke the {@link EventClientDelegateMBean#addListener
+     * addListener} operation on the {@code EventClientDelegateMBean}, it will
+     * result in a call to {@link
+     * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
+     * NotificationFilter, Object) addNotificationListener} on this object.
+     * If this parameter is null, then these requests will be sent to the
+     * newly-created {@code MBeanServerForwarder}.  Usually the parameter will
+     * either be null or will be the result of {@link
+     * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder()
+     * getSystemMBeanServerForwarder()} for the connector server in which
+     * this forwarder will be installed.
+     *
      * @return a new {@code MBeanServerForwarder} that simulates the existence
      * of an {@code EventClientDelegateMBean}.
+     *
+     * @see javax.management.remote.JMXConnectorServer#installStandardForwarders
      */
-    public static MBeanServerForwarder newForwarder() {
-        return new Forwarder();
+    public static MBeanServerForwarder newForwarder(
+            MBeanServer nextMBS, MBeanServer loopMBS) {
+        Forwarder mbsf = new Forwarder();
+        // We must setLoopMBS before setMBeanServer, because when we
+        // setMBeanServer that will call getEventClientDelegate(loopMBS).
+        if (loopMBS == null)
+            loopMBS = mbsf;
+        mbsf.setLoopMBS(loopMBS);
+        if (nextMBS != null)
+            mbsf.setMBeanServer(nextMBS);
+        return mbsf;
     }
 
     /**
@@ -282,7 +322,7 @@
             Constructor<?> foundCons = null;
             if (sig == null)
                 sig = new String[0];
-            for (Constructor cons : c.getConstructors()) {
+            for (Constructor<?> cons : c.getConstructors()) {
                 Class<?>[] types = cons.getParameterTypes();
                 String[] consSig = new String[types.length];
                 for (int i = 0; i < types.length; i++)
@@ -437,10 +477,9 @@
     // private classes
     // ------------------------------------
     private class ClientInfo {
-        String clientId;
-        EventBuffer buffer;
-        NotificationListener clientListener;
-        Map<Integer, AddedListener> listenerInfoMap =
+        final String clientId;
+        final NotificationListener clientListener;
+        final Map<Integer, AddedListener> listenerInfoMap =
                 new HashMap<Integer, AddedListener>();
 
         ClientInfo(String clientId, EventForwarder forwarder) {
@@ -703,7 +742,8 @@
         clientInfo = clientInfoMap.get(clientId);
 
         if (clientInfo == null) {
-            throw new EventClientNotFoundException("The client is not found.");
+            throw new EventClientNotFoundException(
+                    "Client not found (id " + clientId + ")");
         }
 
         return clientInfo;
--- a/src/share/classes/javax/management/event/EventClientDelegateMBean.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/event/EventClientDelegateMBean.java	Tue Nov 11 09:07:58 2008 +0000
@@ -51,7 +51,8 @@
  * and the MBean Server, that will intercept accesses to the Event Client
  * Delegate MBean and treat them as the real MBean would. This forwarder is
  * inserted by default with the standard RMI Connector Server, and can also
- * be created explicitly using {@link EventClientDelegate#newForwarder()}.
+ * be created explicitly using {@link EventClientDelegate#newForwarder
+ * EventClientDelegate.newForwarder}.
  *
  * <li><p>A variant on the above is to replace the MBean Server that is
  * used locally with a forwarder as described above.  Since
@@ -61,9 +62,7 @@
  *
  * <pre>
  * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  // or whatever
- * MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
- * mbsf.setMBeanServer(mbs);
- * mbs = mbsf;
+ * mbs = EventClientDelegate.newForwarder(mbs, null);
  * // now use mbs just as you did before, but it will have an EventClientDelegate
  * </pre>
  *
--- a/src/share/classes/javax/management/event/EventRelay.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/event/EventRelay.java	Tue Nov 11 09:07:58 2008 +0000
@@ -27,7 +27,6 @@
 
 import java.io.IOException;
 import java.util.concurrent.Executors;  // for javadoc
-import java.util.concurrent.ScheduledFuture;
 
 /**
  * This interface is used to specify a way to receive
--- a/src/share/classes/javax/management/event/EventSubscriber.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/event/EventSubscriber.java	Tue Nov 11 09:07:58 2008 +0000
@@ -350,8 +350,7 @@
     static {
         QueryExp broadcasterExp;
         try {
-            final Method m = Query.class.getMethod("isInstanceOf",
-                    new Class[] {String.class});
+            final Method m = Query.class.getMethod("isInstanceOf", String.class);
             broadcasterExp = (QueryExp)m.invoke(Query.class,
                     new Object[] {NotificationBroadcaster.class.getName()});
         } catch (Exception e) {
--- a/src/share/classes/javax/management/event/package-info.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/event/package-info.java	Tue Nov 11 09:07:58 2008 +0000
@@ -83,8 +83,8 @@
  * javax.management.event.EventClientDelegateMBean EventClientDelegateMBean}
  * must be registered in the MBean Server, or the connector server must
  * be configured to simulate the existence of this MBean, for example
- * using {@link javax.management.event.EventClientDelegate#newForwarder()
- * EventClientDelegate.newForwarder()}. The standard RMI connector is so
+ * using {@link javax.management.event.EventClientDelegate#newForwarder
+ * EventClientDelegate.newForwarder}. The standard RMI connector is so
  * configured by default. The {@code EventClientDelegateMBean} documentation
  * has further details.</p>
  *
--- a/src/share/classes/javax/management/loading/DefaultLoaderRepository.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/loading/DefaultLoaderRepository.java	Tue Nov 11 09:07:58 2008 +0000
@@ -69,7 +69,7 @@
      * @exception ClassNotFoundException The specified class could not be
      *            found.
      */
-    public static Class loadClass(String className)
+    public static Class<?> loadClass(String className)
         throws ClassNotFoundException {
         MBEANSERVER_LOGGER.logp(Level.FINEST,
                 DefaultLoaderRepository.class.getName(),
@@ -93,7 +93,7 @@
      * @exception ClassNotFoundException The specified class could not be
      *    found.
      */
-    public static Class loadClassWithout(ClassLoader loader,
+    public static Class<?> loadClassWithout(ClassLoader loader,
                                          String className)
         throws ClassNotFoundException {
         MBEANSERVER_LOGGER.logp(Level.FINEST,
@@ -102,12 +102,11 @@
         return load(loader, className);
     }
 
-    private static Class load(ClassLoader without, String className)
+    private static Class<?> load(ClassLoader without, String className)
             throws ClassNotFoundException {
-        final List mbsList = MBeanServerFactory.findMBeanServer(null);
+        final List<MBeanServer> mbsList = MBeanServerFactory.findMBeanServer(null);
 
-        for (Iterator it = mbsList.iterator(); it.hasNext(); ) {
-            MBeanServer mbs = (MBeanServer) it.next();
+        for (MBeanServer mbs : mbsList) {
             ClassLoaderRepository clr = mbs.getClassLoaderRepository();
             try {
                 return clr.loadClassWithout(without, className);
--- a/src/share/classes/javax/management/loading/MLet.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/loading/MLet.java	Tue Nov 11 09:07:58 2008 +0000
@@ -1291,7 +1291,7 @@
          if (c != null) {
             try {
                 Constructor<?> cons =
-                    c.getConstructor(new Class[] {String.class});
+                    c.getConstructor(String.class);
                 Object[] oo = new Object[1];
                 oo[0]=param;
                 return(cons.newInstance(oo));
--- a/src/share/classes/javax/management/loading/MLetObjectInputStream.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/loading/MLetObjectInputStream.java	Tue Nov 11 09:07:58 2008 +0000
@@ -55,30 +55,30 @@
         this.loader = loader;
     }
 
-    private Class primitiveType(char c) {
+    private Class<?> primitiveType(char c) {
         switch(c) {
-        case 66: /* 'B' */
+        case 'B':
             return Byte.TYPE;
 
-        case 67: /* 'C' */
+        case 'C':
             return Character.TYPE;
 
-        case 68: /* 'D' */
+        case 'D':
             return Double.TYPE;
 
-        case 70: /* 'F' */
+        case 'F':
             return Float.TYPE;
 
-        case 73: /* 'I' */
+        case 'I':
             return Integer.TYPE;
 
-        case 74: /* 'J' */
+        case 'J':
             return Long.TYPE;
 
-        case 83: /* 'S' */
+        case 'S':
             return Short.TYPE;
 
-        case 90: /* 'Z' */
+        case 'Z':
             return Boolean.TYPE;
         }
         return null;
@@ -87,14 +87,15 @@
     /**
      * Use the given ClassLoader rather than using the system class
      */
-    protected Class resolveClass(ObjectStreamClass objectstreamclass)
+    @Override
+    protected Class<?> resolveClass(ObjectStreamClass objectstreamclass)
         throws IOException, ClassNotFoundException {
 
         String s = objectstreamclass.getName();
         if (s.startsWith("[")) {
             int i;
             for (i = 1; s.charAt(i) == '['; i++);
-            Class class1;
+            Class<?> class1;
             if (s.charAt(i) == 'L') {
                 class1 = loader.loadClass(s.substring(i + 1, s.length() - 1));
             } else {
--- a/src/share/classes/javax/management/modelmbean/DescriptorSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/DescriptorSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -589,7 +589,7 @@
         int numberOfEntries = descriptorMap.size();
 
         String[] responseFields = new String[numberOfEntries];
-        Set returnedSet = descriptorMap.entrySet();
+        Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet();
 
         int i = 0;
 
@@ -598,8 +598,9 @@
                     DescriptorSupport.class.getName(),
                     "getFields()", "Returning " + numberOfEntries + " fields");
         }
-        for (Iterator iter = returnedSet.iterator(); iter.hasNext(); i++) {
-            Map.Entry currElement = (Map.Entry) iter.next();
+        for (Iterator<Map.Entry<String, Object>> iter = returnedSet.iterator();
+             iter.hasNext(); i++) {
+            Map.Entry<String, Object> currElement = iter.next();
 
             if (currElement == null) {
                 if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
@@ -642,7 +643,7 @@
         int numberOfEntries = descriptorMap.size();
 
         String[] responseFields = new String[numberOfEntries];
-        Set returnedSet = descriptorMap.entrySet();
+        Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet();
 
         int i = 0;
 
@@ -653,8 +654,9 @@
                     "Returning " + numberOfEntries + " fields");
         }
 
-        for (Iterator iter = returnedSet.iterator(); iter.hasNext(); i++) {
-            Map.Entry currElement = (Map.Entry) iter.next();
+        for (Iterator<Map.Entry<String, Object>> iter = returnedSet.iterator();
+             iter.hasNext(); i++) {
+            Map.Entry<String, Object> currElement = iter.next();
 
             if (( currElement == null ) || (currElement.getKey() == null)) {
                 if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
@@ -700,9 +702,8 @@
         }
 
         if (fieldNames == null) {
-            for (Iterator iter = descriptorMap.values().iterator();
-                 iter.hasNext(); i++)
-                responseFields[i] = iter.next();
+            for (Object value : descriptorMap.values())
+                responseFields[i++] = value;
         } else {
             for (i=0; i < fieldNames.length; i++) {
                 if ((fieldNames[i] == null) || (fieldNames[i].equals(""))) {
@@ -883,9 +884,9 @@
      * not a String with value "t", "f", "true", "false". These String
      * values must not be case sensitive.
      * <LI> visibility fieldName, if defined, is null, or not a
-     * Numeric String or a not Numeric Value >= 1 and <= 4
+     * Numeric String or a not Numeric Value >= 1 and &lt;= 4
      * <LI> severity fieldName, if defined, is null, or not a Numeric
-     * String or not a Numeric Value >= 0 and <= 6<br>
+     * String or not a Numeric Value >= 0 and &lt;= 6<br>
      * <LI> persistPolicy fieldName, if defined, is null, or not one of
      * the following strings:<br>
      *   "OnUpdate", "OnTimer", "NoMoreOftenThan", "OnUnregister", "Always",
@@ -904,7 +905,7 @@
         }
         // verify that the descriptor is valid, by iterating over each field...
 
-        Set returnedSet = descriptorMap.entrySet();
+        Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet();
 
         if (returnedSet == null) {   // null descriptor, not valid
             if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
@@ -925,9 +926,7 @@
 
         // According to the descriptor type we validate the fields contained
 
-        for (Iterator iter = returnedSet.iterator(); iter.hasNext();) {
-            Map.Entry currElement = (Map.Entry) iter.next();
-
+        for (Map.Entry<String, Object> currElement : returnedSet) {
             if (currElement != null) {
                 if (currElement.getValue() != null) {
                     // validate the field valued...
@@ -1083,10 +1082,9 @@
      */
     public synchronized String toXMLString() {
         final StringBuilder buf = new StringBuilder("<Descriptor>");
-        Set returnedSet = descriptorMap.entrySet();
-        for (Iterator iter = returnedSet.iterator(); iter.hasNext(); ) {
-            final Map.Entry currElement = (Map.Entry) iter.next();
-            final String name = currElement.getKey().toString();
+        Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet();
+        for (Map.Entry<String, Object> currElement : returnedSet) {
+            final String name = currElement.getKey();
             Object value = currElement.getValue();
             String valueString = null;
             /* Set valueString to non-null if and only if this is a string that
@@ -1256,7 +1254,7 @@
             }
             final Class<?> c =
                 Class.forName(className, false, contextClassLoader);
-            constr = c.getConstructor(new Class[] {String.class});
+            constr = c.getConstructor(new Class<?>[] {String.class});
         } catch (Exception e) {
             throw new XMLParseException(e,
                                         "Cannot parse value: <" + s + ">");
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -39,7 +39,6 @@
 import java.io.ObjectStreamField;
 import java.lang.reflect.Method;
 import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.logging.Level;
 
 import javax.management.Descriptor;
@@ -49,32 +48,56 @@
 import javax.management.RuntimeOperationsException;
 
 /**
- * The ModelMBeanAttributeInfo object describes an attribute of the ModelMBean.
+ * <p>The ModelMBeanAttributeInfo object describes an attribute of the ModelMBean.
  * It is a subclass of MBeanAttributeInfo with the addition of an associated Descriptor
- * and an implementation of the DescriptorAccess interface.
- * <P>
- * The fields in the descriptor are defined, but not limited to, the following: <P>
- * <PRE>
- * name           : attribute name
- * descriptorType : must be "attribute"
- * value          : current value for attribute
- * default        : default value for attribute
- * displayName    : name of attribute to be used in displays
- * getMethod      : name of operation descriptor for get method
- * setMethod      : name of operation descriptor for set method
- * protocolMap    : object which implements the Descriptor interface: mappings
- *                  must be appropriate for the attribute
- *                  and entries can be updated or augmented at runtime.
- * persistPolicy  : OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never
- * persistPeriod  : seconds - frequency of persist cycle. Used when persistPolicy
- *                  is "OnTimer" or "NoMoreOftenThan".
- * currencyTimeLimit : how long value is valid, &lt;0 never, =0 always, &gt;0 seconds
- * lastUpdatedTimeStamp : when value was set
- * visibility     : 1-4 where 1: always visible, 4: rarely visible
- * presentationString : xml formatted string to allow presentation of data
- * </PRE>
- * The default descriptor contains the name, descriptorType and displayName fields.
- * The default value of the name and displayName fields is the name of the attribute.
+ * and an implementation of the DescriptorAccess interface.</p>
+ *
+ * <P id="descriptor">
+ * The fields in the descriptor are defined, but not limited to, the following.
+ * Note that when the Type in this table is Number, a String that is the decimal
+ * representation of a Long can also be used.</P>
+ *
+ * <table border="1" cellpadding="5">
+ * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr>
+ * <tr><td>name</td><td>String</td>
+ *     <td>Attribute name.</td></tr>
+ * <tr><td>descriptorType</td><td>String</td>
+ *     <td>Must be "attribute".</td></tr>
+ * <tr id="value-field"><td>value</td><td>Object</td>
+ *     <td>Current (cached) value for attribute.</td></tr>
+ * <tr><td>default</td><td>Object</td>
+ *     <td>Default value for attribute.</td></tr>
+ * <tr><td>displayName</td><td>String</td>
+ *     <td>Name of attribute to be used in displays.</td></tr>
+ * <tr><td>getMethod</td><td>String</td>
+ *     <td>Name of operation descriptor for get method.</td></tr>
+ * <tr><td>setMethod</td><td>String</td>
+ *     <td>Name of operation descriptor for set method.</td></tr>
+ * <tr><td>protocolMap</td><td>Descriptor</td>
+ *     <td>See the section "Protocol Map Support" in the JMX specification
+ *         document.  Mappings must be appropriate for the attribute and entries
+ *         can be updated or augmented at runtime.</td></tr>
+ * <tr><td>persistPolicy</td><td>String</td>
+ *     <td>One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
+ *         See the section "MBean Descriptor Fields" in the JMX specification
+ *         document.</td></tr>
+ * <tr><td>persistPeriod</td><td>Number</td>
+ *     <td>Frequency of persist cycle in seconds. Used when persistPolicy is
+ *         "OnTimer" or "NoMoreOftenThan".</td></tr>
+ * <tr><td>currencyTimeLimit</td><td>Number</td>
+ *     <td>How long <a href="#value=field">value</a> is valid: &lt;0 never,
+ *         =0 always, &gt;0 seconds.</td></tr>
+ * <tr><td>lastUpdatedTimeStamp</td><td>Number</td>
+ *     <td>When <a href="#value-field">value</a> was set.</td></tr>
+ * <tr><td>visibility</td><td>Number</td>
+ *     <td>1-4 where 1: always visible, 4: rarely visible.</td></tr>
+ * <tr><td>presentationString</td><td>String</td>
+ *     <td>XML formatted string to allow presentation of data.</td></tr>
+ * </table>
+ *
+ * <p>The default descriptor contains the name, descriptorType and displayName
+ * fields.  The default value of the name and displayName fields is the name of
+ * the attribute.</p>
  *
  * <p><b>Note:</b> because of inconsistencies in previous versions of
  * this specification, it is recommended not to use negative or zero
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -49,22 +49,33 @@
 import javax.management.RuntimeOperationsException;
 
 /**
- * The ModelMBeanConstructorInfo object describes a constructor of the ModelMBean.
+ * <p>The ModelMBeanConstructorInfo object describes a constructor of the ModelMBean.
  * It is a subclass of MBeanConstructorInfo with the addition of an associated Descriptor
- * and an implementation of the DescriptorAccess interface.
- * <P>
- * <PRE>
- * The fields in the descriptor are defined, but not limited to, the following: <P>
- * name           : constructor name
- * descriptorType : must be "operation"
- * role           : must be "constructor"
- * displayName    : human readable name of constructor
- * visibility            : 1-4 where 1: always visible 4: rarely visible
- * presentationString :  xml formatted string to describe how to present operation
- *</PRE>
+ * and an implementation of the DescriptorAccess interface.</p>
+ *
+ * <P id="descriptor">
+ * The fields in the descriptor are defined, but not limited to, the following.
+ * Note that when the Type in this table is Number, a String that is the decimal
+ * representation of a Long can also be used.</P>
+ *
+ * <table border="1" cellpadding="5">
+ * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr>
+ * <tr><td>name</td><td>String</td>
+ *     <td>Constructor name.</td></tr>
+ * <tr><td>descriptorType</td><td>String</td>
+ *     <td>Must be "operation".</td></tr>
+ * <tr><td>role</td><td>String</td>
+ *     <td>Must be "constructor".</td></tr>
+ * <tr><td>displayName</td><td>String</td>
+ *     <td>Human readable name of constructor.</td></tr>
+ * <tr><td>visibility</td><td>Number</td>
+ *     <td>1-4 where 1: always visible 4: rarely visible.</td></tr>
+ * <tr><td>presentationString</td><td>String</td>
+ *     <td>XML formatted string to describe how to present operation</td></tr>
+ * </table>
  *
  * <p>The {@code persistPolicy} and {@code currencyTimeLimit} fields
- * are meaningless for constructors, but are not considered invalid.
+ * are meaningless for constructors, but are not considered invalid.</p>
  *
  * <p>The default descriptor will have the {@code name}, {@code
  * descriptorType}, {@code displayName} and {@code role} fields.  The
@@ -152,7 +163,7 @@
         * describing the MBean constructor.
         */
         public ModelMBeanConstructorInfo(String description,
-                                         Constructor constructorMethod)
+                                         Constructor<?> constructorMethod)
     {
                 super(description, constructorMethod);
                 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
@@ -194,7 +205,7 @@
         */
 
         public ModelMBeanConstructorInfo(String description,
-                                         Constructor constructorMethod,
+                                         Constructor<?> constructorMethod,
                                          Descriptor descriptor)
         {
 
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -156,29 +156,55 @@
 
 
     /**
-     * Returns the ModelMBean's descriptor which contains MBean wide policies.  This descriptor contains
-     * metadata about the MBean and default policies for persistence and caching.
-     * <P>
-     * The fields in the descriptor are defined, but not limited to, the following:
-     * <PRE>
-     * name           : MBean name
-     * descriptorType : must be "mbean"
-     * displayName    : name of attribute to be used in displays
-     * persistPolicy  : OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never
-     * persistLocation : The fully qualified directory name where the MBean should be persisted (if appropriate)
-     * persistFile    : File name into which the MBean should be persisted
-     * persistPeriod  : seconds - frequency of persist cycle for OnTime and NoMoreOftenThan PersistPolicy
-     * currencyTimeLimit : how long value is valid, &lt;0 never, =0 always, &gt;0 seconds
-     * log            : where t: log all notifications f: log no notifications
-     * logfile        : fully qualified filename to log events to
-     * visibility     : 1-4 where 1: always visible 4: rarely visible
-     * export         : name to be used to export/expose this MBean so that it is findable by
-     *                  other JMX Agents.
-     * presentationString : xml formatted string to allow presentation of data to be associated with the MBean.
-     * </PRE>
+     * <p>Returns the ModelMBean's descriptor which contains MBean wide
+     * policies.  This descriptor contains metadata about the MBean and default
+     * policies for persistence and caching.</p>
+     *
+     * <P id="descriptor">
+     * The fields in the descriptor are defined, but not limited to, the
+     * following.  Note that when the Type in this table is Number, a String
+     * that is the decimal representation of a Long can also be used.</P>
+     *
+     * <table border="1" cellpadding="5">
+     * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr>
+     * <tr><td>name</td><td>String</td>
+     *     <td>MBean name.</td></tr>
+     * <tr><td>descriptorType</td><td>String</td>
+     *     <td>Must be "mbean".</td></tr>
+     * <tr><td>displayName</td><td>String</td>
+     *     <td>Name of MBean to be used in displays.</td></tr>
+     * <tr><td>persistPolicy</td><td>String</td>
+     *     <td>One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
+     *         See the section "MBean Descriptor Fields" in the JMX specification
+     *         document.</td></tr>
+     * <tr><td>persistLocation</td><td>String</td>
+     *     <td>The fully qualified directory name where the MBean should be
+     *         persisted (if appropriate).</td></tr>
+     * <tr><td>persistFile</td><td>String</td>
+     *     <td>File name into which the MBean should be persisted.</td></tr>
+     * <tr><td>persistPeriod</td><td>Number</td>
+     *     <td>Frequency of persist cycle in seconds, for OnTime and
+     *         NoMoreOftenThan PersistPolicy</td></tr>
+     * <tr><td>currencyTimeLimit</td><td>Number</td>
+     *     <td>How long cached value is valid: &lt;0 never, =0 always,
+     *         &gt;0 seconds.</td></tr>
+     * <tr><td>log</td><td>String</td>
+     *     <td>t: log all notifications, f: log no notifications.</td></tr>
+     * <tr><td>logfile</td><td>String</td>
+     *     <td>Fully qualified filename to log events to.</td></tr>
+     * <tr><td>visibility</td><td>Number</td>
+     *     <td>1-4 where 1: always visible 4: rarely visible.</td></tr>
+     * <tr><td>export</td><td>String</td>
+     *     <td>Name to be used to export/expose this MBean so that it is
+     *         findable by other JMX Agents.</td></tr>
+     * <tr><td>presentationString</td><td>String</td>
+     *     <td>XML formatted string to allow presentation of data to be
+     *         associated with the MBean.</td></tr>
+     * </table>
+     *
      * <P>
      * The default descriptor is: name=className,descriptorType="mbean", displayName=className,
-     *  persistPolicy="never",log="F",export="F",visibility="1"
+     *  persistPolicy="never",log="F",visibility="1"
      * If the descriptor does not contain all these fields, they will be added with these default values.
      *
      * <p><b>Note:</b> because of inconsistencies in previous versions of
@@ -207,7 +233,7 @@
      * does a complete replacement of the descriptor, no merging is done. If the descriptor to
      * set to is null then the default descriptor will be created.
      * The default descriptor is: name=className,descriptorType="mbean", displayName=className,
-     *  persistPolicy="never",log="F",export="F",visibility="1"
+     *  persistPolicy="never",log="F",visibility="1"
      * If the descriptor does not contain all these fields, they will be added with these default values.
      *
      * See {@link #getMBeanDescriptor getMBeanDescriptor} method javadoc for description of valid field names.
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -46,34 +46,46 @@
 import javax.management.RuntimeOperationsException;
 
 /**
- * The ModelMBeanNotificationInfo object describes a notification emitted
+ * <p>The ModelMBeanNotificationInfo object describes a notification emitted
  * by a ModelMBean.
  * It is a subclass of MBeanNotificationInfo with the addition of an
- * associated Descriptor and an implementation of the Descriptor interface.
- * <P>
- * The fields in the descriptor are defined, but not limited to,
- * the following:
- * <PRE>
- * name           : notification name
- * descriptorType : must be "notification"
- * severity       : 0-6 where 0: unknown; 1: non-recoverable;
- *                  2: critical, failure; 3: major, severe;
- *                  4: minor, marginal, error; 5: warning;
- *                  6: normal, cleared, informative
- * messageID      : unique key for message text (to allow translation,
- *                  analysis)
- * messageText    : text of notification
- * log            : T - log message F - do not log message
- * logfile        : string fully qualified file name appropriate for
- *                  operating system
- * visibility     : 1-4 where 1: always visible 4: rarely visible
- * presentationString : xml formatted string to allow presentation of data
- * </PRE>
- * The default descriptor contains the name, descriptorType,
+ * associated Descriptor and an implementation of the Descriptor interface.</p>
+ *
+ * <P id="descriptor">
+ * The fields in the descriptor are defined, but not limited to, the following.
+ * Note that when the Type in this table is Number, a String that is the decimal
+ * representation of a Long can also be used.</P>
+ *
+ * <table border="1" cellpadding="5">
+ * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr>
+ * <tr><td>name</td><td>String</td>
+ *     <td>Notification name.</td></tr>
+ * <tr><td>descriptorType</td><td>String</td>
+ *     <td>Must be "notification".</td></tr>
+ * <tr><td>severity</td><td>Number</td>
+ *     <td>0-6 where 0: unknown; 1: non-recoverable;
+ *         2: critical, failure; 3: major, severe;
+ *         4: minor, marginal, error; 5: warning;
+ *         6: normal, cleared, informative</td></tr>
+ * <tr><td>messageID</td><td>String</td>
+ *     <td>Unique key for message text (to allow translation, analysis).</td></tr>
+ * <tr><td>messageText</td><td>String</td>
+ *     <td>Text of notification.</td></tr>
+ * <tr><td>log</td><td>String</td>
+ *     <td>T - log message, F - do not log message.</td></tr>
+ * <tr><td>logfile</td><td>String</td>
+ *     <td>fully qualified file name appropriate for operating system.</td></tr>
+ * <tr><td>visibility</td><td>Number</td>
+ *     <td>1-4 where 1: always visible 4: rarely visible.</td></tr>
+ * <tr><td>presentationString</td><td>String</td>
+ *     <td>XML formatted string to allow presentation of data.</td></tr>
+ * </table>
+ *
+ * <p>The default descriptor contains the name, descriptorType,
  * displayName and severity(=6) fields.  The default value of the name
  * and displayName fields is the name of the Notification class (as
  * specified by the <code>name</code> parameter of the
- * ModelMBeanNotificationInfo constructor).
+ * ModelMBeanNotificationInfo constructor).</p>
  *
  * <p>The <b>serialVersionUID</b> of this class is <code>-7445681389570207141L</code>.
  *
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java	Tue Nov 11 09:07:58 2008 +0000
@@ -49,27 +49,48 @@
 import javax.management.RuntimeOperationsException;
 
 /**
- * The ModelMBeanOperationInfo object describes a management operation of the ModelMBean.
- * It is a subclass of MBeanOperationInfo with the addition of an associated Descriptor
- * and an implementation of the DescriptorAccess interface.
- * <P>
- * <PRE>
- * The fields in the descriptor are defined, but not limited to, the following:
- * name           : operation name
- * descriptorType : must be "operation"
- * class          : class where method is defined (fully qualified)
- * role           : must be "operation", "getter", or "setter
- * targetObject   : object on which to execute this method
- * targetType     : type of object reference for targetObject. Can be:
- *                  ObjectReference | Handle | EJBHandle | IOR | RMIReference.
- * value          : cached value for operation
- * currencyTimeLimit : how long cached value is valid
- * lastUpdatedTimeStamp : when cached value was set
- * visibility            : 1-4 where 1: always visible 4: rarely visible
- * presentationString :  xml formatted string to describe how to present operation
- * </PRE>
- * The default descriptor will have name, descriptorType, displayName and role fields set.
- * The default value of the name and displayName fields is the operation name.
+ * <p>The ModelMBeanOperationInfo object describes a management operation of
+ * the ModelMBean.  It is a subclass of MBeanOperationInfo with the addition
+ * of an associated Descriptor and an implementation of the DescriptorAccess
+ * interface.</p>
+ *
+ * <P id="descriptor">
+ * The fields in the descriptor are defined, but not limited to, the following.
+ * Note that when the Type in this table is Number, a String that is the decimal
+ * representation of a Long can also be used.</P>
+ *
+ * <table border="1" cellpadding="5">
+ * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr>
+ * <tr><td>name</td><td>String</td>
+ *     <td>Operation name.</td></tr>
+ * <tr><td>descriptorType</td><td>String</td>
+ *     <td>Must be "operation".</td></tr>
+ * <tr><td>class</td><td>String</td>
+ *     <td>Class where method is defined (fully qualified).</td></tr>
+ * <tr><td>role</td><td>String</td>
+ *     <td>Must be "operation", "getter", or "setter".</td></tr>
+ * <tr><td>targetObject</td><td>Object</td>
+ *     <td>Object on which to execute this method.</td></tr>
+ * <tr><td>targetType</td><td>String</td>
+ *     <td>type of object reference for targetObject. Can be:
+ *         ObjectReference | Handle | EJBHandle | IOR | RMIReference.</td></tr>
+ * <tr><td>value</td><td>Object</td>
+ *     <td>Cached value for operation.</td></tr>
+ * <tr><td>displayName</td><td>String</td>
+ *     <td>Human readable display name of the operation.</td>
+ * <tr><td>currencyTimeLimit</td><td>Number</td>
+ *     <td>How long cached value is valid.</td></tr>
+ * <tr><td>lastUpdatedTimeStamp</td><td>Number</td>
+ *     <td>When cached value was set.</td></tr>
+ * <tr><td>visibility</td><td>Number</td>
+ *     <td>1-4 where 1: always visible 4: rarely visible.</td></tr>
+ * <tr><td>presentationString</td><td>String</td>
+ *     <td>XML formatted string to describe how to present operation</td></tr>
+ * </table>
+ *
+ * <p>The default descriptor will have name, descriptorType, displayName and
+ * role fields set.  The default value of the name and displayName fields is
+ * the operation name.</p>
  *
  * <p><b>Note:</b> because of inconsistencies in previous versions of
  * this specification, it is recommended not to use negative or zero
--- a/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java	Tue Nov 11 09:07:58 2008 +0000
@@ -1074,7 +1074,7 @@
                 }
             }
 
-            final Class targetClass;
+            final Class<?> targetClass;
 
             if (opClassName != null) {
                 try {
@@ -1126,20 +1126,20 @@
                   "resolving " + targetClass.getName() + "." + opMethodName);
         }
 
-        final Class[] argClasses;
+        final Class<?>[] argClasses;
 
         if (sig == null)
             argClasses = null;
         else {
             final ClassLoader targetClassLoader = targetClass.getClassLoader();
-            argClasses = new Class[sig.length];
+            argClasses = new Class<?>[sig.length];
             for (int i = 0; i < sig.length; i++) {
                 if (tracing) {
                     MODELMBEAN_LOGGER.logp(Level.FINER,
                         RequiredModelMBean.class.getName(),"resolveMethod",
                             "resolve type " + sig[i]);
                 }
-                argClasses[i] = (Class) primitiveClassMap.get(sig[i]);
+                argClasses[i] = (Class<?>) primitiveClassMap.get(sig[i]);
                 if (argClasses[i] == null) {
                     try {
                         argClasses[i] =
@@ -1170,7 +1170,7 @@
 
     /* Map e.g. "int" to int.class.  Goodness knows how many time this
        particular wheel has been reinvented.  */
-    private static final Class[] primitiveClasses = {
+    private static final Class<?>[] primitiveClasses = {
         int.class, long.class, boolean.class, double.class,
         float.class, short.class, byte.class, char.class,
     };
@@ -1178,7 +1178,7 @@
         new HashMap<String,Class<?>>();
     static {
         for (int i = 0; i < primitiveClasses.length; i++) {
-            final Class c = primitiveClasses[i];
+            final Class<?> c = primitiveClasses[i];
             primitiveClassMap.put(c.getName(), c);
         }
     }
@@ -1645,7 +1645,7 @@
                             try {
                                 ClassLoader cl =
                                     response.getClass().getClassLoader();
-                                Class c = Class.forName(respType, true, cl);
+                                Class<?> c = Class.forName(respType, true, cl);
                                 subtype = c.isInstance(response);
                             } catch (Exception e) {
                                 subtype = false;
@@ -1904,7 +1904,7 @@
             if (attrSetMethod == null) {
                 if (attrValue != null) {
                     try {
-                        final Class  clazz    = loadClass(attrType);
+                        final Class<?> clazz = loadClass(attrType);
                         if (! clazz.isInstance(attrValue))  throw new
                             InvalidAttributeValueException(clazz.getName() +
                                                            " expected, "   +
@@ -2044,8 +2044,7 @@
         final AttributeList responseList = new AttributeList();
 
         // Go through the list of attributes
-        for (Iterator i = attributes.iterator(); i.hasNext();) {
-            final Attribute attr = (Attribute) i.next();
+        for (Attribute attr : attributes.asList()) {
             try {
                 setAttribute(attr);
                 responseList.add(attr);
@@ -2799,7 +2798,7 @@
         return MBeanServerFactory.getClassLoaderRepository(server);
     }
 
-    private  Class loadClass(String className)
+    private Class<?> loadClass(String className)
         throws ClassNotFoundException {
         try {
             return Class.forName(className);
--- a/src/share/classes/javax/management/namespace/JMXNamespaces.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/namespace/JMXNamespaces.java	Tue Nov 11 09:07:58 2008 +0000
@@ -26,21 +26,19 @@
 package javax.management.namespace;
 
 import com.sun.jmx.defaults.JmxProperties;
-import com.sun.jmx.namespace.JMXNamespaceUtils;
 import com.sun.jmx.namespace.ObjectNameRouter;
 import com.sun.jmx.namespace.serial.RewritingProcessor;
 import com.sun.jmx.namespace.RoutingConnectionProxy;
 import com.sun.jmx.namespace.RoutingServerProxy;
 
-import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.management.InstanceNotFoundException;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerConnection;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
-import javax.management.remote.JMXConnector;
 
 /**
  * Static constants and utility methods to help work with
@@ -69,23 +67,6 @@
 
 
     /**
-     * Returns a connector connected to a sub name space exposed through
-     * the parent connector.
-     * @param parent the parent connector.
-     * @param namespace the {@linkplain javax.management.namespace name space}
-     *                  to which the returned connector is
-     *                  connected.
-     * @return A connector connected to a sub name space exposed through
-     * the parent connector.
-     **/
-    public static JMXConnector narrowToNamespace(final JMXConnector parent,
-                                  final String namespace)
-        throws IOException {
-
-        return JMXNamespaceUtils.cd(parent,namespace,true);
-    }
-
-    /**
      * Creates a new {@code MBeanServerConnection} proxy on a
      * {@linkplain javax.management.namespace sub name space}
      * of the given parent.
@@ -96,15 +77,18 @@
      *               name space} in which to narrow.
      * @return A new {@code MBeanServerConnection} proxy that shows the content
      *         of that name space.
-     * @throws IllegalArgumentException if the name space does not exist, or
-     *         if a proxy for that name space cannot be created.
+     * @throws IllegalArgumentException if either argument is null,
+     * or the name space does not exist, or if a proxy for that name space
+     * cannot be created.  The {@linkplain Throwable#getCause() cause} of
+     * this exception will be an {@link InstanceNotFoundException} if and only
+     * if the name space is found not to exist.
      */
     public static MBeanServerConnection narrowToNamespace(
                         MBeanServerConnection parent,
                         String namespace) {
         if (LOG.isLoggable(Level.FINER))
             LOG.finer("Making MBeanServerConnection for: " +namespace);
-        return RoutingConnectionProxy.cd(parent,namespace);
+        return RoutingConnectionProxy.cd(parent, namespace, true);
     }
 
     /**
@@ -120,13 +104,15 @@
      *         of that name space.
      * @throws IllegalArgumentException if either argument is null,
      * or the name space does not exist, or if a proxy for that name space
-     * cannot be created.
+     * cannot be created.  The {@linkplain Throwable#getCause() cause} of
+     * this exception will be an {@link InstanceNotFoundException} if and only
+     * if the name space is found not to exist.
      */
     public static MBeanServer narrowToNamespace(MBeanServer parent,
             String namespace) {
         if (LOG.isLoggable(Level.FINER))
-            LOG.finer("Making NamespaceServerProxy for: " +namespace);
-        return RoutingServerProxy.cd(parent,namespace);
+            LOG.finer("Making MBeanServer for: " +namespace);
+        return RoutingServerProxy.cd(parent, namespace, true);
     }
 
     /**
@@ -266,7 +252,7 @@
                 ObjectNameRouter.normalizeNamespacePath(namespace,false,
                             true,false);
         try {
-            // We could use Util.newObjectName here - but throwing an
+            // We could use ObjectName.valueOf here - but throwing an
             // IllegalArgumentException that contains just the supplied
             // namespace instead of the whole ObjectName seems preferable.
             return ObjectName.getInstance(sourcePath+
--- a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java	Tue Nov 11 09:07:58 2008 +0000
@@ -27,10 +27,10 @@
 
 import com.sun.jmx.defaults.JmxProperties;
 import com.sun.jmx.mbeanserver.Util;
-import com.sun.jmx.namespace.JMXNamespaceUtils;
 import com.sun.jmx.remote.util.EnvHelp;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
@@ -39,6 +39,7 @@
 
 import javax.management.AttributeChangeNotification;
 
+import javax.management.ClientContext;
 import javax.management.InstanceNotFoundException;
 import javax.management.ListenerNotFoundException;
 import javax.management.MBeanNotificationInfo;
@@ -220,17 +221,26 @@
                 initParentOnce(this);
 
         // URL must not be null.
-        this.jmxURL     = JMXNamespaceUtils.checkNonNull(sourceURL,"url");
+        if (sourceURL == null)
+            throw new IllegalArgumentException("Null URL");
+        this.jmxURL     = sourceURL;
         this.broadcaster =
             new NotificationBroadcasterSupport(connectNotification);
 
         // handles options
-        this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap);
+        this.optionsMap = unmodifiableMap(optionsMap);
 
         // handles (dis)connection events
         this.listener = new ConnectionListener();
     }
 
+    // returns un unmodifiable view of a map.
+    private static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) {
+        if (aMap == null || aMap.isEmpty())
+            return Collections.emptyMap();
+        return Collections.unmodifiableMap(aMap);
+    }
+
    /**
     * Returns the {@code JMXServiceURL} that is (or will be) used to
     * connect to the remote name space. <p>
@@ -483,106 +493,171 @@
         }
     }
 
-    JMXConnector connect(JMXServiceURL url, Map<String,?> env)
+    private JMXConnector connect(JMXServiceURL url, Map<String,?> env)
             throws IOException {
-        final JMXConnector c = newJMXConnector(jmxURL, env);
+        final JMXConnector c = newJMXConnector(url, env);
         c.connect(env);
         return c;
     }
 
     /**
-     * Creates a new JMXConnector with the specified {@code url} and
-     * {@code env} options map.
-     * <p>
-     * This method first calls {@link JMXConnectorFactory#newJMXConnector
-     * JMXConnectorFactory.newJMXConnector(jmxURL, env)} to obtain a new
-     * JMX connector, and returns that.
-     * </p>
-     * <p>
-     * A subclass of {@link JMXRemoteNamespace} can provide an implementation
-     * that connects to a  sub namespace of the remote server by subclassing
-     * this class in the following way:
-     * <pre>
-     * class JMXRemoteSubNamespace extends JMXRemoteNamespace {
-     *    private final String subnamespace;
-     *    JMXRemoteSubNamespace(JMXServiceURL url,
-     *              Map{@code <String,?>} env, String subnamespace) {
-     *        super(url,options);
-     *        this.subnamespace = subnamespace;
-     *    }
-     *    protected JMXConnector newJMXConnector(JMXServiceURL url,
-     *              Map<String,?> env) throws IOException {
-     *        final JMXConnector inner = super.newJMXConnector(url,env);
-     *        return {@link JMXNamespaces#narrowToNamespace(JMXConnector,String)
-     *               JMXNamespaces.narrowToNamespace(inner,subnamespace)};
-     *    }
-     * }
-     * </pre>
-     * </p>
-     * <p>
-     * Some connectors, like the JMXMP connector server defined by the
-     * version 1.2 of the JMX API may not have been upgraded to use the
-     * new {@linkplain javax.management.event Event Service} defined in this
-     * version of the JMX API.
-     * <p>
-     * In that case, and if the remote server to which this JMXRemoteNamespace
-     * connects also contains namespaces, it may be necessary to configure
-     * explicitly an {@linkplain
-     * javax.management.event.EventClientDelegate#newForwarder()
-     * Event Client Forwarder} on the remote server side, and to force the use
-     * of an {@link EventClient} on this client side.
-     * <br>
-     * A subclass of {@link JMXRemoteNamespace} can provide an implementation
-     * of {@code newJMXConnector} that will force notification subscriptions
-     * to flow through an {@link EventClient} over a legacy protocol by
-     * overriding this method in the following way:
-     * </p>
-     * <pre>
-     * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace {
-     *    JMXRemoteSubNamespaceConnector(JMXServiceURL url,
-     *              Map<String,?> env) {
-     *        super(url,options);
-     *    }
-     *    protected JMXConnector newJMXConnector(JMXServiceURL url,
-     *              Map<String,?> env) throws IOException {
-     *        final JMXConnector inner = super.newJMXConnector(url,env);
-     *        return {@link EventClient#withEventClient(
-     *                JMXConnector) EventClient.withEventClient(inner)};
-     *    }
-     * }
-     * </pre>
-     * <p>
-     * Note that the remote server also needs to provide an {@link
-     * javax.management.event.EventClientDelegateMBean}: only configuring
-     * the client side (this object) is not enough.<br>
-     * In summary, this technique should be used if the remote server
-     * supports JMX namespaces, but uses a JMX Connector Server whose
-     * implementation does not transparently use the new Event Service
-     * (as would be the case with the JMXMPConnectorServer implementation
-     * from the reference implementation of the JMX Remote API 1.0
-     * specification).
-     * </p>
+     * <p>Creates a new JMXConnector with the specified {@code url} and
+     * {@code env} options map.  The default implementation of this method
+     * returns {@link JMXConnectorFactory#newJMXConnector
+     * JMXConnectorFactory.newJMXConnector(jmxURL, env)}.  Subclasses can
+     * override this method to customize behavior.</p>
+     *
      * @param url  The JMXServiceURL of the remote server.
-     * @param optionsMap An unmodifiable options map that will be passed to the
+     * @param optionsMap An options map that will be passed to the
      *        {@link JMXConnectorFactory} when {@linkplain
      *        JMXConnectorFactory#newJMXConnector creating} the
      *        {@link JMXConnector} that can connect to the remote source
      *        MBean Server.
-     * @return An unconnected JMXConnector to use to connect to the remote
-     *         server
-     * @throws java.io.IOException if the connector could not be created.
+     * @return A JMXConnector to use to connect to the remote server
+     * @throws IOException if the connector could not be created.
      * @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map)
      * @see #JMXRemoteNamespace
      */
     protected JMXConnector newJMXConnector(JMXServiceURL url,
             Map<String,?> optionsMap) throws IOException {
-        final JMXConnector c =
-                JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
-// TODO: uncomment this when contexts are added
-//        return ClientContext.withDynamicContext(c);
-        return c;
+        return JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
     }
 
+    /**
+     * <p>Called when a new connection is established using {@link #connect}
+     * so that subclasses can customize the connection.  The default
+     * implementation of this method effectively does the following:</p>
+     *
+     * <pre>
+     * MBeanServerConnection mbsc = {@link JMXConnector#getMBeanServerConnection()
+     *                               jmxc.getMBeanServerConnection()};
+     * try {
+     *     return {@link ClientContext#withDynamicContext
+     *             ClientContext.withDynamicContext(mbsc)};
+     * } catch (IllegalArgumentException e) {
+     *     return mbsc;
+     * }
+     * </pre>
+     *
+     * <p>In other words, it arranges for the client context to be forwarded
+     * to the remote MBean Server if the remote MBean Server supports contexts;
+     * otherwise it ignores the client context.</p>
+     *
+     * <h4>Example: connecting to a remote namespace</h4>
+     *
+     * <p>A subclass that wanted to narrow into a namespace of
+     * the remote MBeanServer might look like this:</p>
+     *
+     * <pre>
+     * class JMXRemoteSubNamespace extends JMXRemoteNamespace {
+     *     private final String subnamespace;
+     *
+     *     JMXRemoteSubNamespace(
+     *             JMXServiceURL url, Map{@code <String, ?>} env, String subnamespace) {
+     *        super(url, env);
+     *        this.subnamespace = subnamespace;
+     *     }
+     *
+     *     {@code @Override}
+     *     protected MBeanServerConnection getMBeanServerConnection(
+     *             JMXConnector jmxc) throws IOException {
+     *         MBeanServerConnection mbsc = super.getMBeanServerConnection(jmxc);
+     *         return {@link JMXNamespaces#narrowToNamespace(MBeanServerConnection,String)
+     *                 JMXNamespaces.narrowToNamespace(mbsc, subnamespace)};
+     *     }
+     * }
+     * </pre>
+     *
+     * <h4>Example: using the Event Service for notifications</h4>
+     *
+     * <p>Some connectors may have been designed to work with an earlier
+     * version of the JMX API, and may not have been upgraded to use
+     * the {@linkplain javax.management.event Event Service} defined in
+     * this version of the JMX API.  In that case, and if the remote
+     * server to which this JMXRemoteNamespace connects also contains
+     * namespaces, it may be necessary to configure explicitly an {@linkplain
+     * javax.management.event.EventClientDelegate#newForwarder Event Client
+     * Forwarder} on the remote server side, and to force the use of an {@link
+     * EventClient} on this client side.</p>
+     *
+     * <p>A subclass of {@link JMXRemoteNamespace} can provide an
+     * implementation of {@code getMBeanServerConnection} that will force
+     * notification subscriptions to flow through an {@link EventClient} over
+     * a legacy protocol.  It can do so by overriding this method in the
+     * following way:</p>
+     *
+     * <pre>
+     * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace {
+     *     JMXRemoteEventClientNamespace(JMXServiceURL url, {@code Map<String,?>} env) {
+     *         super(url, env);
+     *     }
+     *
+     *     {@code @Override}
+     *     protected MBeanServerConnection getMBeanServerConnection(JMXConnector jmxc)
+     *             throws IOException {
+     *         MBeanServerConnection mbsc = super.getMBeanServerConnection(jmxc);
+     *         return EventClient.getEventClientConnection(mbsc);
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * Note that the remote server also needs to provide an {@link
+     * javax.management.event.EventClientDelegateMBean}: configuring only
+     * the client side (this object) is not enough.</p>
+     *
+     * <p>In summary, this technique should be used if the remote server
+     * supports JMX namespaces, but uses a JMX Connector Server whose
+     * implementation does not transparently use the new Event Service
+     * (as would be the case with the JMXMPConnectorServer implementation
+     * from the reference implementation of the JMX Remote API 1.0
+     * specification).</p>
+     *
+     * @param jmxc the newly-created {@code JMXConnector}.
+     *
+     * @return an {@code MBeanServerConnection} connected to the remote
+     * MBeanServer.
+     *
+     * @throws IOException if the connection cannot be made.  If this method
+     * throws {@code IOException} then the calling {@link #connect()} method
+     * will also fail with an {@code IOException}.
+     *
+     * @see #connect
+     */
+    protected MBeanServerConnection getMBeanServerConnection(JMXConnector jmxc)
+            throws IOException {
+        final MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
+        try {
+            return ClientContext.withDynamicContext(mbsc);
+        } catch (IllegalArgumentException e) {
+            LOG.log(Level.FINER, "ClientContext.withDynamicContext", e);
+            return mbsc;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The sequence of events when this method is called includes,
+     * effectively, the following code:</p>
+     *
+     * <pre>
+     * JMXServiceURL url = {@link #getJMXServiceURL getJMXServiceURL}();
+     * JMXConnector jmxc = {@link #newJMXConnector newJMXConnector}(url, env);
+     * jmxc.connect();
+     * MBeanServerConnection mbsc = {@link #getMBeanServerConnection(JMXConnector)
+     *                               getMBeanServerConnection}(jmxc);
+     * </pre>
+     *
+     * <p>Here, {@code env} is a {@code Map} containing the entries from the
+     * {@code optionsMap} that was passed to the {@linkplain #JMXRemoteNamespace
+     * constructor} or to the {@link #newJMXRemoteNamespace newJMXRemoteNamespace}
+     * factory method.</p>
+     *
+     * <p>Subclasses can customize connection behavior by overriding the
+     * {@code getJMXServiceURL}, {@code newJMXConnector}, or
+     * {@code getMBeanServerConnection} methods.</p>
+     */
     public void connect() throws IOException {
         LOG.fine("connecting...");
         final Map<String,Object> env =
@@ -590,7 +665,7 @@
         try {
             // XXX: We should probably document this...
             // This allows to specify a loader name - which will be
-            // retrieved from the paret MBeanServer.
+            // retrieved from the parent MBeanServer.
             defaultClassLoader =
                 EnvHelp.resolveServerClassLoader(env,getMBeanServer());
         } catch (InstanceNotFoundException x) {
@@ -604,7 +679,7 @@
         final JMXConnector aconn = connect(url,env);
         final MBeanServerConnection msc;
         try {
-            msc = aconn.getMBeanServerConnection();
+            msc = getMBeanServerConnection(aconn);
             aconn.addConnectionNotificationListener(listener,null,aconn);
         } catch (IOException io) {
             close(aconn);
--- a/src/share/classes/javax/management/namespace/MBeanServerSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/namespace/MBeanServerSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -457,7 +457,11 @@
      * All the various flavors of {@code MBeanServer.createMBean} methods
      * will eventually call this method. A subclass that wishes to
      * support MBean creation through {@code createMBean} thus only
-     * needs to provide an implementation for this one method.
+     * needs to provide an implementation for this one method.</p>
+     *
+     * <p>A subclass implementation of this method should respect the contract
+     * of the various {@code createMBean} methods in the {@link MBeanServer}
+     * interface, in particular as regards exception wrapping.</p>
      *
      * @param className The class name of the MBean to be instantiated.
      * @param name The object name of the MBean. May be null.
@@ -488,6 +492,17 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
+     * @exception RuntimeMBeanException If the MBean's constructor or its
+     * {@code preRegister} or {@code postRegister} method threw
+     * a {@code RuntimeException}. If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>createMBean</CODE> method will
+     * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean</CODE> method
+     * threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
      * @exception MBeanException The constructor of the MBean has
      * thrown an exception
      * @exception NotCompliantMBeanException This class is not a JMX
@@ -1096,7 +1111,7 @@
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException {
         try {
-            return safeCreateMBean(className, name, null, params, signature, true);
+            return createMBean(className, name, null, params, signature, true);
         } catch (InstanceNotFoundException ex) {
             // should not happen!
             throw new MBeanException(ex, "Unexpected exception: " + ex);
@@ -1113,7 +1128,7 @@
             throws ReflectionException, InstanceAlreadyExistsException,
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException, InstanceNotFoundException {
-        return safeCreateMBean(className, name, loaderName, params, signature, false);
+        return createMBean(className, name, loaderName, params, signature, false);
     }
 
     /**
@@ -1126,7 +1141,7 @@
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException {
         try {
-            return safeCreateMBean(className, name, null, null, null, true);
+            return createMBean(className, name, null, null, null, true);
         } catch (InstanceNotFoundException ex) {
             // should not happen!
             throw new MBeanException(ex, "Unexpected exception: " + ex);
@@ -1143,32 +1158,7 @@
             throws ReflectionException, InstanceAlreadyExistsException,
             MBeanRegistrationException, MBeanException,
             NotCompliantMBeanException, InstanceNotFoundException {
-        return safeCreateMBean(className, name, loaderName, null, null, false);
-    }
-
-    // make sure all exceptions are correctly wrapped in a JMXException
-    private ObjectInstance safeCreateMBean(String className,
-            ObjectName name, ObjectName loaderName, Object[] params,
-            String[] signature, boolean useRepository)
-            throws ReflectionException, InstanceAlreadyExistsException,
-            MBeanRegistrationException, MBeanException,
-            NotCompliantMBeanException, InstanceNotFoundException {
-        try {
-            return createMBean(className, name, loaderName, params,
-                               signature, useRepository);
-        } catch (ReflectionException x) { throw x;
-        } catch (InstanceAlreadyExistsException x) { throw x;
-        } catch (MBeanRegistrationException x) { throw x;
-        } catch (MBeanException x) { throw x;
-        } catch (NotCompliantMBeanException x) { throw x;
-        } catch (InstanceNotFoundException x) { throw x;
-        } catch (SecurityException x) { throw x;
-        } catch (JMRuntimeException x) { throw x;
-        } catch (RuntimeException x) {
-            throw new RuntimeOperationsException(x, x.toString());
-        } catch (Exception x) {
-            throw new MBeanException(x, x.toString());
-        }
+        return createMBean(className, name, loaderName, null, null, false);
     }
 
 
--- a/src/share/classes/javax/management/openmbean/ArrayType.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/ArrayType.java	Tue Nov 11 09:07:58 2008 +0000
@@ -296,7 +296,7 @@
         // Check and construct state specific to ArrayType
         //
         if (elementType.isArray()) {
-            ArrayType at = (ArrayType) elementType;
+            ArrayType<?> at = (ArrayType<?>) elementType;
             this.dimension = at.getDimension() + dimension;
             this.elementType = at.getElementOpenType();
             this.primitiveArray = at.isPrimitiveArray();
@@ -384,7 +384,7 @@
 
     /* Package-private constructor for callers we trust to get it right. */
     ArrayType(String className, String typeName, String description,
-              int dimension, OpenType elementType,
+              int dimension, OpenType<?> elementType,
               boolean primitiveArray) {
         super(className, typeName, description, true);
         this.dimension = dimension;
@@ -397,7 +397,7 @@
         throws OpenDataException {
         boolean isPrimitiveArray = false;
         if (elementType.isArray()) {
-            isPrimitiveArray = ((ArrayType) elementType).isPrimitiveArray();
+            isPrimitiveArray = ((ArrayType<?>) elementType).isPrimitiveArray();
         }
         return buildArrayClassName(dimension, elementType, isPrimitiveArray);
     }
@@ -443,7 +443,7 @@
         throws OpenDataException {
         boolean isPrimitiveArray = false;
         if (elementType.isArray()) {
-            isPrimitiveArray = ((ArrayType) elementType).isPrimitiveArray();
+            isPrimitiveArray = ((ArrayType<?>) elementType).isPrimitiveArray();
         }
         return buildArrayDescription(dimension, elementType, isPrimitiveArray);
     }
@@ -453,7 +453,7 @@
                                                 boolean isPrimitiveArray)
         throws OpenDataException {
         if (elementType.isArray()) {
-            ArrayType at = (ArrayType) elementType;
+            ArrayType<?> at = (ArrayType<?>) elementType;
             dimension += at.getDimension();
             elementType = at.getElementOpenType();
             isPrimitiveArray = at.isPrimitiveArray();
@@ -551,7 +551,7 @@
             return false;
         }
 
-        Class  objClass     = obj.getClass();
+        Class<?> objClass = obj.getClass();
         String objClassName = objClass.getName();
 
         // if obj is not an array, return false
@@ -636,8 +636,8 @@
     }
 
     @Override
-    boolean isAssignableFrom(OpenType ot) {
-        if (!(ot instanceof ArrayType))
+    boolean isAssignableFrom(OpenType<?> ot) {
+        if (!(ot instanceof ArrayType<?>))
             return false;
         ArrayType<?> at = (ArrayType<?>) ot;
         return (at.getDimension() == getDimension() &&
@@ -675,9 +675,9 @@
 
         // if obj is not an ArrayType, return false
         //
-        if (!(obj instanceof ArrayType))
+        if (!(obj instanceof ArrayType<?>))
             return false;
-        ArrayType other = (ArrayType) obj;
+        ArrayType<?> other = (ArrayType<?>) obj;
 
         // if other's dimension is different than this instance's, return false
         //
@@ -879,6 +879,7 @@
         // Build primitive array
         //
         try {
+            @SuppressWarnings("rawtypes")
             ArrayType at = new ArrayType(simpleType, true);
             if (n > 1)
                 at = new ArrayType<T>(n - 1, at);
@@ -934,7 +935,7 @@
         }
     }
 
-    private ArrayType convertFromWrapperToPrimitiveTypes() {
+    private <T> ArrayType<T> convertFromWrapperToPrimitiveTypes() {
         String cn = getClassName();
         String tn = getTypeName();
         String d = getDescription();
@@ -952,8 +953,8 @@
                 break;
             }
         }
-        return new ArrayType(cn, tn, d,
-                             dimension, elementType, primitiveArray);
+        return new ArrayType<T>(cn, tn, d,
+                                dimension, elementType, primitiveArray);
     }
 
     /**
@@ -1002,7 +1003,7 @@
         }
     }
 
-    private ArrayType convertFromPrimitiveToWrapperTypes() {
+    private <T> ArrayType<T> convertFromPrimitiveToWrapperTypes() {
         String cn = getClassName();
         String tn = getTypeName();
         String d = getDescription();
@@ -1020,7 +1021,7 @@
                 break;
             }
         }
-        return new ArrayType(cn, tn, d,
-                             dimension, elementType, primitiveArray);
+        return new ArrayType<T>(cn, tn, d,
+                                dimension, elementType, primitiveArray);
     }
 }
--- a/src/share/classes/javax/management/openmbean/CompositeDataInvocationHandler.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/CompositeDataInvocationHandler.java	Tue Nov 11 09:07:58 2008 +0000
@@ -236,8 +236,8 @@
         if (other == null)
             return false;
 
-        final Class proxyClass = proxy.getClass();
-        final Class otherClass = other.getClass();
+        final Class<?> proxyClass = proxy.getClass();
+        final Class<?> otherClass = other.getClass();
         if (proxyClass != otherClass)
             return false;
         InvocationHandler otherih = Proxy.getInvocationHandler(other);
--- a/src/share/classes/javax/management/openmbean/CompositeDataSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/CompositeDataSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -33,12 +33,14 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
 // jmx import
+import java.util.TreeSet;
 //
 
 
@@ -60,16 +62,15 @@
      * respective values.
      *         A {@link SortedMap} is used for faster retrieval of elements.
      */
-    private SortedMap<String, Object> contents = new TreeMap<String, Object>();
+    private final SortedMap<String, Object> contents;
 
     /**
      * @serial The <i>composite type </i> of this <i>composite data</i> instance.
      */
-    private CompositeType compositeType;
+    private final CompositeType compositeType;
 
     /**
-     * <p>
-     * Constructs a <tt>CompositeDataSupport</tt> instance with the specified
+     * <p>Constructs a <tt>CompositeDataSupport</tt> instance with the specified
      * <tt>compositeType</tt>, whose item values
      * are specified by <tt>itemValues[]</tt>, in the same order as in
      * <tt>itemNames[]</tt>.
@@ -79,41 +80,124 @@
      * The items contained in this <tt>CompositeDataSupport</tt> instance are
      * internally stored in a <tt>TreeMap</tt>,
      * thus sorted in ascending lexicographic order of their names, for faster
-     * retrieval of individual item values.
+     * retrieval of individual item values.</p>
+     *
+     * <p>The constructor checks that all the constraints listed below for each
+     * parameter are satisfied,
+     * and throws the appropriate exception if they are not.</p>
+     *
+     * @param compositeType the <i>composite type </i> of this <i>composite
+     * data</i> instance; must not be null.
+     *
+     * @param itemNames <tt>itemNames</tt> must list, in any order, all the
+     * item names defined in <tt>compositeType</tt>; the order in which the
+     * names are listed, is used to match values in <tt>itemValues[]</tt>; must
+     * not be null.
+     *
+     * @param itemValues the values of the items, listed in the same order as
+     * their respective names in <tt>itemNames</tt>; each item value can be
+     * null, but if it is non-null it must be a valid value for the open type
+     * defined in <tt>compositeType</tt> for the corresponding item; must be of
+     * the same size as <tt>itemNames</tt>; must not be null.
+     *
+     * @throws IllegalArgumentException <tt>compositeType</tt> is null, or
+     * <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty, or one
+     * of the elements in <tt>itemNames[]</tt> is a null or empty string, or
+     * <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size.
+     *
+     * @throws OpenDataException <tt>itemNames[]</tt> or
+     * <tt>itemValues[]</tt>'s size differs from the number of items defined in
+     * <tt>compositeType</tt>, or one of the elements in <tt>itemNames[]</tt>
+     * does not exist as an item name defined in <tt>compositeType</tt>, or one
+     * of the elements in <tt>itemValues[]</tt> is not a valid value for the
+     * corresponding item as defined in <tt>compositeType</tt>.
+     */
+    public CompositeDataSupport(
+            CompositeType compositeType, String[] itemNames, Object[] itemValues)
+            throws OpenDataException {
+        this(makeMap(itemNames, itemValues), compositeType);
+    }
+
+    private static SortedMap<String, Object> makeMap(
+            String[] itemNames, Object[] itemValues)
+            throws OpenDataException {
+
+        if (itemNames == null || itemValues == null)
+            throw new IllegalArgumentException("Null itemNames or itemValues");
+        if (itemNames.length != itemValues.length) {
+            throw new IllegalArgumentException(
+                    "Different lengths: itemNames[" + itemNames.length +
+                    "], itemValues[" + itemValues.length + "]");
+        }
+
+        SortedMap<String, Object> map = new TreeMap<String, Object>();
+        for (int i = 0; i < itemNames.length; i++) {
+            String name = itemNames[i];
+            if (name == null || name.equals(""))
+                throw new IllegalArgumentException("Null or empty item name");
+            if (map.containsKey(name))
+                throw new OpenDataException("Duplicate item name " + name);
+            map.put(itemNames[i], itemValues[i]);
+        }
+
+        return map;
+    }
+
+    /**
      * <p>
-     * The constructor checks that all the constraints listed below for each
-     * parameter are satisfied,
-     * and throws the appropriate exception if they are not.
-     * <p>
-     * @param  compositeType  the <i>composite type </i> of this <i>composite
-     * data</i> instance;
+     * Constructs a <tt>CompositeDataSupport</tt> instance with the specified <tt>compositeType</tt>, whose item names and corresponding values
+     * are given by the mappings in the map <tt>items</tt>.
+     * This constructor converts the keys to a string array and the values to an object array and calls
+     * <tt>CompositeDataSupport(javax.management.openmbean.CompositeType, java.lang.String[], java.lang.Object[])</tt>.
+     *
+     * @param  compositeType  the <i>composite type </i> of this <i>composite data</i> instance;
      *                        must not be null.
-     * <p>
-     * @param  itemNames  <tt>itemNames</tt> must list, in any order, all the
-     * item names defined in <tt>compositeType</tt>;
-     *                    the order in which the names are listed, is used to
-     * match values in <tt>itemValues[]</tt>;
-     *                    must not be null or empty.
-     * <p>
-     * @param  itemValues  the values of the items, listed in the same order as
-     * their respective names in <tt>itemNames</tt>;
-     *                     each item value can be null, but if it is non-null it must be
-     *                     a valid value for the open type defined in <tt>compositeType</tt> for the corresponding item;
-     *                     must be of the same size as <tt>itemNames</tt>; must not be null or empty.
-     * <p>
-     * @throws  IllegalArgumentException  <tt>compositeType</tt> is null, or <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty,
-     *                                    or one of the elements in <tt>itemNames[]</tt>  is a null or empty string,
-     *                                    or <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size.
-     * <p>
-     * @throws  OpenDataException  <tt>itemNames[]</tt> or <tt>itemValues[]</tt>'s size differs from
-     *                             the number of items defined in <tt>compositeType</tt>,
-     *                             or one of the elements in <tt>itemNames[]</tt> does not exist as an item name defined in <tt>compositeType</tt>,
-     *                             or one of the elements in <tt>itemValues[]</tt> is not a valid value for the corresponding item
-     *                             as defined in <tt>compositeType</tt>.
-     * <p>
+     * @param  items  the mappings of all the item names to their values;
+     *                <tt>items</tt> must contain all the item names defined in <tt>compositeType</tt>;
+     *                must not be null.
+     *
+     * @throws IllegalArgumentException <tt>compositeType</tt> is null, or
+     * <tt>items</tt> is null, or one of the keys in <tt>items</tt> is a null
+     * or empty string.
+     * @throws OpenDataException <tt>items</tt>' size differs from the
+     * number of items defined in <tt>compositeType</tt>, or one of the
+     * keys in <tt>items</tt> does not exist as an item name defined in
+     * <tt>compositeType</tt>, or one of the values in <tt>items</tt>
+     * is not a valid value for the corresponding item as defined in
+     * <tt>compositeType</tt>.
+     * @throws ArrayStoreException one or more keys in <tt>items</tt> is not of
+     * the class <tt>java.lang.String</tt>.
+     *
+     * @see #toMap
      */
-    public CompositeDataSupport(CompositeType compositeType, String[] itemNames, Object[] itemValues)
-        throws OpenDataException {
+    public CompositeDataSupport(CompositeType compositeType,
+                                Map<String,?> items)
+            throws OpenDataException {
+        this(makeMap(items), compositeType);
+    }
+
+    private static SortedMap<String, Object> makeMap(Map<String, ?> items) {
+        if (items == null)
+            throw new IllegalArgumentException("Null items map");
+        if (items.containsKey(null) || items.containsKey(""))
+            throw new IllegalArgumentException("Null or empty item name");
+
+        SortedMap<String, Object> map = new TreeMap<String, Object>();
+        for (Object key : items.keySet()) {
+            if (!(key instanceof String)) {
+                throw new ArrayStoreException("Item name is not string: " + key);
+                // This can happen because of erasure.  The particular
+                // exception is a historical artifact - an implementation
+                // detail that leaked into the API.
+            }
+            map.put((String) key, items.get(key));
+        }
+        return map;
+    }
+
+    private CompositeDataSupport(
+            SortedMap<String, Object> items, CompositeType compositeType)
+            throws OpenDataException {
 
         // Check compositeType is not null
         //
@@ -122,126 +206,42 @@
         }
 
         // item names defined in compositeType:
-        Set<String> namesSet = compositeType.keySet();
+        Set<String> namesFromType = compositeType.keySet();
+        Set<String> namesFromItems = items.keySet();
 
-        // Check the array itemNames is not null or empty (length!=0) and
-        // that there is no null element or empty string in it
-        //
-        checkForNullElement(itemNames, "itemNames");
-        checkForEmptyString(itemNames, "itemNames");
-
-        // Check the array itemValues is not null or empty (length!=0)
-        // (NOTE: we allow null values as array elements)
-        //
-        if ( (itemValues == null) || (itemValues.length == 0) ) {
-            throw new IllegalArgumentException("Argument itemValues[] cannot be null or empty.");
+        // This is just a comparison, but we do it this way for a better
+        // exception message.
+        if (!namesFromType.equals(namesFromItems)) {
+            Set<String> extraFromType = new TreeSet<String>(namesFromType);
+            extraFromType.removeAll(namesFromItems);
+            Set<String> extraFromItems = new TreeSet<String>(namesFromItems);
+            extraFromItems.removeAll(namesFromType);
+            if (!extraFromType.isEmpty() || !extraFromItems.isEmpty()) {
+                throw new OpenDataException(
+                        "Item names do not match CompositeType: " +
+                        "names in items but not in CompositeType: " + extraFromItems +
+                        "; names in CompositeType but not in items: " + extraFromType);
+            }
         }
 
-        // Check that the sizes of the 2 arrays itemNames and itemValues are the same
-        //
-        if (itemNames.length != itemValues.length) {
-            throw new IllegalArgumentException("Array arguments itemNames[] and itemValues[] "+
-                                               "should be of same length (got "+ itemNames.length +
-                                               " and "+ itemValues.length +").");
-        }
-
-        // Check the size of the 2 arrays is equal to the number of items defined in compositeType
-        //
-        if (itemNames.length != namesSet.size()) {
-            throw new OpenDataException("The size of array arguments itemNames[] and itemValues[] should be equal to the number of items defined"+
-                                        " in argument compositeType (found "+ itemNames.length +" elements in itemNames[] and itemValues[],"+
-                                        " expecting "+ namesSet.size() +" elements according to compositeType.");
-        }
-
-        // Check parameter itemNames[] contains all names defined in the compositeType of this instance
-        //
-        if ( ! Arrays.asList(itemNames).containsAll(namesSet) ) {
-            throw new OpenDataException("Argument itemNames[] does not contain all names defined in the compositeType of this instance.");
-        }
-
-        // Check each element of itemValues[], if not null, is of the open type defined for the corresponding item
-        //
-        OpenType<?> itemType;
-        for (int i=0; i<itemValues.length; i++) {
-            itemType = compositeType.getType(itemNames[i]);
-            if ( (itemValues[i] != null) && (! itemType.isValue(itemValues[i])) ) {
-                throw new OpenDataException("Argument's element itemValues["+ i +"]=\""+ itemValues[i] +"\" is not a valid value for"+
-                                            " this item (itemName="+ itemNames[i] +",itemType="+ itemType +").");
+        // Check each value, if not null, is of the open type defined for the
+        // corresponding item
+        for (String name : namesFromType) {
+            Object value = items.get(name);
+            if (value != null) {
+                OpenType<?> itemType = compositeType.getType(name);
+                if (!itemType.isValue(value)) {
+                    throw new OpenDataException(
+                            "Argument value of wrong type for item " + name +
+                            ": value " + value + ", type " + itemType);
+                }
             }
         }
 
         // Initialize internal fields: compositeType and contents
         //
         this.compositeType = compositeType;
-        for (int i=0; i<itemNames.length; i++) {
-            this.contents.put(itemNames[i], itemValues[i]);
-        }
-    }
-
-    /**
-     * <p>
-     * Constructs a <tt>CompositeDataSupport</tt> instance with the specified <tt>compositeType</tt>, whose item names and corresponding values
-     * are given by the mappings in the map <tt>items</tt>.
-     * This constructor converts the keys to a string array and the values to an object array and calls
-     * <tt>CompositeDataSupport(javax.management.openmbean.CompositeType, java.lang.String[], java.lang.Object[])</tt>.
-     * <p>
-     * @param  compositeType  the <i>composite type </i> of this <i>composite data</i> instance;
-     *                        must not be null.
-     * <p>
-     * @param  items  the mappings of all the item names to their values;
-     *                <tt>items</tt> must contain all the item names defined in <tt>compositeType</tt>;
-     *                must not be null or empty.
-     * <p>
-     * @throws  IllegalArgumentException  <tt>compositeType</tt> is null, or <tt>items</tt> is null or empty,
-     *                                    or one of the keys in <tt>items</tt>  is a null or empty string,
-     *                                    or one of the values in <tt>items</tt>  is null.
-     * <p>
-     * @throws  OpenDataException  <tt>items</tt>' size differs from the number of items defined in <tt>compositeType</tt>,
-     *                             or one of the keys in <tt>items</tt> does not exist as an item name defined in <tt>compositeType</tt>,
-     *                             or one of the values in <tt>items</tt> is not a valid value for the corresponding item
-     *                             as defined in <tt>compositeType</tt>.
-     * <p>
-     * @throws ArrayStoreException  one or more keys in <tt>items</tt> is not of the class <tt>java.lang.String</tt>.
-     * <p>
-     */
-    public CompositeDataSupport(CompositeType compositeType,
-                                Map<String,?> items)
-            throws OpenDataException {
-
-
-        // Let the other constructor do the job, as the call to another constructor must be the first call
-        //
-        this( compositeType,
-              (items==null  ?  null  :  items.keySet().toArray(new String[items.size()])), // may raise an ArrayStoreException
-              (items==null  ?  null  :  items.values().toArray()) );
-    }
-
-    /**
-     *
-     */
-    private static void checkForNullElement(Object[] arg, String argName) {
-        if ( (arg == null) || (arg.length == 0) ) {
-            throw new IllegalArgumentException(
-                       "Argument "+ argName +"[] cannot be null or empty.");
-        }
-        for (int i=0; i<arg.length; i++) {
-            if (arg[i] == null) {
-                throw new IllegalArgumentException(
-                       "Argument's element "+ argName +"["+ i +"] cannot be null.");
-            }
-        }
-    }
-
-    /**
-     *
-     */
-    private static void checkForEmptyString(String[] arg, String argName) {
-        for (int i=0; i<arg.length; i++) {
-            if (arg[i].trim().equals("")) {
-                throw new IllegalArgumentException(
-                  "Argument's element "+ argName +"["+ i +"] cannot be an empty string.");
-            }
-        }
+        this.contents = items;
     }
 
     /**
@@ -329,6 +329,54 @@
     }
 
     /**
+     * <p>Returns a Map representing the contents of the given CompositeData.
+     * Each item in the CompositeData is represented by an entry in the map,
+     * where the name and value of the item are the key and value of the entry.
+     * The returned value is modifiable but modifications to it have no effect
+     * on the original CompositeData.</p>
+     *
+     * <p>For example, if you have a CompositeData {@code cd1} and you want
+     * to produce another CompositeData {@code cd2} which is the same except
+     * that the value of its {@code id} item has been changed to 253, you
+     * could write:</p>
+     *
+     * <pre>
+     * CompositeData cd1 = ...;
+     * {@code Map<String, Object>} map = CompositeDataSupport.toMap(cd1);
+     * assert(map.get("id") instanceof Integer);
+     * map.put("id", 253);
+     * CompositeData cd2 = {@link #CompositeDataSupport(CompositeType, Map)
+     * new CompositeDataSupport}(cd1.getCompositeType(), map);
+     * </pre>
+     *
+     * <p>Logically, this method would be a method in the {@link CompositeData}
+     * interface, but cannot be for compatibility reasons.</p>
+     *
+     * @param cd the CompositeData to convert to a Map.
+     *
+     * @return a Map that is a copy of the contents of {@code cd}.
+     *
+     * @throws IllegalArgumentException if {@code cd} is null.
+     *
+     * @see #CompositeDataSupport(CompositeType, Map)
+     */
+    public static Map<String, Object> toMap(CompositeData cd) {
+        if (cd == null)
+            throw new IllegalArgumentException("Null argument");
+
+        // If we really wanted, we could check whether cd is a
+        // CompositeDataSupport and return a copy of cd.contents if so,
+        // but I don't think that would be substantially faster.
+        Map<String, Object> map = new LinkedHashMap<String, Object>();
+        CompositeType ct = cd.getCompositeType();
+        for (String key : ct.keySet()) {
+            Object value = cd.get(key);
+            map.put(key, value);
+        }
+        return map;
+    }
+
+    /**
      * Compares the specified <var>obj</var> parameter with this
      * <code>CompositeDataSupport</code> instance for equality.
      * <p>
--- a/src/share/classes/javax/management/openmbean/CompositeType.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/CompositeType.java	Tue Nov 11 09:07:58 2008 +0000
@@ -329,7 +329,7 @@
      * @return true if {@code ot} is assignable to this open type.
      */
     @Override
-    boolean isAssignableFrom(OpenType ot) {
+    boolean isAssignableFrom(OpenType<?> ot) {
         if (!(ot instanceof CompositeType))
             return false;
         CompositeType ct = (CompositeType) ot;
@@ -420,9 +420,7 @@
         if (myHashCode == null) {
             int value = 0;
             value += this.getTypeName().hashCode();
-            String key;
-            for (Iterator k = nameToDescription.keySet().iterator(); k.hasNext();  ) {
-                key = (String) k.next();
+            for (String key : nameToDescription.keySet()) {
                 value += key.hashCode();
                 value += this.nameToType.get(key).hashCode();
             }
@@ -457,10 +455,10 @@
             result.append(getTypeName());
             result.append(",items=(");
             int i=0;
-            Iterator k=nameToType.keySet().iterator();
+            Iterator<String> k=nameToType.keySet().iterator();
             String key;
             while (k.hasNext()) {
-                key = (String) k.next();
+                key = k.next();
                 if (i > 0) result.append(",");
                 result.append("(itemName=");
                 result.append(key);
--- a/src/share/classes/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -78,12 +78,12 @@
     /**
      * @serial The open mbean attribute's min value
      */
-    private final Comparable minValue;
+    private final Comparable<?> minValue;
 
     /**
      * @serial The open mbean attribute's max value
      */
-    private final Comparable maxValue;
+    private final Comparable<?> maxValue;
 
 
     // As this instance is immutable, these two values need only
@@ -450,7 +450,7 @@
     }
 
     static void check(OpenMBeanParameterInfo info) throws OpenDataException {
-        OpenType openType = info.getOpenType();
+        OpenType<?> openType = info.getOpenType();
         if (openType == null)
             throw new IllegalArgumentException("OpenType cannot be null");
 
@@ -562,7 +562,7 @@
 
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({"unchecked", "rawtypes"})
     static int compare(Object x, Object y) {
         return ((Comparable) x).compareTo(y);
     }
@@ -657,11 +657,11 @@
         return result;
     }
 
-    static <T> Comparable comparableValueFrom(Descriptor d, String name,
-                                              OpenType<T> openType) {
+    static <T> Comparable<?> comparableValueFrom(Descriptor d, String name,
+                                                 OpenType<T> openType) {
         T t = valueFrom(d, name, openType);
         if (t == null || t instanceof Comparable<?>)
-            return (Comparable) t;
+            return (Comparable<?>) t;
         final String msg =
             "Descriptor field " + name + " with value " + t +
             " is not Comparable";
@@ -925,7 +925,7 @@
         return isValue(this, obj);
     }
 
-    @SuppressWarnings("unchecked")  // cast to Comparable
+    @SuppressWarnings({"unchecked", "rawtypes"})  // cast to Comparable
     static boolean isValue(OpenMBeanParameterInfo info, Object obj) {
         if (info.hasDefaultValue() && obj == null)
             return true;
--- a/src/share/classes/javax/management/openmbean/OpenMBeanParameterInfoSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/OpenMBeanParameterInfoSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -74,12 +74,12 @@
     /**
      * @serial The open mbean parameter's min value
      */
-    private Comparable minValue        = null;
+    private Comparable<?> minValue        = null;
 
     /**
      * @serial The open mbean parameter's max value
      */
-    private Comparable maxValue        = null;
+    private Comparable<?> maxValue        = null;
 
 
     // As this instance is immutable, these two values need only
--- a/src/share/classes/javax/management/openmbean/OpenType.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/OpenType.java	Tue Nov 11 09:07:58 2008 +0000
@@ -206,7 +206,7 @@
         }
     }
 
-    private static boolean overridesGetClassName(final Class<? extends OpenType> c) {
+    private static boolean overridesGetClassName(final Class<?> c) {
         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
             public Boolean run() {
                 try {
--- a/src/share/classes/javax/management/openmbean/SimpleType.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/SimpleType.java	Tue Nov 11 09:07:58 2008 +0000
@@ -163,7 +163,7 @@
     public static final SimpleType<ObjectName> OBJECTNAME =
         new SimpleType<ObjectName>(ObjectName.class);
 
-    private static final SimpleType[] typeArray = {
+    private static final SimpleType<?>[] typeArray = {
         VOID, BOOLEAN, CHARACTER, BYTE, SHORT, INTEGER, LONG, FLOAT,
         DOUBLE, STRING, BIGDECIMAL, BIGINTEGER, DATE, OBJECTNAME,
     };
@@ -232,10 +232,10 @@
            return (this == obj);
         */
 
-        if (!(obj instanceof SimpleType))
+        if (!(obj instanceof SimpleType<?>))
             return false;
 
-        SimpleType other = (SimpleType) obj;
+        SimpleType<?> other = (SimpleType<?>) obj;
 
         // Test if other's className field is the same as for this instance
         //
@@ -290,11 +290,11 @@
         return myToString;
     }
 
-    private static final Map<SimpleType,SimpleType> canonicalTypes =
-        new HashMap<SimpleType,SimpleType>();
+    private static final Map<SimpleType<?>,SimpleType<?>> canonicalTypes =
+        new HashMap<SimpleType<?>,SimpleType<?>>();
     static {
         for (int i = 0; i < typeArray.length; i++) {
-            final SimpleType type = typeArray[i];
+            final SimpleType<?> type = typeArray[i];
             canonicalTypes.put(type, type);
         }
     }
@@ -310,7 +310,7 @@
      * resolved.
      */
     public Object readResolve() throws ObjectStreamException {
-        final SimpleType canonical = canonicalTypes.get(this);
+        final SimpleType<?> canonical = canonicalTypes.get(this);
         if (canonical == null) {
             // Should not happen
             throw new InvalidObjectException("Invalid SimpleType: " + this);
--- a/src/share/classes/javax/management/openmbean/TabularDataSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/TabularDataSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -30,6 +30,7 @@
 // java import
 //
 import com.sun.jmx.mbeanserver.GetPropertyAction;
+import com.sun.jmx.mbeanserver.Util;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
@@ -611,7 +612,7 @@
     @SuppressWarnings("unchecked")  // historical confusion about the return type
     public Collection<Object> values() {
 
-        return (Collection) dataMap.values() ;
+        return Util.cast(dataMap.values());
     }
 
 
@@ -647,7 +648,7 @@
     @SuppressWarnings("unchecked")  // historical confusion about the return type
     public Set<Map.Entry<Object,Object>> entrySet() {
 
-        return (Set) dataMap.entrySet();
+        return Util.cast(dataMap.entrySet());
     }
 
 
@@ -725,8 +726,7 @@
         if (this.size() != other.size()) {
             return false;
         }
-        for (Iterator iter = this.values().iterator(); iter.hasNext();  ) {
-            CompositeData value = (CompositeData) iter.next();
+        for (CompositeData value : dataMap.values()) {
             if ( ! other.containsValue(value) ) {
                 return false;
             }
@@ -760,9 +760,8 @@
         int result = 0;
 
         result += this.tabularType.hashCode();
-        for (Iterator iter = this.values().iterator(); iter.hasNext();  ) {
-            result += ((CompositeData)iter.next()).hashCode();
-        }
+        for (Object value : values())
+            result += value.hashCode();
 
         return result;
 
--- a/src/share/classes/javax/management/openmbean/TabularType.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/openmbean/TabularType.java	Tue Nov 11 09:07:58 2008 +0000
@@ -237,7 +237,7 @@
     }
 
     @Override
-    boolean isAssignableFrom(OpenType ot) {
+    boolean isAssignableFrom(OpenType<?> ot) {
         if (!(ot instanceof TabularType))
             return false;
         TabularType tt = (TabularType) ot;
@@ -329,9 +329,8 @@
             int value = 0;
             value += this.getTypeName().hashCode();
             value += this.rowType.hashCode();
-            for (Iterator k = indexNames.iterator(); k.hasNext();  ) {
-                value += k.next().hashCode();
-            }
+            for (String index : indexNames)
+                value += index.hashCode();
             myHashCode = Integer.valueOf(value);
         }
 
@@ -364,12 +363,10 @@
                 .append(",rowType=")
                 .append(rowType.toString())
                 .append(",indexNames=(");
-            int i=0;
-            Iterator k = indexNames.iterator();
-            while( k.hasNext() ) {
-                if (i > 0) result.append(",");
-                result.append(k.next().toString());
-                i++;
+            String sep = "";
+            for (String index : indexNames) {
+                result.append(sep).append(index);
+                sep = ",";
             }
             result.append("))");
             myToString = result.toString();
--- a/src/share/classes/javax/management/package.html	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/package.html	Tue Nov 11 09:07:58 2008 +0000
@@ -1,7 +1,7 @@
 <html>
-<head>
-<title>javax.management package</title>
-<!--
+    <head>
+        <title>javax.management package</title>
+        <!--
 Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
@@ -24,37 +24,37 @@
 Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 CA 95054 USA or visit www.sun.com if you need additional information or
 have any questions.
--->
-</head>
-<body bgcolor="white">
-      <p>Provides the core classes for the Java Management Extensions.</p>
+        -->
+    </head>
+    <body bgcolor="white">
+        <p>Provides the core classes for the Java Management Extensions.</p>
 
-      <p>The Java Management Extensions
-	(JMX<sup><font size="-1">TM</font></sup>) API is a standard
-	API for management and monitoring.  Typical uses include:</p>
+        <p>The Java Management Extensions
+            (JMX<sup><font size="-1">TM</font></sup>) API is a standard
+        API for management and monitoring.  Typical uses include:</p>
 
-      <ul>
-	<li>consulting and changing application configuration</li>
+        <ul>
+            <li>consulting and changing application configuration</li>
 
-	<li>accumulating statistics about application behavior and
-	  making them available</li>
+            <li>accumulating statistics about application behavior and
+            making them available</li>
 
-	<li>notifying of state changes and erroneous conditions.</li>
-      </ul>
+            <li>notifying of state changes and erroneous conditions.</li>
+        </ul>
 
-      <p>The JMX API can also be used as part of a solution for
-	managing systems, networks, and so on.</p>
+        <p>The JMX API can also be used as part of a solution for
+        managing systems, networks, and so on.</p>
 
-      <p>The API includes remote access, so a remote management
-	program can interact with a running application for these
-	purposes.</p>
+        <p>The API includes remote access, so a remote management
+            program can interact with a running application for these
+        purposes.</p>
 
-      <h2>MBeans</h2>
+        <h2>MBeans</h2>
 
-      <p>The fundamental notion of the JMX API is the <em>MBean</em>.
-	An MBean is a named <em>managed object</em> representing a
-	resource.  It has a <em>management interface</em> consisting
-	of:</p>
+        <p>The fundamental notion of the JMX API is the <em>MBean</em>.
+            An MBean is a named <em>managed object</em> representing a
+            resource.  It has a <em>management interface</em> consisting
+        of:</p>
 
         <ul>
             <li>named and typed attributes that can be read and/or
@@ -92,40 +92,40 @@
 
         <pre>
     public interface ConfigurationMBean {
-	public int getCacheSize();
-	public void setCacheSize(int size);
-	public long getLastChangedTime();
-	public void save();
+         public int getCacheSize();
+         public void setCacheSize(int size);
+         public long getLastChangedTime();
+         public void save();
     }
-      </pre>
+        </pre>
 
-      <p>The methods <code>getCacheSize</code> and
-	<code>setCacheSize</code> define a read-write attribute of
-	type <code>int</code> called <code>CacheSize</code> (with an
-	initial capital, unlike the JavaBeans convention).</p>
+        <p>The methods <code>getCacheSize</code> and
+            <code>setCacheSize</code> define a read-write attribute of
+            type <code>int</code> called <code>CacheSize</code> (with an
+        initial capital, unlike the JavaBeans convention).</p>
 
-      <p>The method <code>getLastChangedTime</code> defines an
-	attribute of type <code>long</code> called
-	<code>LastChangedTime</code>.  This is a read-only attribute,
-	since there is no method <code>setLastChangedTime</code>.</p>
+        <p>The method <code>getLastChangedTime</code> defines an
+            attribute of type <code>long</code> called
+            <code>LastChangedTime</code>.  This is a read-only attribute,
+        since there is no method <code>setLastChangedTime</code>.</p>
 
-      <p>The method <code>save</code> defines an operation called
-	<code>save</code>.  It is not an attribute, since its name
-	does not begin with <code>get</code>, <code>set</code>, or
-	<code>is</code>.</p>
+        <p>The method <code>save</code> defines an operation called
+            <code>save</code>.  It is not an attribute, since its name
+            does not begin with <code>get</code>, <code>set</code>, or
+        <code>is</code>.</p>
 
-      <p>The exact naming patterns for Standard MBeans are detailed in
-	the <a href="#spec">JMX Specification</a>.</p>
+        <p>The exact naming patterns for Standard MBeans are detailed in
+        the <a href="#spec">JMX Specification</a>.</p>
 
-      <p>There are two ways to make a Java object that is an MBean
-	with this management interface.  One is for the object to be
-	of a class that has exactly the same name as the Java
-	interface but without the <code>MBean</code> suffix.  So in
-	the example the object would be of the class
-	<code>Configuration</code>, in the same Java package as
-	<code>ConfigurationMBean</code>.  The second way is to use the
-	{@link javax.management.StandardMBean StandardMBean}
-	class.</p>
+        <p>There are two ways to make a Java object that is an MBean
+            with this management interface.  One is for the object to be
+            of a class that has exactly the same name as the Java
+            interface but without the <code>MBean</code> suffix.  So in
+            the example the object would be of the class
+            <code>Configuration</code>, in the same Java package as
+            <code>ConfigurationMBean</code>.  The second way is to use the
+            {@link javax.management.StandardMBean StandardMBean}
+        class.</p>
 
 
         <h3 id="stdannot">Defining Standard MBeans with annotations</h3>
@@ -272,37 +272,37 @@
         <pre>
     int cacheSize = mbs.getAttribute(name, "CacheSize");
     {@link javax.management.Attribute Attribute} newCacheSize =
-    	new Attribute("CacheSize", new Integer(2000));
+         new Attribute("CacheSize", new Integer(2000));
     mbs.setAttribute(name, newCacheSize);
     mbs.invoke(name, "save", new Object[0], new Class[0]);
-      </pre>
+        </pre>
 
         <p id="proxy">Alternatively, if you have a Java interface that
             corresponds to the management interface for the MBean, you can use an
         <em>MBean proxy</em> like this:</p>
 
-      <pre>
+        <pre>
     ConfigurationMBean conf =
         {@link javax.management.JMX#newMBeanProxy
             JMX.newMBeanProxy}(mbs, name, ConfigurationMBean.class);
     int cacheSize = conf.getCacheSize();
     conf.setCacheSize(2000);
     conf.save();
-      </pre>
+        </pre>
 
-      <p>Using an MBean proxy is just a convenience.  The second
-	example ends up calling the same <code>MBeanServer</code>
-	operations as the first one.</p>
+        <p>Using an MBean proxy is just a convenience.  The second
+            example ends up calling the same <code>MBeanServer</code>
+        operations as the first one.</p>
 
-      <p>An MBean Server can be queried for MBeans whose names match
-	certain patterns and/or whose attributes meet certain
-	constraints.  Name patterns are constructed using the {@link
-	javax.management.ObjectName ObjectName} class and constraints
-	are constructed using the {@link javax.management.Query Query}
-	class.  The methods {@link
-	javax.management.MBeanServer#queryNames queryNames} and {@link
-	javax.management.MBeanServer#queryMBeans queryMBeans} then
-	perform the query.</p>
+        <p>An MBean Server can be queried for MBeans whose names match
+            certain patterns and/or whose attributes meet certain
+            constraints.  Name patterns are constructed using the {@link
+            javax.management.ObjectName ObjectName} class and constraints
+            are constructed using the {@link javax.management.Query Query}
+            class.  The methods {@link
+            javax.management.MBeanServer#queryNames queryNames} and {@link
+            javax.management.MBeanServer#queryMBeans queryMBeans} then
+        perform the query.</p>
 
 
         <h3>MBean lifecycle and resource injection</h3>
@@ -407,6 +407,92 @@
             So for example an SNMP GET operation might result in a
         <code>getAttribute</code> on the MBean Server.</p>
 
+	<h3 id="interop">Interoperability between versions of the JMX
+	  specification</h3>
+
+	<p>When a client connects to a server using the JMX Remote
+	  API, it is possible that they do not have the same version
+	  of the JMX specification.  The version of the JMX
+	  specification described here is version 2.0.  Previous
+	  versions were 1.0, 1.1, 1.2, and 1.4.  (There was no 1.3.)
+	  The standard JMX Remote API is defined to work with version
+	  1.2 onwards, so in standards-based deployment the only
+	  interoperability questions that arise concern version 1.2
+	  onwards.</p>
+
+	<p>Every version of the JMX specification continues to
+	  implement the features of previous versions.  So when the
+	  client is running an earlier version than the server, there
+	  should not be any interoperability concerns.  The only
+	  exception is the unlikely one where a pre-2.0 client used
+	  the string {@code //} in the domain part of an {@link
+	  javax.management.ObjectName ObjectName}.</p>
+
+	<p>When the client is running a later version than the server,
+	  certain newer features may not be available, as detailed in
+	  the next sections.  The method {@link
+	  javax.management.JMX#getSpecificationVersion
+	  JMX.getSpecificationVersion} can be used to determine the
+	  server version to check if required features are
+	  available.</p>
+
+	<h4 id="interop-1.4">If the remote MBean Server is 1.4</h4>
+
+	<ul>
+
+	  <li><p>You cannot use {@link
+	      javax.management.QueryNotificationFilter
+	      QueryNotificationFilter} in {@link
+	      javax.management.MBeanServerConnection#addNotificationListener
+	      addNotificationListener} since this class did not exist
+	      in 1.4.</p>
+
+	  <li><p>In an attribute in a query, you cannot access values
+	      inside complex types using dot syntax, for example
+	      {@link javax.management.Query#attr Query.attr}{@code
+	      ("HeapMemoryUsage.used")}.</p>
+
+	  <li><p>The packages {@link javax.management.event} and
+	      {@link javax.management.namespace} did not exist in 1.4,
+	      so you cannot remotely create instances of the MBeans
+	      they define.</p>
+
+	  <li><p>Even if the remote MBean Server is 2.0, you cannot in
+	      general suppose that {@link
+	      javax.management.event.EventClient EventClient} or
+	      {@link javax.management.ClientContext ClientContext}
+	      will work there without first checking. If the remote
+	      MBean Server is 1.4 then those checks will return false.
+	      An attempt to use these features without checking will
+	      fail in the same way as for a remote 2.0 that is not
+	      configured to support them.</p>
+	</ul>
+
+	<h4 id="interop-1.2">If the remote MBean Server is 1.2</h4>
+
+	<p><b>In addition to the above</b>,</p>
+
+	<ul>
+
+	  <li><p>You cannot use wildcards in a key property of an
+	      {@link javax.management.ObjectName ObjectName}, for
+	      example {@code domain:type=Foo,name=*}. Wildcards that
+	      match whole properties are still allowed, for example
+	      {@code *:*} or {@code *:type=Foo,*}.</p>
+
+	  <li><p>You cannot use {@link
+	      javax.management.Query#isInstanceOf Query.isInstanceOf}
+	      in a query.</p>
+
+	  <li><p>You cannot use dot syntax such as {@code
+	      HeapMemoryUsage.used} in the {@linkplain
+	      javax.management.monitor.Monitor#setObservedAttribute
+	      observed attribute} of a monitor, as described in the
+	      documentation for the {@link javax.management.monitor}
+	      package.</p>
+
+	</ul>
+
         <p id="spec">
         @see <a href="{@docRoot}/../technotes/guides/jmx/index.html">
         Java SE 6 Platform documentation on JMX technology</a>
--- a/src/share/classes/javax/management/relation/MBeanServerNotificationFilter.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/MBeanServerNotificationFilter.java	Tue Nov 11 09:07:58 2008 +0000
@@ -354,7 +354,7 @@
 
         // Checks the type first
         String ntfType = notif.getType();
-        Vector enabledTypes = getEnabledTypes();
+        Vector<String> enabledTypes = getEnabledTypes();
         if (!(enabledTypes.contains(ntfType))) {
             RELATION_LOGGER.logp(Level.FINER,
                     MBeanServerNotificationFilter.class.getName(),
@@ -464,8 +464,8 @@
         // Serializes this instance in the old serial form
         //
         ObjectOutputStream.PutField fields = out.putFields();
-        fields.put("mySelectObjNameList", (Vector)selectedNames);
-        fields.put("myDeselectObjNameList", (Vector)deselectedNames);
+        fields.put("mySelectObjNameList", selectedNames);
+        fields.put("myDeselectObjNameList", deselectedNames);
         out.writeFields();
       }
       else
--- a/src/share/classes/javax/management/relation/RelationService.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/RelationService.java	Tue Nov 11 09:07:58 2008 +0000
@@ -1111,7 +1111,7 @@
             throw new IllegalArgumentException(excMsg);
         }
 
-        if (!(oldValue instanceof ArrayList))
+        if (!(oldValue instanceof ArrayList<?>))
             oldValue = new ArrayList<ObjectName>(oldValue);
 
         RELATION_LOGGER.entering(RelationService.class.getName(),
@@ -1881,7 +1881,7 @@
                                          "getRole",
                                          params,
                                          signature));
-                if (invokeResult == null || invokeResult instanceof ArrayList)
+                if (invokeResult == null || invokeResult instanceof ArrayList<?>)
                     result = invokeResult;
                 else
                     result = new ArrayList<ObjectName>(invokeResult);
@@ -2786,7 +2786,7 @@
             // Note that it is possible that the MBean has already been removed
             // from the internal map: this is the case when the MBean is
             // unregistered, the role is updated, then we arrive here.
-            HashMap mbeanRefMap = (HashMap)
+            Map<String,List<String>> mbeanRefMap =
                 (myRefedMBeanObjName2RelIdsMap.get(objectName));
 
             if (mbeanRefMap == null) {
@@ -2796,11 +2796,11 @@
                 return true;
             }
 
-            ArrayList roleNames = new ArrayList();
+            List<String> roleNames = null;
             if (!allRolesFlag) {
                 // Now retrieves the roles of current relation where the MBean
                 // was referenced
-                roleNames = (ArrayList)(mbeanRefMap.get(relationId));
+                roleNames = mbeanRefMap.get(relationId);
 
                 // Removes obsolete reference to role
                 int obsRefIdx = roleNames.indexOf(roleName);
@@ -2840,8 +2840,8 @@
     //
     // -exception RelationServiceNotRegisteredException  if the Relation
     //  Service is not registered in the MBean Server.
-    private void updateUnregistrationListener(List newRefList,
-                                              List obsoleteRefList)
+    private void updateUnregistrationListener(List<ObjectName> newRefList,
+                                              List<ObjectName> obsoleteRefList)
         throws RelationServiceNotRegisteredException {
 
         if (newRefList != null && obsoleteRefList != null) {
@@ -2871,24 +2871,14 @@
 
                 // Enables ObjectNames in newRefList
                 if (newRefList != null) {
-                    for (Iterator newRefIter = newRefList.iterator();
-                         newRefIter.hasNext();) {
-
-                        ObjectName newObjName = (ObjectName)
-                            (newRefIter.next());
+                    for (ObjectName newObjName : newRefList)
                         myUnregNtfFilter.enableObjectName(newObjName);
-                    }
                 }
 
                 if (obsoleteRefList != null) {
                     // Disables ObjectNames in obsoleteRefList
-                    for (Iterator obsRefIter = obsoleteRefList.iterator();
-                         obsRefIter.hasNext();) {
-
-                        ObjectName obsObjName = (ObjectName)
-                            (obsRefIter.next());
+                    for (ObjectName obsObjName : obsoleteRefList)
                         myUnregNtfFilter.disableObjectName(obsObjName);
-                    }
                 }
 
 // Under test
@@ -3047,18 +3037,13 @@
         // to see which roles have not been initialized
         // Note: no need to test if list not null before cloning, not allowed
         //       to have an empty relation type.
-        ArrayList roleInfoList = (ArrayList)
-            (((ArrayList)(relType.getRoleInfos())).clone());
+        List<RoleInfo> roleInfoList = new ArrayList<RoleInfo>(relType.getRoleInfos());
 
         if (roleList != null) {
 
-            for (Iterator roleIter = roleList.iterator();
-                 roleIter.hasNext();) {
-
-                Role currRole = (Role)(roleIter.next());
+            for (Role currRole : roleList.asList()) {
                 String currRoleName = currRole.getRoleName();
-                ArrayList currRoleValue = (ArrayList)
-                    (currRole.getRoleValue());
+                List<ObjectName> currRoleValue = currRole.getRoleValue();
                 // Retrieves corresponding role info
                 // Can throw a RoleInfoNotFoundException to be converted into a
                 // RoleNotFoundException
@@ -3137,9 +3122,7 @@
         // Only role list parameter used, as default initialization of roles
         // done automatically in initializeMissingRoles() sets each
         // uninitialized role to an empty value.
-        for (Iterator roleIter = roleList.iterator();
-             roleIter.hasNext();) {
-            Role currRole = (Role)(roleIter.next());
+        for (Role currRole : roleList.asList()) {
             // Creates a dummy empty ArrayList of ObjectNames to be the old
             // role value :)
             List<ObjectName> dummyList = new ArrayList<ObjectName>();
@@ -3191,7 +3174,7 @@
     // -exception IllegalArgumentException  if null parameter
     private Integer checkRoleInt(int chkType,
                                  String roleName,
-                                 List roleValue,
+                                 List<ObjectName> roleValue,
                                  RoleInfo roleInfo,
                                  boolean writeChkFlag)
         throws IllegalArgumentException {
@@ -3266,9 +3249,7 @@
         // registered in the same MBean Server.
         String expClassName = roleInfo.getRefMBeanClassName();
 
-        for (Iterator refMBeanIter = roleValue.iterator();
-             refMBeanIter.hasNext();) {
-            ObjectName currObjName = (ObjectName)(refMBeanIter.next());
+        for (ObjectName currObjName : roleValue) {
 
             // Checks it is registered
             if (currObjName == null) {
@@ -3330,7 +3311,7 @@
                                         ObjectName relationObjName,
                                         String relationId,
                                         String relationTypeName,
-                                        List roleInfoList)
+                                        List<RoleInfo> roleInfoList)
         throws IllegalArgumentException,
                RelationServiceNotRegisteredException,
                InvalidRoleValueException {
@@ -3361,10 +3342,8 @@
         // with an empty list of ObjectNames.
         // A check is performed to verify that the role can be set to an
         // empty value, according to its minimum cardinality
-        for (Iterator roleInfoIter = roleInfoList.iterator();
-             roleInfoIter.hasNext();) {
-
-            RoleInfo currRoleInfo = (RoleInfo)(roleInfoIter.next());
+        for (RoleInfo currRoleInfo : roleInfoList) {
+
             String roleName = currRoleInfo.getName();
 
             // Creates an empty value
@@ -3663,7 +3642,7 @@
     //  not exist in the relation
     private void handleReferenceUnregistration(String relationId,
                                                ObjectName objectName,
-                                               List roleNameList)
+                                               List<String> roleNameList)
         throws IllegalArgumentException,
                RelationServiceNotRegisteredException,
                RelationNotFoundException,
@@ -3694,14 +3673,12 @@
         // Flag to specify if the relation has to be deleted
         boolean deleteRelFlag = false;
 
-        for (Iterator roleNameIter = roleNameList.iterator();
-             roleNameIter.hasNext();) {
+        for (String currRoleName : roleNameList) {
 
             if (deleteRelFlag) {
                 break;
             }
 
-            String currRoleName = (String)(roleNameIter.next());
             // Retrieves number of MBeans currently referenced in role
             // BEWARE! Do not use getRole() as role may be not readable
             //
@@ -3753,10 +3730,7 @@
             //         using setRole(). So the Relation Service will update the
             //         myRefedMBeanObjName2RelIdsMap to refelect the new role
             //         value!
-            for (Iterator roleNameIter = roleNameList.iterator();
-                 roleNameIter.hasNext();) {
-
-                String currRoleName = (String)(roleNameIter.next());
+            for (String currRoleName : roleNameList) {
 
                 if (relObj instanceof RelationSupport) {
                     // Internal relation
--- a/src/share/classes/javax/management/relation/RelationSupport.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/RelationSupport.java	Tue Nov 11 09:07:58 2008 +0000
@@ -108,7 +108,7 @@
     //   via Relation Service setRole() and setRoles() methods
     // - if the relation is internal to the Relation Service, via
     //   setRoleInt() and setRolesInt() methods.
-    private Map<String,Role> myRoleName2ValueMap = new HashMap<String,Role>();
+    private final Map<String,Role> myRoleName2ValueMap = new HashMap<String,Role>();
 
     // Flag to indicate if the object has been added in the Relation Service
     private final AtomicBoolean myInRelServFlg = new AtomicBoolean();
@@ -424,7 +424,7 @@
             }
         }
 
-        ArrayList roleValue = (ArrayList)(role.getRoleValue());
+        List<ObjectName> roleValue = role.getRoleValue();
 
         RELATION_LOGGER.exiting(RelationSupport.class.getName(),
                 "getRoleCardinality");
@@ -855,8 +855,7 @@
                 // Note: no need to test if role value (list) not null before
                 //       cloning, null value not allowed, empty list if
                 //       nothing.
-                result = (ArrayList)
-                    (((ArrayList)(role.getRoleValue())).clone());
+                result = new ArrayList<ObjectName>(role.getRoleValue());
 
             } else {
                 // Role retrieved during multi-role retrieval: returns the
@@ -1492,10 +1491,7 @@
         RoleList roleList = new RoleList();
         RoleUnresolvedList roleUnresList = new RoleUnresolvedList();
 
-        for (Iterator roleIter = list.iterator();
-             roleIter.hasNext();) {
-
-            Role currRole = (Role)(roleIter.next());
+        for (Role currRole : list.asList()) {
 
             Object currResult = null;
             // Can throw:
@@ -1617,12 +1613,10 @@
 
         synchronized(myRoleName2ValueMap) {
 
-            for (Iterator roleIter = list.iterator();
-                 roleIter.hasNext();) {
+            for (Role currRole : list.asList()) {
 
                 // No need to check if role is null, it is not allowed to store
                 // a null role in a RoleList :)
-                Role currRole = (Role)(roleIter.next());
                 String currRoleName = currRole.getRoleName();
 
                 if (myRoleName2ValueMap.containsKey(currRoleName)) {
--- a/src/share/classes/javax/management/relation/Role.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/Role.java	Tue Nov 11 09:07:58 2008 +0000
@@ -228,9 +228,9 @@
     public String toString() {
         StringBuilder result = new StringBuilder();
         result.append("role name: " + name + "; role value: ");
-        for (Iterator objNameIter = objectNameList.iterator();
+        for (Iterator<ObjectName> objNameIter = objectNameList.iterator();
              objNameIter.hasNext();) {
-            ObjectName currObjName = (ObjectName)(objNameIter.next());
+            ObjectName currObjName = objNameIter.next();
             result.append(currObjName.toString());
             if (objNameIter.hasNext()) {
                 result.append(", ");
@@ -325,7 +325,7 @@
         //
         ObjectOutputStream.PutField fields = out.putFields();
         fields.put("myName", name);
-        fields.put("myObjNameList", (ArrayList)objectNameList);
+        fields.put("myObjNameList", objectNameList);
         out.writeFields();
       }
       else
--- a/src/share/classes/javax/management/relation/RoleList.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/RoleList.java	Tue Nov 11 09:07:58 2008 +0000
@@ -25,6 +25,7 @@
 
 package javax.management.relation;
 
+import com.sun.jmx.mbeanserver.Util;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -140,7 +141,7 @@
                 checkTypeSafe(this);
             typeSafe = true;
         }
-        return (List<Role>) (List) this;
+        return Util.cast(this);
     }
 
     //
--- a/src/share/classes/javax/management/relation/RoleResult.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/RoleResult.java	Tue Nov 11 09:07:58 2008 +0000
@@ -172,7 +172,7 @@
 
             roleList = new RoleList();
 
-            for (Iterator roleIter = list.iterator();
+            for (Iterator<?> roleIter = list.iterator();
                  roleIter.hasNext();) {
                 Role currRole = (Role)(roleIter.next());
                 roleList.add((Role)(currRole.clone()));
@@ -195,7 +195,7 @@
 
             unresolvedRoleList = new RoleUnresolvedList();
 
-            for (Iterator roleUnresIter = unresolvedList.iterator();
+            for (Iterator<?> roleUnresIter = unresolvedList.iterator();
                  roleUnresIter.hasNext();) {
                 RoleUnresolved currRoleUnres =
                     (RoleUnresolved)(roleUnresIter.next());
--- a/src/share/classes/javax/management/relation/RoleUnresolved.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/RoleUnresolved.java	Tue Nov 11 09:07:58 2008 +0000
@@ -285,9 +285,9 @@
         result.append("role name: " + roleName);
         if (roleValue != null) {
             result.append("; value: ");
-            for (Iterator objNameIter = roleValue.iterator();
+            for (Iterator<ObjectName> objNameIter = roleValue.iterator();
                  objNameIter.hasNext();) {
-                ObjectName currObjName = (ObjectName)(objNameIter.next());
+                ObjectName currObjName = objNameIter.next();
                 result.append(currObjName.toString());
                 if (objNameIter.hasNext()) {
                     result.append(", ");
@@ -344,7 +344,7 @@
         //
         ObjectOutputStream.PutField fields = out.putFields();
         fields.put("myRoleName", roleName);
-        fields.put("myRoleValue", (ArrayList)roleValue);
+        fields.put("myRoleValue", roleValue);
         fields.put("myPbType", problemType);
         out.writeFields();
       }
--- a/src/share/classes/javax/management/relation/RoleUnresolvedList.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/relation/RoleUnresolvedList.java	Tue Nov 11 09:07:58 2008 +0000
@@ -25,6 +25,7 @@
 
 package javax.management.relation;
 
+import com.sun.jmx.mbeanserver.Util;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -140,7 +141,7 @@
                 checkTypeSafe(this);
             typeSafe = true;
         }
-        return (List<RoleUnresolved>) (List) this;
+        return Util.cast(this);
     }
 
     //
--- a/src/share/classes/javax/management/remote/JMXConnectorFactory.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/remote/JMXConnectorFactory.java	Tue Nov 11 09:07:58 2008 +0000
@@ -322,10 +322,12 @@
                 JMXConnectorProvider.class;
         final String protocol = serviceURL.getProtocol();
         final String providerClassName = "ClientProvider";
+        final JMXServiceURL providerURL = serviceURL;
 
-        JMXConnectorProvider provider =
-            getProvider(serviceURL, envcopy, providerClassName,
-                        targetInterface, loader);
+        JMXConnectorProvider provider = getProvider(providerURL, envcopy,
+                                               providerClassName,
+                                               targetInterface,
+                                               loader);
 
         IOException exception = null;
         if (provider == null) {
@@ -336,7 +338,7 @@
             if (loader != null) {
                 try {
                     JMXConnector connection =
-                        getConnectorAsService(loader, serviceURL, envcopy);
+                        getConnectorAsService(loader, providerURL, envcopy);
                     if (connection != null)
                         return connection;
                 } catch (JMXProviderException e) {
@@ -345,8 +347,7 @@
                     exception = e;
                 }
             }
-            provider =
-                getProvider(protocol, PROTOCOL_PROVIDER_DEFAULT_PACKAGE,
+            provider = getProvider(protocol, PROTOCOL_PROVIDER_DEFAULT_PACKAGE,
                             JMXConnectorFactory.class.getClassLoader(),
                             providerClassName, targetInterface);
         }
@@ -367,7 +368,8 @@
         return provider.newJMXConnector(serviceURL, fixedenv);
     }
 
-    private static String resolvePkgs(Map env) throws JMXProviderException {
+    private static String resolvePkgs(Map<String, ?> env)
+            throws JMXProviderException {
 
         Object pkgsObject = null;
 
@@ -447,9 +449,10 @@
                 getProviderIterator(JMXConnectorProvider.class, loader);
         JMXConnector connection;
         IOException exception = null;
-        while(providers.hasNext()) {
+        while (providers.hasNext()) {
+            JMXConnectorProvider provider = providers.next();
             try {
-                connection = providers.next().newJMXConnector(url, map);
+                connection = provider.newJMXConnector(url, map);
                 return connection;
             } catch (JMXProviderException e) {
                 throw e;
@@ -521,7 +524,7 @@
         return null;
     }
 
-    static ClassLoader resolveClassLoader(Map environment) {
+    static ClassLoader resolveClassLoader(Map<String, ?> environment) {
         ClassLoader loader = null;
 
         if (environment != null) {
@@ -552,4 +555,5 @@
     private static String protocol2package(String protocol) {
         return protocol.replace('+', '.').replace('-', '_');
     }
+
 }
--- a/src/share/classes/javax/management/remote/JMXConnectorServer.java	Tue Nov 11 08:59:43 2008 +0000
+++ b/src/share/classes/javax/management/remote/JMXConnectorServer.java	Tue Nov 11 09:07:58 2008 +0000
@@ -33,6 +33,7 @@
 import java.util.Map;
 
 import java.util.NoSuchElementException;
+import javax.management.ClientContext;
 import javax.management.MBeanInfo;  // for javadoc
 import javax.management.MBeanNotificationInfo;
 import javax.management.MBeanRegistration;
@@ -103,6 +104,56 @@
 
      /**
       * <p>Name of the attribute that specifies whether this connector
+      * server allows clients to communicate a context with each request.
+      * The value associated with this attribute, if any, must be a string
+      * that is equal to {@code "true"} or {@code "false"}, ignoring case.
+      * If it is {@code "true"}, then the connector server will simulate
+      * a namespace {@code jmx.context//}, as described in
+      * {@link ClientContext#newContextForwarder}.  This namespace is needed
+      * for {@link ClientContext#withContext ClientContext.withContext} to
+      * function correctly.</p>
+      *
+      * <p>Not all connector servers will understand this attribute, but the
+      * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer
+      * RMI Connector Server} does.  For a connector server that understands
+      * this attribute, the default value is {@code "true"}.</p>
+      *
+      * @since 1.7
+      */
+     public static final String CONTEXT_FORWARDER =
+         "jmx.remote.context.forwarder";
+
+     /**
+      * <p>Name of the attribute that specifies whether this connector server
+      * localizes the descriptions in the {@link MBeanInfo} object returned by
+      * {@link MBeanServer#getMBeanInfo MBeanServer.getMBeanInfo}, based on the
+      * locale communicated by the client.</p>
+      *
+      * <p>The value associated with this attribute, if any, must be a string
+      * that is equal to {@code "true"} or {@code "false"}, ignoring case.
+      * If it is {@code "true"}, then the connector server will localize
+      * {@code MBeanInfo} descriptions as specified in {@link
+      * ClientContext#newLocalizeMBeanInfoForwarder}.</p>
+      *
+      * <p>Not all connector servers will understand this attribute, but the
+      * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer
+      * RMI Connector Server} does.  For a connector server that understands
+      * this attribute, the default value is {@code "false"}.</p>
+      *
+      * <p>Because localization requires the client to be able to communicate
+      * its locale, it does not make sense to specify this attribute as
+      * {@code "true"} if {@link #CONTEXT_FORWARDER} is not also {@code "true"}.
+      * For a connector server that understands these attributes, specifying
+      * this inconsistent combination will result in an {@link
+      * IllegalArgumentException}.</p>
+      *
+      * @since 1.7
+      */
+     public static final String LOCALIZE_MBEAN_INFO_FORWARDER =
+        "jmx.remote.localize.mbean.info";
+
+     /**
+      * <p>Name of the attribute that specifies whether this connector
       * server simulates the existence of the {@link EventClientDelegate}
       * MBean. The value associated with this attribute, if any, must
       * be a string that is equal to {@code "true"} or {@code "false"},
@@ -155,7 +206,7 @@
      * to, or null if it is not yet attached to an MBean server.
      *
      * @see #setMBeanServerForwarder
-     * @see #getSystemMBeanServer
+     * @see #getSystemMBeanServerForwarder
      */
     public synchronized MBeanServer getMBeanServer() {
         return userMBeanServer;
@@ -176,30 +227,36 @@
      * this method, the first occurrence in the chain of an object that is
      * {@linkplain Object#equals equal} to {@code mbsf} will have been
      * removed.</p>
+     *
      * @param mbsf the forwarder to remove
+     *
      * @throws NoSuchElementException if there is no occurrence of {@code mbsf}
      * in the chain.
-     * @throws IllegalArgumentException if {@code mbsf} is null.
+     * @throws IllegalArgumentException if {@code mbsf} is null or is the
+     * {@linkplain #getSystemMBeanServerForwarder() system forwarder}.
+     *
+     * @since 1.7
      */
     public synchronized void removeMBeanServerForwarder(MBeanServerForwarder mbsf) {
         if (mbsf == null)
             throw new IllegalArgumentException("Invalid null argument: mbsf");
+        if (systemMBeanServerForwarder.equals(mbsf))
+            throw new IllegalArgumentException("Cannot remove system forwarder");
 
-        MBeanServerForwarder prev = null;
-        MBeanServer curr = systemMBeanServer;
-        while (curr instanceof MBeanServerForwarder && !mbsf.equals(curr)) {
-            prev = (MBeanServerForwarder) curr;
+        MBeanServerForwarder prev = systemMBeanServerForwarder;
+        MBeanServer curr;
+        while (true) {
             curr = prev.getMBeanServer();
+            if (mbsf.equals(curr))
+                break;
+            if (curr instanceof MBeanServerForwarder)
+                prev = (MBeanServerForwarder) curr;
+            else
+                throw new NoSuchElementException("MBeanServerForwarder not in chain");
         }
-        if (!(curr instanceof MBeanServerForwarder))
-            throw new NoSuchElementException("MBeanServerForwarder not in chain");
-        MBeanServerForwarder deleted = (MBeanServerForwarder) curr;
-        MBeanServer next = deleted.getMBeanServer();
-        if (prev != null)
-            prev.setMBeanServer(next);
-        if (systemMBeanServer == deleted)
-            systemMBeanServer = next;
-        if (userMBeanServer == deleted)
+        MBeanServer next = mbsf.getMBeanServer();
+        prev.setMBeanServer(next);
+        if (userMBeanServer == mbsf)
             userMBeanServer = next;
     }
 
@@ -209,66 +266,63 @@
      * the systemMBeanServer and userMBeanServer field declarations.
      */
     private void insertUserMBeanServer(MBeanServer mbs) {
-        MBeanServerForwarder lastSystemMBSF = null;
-        for (MBeanServer mbsi = systemMBeanServer;
-             mbsi != userMBeanServer;
-             mbsi = lastSystemMBSF.getMBeanServer()) {
+        MBeanServerForwarder lastSystemMBSF = systemMBeanServerForwarder;
+        while (true) {
+            MBeanServer mbsi = lastSystemMBSF.getMBeanServer();
+            if (mbsi == userMBeanServer)
+                break;
             lastSystemMBSF = (MBeanServerForwarder) mbsi;
         }
         userMBeanServer = mbs;
-        if (lastSystemMBSF == null)
-            systemMBeanServer = mbs;
-        else
-            lastSystemMBSF.setMBeanServer(mbs);
+        lastSystemMBSF.setMBeanServer(mbs);
     }
 
     /**
      * <p>Returns the first item in the chain of system and then user
-     * forwarders.  In the simplest case, a {@code JMXConnectorServer}
-     * is connected directly to an {@code MBeanServer}.  But there can
-     * also be a chain of {@link MBeanServerForwarder}s between the two.
-     * This chain consists of two sub-chains: first the <em>system chain</em>
-     * and then the <em>user chain</em>.  Incoming requests are given to the
-     * first forwarder in the system chain.  Each forwarder can handle
-     * a request itself, or more usually forward it to the next forwarder,
-     * perhaps with some extra behavior such as logging or security
-     * checking before or after the forwarding.  The last forwarder in
-     * the system chain is followed by the first forwarder in the user
-     * chain.</p>
+     * forwarders.  There is a chain of {@link MBeanServerForwarder}s between
+     * a {@code JMXConnectorServer} and its {@code MBeanServer}.  This chain
+     * consists of two sub-chains: first the <em>system chain</em> and then
+     * the <em>user chain</em>.  Incoming requests are given to the first
+     * forwarder in the system chain.  Each forwarder can handle a request
+     * itself, or more usually forward it to the next forwarder, perhaps with
+     * some extra behavior such as logging or security checking before or after
+     * the forwarding.  The last forwarder in the system chain is followed by
+     * the first forwarder in the user chain.</p>
      *
-     * <p>The <em>system chain</em> is usually
-     * defined by a connector server based on the environment Map;
-     * see {@link JMXConnectorServerFactory#newJMXConnectorServer}.  Allowing the
-     * connector server to define its forwarders in this way ensures that
-     * they are in the correct order - some forwarders need to be inserted
-     * before others for correct behavior.  It is possible to modify the
-     * system chain, for example using {@link #setSystemMBeanServerForwarder} or
-     * {@link #removeMBeanServerForwarder}, but in that case the system
-     * chain is no longer guaranteed to be correct.</p>
+     * <p>The object returned by this method is the first forwarder in the
+     * system chain.  For a given {@code JMXConnectorServer}, this method
+     * always returns the same object, which simply forwards every request
+     * to the next object in the chain.</p>
+     *
+     * <p>Not all connector servers support a system chain of forwarders,
+     * although the standard {@linkplain
+     * javax.management.remote.rmi.RMIConnectorServer RMI connector
+     * server} does.  For those that do not, this method will throw {@code
+     * UnsupportedOperationException}.  All
+     * connector servers do support a user chain of forwarders.</p>
+     *
+     * <p>The <em>system chain</em> is usually defined by a
+     * connector server based on the environment Map; see {@link
+     * JMXConnectorServerFactory#newJMXConnectorServer
+     * JMXConnectorServerFactory.newJMXConnectorServer}.  Allowing
+     * the connector server to define its forwarders in this way
+     * ensures that they are in the correct order - some forwarders
+     * need to be inserted before others for correct behavior.  It is
+     * possible to modify the system chain, for example using {@code
+     * connectorServer.getSystemMBeanServerForwarder().setMBeanServer(mbsf)} or
+     * {@link #removeMBeanServerForwarder removeMBeanServerForwarder}, but in
+     * that case the system chain is no longer guaranteed to be correct.</p>
      *
      * <p>The <em>user chain</em> is defined by calling {@link
-     * #setMBeanServerForwarder} to insert forwarders at the head of the user
-     * chain.</p>
-     *
-     * <p>If there are no forwarders in either chain, then both
-     * {@link #getMBeanServer()} and {@code getSystemMBeanServer()} will
-     * return the {@code MBeanServer} for this connector server.  If there
-     * are forwarders in the user chain but not the system chain, then
-     * both methods will return the first forwarder in the user chain.
-     * If there are forwarders in the system chain but not the user chain,
-     * then {@code getSystemMBeanServer()} will return the first forwarder
-     * in the system chain, and {@code getMBeanServer()} will return the
-     * {@code MBeanServer} for this connector server.  Finally, if there
-     * are forwarders in each chain then {@code getSystemMBeanServer()}
-     * will return the first forwarder in the system chain, and {@code
-     * getMBeanServer()} will return the first forwarder in the user chain.</p>
+     * #setMBeanServerForwarder setMBeanServerForwarder} to insert forwarders
+     * at the head of the user chain.</p>
      *
      * <p>This code illustrates how the chains can be traversed:</p>
      *
      * <pre>
      * JMXConnectorServer cs;
      * System.out.println("system chain:");
-     * MBeanServer mbs = cs.getSystemMBeanServer();
+     * MBeanServer mbs = cs.getSystemMBeanServerForwarder();
      * while (true) {
      *     if (mbs == cs.getMBeanServer())
      *         System.out.println("user chain:");
@@ -281,65 +335,40 @@
      * System.out.println("--MBean Server");
      * </pre>
      *
+     * <h4>Note for connector server implementors</h4>
+     *
+     * <p>Existing connector server implementations can be updated to support
+     * a system chain of forwarders as follows:</p>
+     *
+     * <ul>
+     * <li><p>Override the {@link #supportsSystemMBeanServerForwarder()}
+     * method so that it returns true.</p>
+     *
+     * <li><p>Call {@link #installStandardForwarders} from the constructor of
+     * the connector server.</p>
+     *
+     * <li><p>Direct incoming requests to the result of {@link
+     * #getSystemMBeanServerForwarder()} instead of the result of {@link
+     * #getMBeanServer()}.</p>
+     * </ul>
+     *
      * @return the first item in the system chain of forwarders.
      *
-     * @see #setSystemMBeanServerForwarder
+     * @throws UnsupportedOperationException if {@link
+     * #supportsSystemMBeanServerForwarder} returns false.
+     *
+     * @see #supportsSystemMBeanServerForwarder
+     * @see #setMBeanServerForwarder
+     *
+     * @since 1.7
      */
-    public synchronized MBeanServer getSystemMBeanServer() {
-        return systemMBeanServer;
-    }
-
-    /**
-     * <p>Inserts an object that intercepts requests for the MBean server
-     * that arrive through this connector server.  This object will be
-     * supplied as the <code>MBeanServer</code> for any new connection
-     * created by this connector server.  Existing connections are
-     * unaffected.</p>
-     *
-     * <p>This method can be called more than once with different
-     * {@link MBeanServerForwarder} objects.  The result is a chain
-     * of forwarders.  The last forwarder added is the first in the chain.</p>
-     *
-     * <p>This method modifies the system chain of {@link MBeanServerForwarder}s.
-     * Usually user code should change the user chain instead, via
-     * {@link #setMBeanServerForwarder}.</p>
-     *
-     * <p>Not all connector servers support a system chain of forwarders.
-     * Calling this method on a connector server that does not will produce an
-     * {@link UnsupportedOperationException}.</p>
-     *
-     * <p>Suppose {@code mbs} is the result of {@link #getSystemMBeanServer()}
-     * before calling this method.  If {@code mbs} is not null, then
-     * {@code mbsf.setMBeanServer(mbs)} will be called.  If doing so
-     * produces an exception, this method throws the same exception without
-     * any other effect.  If {@code mbs} is null, or if the call to
-     * {@code mbsf.setMBeanServer(mbs)} succeeds, then this method will
-     * return normally and {@code getSystemMBeanServer()} will then return
-     * {@code mbsf}.</p>
-     *
-     * <p>The result of {@link #getMBeanServer()} is unchanged by this method.</p>
-     *
-     * @param mbsf the new <code>MBeanServerForwarder</code>.
-     *
-     * @throws IllegalArgumentException if the call to {@link
-     * MBeanServerForwarder#setMBeanServer mbsf.setMBeanServer} fails
-     * with <code>IllegalArgumentException</code>, or if
-     * <code>mbsf</code> is null.
-     *
-     * @throws UnsupportedOperationException if
-     * {@link #supportsSystemMBeanServerForwarder} returns false.
-     *
-     * @see #getSystemMBeanServer()
-     */
-    public synchronized void setSystemMBeanServerForwarder(
-            MBeanServerForwarder mbsf) {
-        if (mbsf == null)
-            throw new IllegalArgumentException("Invalid null argument: mbsf");
-        mustSupportSystemMBSF();
-
-        if (systemMBeanServer != null)
-            mbsf.setMBeanServer(systemMBeanServer);
-        systemMBeanServer = mbsf;
+    public MBeanServerForwarder getSystemMBeanServerForwarder() {
+        if (!supportsSystemMBeanServerForwarder()) {
+            throw new UnsupportedOperationException(
+                    "System MBeanServerForwarder not supported by this " +
+                    "connector server");
+        }
+        return systemMBeanServerForwarder;
     }
 
     /**
@@ -350,19 +379,13 @@
      *
      * @return true if this connector server supports the system chain of
      * forwarders.
+     *
+     * @since 1.7
      */
     public boolean supportsSystemMBeanServerForwarder() {
         return false;
     }
 
-    private void mustSupportSystemMBSF() {
-        if (!supportsSystemMBeanServerForwarder()) {
-            throw new UnsupportedOperationException(
-                    "System MBeanServerForwarder not supported by this " +
-                    "connector server");
-        }
-    }
-
     /**
      * <p>Install {@link MBeanServerForwarder}s in the system chain
      * based on the attributes in the given {@code Map}.  A connector
@@ -374,34 +397,90 @@
      * <ul>
      *
      * <li>If {@link #EVENT_CLIENT_DELEGATE_FORWARDER} is absent, or is
-     * present with the value {@code "true"}, then a forwarder with the
-     * functionality of {@link EventClientDelegate#newForwarder} is inserted
-     * at the start of the system chain.</li>
+     * present with the value {@code "true"}, then a forwarder
+     * equivalent to {@link EventClientDelegate#newForwarder
+     * EventClientDelegate.newForwarder}{@code (sysMBSF.getMBeanServer(),
+     * sysMBSF)} is inserted at the start of the system chain,
+     * where {@code sysMBSF} is the object returned by {@link
+     * #getSystemMBeanServerForwarder()}. </li>
+     *
+     * <li>If {@link #LOCALIZE_MBEAN_INFO_FORWARDER} is present with the
+     * value {@code "true"}, then a forwarder equivalent to
+     * {@link ClientContext#newLocalizeMBeanInfoForwarder
+     * ClientContext.newLocalizeMBeanInfoForwarder}{@code
+     * (sysMBSF.getMBeanServer())} is inserted at the start of the system
+     * chain.</li>
+     *
+     * <li>If {@link #CONTEXT_FORWARDER} is absent, or is present with
+     * the value {@code "true"}, then a forwarder equivalent to
+     * {@link ClientContext#newContextForwarder
+     * ClientContext.newContextForwarder}{@code (sysMSBF.getMBeanServer(),
+     * sysMBSF)} is inserted at the tart of the system chain.</li>
      *
      * </ul>
      *
-     * <p>For {@code EVENT_CLIENT_DELEGATE_FORWARDER}, if the
-     * attribute is absent from the {@code Map} and a system property
-     * of the same name is defined, then the value of the system
-     * property is used as if it were in the {@code Map}.
+     * <p>For {@code EVENT_CLIENT_DELEGATE_FORWARDER} and {@code
+     * CONTEXT_FORWARDER}, if the attribute is absent from the {@code
+     * Map} and a system property of the same name is defined, then
+     * the value of the system property is used as if it were in the
+     * {@code Map}.
+     *
+     * <p>Since each forwarder is inserted at the start of the chain,
+     * the final order of the forwarders is the <b>reverse</b> of the order
+     * above.  This is important, because the {@code
+     * LOCALIZE_MBEAN_INFO_FORWARDER} can only work if the {@code
+     * CONTEXT_FORWARDER} has already installed the remote client's locale
+     * in the {@linkplain ClientContext#getContext context} of the current
+     * thread.</p>
      *
      * <p>Attributes in {@code env} that are not listed above are ignored
      * by this method.</p>
      *
      * @throws UnsupportedOperationException if {@link
      * #supportsSystemMBeanServerForwarder} is false.
+     *
+     * @throws IllegalArgumentException if the relevant attributes in {@code env} are
+     * inconsistent, for example if {@link #LOCALIZE_MBEAN_INFO_FORWARDER} is
+     * {@code "true"} but {@link #CONTEXT_FORWARDER} is {@code "false"}; or
+     * if one of the attributes has an illegal value.
+     *
+     * @since 1.7
      */
     protected void installStandardForwarders(Map<String, ?> env) {
-        mustSupportSystemMBSF();
+        MBeanServerForwarder sysMBSF = getSystemMBeanServerForwarder();
 
         // Remember that forwarders must be added in reverse order!
 
         boolean ecd = EnvHelp.computeBooleanFromString(
                 env, EVENT_CLIENT_DELEGATE_FORWARDER, false, true);
+        boolean localize = EnvHelp.computeBooleanFromString(
+                env, LOCALIZE_MBEAN_INFO_FORWARDER, false, false);
+        boolean context = EnvHelp.computeBooleanFromString(
+                env, CONTEXT_FORWARDER, false, true);
+
+        if (localize && !context) {
+            throw new IllegalArgumentException(
+                    "Inconsistent environment parameters: " +
+                    LOCALIZE_MBEAN_INFO_FORWARDER + "=\"true\" requires " +
+                    CONTEXT_FORWARDER + "=\"true\"");
+        }
 
         if (ecd) {
-            MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
-            setSystemMBeanServerForwarder(mbsf);
+            MBeanServerForwarder mbsf = EventClientDelegate.newForwarder(
+                    sysMBSF.getMBeanServer(), sysMBSF);
+            sysMBSF.setMBeanServer(mbsf);
+        }
+
+        if (localize) {
+            MBeanServerForwarder mbsf = ClientContext.newLocalizeMBeanInfoForwarder(
+                    sysMBSF.getMBeanServer());
+            sysMBSF.setMBeanServer(mbsf);
+        }
+
+        if (context) {
+            MBeanServerForwarder mbsf = ClientContext.newContextForwarder(
+                    sysMBSF.getMBeanServer(), sysMBSF);
+            sysMBSF.setMBeanServer(mbsf);
         }
     }
 
@@ -473,6 +552,7 @@
      *