methods =
@@ -1401,7 +1436,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
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 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
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 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
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 " +
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java
index 52783fd5a6043b2b8cda001615fc6ddd3af47d63..da4209cd2b316a9aefe2bf0de17e9e95cf6687b2 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java
@@ -115,7 +115,7 @@ public class Introspector {
* Dynamic MBeans, false 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 @@ public class Introspector {
* 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 @@ public class Introspector {
}
// 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 @@ public class Introspector {
* @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 @@ public class Introspector {
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 @@ public class Introspector {
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.
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java
index 777cd1cce65461b641dc5ca217dd3bf5ca0a7b3f..4fc25e912786f5e85b59322f6bae8b98f8302470 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java
@@ -33,6 +33,7 @@ import java.security.AccessController;
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 @@ public final class JmxMBeanServer
* {@link javax.management.MBeanServerFactory#newMBeanServer(java.lang.String)}
* instead.
*
- * 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.
*
* @param domain The default domain name used by this MBeanServer.
@@ -238,7 +239,7 @@ public final class JmxMBeanServer
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 @@ public final class JmxMBeanServer
// 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 @@ public final class JmxMBeanServer
*/
private AttributeList cloneAttributeList(AttributeList list) {
if (list != null) {
+ List 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));
}
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java
index 019793b8d859d0011e692f880f81b81a91037a2e..789fd661aa9927d9dca097e99d682be790643db7 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java
@@ -70,7 +70,7 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
// 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
}
// 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 @@ public class MBeanInstantiator {
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 @@ public class MBeanInstantiator {
throws ReflectionException,
MBeanException {
- Class theClass = findClassWithDefaultLoaderRepository(className);
+ Class> theClass = findClassWithDefaultLoaderRepository(className);
return instantiate(theClass, params, signature, loader);
}
@@ -595,7 +595,7 @@ public class MBeanInstantiator {
// ------------------------------
// ------------------------------
- Class theClass;
+ Class> theClass;
if (loaderName == null) {
theClass = findClass(className, loader);
@@ -617,10 +617,10 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
* 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 @@ public class MBeanInstantiator {
// 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 @@ public class MBeanInstantiator {
private static final Map> 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);
}
}
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java
index 6479f9751e07adfa28f0a956afe3183794c971b8..af5420c38f32201bbd75c4231e661e796a99f9b3 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java
@@ -160,7 +160,7 @@ class MXBeanIntrospector extends MBeanIntrospector {
// 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 @@ class MXBeanIntrospector extends MBeanIntrospector {
}
}
- private static Descriptor typeDescriptor(OpenType openType,
+ private static Descriptor typeDescriptor(OpenType> openType,
Type originalType) {
return new ImmutableDescriptor(
new String[] {"openType",
@@ -380,37 +380,37 @@ class MXBeanIntrospector extends MBeanIntrospector {
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();
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/ObjectInputStreamWithLoader.java b/src/share/classes/com/sun/jmx/mbeanserver/ObjectInputStreamWithLoader.java
index 2c74e5890c0cb60a64db4e1db43fe2b5da88be02..cbdce77a71e57882b3383e6989f6313740e61017 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/ObjectInputStreamWithLoader.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/ObjectInputStreamWithLoader.java
@@ -54,7 +54,8 @@ class ObjectInputStreamWithLoader extends ObjectInputStream {
this.loader = theLoader;
}
- protected Class resolveClass(ObjectStreamClass aClass)
+ @Override
+ protected Class> resolveClass(ObjectStreamClass aClass)
throws IOException, ClassNotFoundException {
if (loader == null) {
return super.resolveClass(aClass);
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/SecureClassLoaderRepository.java b/src/share/classes/com/sun/jmx/mbeanserver/SecureClassLoaderRepository.java
index 0576f80ebed424cb47299848dd5de470d3c6939c..b078bac8f5760682d560f6d0b0da9b12c5fbebbe 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/SecureClassLoaderRepository.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/SecureClassLoaderRepository.java
@@ -47,16 +47,16 @@ final class SecureClassLoaderRepository
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);
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Util.java b/src/share/classes/com/sun/jmx/mbeanserver/Util.java
index 6307adbf8d92442278539c4377a7fe6d3d386c67..5fe4d1542cc8d4ec7055c3503563238cd60d9a01 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/Util.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Util.java
@@ -669,7 +669,7 @@ public class Util {
}
public static Set cloneSet(Set set) {
- if (set instanceof SortedSet) {
+ if (set instanceof SortedSet>) {
@SuppressWarnings("unchecked")
SortedSet sset = (SortedSet) set;
set = new TreeSet(sset.comparator());
@@ -680,7 +680,7 @@ public class Util {
}
public static Set equivalentEmptySet(Set set) {
- if (set instanceof SortedSet) {
+ if (set instanceof SortedSet>) {
@SuppressWarnings("unchecked")
SortedSet sset = (SortedSet) set;
set = new TreeSet(sset.comparator());
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java b/src/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java
index b6662937f935634a45207682c84cd80aeb3a328e..6f8ed6e9474b45e729ced28bb0b1b4d8f6cd63ab 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java
@@ -118,9 +118,9 @@ class WeakIdentityHashMap {
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());
}
diff --git a/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java b/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java
deleted file mode 100644
index 49f875144f2751604094023018b1c2678ba3dd06..0000000000000000000000000000000000000000
--- a/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java
+++ /dev/null
@@ -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.
- *
- * This API is a Sun internal API and is subject to changes without notice.
- *
- * @since 1.7
- */
-public final class JMXNamespaceUtils {
-
- /**
- * A logger for this class.
- **/
- private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
-
-
- private static Map newWeakHashMap() {
- return new WeakHashMap();
- }
-
- /** There are no instances of this class */
- private JMXNamespaceUtils() {
- }
-
- // returns un unmodifiable view of a map.
- public static Map unmodifiableMap(Map 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.
- *
- * 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 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 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 checkNonNull(T parameter, String name) {
- if (parameter == null)
- throw new IllegalArgumentException(name+" must not be null");
- return parameter;
- }
-
-
-}
diff --git a/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java
index 3c7065c478e323ad4f6262e8960424450e17851d..7d668169fc72a90b27d30fe7778463925102b2ea 100644
--- a/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java
+++ b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java
@@ -49,11 +49,6 @@ public class ObjectNameRouter {
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 @@ public class ObjectNameRouter {
b.append(NAMESPACE_SEPARATOR);
return b.toString();
}
-
-
}
diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java
index 443c80f2ae56ad118e4d065d368ff72ac955746e..b09bc84365c48eb9e23af16e6e414ba9008316ee 100644
--- a/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java
@@ -31,7 +31,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.MBeanServerConnection;
-import javax.management.namespace.JMXNamespaces;
/**
@@ -57,22 +56,14 @@ public class RoutingConnectionProxy
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
- /**
- * Creates a new instance of RoutingConnectionProxy
- */
- public RoutingConnectionProxy(MBeanServerConnection source,
- String sourceDir) {
- this(source,sourceDir,"",false);
- }
-
/**
* Creates a new instance of RoutingConnectionProxy
*/
public RoutingConnectionProxy(MBeanServerConnection source,
String sourceDir,
String targetDir,
- boolean forwardsContext) {
- super(source,sourceDir,targetDir,forwardsContext);
+ boolean probe) {
+ super(source, sourceDir, targetDir, probe);
if (LOG.isLoggable(Level.FINER))
LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
@@ -85,15 +76,13 @@ public class RoutingConnectionProxy
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 @@ public class 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);
}
}
diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
index aa35c5bdaed56754d2591ed463b6632dc3a6f533..12d4b4ceb02c1f4a9788dc764e805ce9125b981e 100644
--- a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
@@ -30,6 +30,7 @@ import java.io.IOException;
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 @@ import javax.management.namespace.JMXNamespaces;
// targetNs= // 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 @@ public abstract class RoutingProxy
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 @@ public abstract class RoutingProxy
// 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 @@ public abstract class RoutingProxy
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 @@ public abstract class RoutingProxy
@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 @@ public abstract class RoutingProxy
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 abstract class RoutingProxy
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 @@ public abstract class RoutingProxy
// instance.
static interface RoutingProxyFactory> {
- 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 @@ public abstract class RoutingProxy
static >
R cd(Class routingProxyClass,
RoutingProxyFactory 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 @@ public abstract class RoutingProxy
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);
}
}
diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java
index f58e39816d34d61acf4a83026b81bc3fda1f2296..a11b0eccbf563a072f8ab2204c3dc4a7a0638256 100644
--- a/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java
@@ -54,7 +54,6 @@ import javax.management.OperationsException;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import javax.management.loading.ClassLoaderRepository;
-import javax.management.namespace.JMXNamespaces;
/**
* A RoutingServerProxy is an MBeanServer proxy that proxies a
@@ -76,19 +75,11 @@ public class RoutingServerProxy
extends RoutingProxy
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 @@ public class RoutingServerProxy
FACTORY = new RoutingProxyFactory() {
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);
}
}
diff --git a/src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java b/src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java
index 234f50f22da7252415a5ba8499fe553ebfd3757c..cd4de2aae10b4849b3913001ce6c0572eb906d36 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java
@@ -120,7 +120,7 @@ public class ArrayNotificationBuffer implements NotificationBuffer {
private final Collection sharers = new HashSet(1);
public static NotificationBuffer getNotificationBuffer(
- MBeanServer mbs, Map env) {
+ MBeanServer mbs, Map env) {
if (env == null)
env = Collections.emptyMap();
diff --git a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
index ab6bd60caf8e5b1cd499cfb7cc410ee310b46cd3..cb94371fdc99705570da591ff9072095b33c9633 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
@@ -54,7 +54,7 @@ import com.sun.jmx.remote.util.EnvHelp;
public abstract class ClientNotifForwarder {
- public ClientNotifForwarder(Map env) {
+ public ClientNotifForwarder(Map env) {
this(null, env);
}
@@ -113,7 +113,7 @@ public abstract class ClientNotifForwarder {
private Thread thread;
}
- public ClientNotifForwarder(ClassLoader defaultClassLoader, Map env) {
+ public ClientNotifForwarder(ClassLoader defaultClassLoader, Map env) {
maxNotifications = EnvHelp.getMaxFetchNotifNumber(env);
timeout = EnvHelp.getFetchTimeout(env);
diff --git a/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java b/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java
index 8d57b8f92a6da87361a404fa2c024804d81ed568..b610828065ada9518d2e7205d02cf17bb09145ae 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java
@@ -36,7 +36,7 @@ import org.omg.CORBA.ORB;
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;
diff --git a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java
index c3542cc1d8a676448928f9661525389940f860ad..dab9b872d6420104a500813abfba8243776d418e 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java
@@ -59,7 +59,7 @@ public class ServerNotifForwarder {
public ServerNotifForwarder(MBeanServer mbeanServer,
- Map env,
+ Map env,
NotificationBuffer notifBuffer,
String connectionId) {
this.mbeanServer = mbeanServer;
diff --git a/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java b/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java
index 64c00b0174b0295768dd994fa61771b39dad0dde..614edd464fb29a08298aa71e2e5e5ad7db988ade 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java
@@ -29,6 +29,6 @@ import java.io.IOException;
import java.rmi.MarshalledObject;
public interface Unmarshal {
- public Object get(MarshalledObject mo)
+ public Object get(MarshalledObject> mo)
throws IOException, ClassNotFoundException;
}
diff --git a/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java b/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java
index a901a19c8f82cf5511e0e293ab771d14fe572ab4..33cd6b4ce7c7689c05b47f44825e42ee42cae19c 100644
--- a/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java
+++ b/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java
@@ -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 @@ public class FileLoginModule implements LoginModule {
// Initial state
private Subject subject;
private CallbackHandler callbackHandler;
- private Map sharedState;
- private Map options;
+ private Map sharedState;
+ private Map options;
private String passwordFile;
private String passwordFileDisplayName;
private boolean userSuppliedPasswordFile;
@@ -172,7 +173,7 @@ public class FileLoginModule implements LoginModule {
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 @@ public class FileLoginModule implements LoginModule {
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
diff --git a/src/share/classes/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java b/src/share/classes/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java
index 631ee3e3b7b9b74ba42f6224f3b0f2e5643f12c7..70c72eaf9ef31ff31437096ff0a45a773687b5f3 100644
--- a/src/share/classes/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java
+++ b/src/share/classes/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java
@@ -87,7 +87,7 @@ public final class JMXPluggableAuthenticator implements JMXAuthenticator {
* @exception SecurityException if the authentication mechanism cannot be
* initialized.
*/
- public JMXPluggableAuthenticator(Map env) {
+ public JMXPluggableAuthenticator(Map, ?> env) {
String loginConfigName = null;
String passwordFile = null;
diff --git a/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java b/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java
index 2e90b11bf4ba40966d27c7afb4e76fe1f0d9c052..66c78f2775eda63860b0033692b3051414dac47e 100644
--- a/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java
+++ b/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java
@@ -249,9 +249,8 @@ public class MBeanServerFileAccessController
}
});
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 principals = s.getPrincipals();
+ for (Principal p : principals) {
String grantedAccessLevel;
synchronized (props) {
grantedAccessLevel = props.getProperty(p.getName());
@@ -271,8 +270,8 @@ public class MBeanServerFileAccessController
}
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)) {
diff --git a/src/share/classes/com/sun/jmx/remote/util/ClassLoaderWithRepository.java b/src/share/classes/com/sun/jmx/remote/util/ClassLoaderWithRepository.java
index dfbabeb4184be3734067c9a31df566816b493f46..f59f3265f4e42b49ef9f74ed8c158a984eacc828 100644
--- a/src/share/classes/com/sun/jmx/remote/util/ClassLoaderWithRepository.java
+++ b/src/share/classes/com/sun/jmx/remote/util/ClassLoaderWithRepository.java
@@ -38,7 +38,7 @@ public class ClassLoaderWithRepository extends ClassLoader {
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) {
diff --git a/src/share/classes/com/sun/jmx/remote/util/ClassLogger.java b/src/share/classes/com/sun/jmx/remote/util/ClassLogger.java
index c3a1c451af641479325cfd056f5d8a45c54551ce..2cd6a02e1bae13d8e3daded5ed39a3904c764983 100644
--- a/src/share/classes/com/sun/jmx/remote/util/ClassLogger.java
+++ b/src/share/classes/com/sun/jmx/remote/util/ClassLogger.java
@@ -41,7 +41,7 @@ public class ClassLogger {
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.
diff --git a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java
index 67b9ea59561d6dfb75c5af4e771acf72f43ff091..c86df1c88ee051242b0028d56fba236d8dd143c8 100644
--- a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java
+++ b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java
@@ -117,7 +117,7 @@ public class EnvHelp {
* jmx.remote.default.class.loader.name is specified
* and the ClassLoader MBean is not found in mbs .
*/
- public static ClassLoader resolveServerClassLoader(Map env,
+ public static ClassLoader resolveServerClassLoader(Map env,
MBeanServer mbs)
throws InstanceNotFoundException {
@@ -194,7 +194,7 @@ public class EnvHelp {
* jmx.remote.default.class.loader is specified
* and is not an instance of {@link ClassLoader}.
*/
- public static ClassLoader resolveClientClassLoader(Map env) {
+ public static ClassLoader resolveClientClassLoader(Map env) {
if (env == null)
return Thread.currentThread().getContextClassLoader();
@@ -241,7 +241,7 @@ public class EnvHelp {
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 @@ public class EnvHelp {
* 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 env) {
int defaultQueueSize = 1000; // default value
// keep it for the compability for the fix:
@@ -327,7 +327,7 @@ public class EnvHelp {
* Returns the maximum notification number which a client will
* fetch every time.
*/
- public static int getMaxFetchNotifNumber(Map env) {
+ public static int getMaxFetchNotifNumber(Map env) {
return (int) getIntegerAttribute(env, MAX_FETCH_NOTIFS, 1000, 1,
Integer.MAX_VALUE);
}
@@ -344,7 +344,7 @@ public class EnvHelp {
/**
* Returns the timeout for a client to fetch notifications.
*/
- public static long getFetchTimeout(Map env) {
+ public static long getFetchTimeout(Map env) {
return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
Long.MAX_VALUE);
}
@@ -361,7 +361,7 @@ public class EnvHelp {
"com.sun.jmx.remote.notification.access.controller";
public static NotificationAccessController getNotificationAccessController(
- Map env) {
+ Map env) {
return (env == null) ? null :
(NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
}
@@ -378,7 +378,7 @@ public class EnvHelp {
* an entry for name but it does not meet the
* constraints above.
*/
- public static long getIntegerAttribute(Map env, String name,
+ public static long getIntegerAttribute(Map env, String name,
long defaultValue, long minValue,
long maxValue) {
final Object o;
@@ -421,9 +421,8 @@ public class EnvHelp {
/* 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 @@ public class EnvHelp {
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 @@ public class EnvHelp {
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 keyIterator = map.keySet().iterator();
+ Iterator stringIterator = hiddenStrings.iterator();
+ Iterator 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 @@ public class EnvHelp {
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 @@ public class EnvHelp {
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 @@ public class EnvHelp {
continue keys;
}
if (prefixIterator.hasNext())
- nextPrefix = (String) prefixIterator.next();
+ nextPrefix = prefixIterator.next();
else
nextPrefix = sentinelKey;
}
@@ -640,7 +639,7 @@ public class EnvHelp {
/**
* Returns the server side connection timeout.
*/
- public static long getServerConnectionTimeout(Map env) {
+ public static long getServerConnectionTimeout(Map env) {
return getIntegerAttribute(env, SERVER_CONNECTION_TIMEOUT, 120000L,
0, Long.MAX_VALUE);
}
@@ -656,7 +655,7 @@ public class EnvHelp {
/**
* Returns the client connection check period.
*/
- public static long getConnectionCheckPeriod(Map env) {
+ public static long getConnectionCheckPeriod(Map env) {
return getIntegerAttribute(env, CLIENT_CONNECTION_CHECK_PERIOD, 60000L,
0, Long.MAX_VALUE);
}
@@ -691,7 +690,7 @@ public class EnvHelp {
* to {@code String}.
*/
public static boolean computeBooleanFromString(
- Map env, String prop, boolean systemProperty) {
+ Map env, String prop, boolean systemProperty) {
if (env == null)
throw new IllegalArgumentException("env map cannot be null");
@@ -744,7 +743,8 @@ public class EnvHelp {
* to {@code String}.
*/
public static boolean computeBooleanFromString(
- Map env, String prop, boolean systemProperty, boolean defaultValue) {
+ Map env, String prop,
+ boolean systemProperty, boolean defaultValue) {
if (env == null)
throw new IllegalArgumentException("env map cannot be null");
@@ -774,7 +774,7 @@ public class EnvHelp {
public static Hashtable mapToHashtable(Map map) {
HashMap m = new HashMap(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(m);
}
@@ -783,7 +783,7 @@ public class EnvHelp {
* 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 env) {
return computeBooleanFromString(env, JMXConnector.USE_EVENT_SERVICE, true);
}
@@ -793,7 +793,7 @@ public class EnvHelp {
* 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 env) {
return computeBooleanFromString(env,
JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true);
}
diff --git a/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java
index 6281b68a574b1e2c1a4450c2206493e106f7b631..d02da69c04758221865bc5f83da1f60baeef6dc2 100644
--- a/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java
+++ b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java
@@ -138,8 +138,8 @@ public class EventClientConnection implements InvocationHandler,
Class interfaceClass, Callable 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 @@ public class EventClientConnection implements InvocationHandler,
// 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 @@ public class EventClientConnection implements InvocationHandler,
}
// 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 @@ public class EventClientConnection implements InvocationHandler,
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 @@ public class EventClientConnection implements InvocationHandler,
* 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 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");
diff --git a/src/share/classes/com/sun/jmx/remote/util/OrderClassLoaders.java b/src/share/classes/com/sun/jmx/remote/util/OrderClassLoaders.java
index b54a23b2bb1631ea27b270ebaa8af0765d28e61d..041736310c19226b185e12c9fe3281da37ed0291 100644
--- a/src/share/classes/com/sun/jmx/remote/util/OrderClassLoaders.java
+++ b/src/share/classes/com/sun/jmx/remote/util/OrderClassLoaders.java
@@ -32,7 +32,7 @@ public class OrderClassLoaders extends ClassLoader {
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) {
diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/utils/IdResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/utils/IdResolver.java
index d7565157e4905595b9d5cbde61132f774a8f887f..da5c4960973c1e67d3cc7b4856688ba8661df1ce 100644
--- a/src/share/classes/com/sun/org/apache/xml/internal/security/utils/IdResolver.java
+++ b/src/share/classes/com/sun/org/apache/xml/internal/security/utils/IdResolver.java
@@ -70,10 +70,13 @@ public class IdResolver {
*/
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 @@ public class IdResolver {
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) {
diff --git a/src/share/classes/java/security/cert/CertPathValidatorException.java b/src/share/classes/java/security/cert/CertPathValidatorException.java
index 8a04aeff5f307238938aba619719c95b54226098..c1ca1d2b8de4cfdb2f41bbd8f58fb01e7a2e14c5 100644
--- a/src/share/classes/java/security/cert/CertPathValidatorException.java
+++ b/src/share/classes/java/security/cert/CertPathValidatorException.java
@@ -113,7 +113,7 @@ public class CertPathValidatorException extends GeneralSecurityException {
* permitted, and indicates that the cause is nonexistent or unknown.)
*/
public CertPathValidatorException(Throwable cause) {
- this(null, cause);
+ this((cause == null ? null : cause.toString()), cause);
}
/**
diff --git a/src/share/classes/javax/management/AttributeList.java b/src/share/classes/javax/management/AttributeList.java
index b385c3c0f79c57ede5c66b1e9058f1f3332f7b48..a629d57ccd4fdaa5c7cc34f759dc0016e51eabeb 100644
--- a/src/share/classes/javax/management/AttributeList.java
+++ b/src/share/classes/javax/management/AttributeList.java
@@ -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 @@ package javax.management;
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 AttributeList overrides the
- * corresponding methods in the superclass
- * ArrayList. This is needed in order to insure that the
- * objects contained in the AttributeList are only
- * Attribute objects. This avoids getting an exception
- * when retrieving elements from the AttributeList.
+ * 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}.
+ *
+ * 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 type-safe , 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.
*
* @since 1.5
*/
@@ -58,8 +64,8 @@ import java.util.List;
*/
public class AttributeList extends ArrayList {
- 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,13 +130,63 @@ public class AttributeList extends ArrayList {
// Check for non-Attribute objects
//
- checkTypeSafe(list);
+ adding(list);
// Build the List
//
super.addAll(list);
}
+ /**
+ * 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 {@code
+ * key} and {@code value} in the {@code Map}, the constructed
+ * {@code AttributeList} will contain {@link Attribute#Attribute
+ * Attribute(key , value )}.
+ *
+ * @param map the {@code Map} defining the elements of the new
+ * {@code AttributeList}.
+ */
+ public AttributeList(Map map) {
+ for (Map.Entry entry : map.entrySet())
+ add(new Attribute(entry.getKey(), entry.getValue()));
+ typeSafe = true;
+ }
+
+ /**
+ * 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.
+ *
+ * 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.
+ *
+ * @return the new {@code Map}.
+ *
+ * @throws IllegalArgumentException if this {@code AttributeList} contains
+ * an element that is not an {@code Attribute}.
+ */
+ public Map toMap() {
+ Map map = new LinkedHashMap();
+
+ // 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}.
* Changes to the returned value are reflected by changes
@@ -154,12 +210,10 @@ public class AttributeList extends ArrayList {
*/
@SuppressWarnings("unchecked")
public List asList() {
- if (!typeSafe) {
- if (tainted)
- checkTypeSafe(this);
- typeSafe = true;
- }
- return (List) (List) this;
+ typeSafe = true;
+ if (tainted)
+ adding((Collection>) this); // will throw IllegalArgumentException
+ return (List) (List>) this;
}
/**
@@ -175,7 +229,7 @@ public class AttributeList extends ArrayList {
* 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 Attribute object to be inserted.
@@ -245,8 +299,7 @@ public class AttributeList extends ArrayList {
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 @@ public class AttributeList extends ArrayList {
* been called on this instance.
*/
+ /**
+ * {@inheritDoc}
+ * @throws IllegalArgumentException if this {@code AttributeList} is
+ * type-safe 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
+ * type-safe 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
+ * type-safe 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
+ * type-safe 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
+ * type-safe 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);
- }
- }
-
- /**
- * 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;
+ private void adding(Object x) {
+ if (x == null || x instanceof Attribute)
+ return;
+ if (typeSafe)
+ throw new IllegalArgumentException("Not an Attribute: " + x);
+ else
+ tainted = true;
}
- /**
- * 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);
}
}
diff --git a/src/share/classes/javax/management/ClientContext.java b/src/share/classes/javax/management/ClientContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..bddde7ca64cc63df66e260042b0dcac75b49a0f2
--- /dev/null
+++ b/src/share/classes/javax/management/ClientContext.java
@@ -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;
+
+/**
+ * Methods to communicate a client context to MBeans. A context is
+ * a {@literal Map} 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.
+ *
+ * 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.
+ *
+ * The locale case is sufficiently important that it has a special
+ * shorthand, the {@link #getLocale()} method. This method calls
+ * {@link #getContext()}.get({@link #LOCALE_KEY}) and converts the
+ * resultant String into a Locale object.
+ *
+ * Here is what an MBean with a localized {@code LastProblemDescription}
+ * attribute might look like:
+ *
+ *
+ * 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);
+ * }
+ * ...
+ * }
+ *
+ *
+ * Here is how a client can communicate its locale to the target
+ * MBean:
+ *
+ *
+ * JMXConnector connector = JMXConnectorFactory.connect(url);
+ * MBeanServerConnection connection = connector.getMBeanServerConnection();
+ * MBeanServerConnection localizedConnection =
+ * {@link #withLocale(MBeanServerConnection, Locale)
+ * ClientContext.withLocale}(connection, Locale.getDefault());
+ * String problem = localizedConnection.getAttribute(
+ * objectName, "LastProblemDescription");
+ *
+ *
+ * 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()}.
+ *
+ *
+ * Remote use of contexts
+ *
+ * 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...
+ *
+ *
+ * MBeanServerConnection mbsc = ...;
+ * Locale french = new Locale("fr");
+ * MBeanServerConnection localizedConnection = ClientContext.withLocale(mbsc, french);
+ *
+ *
+ * ...or, equivalently, like this...
+ *
+ *
+ * MBeanServerConnection localizedConnection =
+ * ClientContext.withContext(mbsc, {@link #LOCALE_KEY "jmx.locale"}, "fr");
+ *
+ *
+ * ...then the context associates {@code "jmx.locale"} with {@code "fr"}
+ * and a request such as
+ * {@code localizedConnection.getAttribute("java.lang:type=Runtime", "Name")}
+ * is translated into
+ * {@code mbsc.getAttribute("jmx.context//jmx.locale=fr//java.lang:Runtime", "Name")}.
+ * 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
+ * {@code getAttribute("java.lang:Runtime", "Name")}.
+ *
+ * The details of how contexts are encoded into ObjectNames are explained
+ * in the {@link #encode encode} method.
+ *
+ * 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
+ * simulated 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}.
+ */
+public class ClientContext {
+ /**
+ * 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()}.
+ */
+ public static final String LOCALE_KEY = "jmx.locale";
+
+ private static final Logger LOG =
+ Logger.getLogger("javax.management.context");
+
+ /**
+ * The namespace that implements contexts, {@value}.
+ */
+ 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> contextThreadLocal =
+ new InheritableThreadLocal>() {
+ @Override
+ protected Map initialValue() {
+ return Collections.emptyMap();
+ }
+ };
+
+ /** There are no instances of this class. */
+ private ClientContext() {
+ }
+
+ /**
+ * 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 getContext() {
+ return Collections.unmodifiableMap(contextThreadLocal.get());
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ *
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}.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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:
+ *
+ *
+ * {@code Map} context =
+ * new {@code HashMap}(ClientContext.getContext());
+ * context.put(ClientContext.LOCALE_KEY, "fr");
+ * String lastProblemDescription =
+ * ClientContext.doWithContext(context, new {@code Callable}() {
+ * public String call() {
+ * return (String) mbeanServer.getAttribute(mbean, "LastProblemDescription");
+ * }
+ * });
+ *
+ *
+ * @param 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}
+ * then {@code T} is {@code String}. If the task does not return a value,
+ * use a {@code Callable} 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 doWithContext(Map context, Callable task)
+ throws Exception {
+ if (context == null || task == null)
+ throw new IllegalArgumentException("Null parameter");
+ Map contextCopy = new TreeMap(context);
+ validateContext(contextCopy);
+ Map oldContextMap = contextThreadLocal.get();
+ try {
+ contextThreadLocal.set(contextCopy);
+ return task.call();
+ } finally {
+ contextThreadLocal.set(oldContextMap);
+ }
+ }
+
+ private static void validateContext(Map context) {
+ for (Map.Entry entry : context.entrySet()) {
+ // If the user passes a raw Map rather than a Map,
+ // 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");
+ }
+ }
+
+ /**
+ * 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 above .
+ *
+ * This method is equivalent to {@link #withContext(MBeanServer,
+ * String, String) withContext}(mbs, {@value LOCALE_KEY},
+ * locale.toString()).
+ *
+ * @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);
+ }
+
+ /**
+ * 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 above .
+ *
+ * This method is equivalent to {@link #withContext(MBeanServerConnection,
+ * String, String) withContext}(mbs, {@value LOCALE_KEY},
+ * locale.toString()).
+ *
+ * @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 withLocale(
+ T mbsc, Class mbscClass, Locale locale) {
+ if (locale == null)
+ throw new IllegalArgumentException("Null locale");
+ return withContext(mbsc, mbscClass, LOCALE_KEY, locale.toString());
+ }
+
+ /**
+ * 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 above .
+ *
+ * @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);
+ }
+
+ /**
+ * 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 above .
+ *
+ * @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);
+ }
+
+
+ /**
+ * 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 above .
+ *
+ * For example, suppose the remote system does support contexts, and you
+ * have created a {@code JMXConnector} like this:
+ *
+ *
+ * JMXServiceURL url = ...;
+ * JMXConnector client = JMXConnectorFactory.connect(url);
+ * MBeanServerConnection mbsc = client.getMBeanServerConnection();
+ * mbsc = ClientContext.withDynamicContext(mbsc);
+ *
+ *
+ * Then if you do this...
+ *
+ *
+ * MBeanInfo mbi = ClientContext.doWithContext(
+ * Collections.singletonMap(ClientContext.LOCALE_KEY, "fr"),
+ * new {@code Callable}() {
+ * public MBeanInfo call() {
+ * return mbsc.getMBeanInfo(objectName);
+ * }
+ * });
+ *
+ *
+ * ...then the context with the locale set to "fr" will be in place
+ * when the {@code getMBeanInfo} is executed on the remote MBean Server.
+ *
+ * @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 withContext(
+ T mbsc, Class mbscClass, String key, String value) {
+ return withContext(
+ mbsc, mbscClass, Collections.singletonMap(key, value), true);
+ }
+
+ private static T withContext(
+ T mbsc, Class mbscClass, Map context,
+ boolean probe) {
+ if (mbsc == null || context == null)
+ throw new IllegalArgumentException("Null parameter");
+ if (context.isEmpty())
+ return mbsc;
+ validateContext(context);
+ Map 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);
+ }
+
+ /**
+ * 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"}.
+ *
+ * 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.
+ *
+ * @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 context) {
+ if (context == null)
+ throw new IllegalArgumentException("Null context");
+ if (context.isEmpty())
+ return "";
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry 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();
+ }
+
+ /**
+ * 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.
+ *
+ * This forwarder can be used in a number of ways:
+ *
+ *
+ *
+ * To add context decoding to a local {@code MBeanServer}, you can
+ * write:
+ *
+ * MBeanServer mbs = {@link
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+ * ManagementFactory.getPlatformMBeanServer()}; // for example
+ * mbs = ClientContext.newContextForwarder(mbs, null);
+ *
+ *
+ *
+ * To add context decoding to a {@linkplain
+ * javax.management.remote.JMXConnectorServer connector server}:
+ *
+ * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(...);
+ * MBeanServer nextMBS = cs.getMBeanServer();
+ * MBeanServerForwarder mbsf = ClientContext.newContextForwarder(nextMBS, null);
+ * cs.{@link
+ * javax.management.remote.JMXConnectorServer#setMBeanServerForwarder
+ * setMBeanServerForwarder}(mbsf);
+ *
+ *
+ *
+ * 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}.
+ *
+ *
+ *
+ *
+ * @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;
+ }
+
+ /**
+ * 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)}.
+ *
+ * This forwarder can be used in a number of ways:
+ *
+ *
+ *
+ * To add description localization to a local {@code MBeanServer}, you
+ * can write:
+ *
+ *
+ * MBeanServer mbs = {@link
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+ * ManagementFactory.getPlatformMBeanServer()}; // for example
+ * mbs = ClientContext.newLocalizeMBeanInfoForwarder(mbs);
+ *
+ *
+ *
+ * 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:
+ *
+ *
+ * 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);
+ *
+ *
+ * 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.
+ *
+ *
+ * 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:
+ *
+ *
+ * MBeanServer mbs = ...;
+ * JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://...");
+ * {@code Map} env = new {@code HashMap}();
+ * env.put(JMXConnectorServer.LOCALIZE_MBEAN_INFO_FORWARDER, "true");
+ * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+ * url, env, mbs);
+ *
+ *
+ *
+ *
+ * @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 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 ctx = new TreeMap(getContext());
+ ctx.putAll(stringToMap(encodedContext));
+
+ return doWithContext(ctx, new Callable() {
+ 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 map) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry 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 stringToMap(String encodedContext) {
+ Map map = stringToMapOrNull(encodedContext);
+ if (map == null) {
+ throw new IllegalArgumentException(
+ "Invalid encoded context: " + encodedContext);
+ }
+ return map;
+ }
+
+ private static Map stringToMapOrNull(String encodedContext) {
+ Map map = new LinkedHashMap();
+ 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);
+ }
+ }
+}
diff --git a/src/share/classes/javax/management/DefaultLoaderRepository.java b/src/share/classes/javax/management/DefaultLoaderRepository.java
index 6cf16435ad6df17f1d8885b28ecd4adbbbfea3d1..85028b44c506f300eb6d574bd335a4908483999b 100644
--- a/src/share/classes/javax/management/DefaultLoaderRepository.java
+++ b/src/share/classes/javax/management/DefaultLoaderRepository.java
@@ -62,7 +62,7 @@ public class DefaultLoaderRepository {
*
* @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 @@ public class DefaultLoaderRepository {
*
* @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);
}
diff --git a/src/share/classes/javax/management/Descriptor.java b/src/share/classes/javax/management/Descriptor.java
index 70c17f2eedb51237d67dd5e002b583ea245047d2..b9c98f4068be3ec9203f619af61ebd01aa0dfacf 100644
--- a/src/share/classes/javax/management/Descriptor.java
+++ b/src/share/classes/javax/management/Descriptor.java
@@ -35,8 +35,8 @@ import java.io.Serializable;
// 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 @@ import javax.management.openmbean.OpenType;
*
* Name Type Used in Meaning
*
- * defaultValue Object
+ * defaultValue Object
* MBeanAttributeInfo MBeanParameterInfo
*
* Default value for an attribute or parameter. See
@@ -118,19 +118,22 @@ import javax.management.openmbean.OpenType;
* deprecation, for example {@code "1.3 Replaced by the Capacity
* attribute"}.
*
- *
- * descriptionResource BundleBaseName String Any
+ * descriptionResource
+ * BundleBaseName String Any
*
* 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"}.
+ * {@code "com.example.myapp.MBeanResources"}. See
+ * {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.
*
- *
- * descriptionResourceKey String Any
+ * descriptionResourceKey
+ * String Any
*
* 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.
+ * this can be used to find a localized version of the description.
+ * See {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.
+ *
*
* enabled String
* MBeanAttributeInfo MBeanNotificationInfo MBeanOperationInfo
@@ -144,7 +147,7 @@ import javax.management.openmbean.OpenType;
* might be disabled if it cannot currently be emitted but could be in
* other circumstances.
*
- * immutableInfo String
+ * immutableInfo String
* MBeanInfo
*
* The string {@code "true"} or {@code "false"} according as this
@@ -153,9 +156,11 @@ import javax.management.openmbean.OpenType;
* 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.
+ * will necessarily change. See also the {@code "jmx.mbean.info.changed"}
+ * notification.
*
- * infoTimeout String Long MBeanInfo
+ * infoTimeout String Long MBeanInfo
*
* 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 @@ import javax.management.openmbean.OpenType;
* 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}.
+ * has the {@code immutableInfo} set to {@code true} or it has {@code "jmx.mbean.info.changed"} in
+ * its {@link MBeanNotificationInfo} array.
*
- * interfaceClassName
+ * interfaceClassName
* String MBeanInfo
*
* The Java interface name for a Standard MBean or MXBean, as
@@ -175,19 +182,26 @@ import javax.management.openmbean.OpenType;
* StandardMBean} class will have this field in its MBeanInfo
* Descriptor.
*
- * legalValues
+ * legalValues
* {@literal Set>} MBeanAttributeInfo MBeanParameterInfo
*
* Legal values for an attribute or parameter. See
* {@link javax.management.openmbean}.
*
- * maxValue Object
+ * locale
+ * String Any
+ *
+ * The {@linkplain Locale locale} of the description in this
+ * {@code MBeanInfo}, {@code MBeanAttributeInfo}, etc, as returned
+ * by {@link Locale#toString()}.
+ *
+ * maxValue Object
* MBeanAttributeInfo MBeanParameterInfo
*
* Maximum legal value for an attribute or parameter. See
* {@link javax.management.openmbean}.
*
- * metricType String
+ * metricType String
* MBeanAttributeInfo MBeanOperationInfo
*
* The type of a metric, one of the strings "counter" or "gauge".
@@ -200,13 +214,13 @@ import javax.management.openmbean.OpenType;
* that can increase or decrease. Examples might be the number of
* open connections or a cache hit rate or a temperature reading.
*
- * minValue Object
+ * minValue Object
* MBeanAttributeInfo MBeanParameterInfo
*
* Minimum legal value for an attribute or parameter. See
* {@link javax.management.openmbean}.
*
- * mxbean String
+ * mxbean String
* MBeanInfo
*
* The string {@code "true"} or {@code "false"} according as this
@@ -223,7 +237,7 @@ import javax.management.openmbean.OpenType;
* MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
* one.
*
- * openType {@link OpenType}
+ * openType {@link OpenType}
* MBeanAttributeInfo MBeanOperationInfo MBeanParameterInfo
*
* The Open Type of this element. In the case of {@code
@@ -240,7 +254,7 @@ import javax.management.openmbean.OpenType;
* which case it indicates the Open Type that the {@link
* Notification#getUserData() user data} will have.
*
- * originalType String
+ * originalType String
* MBeanAttributeInfo MBeanOperationInfo MBeanParameterInfo
*
* The original Java type of this element as it appeared in the
@@ -282,11 +296,132 @@ import javax.management.openmbean.OpenType;
*
*
*
- *
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
- *
- * JMX Specification .
+ * Some additional fields are defined by Model MBeans. See the
+ * information for {@code ModelMBeanInfo} ,
+ * {@code ModelMBeanAttributeInfo} ,
+ * {@code ModelMBeanConstructorInfo} ,
+ * {@code ModelMBeanNotificationInfo} , and
+ * {@code ModelMBeanOperationInfo} , as
+ * well as the chapter "Model MBeans" of the JMX
+ * Specification . 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.
+ *
+ * Nothing prevents the use of these fields in MBeans that are not Model
+ * MBeans. The displayName , severity , and visibility fields are of
+ * interest outside Model MBeans, for example. But only Model MBeans have
+ * a predefined behavior for these fields.
+ *
+ *
+ *
+ * Name Type Used in Meaning
+ *
+ * class String ModelMBeanOperationInfo
+ * Class where method is defined (fully qualified).
+ *
+ * currencyTimeLimit Number
+ * ModelMBeanInfo ModelMBeanAttributeInfo ModelMBeanOperationInfo
+ * How long cached value is valid: <0 never, =0 always,
+ * >0 seconds.
+ *
+ * default Object ModelMBeanAttributeInfo
+ * Default value for attribute.
+ *
+ * descriptorType String Any
+ * Type of descriptor, "mbean", "attribute", "constructor", "operation",
+ * or "notification".
+ *
+ * displayName String Any
+ * Human readable name of this item.
+ *
+ * export String ModelMBeanInfo
+ * Name to be used to export/expose this MBean so that it is
+ * findable by other JMX Agents.
+ *
+ * getMethod String ModelMBeanAttributeInfo
+ * Name of operation descriptor for get method.
+ *
+ * lastUpdatedTimeStamp Number
+ * ModelMBeanAttributeInfo ModelMBeanOperationInfo
+ * When value was set.
+ *
+ * log String ModelMBeanInfo ModelMBeanNotificationInfo
+ * t or T: log all notifications, f or F: log no notifications.
+ *
+ * logFile String ModelMBeanInfo ModelMBeanNotificationInfo
+ * Fully qualified filename to log events to.
+ *
+ * messageID String ModelMBeanNotificationInfo
+ * Unique key for message text (to allow translation, analysis).
+ *
+ * messageText String ModelMBeanNotificationInfo
+ * Text of notification.
+ *
+ * name String Any
+ * Name of this item.
+ *
+ * persistFile String ModelMBeanInfo
+ * File name into which the MBean should be persisted.
+ *
+ * persistLocation String ModelMBeanInfo
+ * The fully qualified directory name where the MBean should be
+ * persisted (if appropriate).
+ *
+ * persistPeriod Number
+ * ModelMBeanInfo ModelMBeanAttributeInfo
+ * Frequency of persist cycle in seconds. Used when persistPolicy is
+ * "OnTimer" or "NoMoreOftenThan".
+ *
+ * persistPolicy String
+ * ModelMBeanInfo ModelMBeanAttributeInfo
+ * One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
+ * See the section "MBean Descriptor Fields" in the JMX specification
+ * document.
+ *
+ * presentationString String Any
+ * XML formatted string to allow presentation of data.
+ *
+ * protocolMap Descriptor ModelMBeanAttributeInfo
+ * 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.
+ *
+ * role String
+ * ModelMBeanConstructorInfo ModelMBeanOperationInfo
+ * One of "constructor", "operation", "getter", or "setter".
+ *
+ * setMethod String ModelMBeanAttributeInfo
+ * Name of operation descriptor for set method.
+ *
+ * severity Number
+ * ModelMBeanNotificationInfo
+ * 0-6 where 0: unknown; 1: non-recoverable;
+ * 2: critical, failure; 3: major, severe;
+ * 4: minor, marginal, error; 5: warning;
+ * 6: normal, cleared, informative
+ *
+ * targetObject Object ModelMBeanOperationInfo
+ * Object on which to execute this method.
+ *
+ * targetType String ModelMBeanOperationInfo
+ * type of object reference for targetObject. Can be:
+ * ObjectReference | Handle | EJBHandle | IOR | RMIReference.
+ *
+ * value Object
+ * ModelMBeanAttributeInfo ModelMBeanOperationInfo
+ * Current (cached) value for attribute or operation.
+ *
+ * visibility Number Any
+ * 1-4 where 1: always visible, 4: rarely visible.
+ *
+ *
*
* @since 1.5
*/
@@ -439,7 +574,7 @@ public interface Descriptor extends Serializable, Cloneable
public boolean isValid() throws RuntimeOperationsException;
/**
- * Compares this descriptor to the given object. The objects are equal if
+ * 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
diff --git a/src/share/classes/javax/management/JMRuntimeException.java b/src/share/classes/javax/management/JMRuntimeException.java
index c27ec1a561b0964c69741b36c01bb679aae63699..70998c8a2d829c612c75f3340eb169d1c91f1979 100644
--- a/src/share/classes/javax/management/JMRuntimeException.java
+++ b/src/share/classes/javax/management/JMRuntimeException.java
@@ -70,7 +70,7 @@ public class JMRuntimeException extends RuntimeException {
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
diff --git a/src/share/classes/javax/management/JMX.java b/src/share/classes/javax/management/JMX.java
index 87c7dd227ce806def6b408af6ef3a05bd9024a1d..60b9605b3152f891cb2425537415e544b011462a 100644
--- a/src/share/classes/javax/management/JMX.java
+++ b/src/share/classes/javax/management/JMX.java
@@ -30,6 +30,7 @@ import com.sun.jmx.mbeanserver.MBeanInjector;
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.Method;
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 class JMX {
*/
public static final String DEFAULT_VALUE_FIELD = "defaultValue";
+ /**
+ * The name of the {@code
+ * descriptionResourceBundleBaseName} field.
+ */
+ public static final String DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD =
+ "descriptionResourceBundleBaseName";
+
+ /**
+ * The name of the {@code
+ * descriptionResourceKey} field.
+ */
+ public static final String DESCRIPTION_RESOURCE_KEY_FIELD =
+ "descriptionResourceKey";
+
/**
* The name of the {@code
* immutableInfo} field.
@@ -78,6 +95,12 @@ public class JMX {
*/
public static final String LEGAL_VALUES_FIELD = "legalValues";
+ /**
+ * The name of the {@code locale}
+ * field.
+ */
+ public static final String LOCALE_FIELD = "locale";
+
/**
* The name of the {@code
* maxValue} field.
@@ -120,13 +143,12 @@ public class JMX {
*
Options to apply to an MBean proxy or to an instance of {@link
* StandardMBean}.
*
- * For example, to specify a custom {@link MXBeanMappingFactory}
- * for a {@code StandardMBean}, you might write this:
+ * For example, to specify the "wrapped object visible" option for a
+ * {@code StandardMBean}, you might write this:
*
*
- * 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);
*
*
@@ -463,6 +485,12 @@ public class JMX {
* likewise for the other methods of {@link
* NotificationBroadcaster} and {@link NotificationEmitter}.
*
+ * 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.
+ *
* @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 @@ public class JMX {
*
*
*
- * The object returned by this method is a
- * {@link Proxy} whose {@code InvocationHandler} is an
- * {@link MBeanServerInvocationHandler}.
- *
* This method is equivalent to {@link
* #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
* boolean) newMXBeanProxy(connection, objectName, interfaceClass,
@@ -601,6 +625,17 @@ public class JMX {
* likewise for the other methods of {@link
* NotificationBroadcaster} and {@link NotificationEmitter}.
*
+ * 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.
+ *
* @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 @@ public class JMX {
* arbitrary Java types and Open Types.
*
*
+ * 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...
+ *
+ *
+ * FooMBean proxy =
+ * JMX.newMBeanProxy(connection, objectName, FooMBean.class, opts);
+ *
+ *
+ * ...then you can get the {@code MBeanServerInvocationHandler} like
+ * this...
+ *
+ *
+ * MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
+ * {@link Proxy#getInvocationHandler(Object)
+ * Proxy.getInvocationHandler}(proxy);
+ *
+ *
+ * ...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()}.
+ *
* @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 @@ public class JMX {
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 @@ public class JMX {
((DynamicWrapperMBean) mbean).getWrappedObject() : mbean;
return (MBeanInjector.injectsSendNotification(resource));
}
+
+ /**
+ * 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:
+ *
+ *
+ * String version = JMX.getSpecificationVersion(mbsc, null);
+ * boolean atLeast2dot0 = (version.compareTo("2.0") >= 0);
+ *
+ *
+ * A remote MBean Server might be running an earlier version of the
+ * JMX API, and in that case certain
+ * features might not be available in it.
+ *
+ * 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.
+ *
+ * @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 Interoperability between
+ * versions of the JMX specification
+ * @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);
+ }
+ }
}
diff --git a/src/share/classes/javax/management/MBeanAttributeInfo.java b/src/share/classes/javax/management/MBeanAttributeInfo.java
index 5b41bb4b63c8d63d6da82b87c2bee7855a9216d9..2566c3e48a2db5673e5595c68cef32fcbe2f3b47 100644
--- a/src/share/classes/javax/management/MBeanAttributeInfo.java
+++ b/src/share/classes/javax/management/MBeanAttributeInfo.java
@@ -316,7 +316,7 @@ public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable {
*/
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 @@ public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable {
}
if (setter != null) {
- Class params[] = setter.getParameterTypes();
+ Class> params[] = setter.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException("bad setter arg count");
}
diff --git a/src/share/classes/javax/management/MBeanConstructorInfo.java b/src/share/classes/javax/management/MBeanConstructorInfo.java
index f66502e2f0653f4d5f78db9b71a58ec63c9e44aa..872c723e3af13045059939381fdc238251bba975 100644
--- a/src/share/classes/javax/management/MBeanConstructorInfo.java
+++ b/src/share/classes/javax/management/MBeanConstructorInfo.java
@@ -64,7 +64,7 @@ public class MBeanConstructorInfo extends MBeanFeatureInfo implements Cloneable
* @param constructor The java.lang.reflect.Constructor
* 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 @@ public class MBeanConstructorInfo extends MBeanFeatureInfo implements Cloneable
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);
}
diff --git a/src/share/classes/javax/management/MBeanInfo.java b/src/share/classes/javax/management/MBeanInfo.java
index 9e30d44a51d3ce587e9f6708472bf1ef6751cfcc..49973c66ce67d285182c5c57a48d9620673b9ab2 100644
--- a/src/share/classes/javax/management/MBeanInfo.java
+++ b/src/share/classes/javax/management/MBeanInfo.java
@@ -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.util.WeakHashMap;
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 @@ import static javax.management.ImmutableDescriptor.nonNullDescriptor;
* management operations. Instances of this class are immutable.
* Subclasses may be mutable but this is not recommended.
*
+ * 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 immutableInfo and
+ * infoTimeout fields in the {@code
+ * MBeanInfo} {@link Descriptor}.
+ *
* The contents of the MBeanInfo for a Dynamic MBean
* are determined by its {@link DynamicMBean#getMBeanInfo
* getMBeanInfo()} method. This includes Open MBeans and Model
@@ -62,27 +80,49 @@ import static javax.management.ImmutableDescriptor.nonNullDescriptor;
* constructors in that object;
*
*
{@link #getAttributes()} returns the list of all attributes
- * whose existence is deduced from the presence in the MBean interface
- * of a getName , isName , or
- * setName method that conforms to the conventions
+ * whose existence is deduced as follows:
+ *
+ * if the Standard MBean is defined with an MBean interface,
+ * from getName , isName , or
+ * setName methods that conform to the conventions
* for Standard MBeans;
+ * if the Standard MBean is defined with the {@link MBean @MBean} or
+ * {@link MXBean @MXBean} annotation on a class, from methods with the
+ * {@link ManagedAttribute @ManagedAttribute} annotation;
+ *
*
- * {@link #getOperations()} returns the list of all methods in
+ * {@link #getOperations()} returns the list of all operations whose
+ * existence is deduced as follows:
+ *
+ * if the Standard MBean is defined with an MBean interface, from methods in
* the MBean interface that do not represent attributes;
+ * if the Standard MBean is defined with the {@link MBean @MBean} or
+ * {@link MXBean @MXBean} annotation on a class, from methods with the
+ * {@link ManagedOperation @ManagedOperation} annotation;
+ *
*
- * {@link #getNotifications()} returns an empty array if the MBean
- * does not implement the {@link NotificationBroadcaster} interface,
- * otherwise the result of calling {@link
+ * {@link #getNotifications()} returns:
+ *
+ * if the MBean implements the {@link NotificationBroadcaster} interface,
+ * the result of calling {@link
* NotificationBroadcaster#getNotificationInfo()} on it;
+ * otherwise, if there is a {@link NotificationInfo @NotificationInfo}
+ * or {@link NotificationInfos @NotificationInfos} annotation on the
+ * MBean interface or @MBean or @MXBean
+ * class, the array implied by those annotations;
+ * otherwise an empty array;
+ *
*
* {@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 @DescriptorFields} and
+ * {@link DescriptorKey @DescriptorKey}).
*
*
*
* The description returned by {@link #getDescription()} and the
* descriptions of the contained attributes and operations are determined
- * by the corresponding Description annotations if any;
+ * by the corresponding {@link Description} annotations if any;
* otherwise their contents are not specified.
*
* The remaining details of the MBeanInfo for a
@@ -257,6 +297,7 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
*
Since this class is immutable, the clone method is chiefly of
* interest to subclasses.
*/
+ @Override
public Object clone () {
try {
return super.clone() ;
@@ -441,6 +482,7 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
return (Descriptor) nonNullDescriptor(descriptor).clone();
}
+ @Override
public String toString() {
return
getClass().getName() + "[" +
@@ -472,6 +514,7 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
* @return true if and only if o 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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
* 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 arrayGettersSafeMap =
- new WeakHashMap();
+ private static final Map, Boolean> arrayGettersSafeMap =
+ new WeakHashMap, Boolean>();
/**
* Return true if subclass is known to preserve the
@@ -537,7 +581,7 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
* 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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
throw new StreamCorruptedException("Got unexpected byte.");
}
}
+
+ /**
+ * 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}.
+ *
+ * Here is how the description {@code this.getDescription()} is
+ * localized.
+ *
+ * First, if the {@linkplain #getDescriptor() descriptor}
+ * of this {@code MBeanInfo} contains a field "locale" , 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()}.
+ *
+ *
A {@code className} is determined. If this
+ * {@code MBeanInfo} contains a descriptor with the field
+ * {@code
+ * "interfaceClassName"} , 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 {@code package} , and everything after is the {@code
+ * simpleClassName} . (If there is no period, then the {@code package}
+ * is empty and the {@code simpleClassName} is the same as the {@code
+ * className}.)
+ *
+ * A {@code resourceKey} 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"}.
+ *
+ * A {@code resourceBundleBaseName} 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"}.
+ *
+ *
Then, a {@link java.util.ResourceBundle ResourceBundle} is
+ * determined, using {@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.
+ *
+ * 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"}.
+ *
+ * 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"}.
+ *
+ * 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.
+ *
+ * Example
+ *
+ * Suppose you have an MBean defined by these two Java source files:
+ *
+ *
+ * // 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) {
+ * ...
+ * }
+ * ...
+ * }
+ *
+ *
+ * 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.
+ *
+ * The file {@code com/example/MBeanDescriptions.properties} might
+ * look like this:
+ *
+ *
+ * # 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
+ *
+ *
+ * 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:
+ *
+ *
+ * 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éfaut
+ * ConfigurationMBean.constructor.com.example.Configuration.p1 = Nom du fichier par défaut
+ *
+ *
+ * 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 @Description} annotations. Annotations
+ * provide descriptions by default but are overridden if {@code
+ * localizeDescriptions} is called.
+ *
+ * @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 map = new HashMap();
+ 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[] 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 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.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");
+ }
+ }
}
diff --git a/src/share/classes/javax/management/MBeanOperationInfo.java b/src/share/classes/javax/management/MBeanOperationInfo.java
index e3c26df5265a3cf69b34c08b9720e1c9c117c8cf..006fc345d93da165c9198527c511d7694942c331 100644
--- a/src/share/classes/javax/management/MBeanOperationInfo.java
+++ b/src/share/classes/javax/management/MBeanOperationInfo.java
@@ -308,17 +308,18 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
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];
diff --git a/src/share/classes/javax/management/MBeanServer.java b/src/share/classes/javax/management/MBeanServer.java
index 90d42d2df6c2d2b2799b5a65c67e00685288d3f1..e6d79e5bd949605ca938cf8770c17185e043c4ed 100644
--- a/src/share/classes/javax/management/MBeanServer.java
+++ b/src/share/classes/javax/management/MBeanServer.java
@@ -377,19 +377,19 @@ public interface MBeanServer extends MBeanServerConnection {
* MBean will not be registered.
* @exception RuntimeMBeanException If the postRegister
* (MBeanRegistration interface) method of the MBean throws a
- * RuntimeException, the registerMBean method will
+ * RuntimeException, the registerMBean method will
* throw a RuntimeMBeanException, although the MBean
* registration succeeded. In such a case, the MBean will be actually
- * registered even though the registerMBean method
+ * registered even though the registerMBean method
* threw an exception. Note that RuntimeMBeanException can
* also be thrown by preRegister, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the postRegister
* (MBeanRegistration interface) method of the MBean throws an
- * Error, the registerMBean method will
+ * Error, the registerMBean method will
* throw a RuntimeErrorException, although the MBean
* registration succeeded. In such a case, the MBean will be actually
- * registered even though the registerMBean method
+ * registered even though the registerMBean method
* threw an exception. Note that RuntimeErrorException can
* also be thrown by preRegister, in which case the MBean
* will not be registered.
@@ -411,6 +411,8 @@ public interface MBeanServer extends MBeanServerConnection {
* is sent as described above .
*
* @throws RuntimeOperationsException {@inheritDoc}
+ * @throws RuntimeMBeanException {@inheritDoc}
+ * @throws RuntimeErrorException {@inheritDoc}
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException;
diff --git a/src/share/classes/javax/management/MBeanServerConnection.java b/src/share/classes/javax/management/MBeanServerConnection.java
index 0897684a0b52f4d826b550a03c8793c2de73cf7d..fadebc10730bf724a55f4ab745a15c46b24a4e80 100644
--- a/src/share/classes/javax/management/MBeanServerConnection.java
+++ b/src/share/classes/javax/management/MBeanServerConnection.java
@@ -76,7 +76,9 @@ public interface MBeanServerConnection extends NotificationManager {
* preRegister (MBeanRegistration
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
- * @exception RuntimeMBeanException If the postRegister
+ * @exception RuntimeMBeanException If the MBean's constructor or its
+ * {@code preRegister} or {@code postRegister} method threw
+ * a {@code RuntimeException}. If the postRegister
* (MBeanRegistration interface) method of the MBean throws a
* RuntimeException, the createMBean method will
* throw a RuntimeMBeanException, although the MBean creation
@@ -148,7 +150,9 @@ public interface MBeanServerConnection extends NotificationManager {
* preRegister (MBeanRegistration
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
- * @exception RuntimeMBeanException If the postRegister
+ * @exception RuntimeMBeanException If the MBean's constructor or its
+ * {@code preRegister} or {@code postRegister} method threw
+ * a {@code RuntimeException}. If the postRegister
* (MBeanRegistration interface) method of the MBean throws a
* RuntimeException, the createMBean method will
* throw a RuntimeMBeanException, although the MBean creation
@@ -223,7 +227,9 @@ public interface MBeanServerConnection extends NotificationManager {
* preRegister (MBeanRegistration
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
- * @exception RuntimeMBeanException If the postRegister
+ * @exception RuntimeMBeanException If the MBean's constructor or its
+ * {@code preRegister} or {@code postRegister} method threw
+ * a {@code RuntimeException}. If the postRegister
* (MBeanRegistration interface) method of the MBean throws a
* RuntimeException, the createMBean method will
* throw a RuntimeMBeanException, although the MBean creation
@@ -295,7 +301,9 @@ public interface MBeanServerConnection extends NotificationManager {
* preRegister (MBeanRegistration
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
- * @exception RuntimeMBeanException If the postRegister
+ * @exception RuntimeMBeanException The MBean's constructor or its
+ * {@code preRegister} or {@code postRegister} method threw
+ * a {@code RuntimeException}. If the postRegister
* (MBeanRegistration interface) method of the MBean throws a
* RuntimeException, the createMBean method will
* throw a RuntimeMBeanException, although the MBean creation
@@ -524,8 +532,30 @@ public interface MBeanServerConnection extends NotificationManager {
/**
- * Enables the values of several attributes of a named MBean. The MBean
- * is identified by its object name.
+ * Retrieves the values of several attributes of a named MBean. The MBean
+ * is identified by its object name.
+ *
+ * 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.
+ *
+ * Here is an example of calling this method and checking that it
+ * succeeded in retrieving all the requested attributes:
+ *
+ *
+ * String[] attrNames = ...;
+ * AttributeList list = mbeanServerConnection.getAttributes(objectName, attrNames);
+ * if (list.size() == attrNames.length)
+ * System.out.println("All attributes were retrieved successfully");
+ * else {
+ * {@code List} missing = new {@code ArrayList}({@link java.util.Arrays#asList Arrays.asList}(attrNames));
+ * missing.removeAll(list.toMap().keySet());
+ * System.out.println("Did not retrieve: " + missing);
+ * }
+ *
*
* @param name The object name of the MBean from which the
* attributes are retrieved.
@@ -549,6 +579,7 @@ public interface MBeanServerConnection extends NotificationManager {
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 @@ public interface MBeanServerConnection extends NotificationManager {
ReflectionException, IOException;
-
/**
- * Sets the values of several attributes of a named MBean. The MBean is
- * identified by its object name.
+ * Sets the values of several attributes of a named MBean. The MBean is
+ * identified by its object name.
+ *
+ * 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.)
+ *
+ *
Here is an example of calling this method and checking that it
+ * succeeded in setting all the requested attributes:
+ *
+ *
+ * AttributeList inputAttrs = ...;
+ * AttributeList outputAttrs = mbeanServerConnection.setAttributes(objectName, inputAttrs);
+ * if (inputAttrs.size() == outputAttrs.size())
+ * System.out.println("All attributes were set successfully");
+ * else {
+ * {@code List} missing = new {@code ArrayList}(inputAttrs.toMap().keySet());
+ * missing.removeAll(outputAttrs.toMap().keySet());
+ * System.out.println("Did not set: " + missing);
+ * }
+ *
*
* @param name The object name of the MBean within which the
* attributes are to be set.
@@ -614,7 +671,39 @@ public interface MBeanServerConnection extends NotificationManager {
throws InstanceNotFoundException, ReflectionException, IOException;
/**
- * Invokes an operation on an MBean.
+ * Invokes an operation on an MBean.
+ *
+ * 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:
+ *
+ *
+ * public interface FooMBean {
+ * public int countMatches(String[] patterns, boolean ignoreCase);
+ * }
+ *
+ *
+ * The {@code countMatches} operation can be invoked as follows:
+ *
+ *
+ * String[] myPatterns = ...;
+ * int count = (Integer) mbeanServerConnection.invoke(
+ * objectName,
+ * "countMatches",
+ * new Object[] {myPatterns, true},
+ * new String[] {String[].class.getName(), boolean.class.getName()});
+ *
+ *
+ * Alternatively, it can be invoked through a proxy as follows:
+ *
+ *
+ * String[] myPatterns = ...;
+ * FooMBean fooProxy = JMX.newMBeanProxy(
+ * mbeanServerConnection, objectName, FooMBean.class);
+ * int count = fooProxy.countMatches(myPatterns, true);
+ *
*
* @param name The object name of the MBean on which the method is
* to be invoked.
@@ -622,7 +711,8 @@ public interface MBeanServerConnection extends NotificationManager {
* @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.
*
diff --git a/src/share/classes/javax/management/MBeanServerFactory.java b/src/share/classes/javax/management/MBeanServerFactory.java
index 365f2a7d9b59360ab3af9777c1c0b6d155924fd5..e0225200d8305a49d3eab61ed919d9870c3c7ff3 100644
--- a/src/share/classes/javax/management/MBeanServerFactory.java
+++ b/src/share/classes/javax/management/MBeanServerFactory.java
@@ -747,7 +747,7 @@ public class MBeanServerFactory {
* 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 @@ public class MBeanServerFactory {
* 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 @@ public class MBeanServerFactory {
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 @@ public class MBeanServerFactory {
// 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...
}
diff --git a/src/share/classes/javax/management/MBeanServerInvocationHandler.java b/src/share/classes/javax/management/MBeanServerInvocationHandler.java
index f111e577bf19bb2e09d923b279ff43d5687769b0..20c934f15c6fe7560c43cfda8722cf07fbeeb5cf 100644
--- a/src/share/classes/javax/management/MBeanServerInvocationHandler.java
+++ b/src/share/classes/javax/management/MBeanServerInvocationHandler.java
@@ -253,12 +253,12 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
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 class MBeanServerInvocationHandler implements InvocationHandler {
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 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
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 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
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(p));
return p;
}
@@ -452,7 +458,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
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;
diff --git a/src/share/classes/javax/management/MBeanServerNotification.java b/src/share/classes/javax/management/MBeanServerNotification.java
index 723d2d4c1e679371e78ac9df09d85017cc1c88f0..d19c73a555a84342e33450d9c41a36884adf62a9 100644
--- a/src/share/classes/javax/management/MBeanServerNotification.java
+++ b/src/share/classes/javax/management/MBeanServerNotification.java
@@ -27,15 +27,70 @@ package javax.management;
/**
- * 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.
*
- * 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
* JMImplementation:type=MBeanServerDelegate.
*
+ *
The following code prints a message every time an MBean is registered
+ * or unregistered in the MBean Server {@code mbeanServer}:
+ *
+ *
+ * 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);
+ *
+ *
+ * The following code prints a message every time an MBean is registered
+ * or unregistered in the MBean Server {@code mbeanServer}:
+ *
+ *
+ * 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);
+ *
+ *
* @since 1.5
*/
public class MBeanServerNotification extends Notification {
diff --git a/src/share/classes/javax/management/Notification.java b/src/share/classes/javax/management/Notification.java
index 07fc19b3e364c0ba2c5ed21f74856794456a30c6..de07ec447488f547dfd1519e77897de24deed7db 100644
--- a/src/share/classes/javax/management/Notification.java
+++ b/src/share/classes/javax/management/Notification.java
@@ -54,7 +54,7 @@ import com.sun.jmx.mbeanserver.GetPropertyAction;
* @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
@@ -243,6 +243,26 @@ public class Notification extends EventObject {
this.message = message ;
}
+ /**
+ * 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.
+ *
+ * @return a copy of this object.
+ */
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
/**
* Sets the source.
*
@@ -285,8 +305,10 @@ public class Notification extends EventObject {
/**
* 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,14 +339,25 @@ public class Notification extends EventObject {
/**
* 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.
*
@@ -355,6 +388,7 @@ public class Notification extends EventObject {
*
* @return A String representation of this notification.
*/
+ @Override
public String toString() {
return super.toString()+"[type="+type+"][message="+message+"]";
}
diff --git a/src/share/classes/javax/management/NotificationListener.java b/src/share/classes/javax/management/NotificationListener.java
index eb29f8bd072a7cd5209a5c7a10df5cd17f05d148..1e7b26c10d88f181c9d84a6529ee252a31c77545 100644
--- a/src/share/classes/javax/management/NotificationListener.java
+++ b/src/share/classes/javax/management/NotificationListener.java
@@ -39,11 +39,10 @@ public interface NotificationListener extends java.util.EventListener {
* 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);
}
diff --git a/src/share/classes/javax/management/QueryNotificationFilter.java b/src/share/classes/javax/management/QueryNotificationFilter.java
index 7d1990fa2b9e1d703f57428aad47d37cd91fdb11..5d7e7815b80af5fd83b4136eb38b26753be272f1 100644
--- a/src/share/classes/javax/management/QueryNotificationFilter.java
+++ b/src/share/classes/javax/management/QueryNotificationFilter.java
@@ -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 @@ import java.util.Set;
* on both the client and the server in the remote case, so using this class
* instead is recommended where possible.
*
+ * 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.
+ *
* 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"},
diff --git a/src/share/classes/javax/management/StandardMBean.java b/src/share/classes/javax/management/StandardMBean.java
index a779e8282bbf19fe8aea3133df8ca1afa455fdaf..492b259d189e2759790b4332ff8c95e87c38a71e 100644
--- a/src/share/classes/javax/management/StandardMBean.java
+++ b/src/share/classes/javax/management/StandardMBean.java
@@ -689,7 +689,7 @@ public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration {
getImplementationClass().getName());
}
- MBeanSupport msupport = mbean;
+ MBeanSupport> msupport = mbean;
final MBeanInfo bi = msupport.getMBeanInfo();
final Object impl = msupport.getWrappedObject();
@@ -1391,8 +1391,8 @@ public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration {
* garbage collected just because we know whether its MBeanInfo
* is immutable.
*/
- private static final Map mbeanInfoSafeMap =
- new WeakHashMap();
+ private static final Map, Boolean> mbeanInfoSafeMap =
+ new WeakHashMap, Boolean>();
/**
* Return true if {@code subclass} is known to preserve the immutability
@@ -1438,9 +1438,9 @@ public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration {
private static class MBeanInfoSafeAction
implements PrivilegedAction {
- private final Class subclass;
+ private final Class> subclass;
- MBeanInfoSafeAction(Class subclass) {
+ MBeanInfoSafeAction(Class> subclass) {
this.subclass = subclass;
}
@@ -1454,13 +1454,13 @@ public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration {
// 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 @@ public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration {
//
if (StandardEmitterMBean.class.isAssignableFrom(subclass))
if (overrides(subclass, StandardEmitterMBean.class,
- "getNotificationInfo", (Class[]) null))
+ "getNotificationInfo", (Class>[]) null))
return false;
return true;
}
diff --git a/src/share/classes/javax/management/event/EventClient.java b/src/share/classes/javax/management/event/EventClient.java
index cfce77b08792c49eb6665c5100edd3c0b087c979..a2f6bc617fee8f904eff4c1d2936e80141f54925 100644
--- a/src/share/classes/javax/management/event/EventClient.java
+++ b/src/share/classes/javax/management/event/EventClient.java
@@ -29,7 +29,6 @@ import com.sun.jmx.event.DaemonThreadFactory;
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.NotificationBroadcasterSupport;
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 class EventClient implements EventConsumer, NotificationManager {
public static final String NONFATAL = "jmx.event.service.nonfatal";
/**
- * 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.
+ * 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.
*
* @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;
/**
* Constructs a default {@code EventClient} object.
@@ -173,7 +172,7 @@ public class EventClient implements EventConsumer, NotificationManager {
*/
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 @@ public class EventClient implements EventConsumer, NotificationManager {
* 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 @@ public class EventClient implements EventConsumer, NotificationManager {
}
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 @@ public class EventClient implements EventConsumer, NotificationManager {
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 @@ public class EventClient implements EventConsumer, NotificationManager {
// 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 @@ public class EventClient implements EventConsumer, NotificationManager {
}
/**
- * Returns the set of listeners that have been added through
- * this {@code EventClient} and not subsequently removed.
+ * 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.
*
* @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 @@ public class EventClient implements EventConsumer, NotificationManager {
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 @@ public class EventClient implements EventConsumer, NotificationManager {
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 @@ public class EventClient implements EventConsumer, NotificationManager {
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
leaseRenewerThreadPool = PerThreadGroupPool.make();
}
diff --git a/src/share/classes/javax/management/event/EventClientDelegate.java b/src/share/classes/javax/management/event/EventClientDelegate.java
index 8d144123a8763d9b9647607b2d3bfe6c1fcbcb9a..8eeeeb1f5c12d1a64fe4bf04b9d7b8f00962ac3b 100644
--- a/src/share/classes/javax/management/event/EventClientDelegate.java
+++ b/src/share/classes/javax/management/event/EventClientDelegate.java
@@ -104,8 +104,8 @@ public class EventClientDelegate implements EventClientDelegateMBean {
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 wrf = delegateMap.get(server);
+ delegate = (wrf == null) ? null : wrf.get();
if (delegate == null) {
delegate = new EventClientDelegate(server);
@@ -149,6 +149,7 @@ public class EventClientDelegate implements EventClientDelegateMBean {
// 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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
AccessController.doPrivileged(
new PrivilegedAction() {
public EventClientDelegate run() {
- return getEventClientDelegate(Forwarder.this);
+ return getEventClientDelegate(loopMBS);
}
});
DynamicMBean mbean = new StandardMBean(
@@ -208,11 +213,46 @@ public class EventClientDelegate implements EventClientDelegateMBean {
* that are targeted for that MBean and handles them itself. All other
* requests are forwarded to the next element in the forwarder chain.
*
+ * @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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
// private classes
// ------------------------------------
private class ClientInfo {
- String clientId;
- EventBuffer buffer;
- NotificationListener clientListener;
- Map listenerInfoMap =
+ final String clientId;
+ final NotificationListener clientListener;
+ final Map listenerInfoMap =
new HashMap();
ClientInfo(String clientId, EventForwarder forwarder) {
@@ -703,7 +742,8 @@ public class EventClientDelegate implements EventClientDelegateMBean {
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;
diff --git a/src/share/classes/javax/management/event/EventClientDelegateMBean.java b/src/share/classes/javax/management/event/EventClientDelegateMBean.java
index a9718a931dca6ae6e98bfa7a007515a720cf3eff..e6030b613a96d24bb3e2de3dbecced5728f056dc 100644
--- a/src/share/classes/javax/management/event/EventClientDelegateMBean.java
+++ b/src/share/classes/javax/management/event/EventClientDelegateMBean.java
@@ -51,7 +51,8 @@ import javax.management.remote.NotificationResult;
* 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}.
*
* 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 @@ import javax.management.remote.NotificationResult;
*
*
* 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
*
*
diff --git a/src/share/classes/javax/management/event/EventRelay.java b/src/share/classes/javax/management/event/EventRelay.java
index d723bb04c4e535864a595a311c46aa5c00f8795b..d106a1605513cbf91146f9a6724b0f99ca50fd4a 100644
--- a/src/share/classes/javax/management/event/EventRelay.java
+++ b/src/share/classes/javax/management/event/EventRelay.java
@@ -27,7 +27,6 @@ package javax.management.event;
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
diff --git a/src/share/classes/javax/management/event/EventSubscriber.java b/src/share/classes/javax/management/event/EventSubscriber.java
index 9948810bfeb52e03fcb40b8c06005014c19d7b53..5a472b5adb5fd0d10cfd5b66596ced4ff1377dcd 100644
--- a/src/share/classes/javax/management/event/EventSubscriber.java
+++ b/src/share/classes/javax/management/event/EventSubscriber.java
@@ -350,8 +350,7 @@ public class EventSubscriber implements EventConsumer {
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) {
diff --git a/src/share/classes/javax/management/event/package-info.java b/src/share/classes/javax/management/event/package-info.java
index c4c7dbed63dd1ae7e9cb302ebd4d96771bc1ad2f..728b095139e339b61358197e6a961a6de0b42c49 100644
--- a/src/share/classes/javax/management/event/package-info.java
+++ b/src/share/classes/javax/management/event/package-info.java
@@ -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.
*
diff --git a/src/share/classes/javax/management/loading/DefaultLoaderRepository.java b/src/share/classes/javax/management/loading/DefaultLoaderRepository.java
index 0d514dd780a80e9b12fa91e0579a218127b8514d..5c2717c256d5db11cc8603c40390347891539551 100644
--- a/src/share/classes/javax/management/loading/DefaultLoaderRepository.java
+++ b/src/share/classes/javax/management/loading/DefaultLoaderRepository.java
@@ -69,7 +69,7 @@ public class DefaultLoaderRepository {
* @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 @@ public class DefaultLoaderRepository {
* @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 @@ public class DefaultLoaderRepository {
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 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);
diff --git a/src/share/classes/javax/management/loading/MLet.java b/src/share/classes/javax/management/loading/MLet.java
index d6540591e9843c244480dd0565d359f5248593ea..c006dc09b1130a159db991d6335adc542dbcb580 100644
--- a/src/share/classes/javax/management/loading/MLet.java
+++ b/src/share/classes/javax/management/loading/MLet.java
@@ -1291,7 +1291,7 @@ public class MLet extends java.net.URLClassLoader
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));
diff --git a/src/share/classes/javax/management/loading/MLetObjectInputStream.java b/src/share/classes/javax/management/loading/MLetObjectInputStream.java
index 8f9ea4cc69a6fbfe0a86cb215dd8e58b188bc255..06262dc5aed15447a8f38693fd34019844e32fee 100644
--- a/src/share/classes/javax/management/loading/MLetObjectInputStream.java
+++ b/src/share/classes/javax/management/loading/MLetObjectInputStream.java
@@ -55,30 +55,30 @@ class MLetObjectInputStream extends ObjectInputStream {
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 @@ class MLetObjectInputStream extends ObjectInputStream {
/**
* 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 {
diff --git a/src/share/classes/javax/management/modelmbean/DescriptorSupport.java b/src/share/classes/javax/management/modelmbean/DescriptorSupport.java
index 66b8fec8b9abce9ae840a88756a4394bdedcb1ad..ee8e3030e54f2eff29ca0e2a0ca6af5f6e285442 100644
--- a/src/share/classes/javax/management/modelmbean/DescriptorSupport.java
+++ b/src/share/classes/javax/management/modelmbean/DescriptorSupport.java
@@ -589,7 +589,7 @@ public class DescriptorSupport
int numberOfEntries = descriptorMap.size();
String[] responseFields = new String[numberOfEntries];
- Set returnedSet = descriptorMap.entrySet();
+ Set> returnedSet = descriptorMap.entrySet();
int i = 0;
@@ -598,8 +598,9 @@ public class DescriptorSupport
DescriptorSupport.class.getName(),
"getFields()", "Returning " + numberOfEntries + " fields");
}
- for (Iterator iter = returnedSet.iterator(); iter.hasNext(); i++) {
- Map.Entry currElement = (Map.Entry) iter.next();
+ for (Iterator> iter = returnedSet.iterator();
+ iter.hasNext(); i++) {
+ Map.Entry currElement = iter.next();
if (currElement == null) {
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
@@ -642,7 +643,7 @@ public class DescriptorSupport
int numberOfEntries = descriptorMap.size();
String[] responseFields = new String[numberOfEntries];
- Set returnedSet = descriptorMap.entrySet();
+ Set> returnedSet = descriptorMap.entrySet();
int i = 0;
@@ -653,8 +654,9 @@ public class DescriptorSupport
"Returning " + numberOfEntries + " fields");
}
- for (Iterator iter = returnedSet.iterator(); iter.hasNext(); i++) {
- Map.Entry currElement = (Map.Entry) iter.next();
+ for (Iterator> iter = returnedSet.iterator();
+ iter.hasNext(); i++) {
+ Map.Entry currElement = iter.next();
if (( currElement == null ) || (currElement.getKey() == null)) {
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
@@ -700,9 +702,8 @@ public class DescriptorSupport
}
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 @@ public class DescriptorSupport
* not a String with value "t", "f", "true", "false". These String
* values must not be case sensitive.
* 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 <= 4
* severity fieldName, if defined, is null, or not a Numeric
- * String or not a Numeric Value >= 0 and <= 6
+ * String or not a Numeric Value >= 0 and <= 6
* persistPolicy fieldName, if defined, is null, or not one of
* the following strings:
* "OnUpdate", "OnTimer", "NoMoreOftenThan", "OnUnregister", "Always",
@@ -904,7 +905,7 @@ public class DescriptorSupport
}
// verify that the descriptor is valid, by iterating over each field...
- Set returnedSet = descriptorMap.entrySet();
+ Set> returnedSet = descriptorMap.entrySet();
if (returnedSet == null) { // null descriptor, not valid
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
@@ -925,9 +926,7 @@ public class DescriptorSupport
// 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 currElement : returnedSet) {
if (currElement != null) {
if (currElement.getValue() != null) {
// validate the field valued...
@@ -1083,10 +1082,9 @@ public class DescriptorSupport
*/
public synchronized String toXMLString() {
final StringBuilder buf = new StringBuilder("");
- 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> returnedSet = descriptorMap.entrySet();
+ for (Map.Entry 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 @@ public class DescriptorSupport
}
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 + ">");
diff --git a/src/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java b/src/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java
index cc2ec0b7a415bae9dcb7a77f9fb230f9a4b14656..9ee9a6b46352b2c3365748b81303357aaca1d037 100644
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java
@@ -39,7 +39,6 @@ import java.io.ObjectOutputStream;
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.MBeanAttributeInfo;
import javax.management.RuntimeOperationsException;
/**
- * The ModelMBeanAttributeInfo object describes an attribute of the ModelMBean.
+ * 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.
- *
- * The fields in the descriptor are defined, but not limited to, the following:
- *
- * 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, <0 never, =0 always, >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
- *
- * 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.
+ *
+ *
+ * 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.
+ *
+ *
+ * Name Type Meaning
+ * name String
+ * Attribute name.
+ * descriptorType String
+ * Must be "attribute".
+ * value Object
+ * Current (cached) value for attribute.
+ * default Object
+ * Default value for attribute.
+ * displayName String
+ * Name of attribute to be used in displays.
+ * getMethod String
+ * Name of operation descriptor for get method.
+ * setMethod String
+ * Name of operation descriptor for set method.
+ * protocolMap Descriptor
+ * 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.
+ * persistPolicy String
+ * One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
+ * See the section "MBean Descriptor Fields" in the JMX specification
+ * document.
+ * persistPeriod Number
+ * Frequency of persist cycle in seconds. Used when persistPolicy is
+ * "OnTimer" or "NoMoreOftenThan".
+ * currencyTimeLimit Number
+ * How long value is valid: <0 never,
+ * =0 always, >0 seconds.
+ * lastUpdatedTimeStamp Number
+ * When value was set.
+ * visibility Number
+ * 1-4 where 1: always visible, 4: rarely visible.
+ * presentationString String
+ * XML formatted string to allow presentation of data.
+ *
+ *
+ * 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.
*
* Note: because of inconsistencies in previous versions of
* this specification, it is recommended not to use negative or zero
diff --git a/src/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java b/src/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java
index a6e7ceab7374c5a61abc2324a4b4ee67e6b066f4..ecf8ecf002bdd7a4a390b969baca9d09d4656de4 100644
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java
@@ -49,22 +49,33 @@ import javax.management.MBeanParameterInfo;
import javax.management.RuntimeOperationsException;
/**
- * The ModelMBeanConstructorInfo object describes a constructor of the ModelMBean.
+ *
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.
- *
- *
- * The fields in the descriptor are defined, but not limited to, the following:
- * 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
- *
+ * and an implementation of the DescriptorAccess interface.
+ *
+ *
+ * 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.
+ *
+ *
+ * Name Type Meaning
+ * name String
+ * Constructor name.
+ * descriptorType String
+ * Must be "operation".
+ * role String
+ * Must be "constructor".
+ * displayName String
+ * Human readable name of constructor.
+ * visibility Number
+ * 1-4 where 1: always visible 4: rarely visible.
+ * presentationString String
+ * XML formatted string to describe how to present operation
+ *
*
* 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.
*
* The default descriptor will have the {@code name}, {@code
* descriptorType}, {@code displayName} and {@code role} fields. The
@@ -152,7 +163,7 @@ public class ModelMBeanConstructorInfo
* 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 class ModelMBeanConstructorInfo
*/
public ModelMBeanConstructorInfo(String description,
- Constructor constructorMethod,
+ Constructor> constructorMethod,
Descriptor descriptor)
{
diff --git a/src/share/classes/javax/management/modelmbean/ModelMBeanInfo.java b/src/share/classes/javax/management/modelmbean/ModelMBeanInfo.java
index 367e616eb09b6b051fe79adf35ad3e5db4c2784d..70c0e74f9f2039ceac86527080d8ed5ce089deff 100644
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanInfo.java
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanInfo.java
@@ -156,29 +156,55 @@ public interface ModelMBeanInfo
/**
- * Returns the ModelMBean's descriptor which contains MBean wide policies. This descriptor contains
- * metadata about the MBean and default policies for persistence and caching.
- *
- * The fields in the descriptor are defined, but not limited to, the following:
- *
- * 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, <0 never, =0 always, >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.
- *
+ * Returns the ModelMBean's descriptor which contains MBean wide
+ * policies. This descriptor contains metadata about the MBean and default
+ * policies for persistence and caching.
+ *
+ *
+ * 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.
+ *
+ *
+ * Name Type Meaning
+ * name String
+ * MBean name.
+ * descriptorType String
+ * Must be "mbean".
+ * displayName String
+ * Name of MBean to be used in displays.
+ * persistPolicy String
+ * One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
+ * See the section "MBean Descriptor Fields" in the JMX specification
+ * document.
+ * persistLocation String
+ * The fully qualified directory name where the MBean should be
+ * persisted (if appropriate).
+ * persistFile String
+ * File name into which the MBean should be persisted.
+ * persistPeriod Number
+ * Frequency of persist cycle in seconds, for OnTime and
+ * NoMoreOftenThan PersistPolicy
+ * currencyTimeLimit Number
+ * How long cached value is valid: <0 never, =0 always,
+ * >0 seconds.
+ * log String
+ * t: log all notifications, f: log no notifications.
+ * logfile String
+ * Fully qualified filename to log events to.
+ * visibility Number
+ * 1-4 where 1: always visible 4: rarely visible.
+ * export String
+ * Name to be used to export/expose this MBean so that it is
+ * findable by other JMX Agents.
+ * presentationString String
+ * XML formatted string to allow presentation of data to be
+ * associated with the MBean.
+ *
+ *
*
* 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.
*
*
Note: because of inconsistencies in previous versions of
@@ -207,7 +233,7 @@ public interface ModelMBeanInfo
* 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.
diff --git a/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java b/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java
index 52f1317db816bce840a3944a8b7f6c9b2f11a1db..4b637ee08f8cf187ff944e8d8adee2a95f806419 100644
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java
@@ -46,34 +46,46 @@ import javax.management.MBeanNotificationInfo;
import javax.management.RuntimeOperationsException;
/**
- * The ModelMBeanNotificationInfo object describes a notification emitted
+ *
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.
- *
- * The fields in the descriptor are defined, but not limited to,
- * the following:
- *
- * 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
- *
- * The default descriptor contains the name, descriptorType,
+ * associated Descriptor and an implementation of the Descriptor interface.
+ *
+ *
+ * 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.
+ *
+ *
+ * Name Type Meaning
+ * name String
+ * Notification name.
+ * descriptorType String
+ * Must be "notification".
+ * severity Number
+ * 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 String
+ * Unique key for message text (to allow translation, analysis).
+ * messageText String
+ * Text of notification.
+ * log String
+ * T - log message, F - do not log message.
+ * logfile String
+ * fully qualified file name appropriate for operating system.
+ * visibility Number
+ * 1-4 where 1: always visible 4: rarely visible.
+ * presentationString String
+ * XML formatted string to allow presentation of data.
+ *
+ *
+ * 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 name parameter of the
- * ModelMBeanNotificationInfo constructor).
+ * ModelMBeanNotificationInfo constructor).
*
* The serialVersionUID of this class is -7445681389570207141L.
*
diff --git a/src/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java b/src/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java
index 2ed992240671802c1481b72da731d944b914ecac..6ebea49954dc0fc2619e615bc6693c77f06fe116 100644
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java
@@ -49,27 +49,48 @@ import javax.management.MBeanParameterInfo;
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.
- *
- *
- * 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
- *
- * 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.
+ * 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.
+ *
+ *
+ * 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.
+ *
+ *
+ * Name Type Meaning
+ * name String
+ * Operation name.
+ * descriptorType String
+ * Must be "operation".
+ * class String
+ * Class where method is defined (fully qualified).
+ * role String
+ * Must be "operation", "getter", or "setter".
+ * targetObject Object
+ * Object on which to execute this method.
+ * targetType String
+ * type of object reference for targetObject. Can be:
+ * ObjectReference | Handle | EJBHandle | IOR | RMIReference.
+ * value Object
+ * Cached value for operation.
+ * displayName String
+ * Human readable display name of the operation.
+ * currencyTimeLimit Number
+ * How long cached value is valid.
+ * lastUpdatedTimeStamp Number
+ * When cached value was set.
+ * visibility Number
+ * 1-4 where 1: always visible 4: rarely visible.
+ * presentationString String
+ * XML formatted string to describe how to present operation
+ *
+ *
+ * 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.
*
* Note: because of inconsistencies in previous versions of
* this specification, it is recommended not to use negative or zero
diff --git a/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java b/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java
index 7d99fba0021ca50f1df2e2f4a8e61d6943adf62f..b9bec5ecc869eb6e2de5ba04cf9b5742935adfd2 100644
--- a/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java
+++ b/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java
@@ -1074,7 +1074,7 @@ public class RequiredModelMBean
}
}
- final Class targetClass;
+ final Class> targetClass;
if (opClassName != null) {
try {
@@ -1126,20 +1126,20 @@ public class RequiredModelMBean
"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 @@ public class RequiredModelMBean
/* 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 @@ public class RequiredModelMBean
new HashMap>();
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 @@ public class RequiredModelMBean
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 @@ public class RequiredModelMBean
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 @@ public class RequiredModelMBean
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 @@ public class RequiredModelMBean
return MBeanServerFactory.getClassLoaderRepository(server);
}
- private Class loadClass(String className)
+ private Class> loadClass(String className)
throws ClassNotFoundException {
try {
return Class.forName(className);
diff --git a/src/share/classes/javax/management/namespace/JMXNamespaces.java b/src/share/classes/javax/management/namespace/JMXNamespaces.java
index 429a9d466d6175a2f56e0f5b4d7c74d2b7fb8211..f19dfa570e4955ef10c5735ca13073265e63ed24 100644
--- a/src/share/classes/javax/management/namespace/JMXNamespaces.java
+++ b/src/share/classes/javax/management/namespace/JMXNamespaces.java
@@ -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
@@ -68,23 +66,6 @@ public class JMXNamespaces {
NAMESPACE_SEPARATOR.length();
- /**
- * 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}
@@ -96,15 +77,18 @@ public class JMXNamespaces {
* 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 @@ public class JMXNamespaces {
* 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 @@ public class JMXNamespaces {
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+
diff --git a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
index 6958f57f2d72db7a17c99e2acb93fb058c33b1f3..1c4d29bae30cb0ae80acb68a14ae2bfa1eef8b46 100644
--- a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
+++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
@@ -27,10 +27,10 @@ package javax.management.namespace;
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 java.util.logging.Logger;
import javax.management.AttributeChangeNotification;
+import javax.management.ClientContext;
import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
@@ -220,17 +221,26 @@ public class JMXRemoteNamespace
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 Map unmodifiableMap(Map 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.
@@ -483,106 +493,171 @@ public class JMXRemoteNamespace
}
}
- JMXConnector connect(JMXServiceURL url, Map env)
+ private JMXConnector connect(JMXServiceURL url, Map 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.
- *
- * This method first calls {@link JMXConnectorFactory#newJMXConnector
- * JMXConnectorFactory.newJMXConnector(jmxURL, env)} to obtain a new
- * JMX connector, and returns that.
- *
- *
- * 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:
+ *
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.
+ *
+ * @param url The JMXServiceURL of the remote server.
+ * @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 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 optionsMap) throws IOException {
+ return JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
+ }
+
+ /**
+ * 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:
+ *
+ *
+ * MBeanServerConnection mbsc = {@link JMXConnector#getMBeanServerConnection()
+ * jmxc.getMBeanServerConnection()};
+ * try {
+ * return {@link ClientContext#withDynamicContext
+ * ClientContext.withDynamicContext(mbsc)};
+ * } catch (IllegalArgumentException e) {
+ * return mbsc;
+ * }
+ *
+ *
+ * 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.
+ *
+ * Example: connecting to a remote namespace
+ *
+ * A subclass that wanted to narrow into a namespace of
+ * the remote MBeanServer might look like this:
+ *
*
* class JMXRemoteSubNamespace extends JMXRemoteNamespace {
- * private final String subnamespace;
- * JMXRemoteSubNamespace(JMXServiceURL url,
- * Map{@code } env, String subnamespace) {
- * super(url,options);
+ * private final String subnamespace;
+ *
+ * JMXRemoteSubNamespace(
+ * JMXServiceURL url, Map{@code } env, String subnamespace) {
+ * super(url, env);
* this.subnamespace = subnamespace;
- * }
- * protected JMXConnector newJMXConnector(JMXServiceURL url,
- * Map env) throws IOException {
- * final JMXConnector inner = super.newJMXConnector(url,env);
- * return {@link JMXNamespaces#narrowToNamespace(JMXConnector,String)
- * JMXNamespaces.narrowToNamespace(inner,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)};
+ * }
* }
*
- *
- *
- * 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.
- *
- * 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.
- *
- * 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:
- *
+ *
+ * Example: using the Event Service for notifications
+ *
+ * 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.
+ *
+ * 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:
+ *
*
* class JMXRemoteEventClientNamespace extends JMXRemoteNamespace {
- * JMXRemoteSubNamespaceConnector(JMXServiceURL url,
- * Map env) {
- * super(url,options);
- * }
- * protected JMXConnector newJMXConnector(JMXServiceURL url,
- * Map env) throws IOException {
- * final JMXConnector inner = super.newJMXConnector(url,env);
- * return {@link EventClient#withEventClient(
- * JMXConnector) EventClient.withEventClient(inner)};
- * }
+ * JMXRemoteEventClientNamespace(JMXServiceURL url, {@code Map} env) {
+ * super(url, env);
+ * }
+ *
+ * {@code @Override}
+ * protected MBeanServerConnection getMBeanServerConnection(JMXConnector jmxc)
+ * throws IOException {
+ * MBeanServerConnection mbsc = super.getMBeanServerConnection(jmxc);
+ * return EventClient.getEventClientConnection(mbsc);
+ * }
* }
*
+ *
*
* 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.
- * In summary, this technique should be used if the remote server
+ * javax.management.event.EventClientDelegateMBean}: configuring only
+ * the client side (this object) is not enough.
+ *
+ * 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).
- *
- * @param url The JMXServiceURL of the remote server.
- * @param optionsMap An unmodifiable 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.
- * @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map)
- * @see #JMXRemoteNamespace
+ * specification).
+ *
+ * @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 JMXConnector newJMXConnector(JMXServiceURL url,
- Map optionsMap) throws IOException {
- final JMXConnector c =
- JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
-// TODO: uncomment this when contexts are added
-// return ClientContext.withDynamicContext(c);
- return c;
+ 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}
+ *
+ * The sequence of events when this method is called includes,
+ * effectively, the following code:
+ *
+ *
+ * JMXServiceURL url = {@link #getJMXServiceURL getJMXServiceURL}();
+ * JMXConnector jmxc = {@link #newJMXConnector newJMXConnector}(url, env);
+ * jmxc.connect();
+ * MBeanServerConnection mbsc = {@link #getMBeanServerConnection(JMXConnector)
+ * getMBeanServerConnection}(jmxc);
+ *
+ *
+ * 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.
+ *
+ * Subclasses can customize connection behavior by overriding the
+ * {@code getJMXServiceURL}, {@code newJMXConnector}, or
+ * {@code getMBeanServerConnection} methods.
+ */
public void connect() throws IOException {
LOG.fine("connecting...");
final Map env =
@@ -590,7 +665,7 @@ public class JMXRemoteNamespace
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 @@ public class JMXRemoteNamespace
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);
diff --git a/src/share/classes/javax/management/namespace/MBeanServerSupport.java b/src/share/classes/javax/management/namespace/MBeanServerSupport.java
index 903be3c308f1029a76777a1cbb18efa7a0de2a92..ea070ae262e2e5d321d0742579fbfbc906cc8ce5 100644
--- a/src/share/classes/javax/management/namespace/MBeanServerSupport.java
+++ b/src/share/classes/javax/management/namespace/MBeanServerSupport.java
@@ -457,7 +457,11 @@ public abstract class MBeanServerSupport implements MBeanServer {
* 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.
+ *
+ * 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.
*
* @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 @@ public abstract class MBeanServerSupport implements MBeanServer {
* preRegister (MBeanRegistration
* 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 postRegister
+ * (MBeanRegistration interface) method of the MBean throws a
+ * RuntimeException, the createMBean method will
+ * throw a RuntimeMBeanException, although the MBean creation
+ * and registration succeeded. In such a case, the MBean will be actually
+ * registered even though the createMBean method
+ * threw an exception. Note that RuntimeMBeanException can
+ * also be thrown by preRegister, 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 @@ public abstract class MBeanServerSupport implements MBeanServer {
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 @@ public abstract class MBeanServerSupport implements MBeanServer {
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 @@ public abstract class MBeanServerSupport implements MBeanServer {
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 @@ public abstract class MBeanServerSupport implements MBeanServer {
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);
}
diff --git a/src/share/classes/javax/management/openmbean/ArrayType.java b/src/share/classes/javax/management/openmbean/ArrayType.java
index 49c8bbf1f63769bd57f66e3d71e8768fd520fbe1..0cbb677cf88145945ec39cdb5e3ac6e2c71c3ba0 100644
--- a/src/share/classes/javax/management/openmbean/ArrayType.java
+++ b/src/share/classes/javax/management/openmbean/ArrayType.java
@@ -296,7 +296,7 @@ public class ArrayType extends OpenType {
// 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 @@ public class ArrayType extends OpenType {
/* 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 @@ public class ArrayType extends OpenType {
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 @@ public class ArrayType extends OpenType {
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 @@ public class ArrayType extends OpenType {
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 @@ public class ArrayType extends OpenType {
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 @@ public class ArrayType extends OpenType {
}
@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 @@ public class ArrayType extends OpenType {
// 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 @@ public class ArrayType extends OpenType {
// Build primitive array
//
try {
+ @SuppressWarnings("rawtypes")
ArrayType at = new ArrayType(simpleType, true);
if (n > 1)
at = new ArrayType(n - 1, at);
@@ -934,7 +935,7 @@ public class ArrayType extends OpenType {
}
}
- private ArrayType convertFromWrapperToPrimitiveTypes() {
+ private ArrayType convertFromWrapperToPrimitiveTypes() {
String cn = getClassName();
String tn = getTypeName();
String d = getDescription();
@@ -952,8 +953,8 @@ public class ArrayType extends OpenType {
break;
}
}
- return new ArrayType(cn, tn, d,
- dimension, elementType, primitiveArray);
+ return new ArrayType(cn, tn, d,
+ dimension, elementType, primitiveArray);
}
/**
@@ -1002,7 +1003,7 @@ public class ArrayType extends OpenType {
}
}
- private ArrayType convertFromPrimitiveToWrapperTypes() {
+ private ArrayType convertFromPrimitiveToWrapperTypes() {
String cn = getClassName();
String tn = getTypeName();
String d = getDescription();
@@ -1020,7 +1021,7 @@ public class ArrayType extends OpenType {
break;
}
}
- return new ArrayType(cn, tn, d,
- dimension, elementType, primitiveArray);
+ return new ArrayType(cn, tn, d,
+ dimension, elementType, primitiveArray);
}
}
diff --git a/src/share/classes/javax/management/openmbean/CompositeDataInvocationHandler.java b/src/share/classes/javax/management/openmbean/CompositeDataInvocationHandler.java
index e0414e9d031fc8bd8beef703c2ec26bcb9904ddf..2262c2a5ef72c245f270f5a7efc0fa27472f823a 100644
--- a/src/share/classes/javax/management/openmbean/CompositeDataInvocationHandler.java
+++ b/src/share/classes/javax/management/openmbean/CompositeDataInvocationHandler.java
@@ -236,8 +236,8 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
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);
diff --git a/src/share/classes/javax/management/openmbean/CompositeDataSupport.java b/src/share/classes/javax/management/openmbean/CompositeDataSupport.java
index 4ef93b47611ccc649afec6294b6c993607a171d2..bd7c77af9b4542296b369e52a6bbf6f6a14dae98 100644
--- a/src/share/classes/javax/management/openmbean/CompositeDataSupport.java
+++ b/src/share/classes/javax/management/openmbean/CompositeDataSupport.java
@@ -33,12 +33,14 @@ import java.io.Serializable;
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 @@ public class CompositeDataSupport
* respective values.
* A {@link SortedMap} is used for faster retrieval of elements.
*/
- private SortedMap contents = new TreeMap();
+ private final SortedMap contents;
/**
* @serial The composite type of this composite data instance.
*/
- private CompositeType compositeType;
+ private final CompositeType compositeType;
/**
- *
- * Constructs a CompositeDataSupport instance with the specified
+ *
Constructs a CompositeDataSupport instance with the specified
* compositeType , whose item values
* are specified by itemValues[] , in the same order as in
* itemNames[] .
@@ -79,103 +80,67 @@ public class CompositeDataSupport
* The items contained in this CompositeDataSupport instance are
* internally stored in a TreeMap ,
* thus sorted in ascending lexicographic order of their names, for faster
- * retrieval of individual item values.
- *
- * The constructor checks that all the constraints listed below for each
+ * retrieval of individual item values.
+ *
+ * The constructor checks that all the constraints listed below for each
* parameter are satisfied,
- * and throws the appropriate exception if they are not.
- *
- * @param compositeType the composite type of this composite
- * data instance;
- * must not be null.
- *
- * @param itemNames itemNames must list, in any order, all the
- * item names defined in compositeType ;
- * the order in which the names are listed, is used to
- * match values in itemValues[] ;
- * must not be null or empty.
- *
- * @param itemValues the values of the items, listed in the same order as
- * their respective names in itemNames ;
- * each item value can be null, but if it is non-null it must be
- * a valid value for the open type defined in compositeType for the corresponding item;
- * must be of the same size as itemNames ; must not be null or empty.
- *
- * @throws IllegalArgumentException compositeType is null, or itemNames[] or itemValues[] is null or empty,
- * or one of the elements in itemNames[] is a null or empty string,
- * or itemNames[] and itemValues[] are not of the same size.
- *
- * @throws OpenDataException itemNames[] or itemValues[] 's size differs from
- * the number of items defined in compositeType ,
- * or one of the elements in itemNames[] does not exist as an item name defined in compositeType ,
- * or one of the elements in itemValues[] is not a valid value for the corresponding item
- * as defined in compositeType .
- *
+ * and throws the appropriate exception if they are not.
+ *
+ * @param compositeType the composite type of this composite
+ * data instance; must not be null.
+ *
+ * @param itemNames itemNames must list, in any order, all the
+ * item names defined in compositeType ; the order in which the
+ * names are listed, is used to match values in itemValues[] ; must
+ * not be null.
+ *
+ * @param itemValues the values of the items, listed in the same order as
+ * their respective names in itemNames ; each item value can be
+ * null, but if it is non-null it must be a valid value for the open type
+ * defined in compositeType for the corresponding item; must be of
+ * the same size as itemNames ; must not be null.
+ *
+ * @throws IllegalArgumentException compositeType is null, or
+ * itemNames[] or itemValues[] is null or empty, or one
+ * of the elements in itemNames[] is a null or empty string, or
+ * itemNames[] and itemValues[] are not of the same size.
+ *
+ * @throws OpenDataException itemNames[] or
+ * itemValues[] 's size differs from the number of items defined in
+ * compositeType , or one of the elements in itemNames[]
+ * does not exist as an item name defined in compositeType , or one
+ * of the elements in itemValues[] is not a valid value for the
+ * corresponding item as defined in compositeType .
*/
- public CompositeDataSupport(CompositeType compositeType, String[] itemNames, Object[] itemValues)
- throws OpenDataException {
-
- // Check compositeType is not null
- //
- if (compositeType == null) {
- throw new IllegalArgumentException("Argument compositeType cannot be null.");
- }
-
- // item names defined in compositeType:
- Set namesSet = compositeType.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");
+ public CompositeDataSupport(
+ CompositeType compositeType, String[] itemNames, Object[] itemValues)
+ throws OpenDataException {
+ this(makeMap(itemNames, itemValues), compositeType);
+ }
- // 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.");
- }
+ private static SortedMap makeMap(
+ String[] itemNames, Object[] itemValues)
+ throws OpenDataException {
- // Check that the sizes of the 2 arrays itemNames and itemValues are the same
- //
+ if (itemNames == null || itemValues == null)
+ throw new IllegalArgumentException("Null itemNames or itemValues");
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.");
+ throw new IllegalArgumentException(
+ "Different lengths: itemNames[" + itemNames.length +
+ "], itemValues[" + itemValues.length + "]");
}
- // 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 map = new TreeMap();
+ 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]);
}
- // Initialize internal fields: compositeType and contents
- //
- this.compositeType = compositeType;
- for (int i=0; iitems.
* This constructor converts the keys to a string array and the values to an object array and calls
* CompositeDataSupport(javax.management.openmbean.CompositeType, java.lang.String[], java.lang.Object[]) .
- *
+ *
* @param compositeType the composite type of this composite data instance;
* must not be null.
- *
* @param items the mappings of all the item names to their values;
* items must contain all the item names defined in compositeType ;
- * must not be null or empty.
- *
- * @throws IllegalArgumentException compositeType is null, or items is null or empty,
- * or one of the keys in items is a null or empty string,
- * or one of the values in items is null.
- *
- * @throws OpenDataException items ' size differs from the number of items defined in compositeType ,
- * or one of the keys in items does not exist as an item name defined in compositeType ,
- * or one of the values in items is not a valid value for the corresponding item
- * as defined in compositeType .
- *
- * @throws ArrayStoreException one or more keys in items is not of the class java.lang.String .
- *
+ * must not be null.
+ *
+ * @throws IllegalArgumentException compositeType is null, or
+ * items is null, or one of the keys in items is a null
+ * or empty string.
+ * @throws OpenDataException items ' size differs from the
+ * number of items defined in compositeType , or one of the
+ * keys in items does not exist as an item name defined in
+ * compositeType , or one of the values in items
+ * is not a valid value for the corresponding item as defined in
+ * compositeType .
+ * @throws ArrayStoreException one or more keys in items is not of
+ * the class java.lang.String .
+ *
+ * @see #toMap
*/
public CompositeDataSupport(CompositeType compositeType,
Map items)
throws OpenDataException {
+ this(makeMap(items), compositeType);
+ }
-
- // 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 SortedMap makeMap(Map 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 map = new TreeMap();
+ 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 static void checkForNullElement(Object[] arg, String argName) {
- if ( (arg == null) || (arg.length == 0) ) {
- throw new IllegalArgumentException(
- "Argument "+ argName +"[] cannot be null or empty.");
+ private CompositeDataSupport(
+ SortedMap items, CompositeType compositeType)
+ throws OpenDataException {
+
+ // Check compositeType is not null
+ //
+ if (compositeType == null) {
+ throw new IllegalArgumentException("Argument compositeType cannot be null.");
}
- for (int i=0; i namesFromType = compositeType.keySet();
+ Set namesFromItems = items.keySet();
+
+ // This is just a comparison, but we do it this way for a better
+ // exception message.
+ if (!namesFromType.equals(namesFromItems)) {
+ Set extraFromType = new TreeSet(namesFromType);
+ extraFromType.removeAll(namesFromItems);
+ Set extraFromItems = new TreeSet(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);
}
}
- }
- /**
- *
- */
- private static void checkForEmptyString(String[] arg, String argName) {
- for (int i=0; i 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;
+ this.contents = items;
}
/**
@@ -328,6 +328,54 @@ public class CompositeDataSupport
return Collections.unmodifiableCollection(contents.values());
}
+ /**
+ * 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.
+ *
+ * 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:
+ *
+ *
+ * CompositeData cd1 = ...;
+ * {@code Map} 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);
+ *
+ *
+ * Logically, this method would be a method in the {@link CompositeData}
+ * interface, but cannot be for compatibility reasons.
+ *
+ * @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 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 map = new LinkedHashMap();
+ CompositeType ct = cd.getCompositeType();
+ for (String key : ct.keySet()) {
+ Object value = cd.get(key);
+ map.put(key, value);
+ }
+ return map;
+ }
+
/**
* Compares the specified obj parameter with this
* CompositeDataSupport instance for equality.
diff --git a/src/share/classes/javax/management/openmbean/CompositeType.java b/src/share/classes/javax/management/openmbean/CompositeType.java
index b4c662ec9bce8a7f0e91a112c990fa6f3dc666fb..28c3fd72b7f7a2e744cbaa6893cb2a2be76e4e9c 100644
--- a/src/share/classes/javax/management/openmbean/CompositeType.java
+++ b/src/share/classes/javax/management/openmbean/CompositeType.java
@@ -329,7 +329,7 @@ public class CompositeType extends OpenType {
* @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 @@ public class CompositeType extends OpenType {
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 @@ public class CompositeType extends OpenType {
result.append(getTypeName());
result.append(",items=(");
int i=0;
- Iterator k=nameToType.keySet().iterator();
+ Iterator 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);
diff --git a/src/share/classes/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java b/src/share/classes/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java
index bcfa4c157ad79ad113690cd6437d80f932481b99..3ad03ef58ae0a83aeb2e5710f77727ef0b7cbf7f 100644
--- a/src/share/classes/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java
+++ b/src/share/classes/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java
@@ -78,12 +78,12 @@ public class OpenMBeanAttributeInfoSupport
/**
* @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 @@ public class OpenMBeanAttributeInfoSupport
}
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 @@ public class OpenMBeanAttributeInfoSupport
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({"unchecked", "rawtypes"})
static int compare(Object x, Object y) {
return ((Comparable) x).compareTo(y);
}
@@ -657,11 +657,11 @@ public class OpenMBeanAttributeInfoSupport
return result;
}
- static Comparable comparableValueFrom(Descriptor d, String name,
- OpenType openType) {
+ static Comparable> comparableValueFrom(Descriptor d, String name,
+ OpenType 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 @@ public class OpenMBeanAttributeInfoSupport
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;
diff --git a/src/share/classes/javax/management/openmbean/OpenMBeanParameterInfoSupport.java b/src/share/classes/javax/management/openmbean/OpenMBeanParameterInfoSupport.java
index b67ac60d77c5fe4568682475b8746a80edabf773..fc50a3b76218fb4129f276d2ffffa42b07de89d6 100644
--- a/src/share/classes/javax/management/openmbean/OpenMBeanParameterInfoSupport.java
+++ b/src/share/classes/javax/management/openmbean/OpenMBeanParameterInfoSupport.java
@@ -74,12 +74,12 @@ public class OpenMBeanParameterInfoSupport
/**
* @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
diff --git a/src/share/classes/javax/management/openmbean/OpenType.java b/src/share/classes/javax/management/openmbean/OpenType.java
index 7aac2c0fd8fd555800d48f71b9bdd9f3d71979c3..3f74c3cda60ece5f4ecab18b894bdf0c3e889503 100644
--- a/src/share/classes/javax/management/openmbean/OpenType.java
+++ b/src/share/classes/javax/management/openmbean/OpenType.java
@@ -206,7 +206,7 @@ public abstract class OpenType implements Serializable {
}
}
- private static boolean overridesGetClassName(final Class extends OpenType> c) {
+ private static boolean overridesGetClassName(final Class> c) {
return AccessController.doPrivileged(new PrivilegedAction() {
public Boolean run() {
try {
diff --git a/src/share/classes/javax/management/openmbean/SimpleType.java b/src/share/classes/javax/management/openmbean/SimpleType.java
index 7837819c4c245858dfe03a81540d491160218a0c..1d4f90e6a9b460243024cc116db72c334becfe08 100644
--- a/src/share/classes/javax/management/openmbean/SimpleType.java
+++ b/src/share/classes/javax/management/openmbean/SimpleType.java
@@ -163,7 +163,7 @@ public final class SimpleType extends OpenType {
public static final SimpleType OBJECTNAME =
new SimpleType(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 @@ public final class SimpleType extends OpenType {
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 @@ public final class SimpleType extends OpenType {
return myToString;
}
- private static final Map canonicalTypes =
- new HashMap