feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,320 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.management.MBeanPermission;
import javax.management.ObjectName;
import javax.management.loading.PrivateClassLoader;
import sun.reflect.misc.ReflectUtil;
/**
* This class keeps the list of Class Loaders registered in the MBean Server.
* It provides the necessary methods to load classes using the
* registered Class Loaders.
*
* @since 1.5
*/
final class ClassLoaderRepositorySupport
implements ModifiableClassLoaderRepository {
/* We associate an optional ObjectName with each entry so that
we can remove the correct entry when unregistering an MBean
that is a ClassLoader. The same object could be registered
under two different names (even though this is not recommended)
so if we did not do this we could disturb the defined
semantics for the order of ClassLoaders in the repository. */
private static class LoaderEntry {
ObjectName name; // can be null
ClassLoader loader;
LoaderEntry(ObjectName name, ClassLoader loader) {
this.name = name;
this.loader = loader;
}
}
private static final LoaderEntry[] EMPTY_LOADER_ARRAY = new LoaderEntry[0];
/**
* List of class loaders
* Only read-only actions should be performed on this object.
*
* We do O(n) operations on this array, e.g. when removing
* a ClassLoader. The assumption is that the number of elements
* is small, probably less than ten, and that the vast majority
* of operations are searches (loadClass) which are by definition
* linear.
*/
private LoaderEntry[] loaders = EMPTY_LOADER_ARRAY;
/**
* Same behavior as add(Object o) in {@link java.util.List}.
* Replace the loader list with a new one in which the new
* loader has been added.
**/
private synchronized boolean add(ObjectName name, ClassLoader cl) {
List<LoaderEntry> l =
new ArrayList<LoaderEntry>(Arrays.asList(loaders));
l.add(new LoaderEntry(name, cl));
loaders = l.toArray(EMPTY_LOADER_ARRAY);
return true;
}
/**
* Same behavior as remove(Object o) in {@link java.util.List}.
* Replace the loader list with a new one in which the old loader
* has been removed.
*
* The ObjectName may be null, in which case the entry to
* be removed must also have a null ObjectName and the ClassLoader
* values must match. If the ObjectName is not null, then
* the first entry with a matching ObjectName is removed,
* regardless of whether ClassLoader values match. (In fact,
* the ClassLoader parameter will usually be null in this case.)
**/
private synchronized boolean remove(ObjectName name, ClassLoader cl) {
final int size = loaders.length;
for (int i = 0; i < size; i++) {
LoaderEntry entry = loaders[i];
boolean match =
(name == null) ?
cl == entry.loader :
name.equals(entry.name);
if (match) {
LoaderEntry[] newloaders = new LoaderEntry[size - 1];
System.arraycopy(loaders, 0, newloaders, 0, i);
System.arraycopy(loaders, i + 1, newloaders, i,
size - 1 - i);
loaders = newloaders;
return true;
}
}
return false;
}
/**
* List of valid search
*/
private final Map<String,List<ClassLoader>> search =
new Hashtable<String,List<ClassLoader>>(10);
/**
* List of named class loaders.
*/
private final Map<ObjectName,ClassLoader> loadersWithNames =
new Hashtable<ObjectName,ClassLoader>(10);
// from javax.management.loading.DefaultLoaderRepository
public final Class<?> loadClass(String className)
throws ClassNotFoundException {
return loadClass(loaders, className, null, null);
}
// from javax.management.loading.DefaultLoaderRepository
public final Class<?> loadClassWithout(ClassLoader without, String className)
throws ClassNotFoundException {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER,
ClassLoaderRepositorySupport.class.getName(),
"loadClassWithout", className + " without " + without);
}
// without is null => just behave as loadClass
//
if (without == null)
return loadClass(loaders, className, null, null);
// We must try to load the class without the given loader.
//
startValidSearch(without, className);
try {
return loadClass(loaders, className, without, null);
} finally {
stopValidSearch(without, className);
}
}
public final Class<?> loadClassBefore(ClassLoader stop, String className)
throws ClassNotFoundException {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER,
ClassLoaderRepositorySupport.class.getName(),
"loadClassBefore", className + " before " + stop);
}
if (stop == null)
return loadClass(loaders, className, null, null);
startValidSearch(stop, className);
try {
return loadClass(loaders, className, null, stop);
} finally {
stopValidSearch(stop, className);
}
}
private Class<?> loadClass(final LoaderEntry list[],
final String className,
final ClassLoader without,
final ClassLoader stop)
throws ClassNotFoundException {
ReflectUtil.checkPackageAccess(className);
final int size = list.length;
for(int i=0; i<size; i++) {
try {
final ClassLoader cl = list[i].loader;
if (cl == null) // bootstrap class loader
return Class.forName(className, false, null);
if (cl == without)
continue;
if (cl == stop)
break;
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER,
ClassLoaderRepositorySupport.class.getName(),
"loadClass", "Trying loader = " + cl);
}
/* We used to have a special case for "instanceof
MLet" here, where we invoked the method
loadClass(className, null) to prevent infinite
recursion. But the rule whereby the MLet only
consults loaders that precede it in the CLR (via
loadClassBefore) means that the recursion can't
happen, and the test here caused some legitimate
classloading to fail. For example, if you have
dependencies C->D->E with loaders {E D C} in the
CLR in that order, you would expect to be able to
load C. The problem is that while resolving D, CLR
delegation is disabled, so it can't find E. */
return Class.forName(className, false, cl);
} catch (ClassNotFoundException e) {
// OK: continue with next class
}
}
throw new ClassNotFoundException(className);
}
private synchronized void startValidSearch(ClassLoader aloader,
String className)
throws ClassNotFoundException {
// Check if we have such a current search
//
List<ClassLoader> excluded = search.get(className);
if ((excluded!= null) && (excluded.contains(aloader))) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER,
ClassLoaderRepositorySupport.class.getName(),
"startValidSearch", "Already requested loader = " +
aloader + " class = " + className);
}
throw new ClassNotFoundException(className);
}
// Add an entry
//
if (excluded == null) {
excluded = new ArrayList<ClassLoader>(1);
search.put(className, excluded);
}
excluded.add(aloader);
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER,
ClassLoaderRepositorySupport.class.getName(),
"startValidSearch",
"loader = " + aloader + " class = " + className);
}
}
private synchronized void stopValidSearch(ClassLoader aloader,
String className) {
// Retrieve the search.
//
List<ClassLoader> excluded = search.get(className);
if (excluded != null) {
excluded.remove(aloader);
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER,
ClassLoaderRepositorySupport.class.getName(),
"stopValidSearch",
"loader = " + aloader + " class = " + className);
}
}
}
public final void addClassLoader(ClassLoader loader) {
add(null, loader);
}
public final void removeClassLoader(ClassLoader loader) {
remove(null, loader);
}
public final synchronized void addClassLoader(ObjectName name,
ClassLoader loader) {
loadersWithNames.put(name, loader);
if (!(loader instanceof PrivateClassLoader))
add(name, loader);
}
public final synchronized void removeClassLoader(ObjectName name) {
ClassLoader loader = loadersWithNames.remove(name);
if (!(loader instanceof PrivateClassLoader))
remove(name, loader);
}
public final ClassLoader getClassLoader(ObjectName name) {
ClassLoader instance = loadersWithNames.get(name);
if (instance != null) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm =
new MBeanPermission(instance.getClass().getName(),
null,
name,
"getClassLoader");
sm.checkPermission(perm);
}
}
return instance;
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.io.InvalidObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import javax.management.Descriptor;
import javax.management.MBeanException;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import sun.reflect.misc.MethodUtil;
final class ConvertingMethod {
static ConvertingMethod from(Method m) {
try {
return new ConvertingMethod(m);
} catch (OpenDataException ode) {
final String msg = "Method " + m.getDeclaringClass().getName() +
"." + m.getName() + " has parameter or return type that " +
"cannot be translated into an open type";
throw new IllegalArgumentException(msg, ode);
}
}
Method getMethod() {
return method;
}
Descriptor getDescriptor() {
return Introspector.descriptorForElement(method);
}
Type getGenericReturnType() {
return method.getGenericReturnType();
}
Type[] getGenericParameterTypes() {
return method.getGenericParameterTypes();
}
String getName() {
return method.getName();
}
OpenType<?> getOpenReturnType() {
return returnMapping.getOpenType();
}
OpenType<?>[] getOpenParameterTypes() {
final OpenType<?>[] types = new OpenType<?>[paramMappings.length];
for (int i = 0; i < paramMappings.length; i++)
types[i] = paramMappings[i].getOpenType();
return types;
}
/* Check that this method will be callable when we are going from
* open types to Java types, for example when we are going from
* an MXBean wrapper to the underlying resource.
* The parameters will be converted to
* Java types, so they must be "reconstructible". The return
* value will be converted to an Open Type, so if it is convertible
* at all there is no further check needed.
*/
void checkCallFromOpen() {
try {
for (MXBeanMapping paramConverter : paramMappings)
paramConverter.checkReconstructible();
} catch (InvalidObjectException e) {
throw new IllegalArgumentException(e);
}
}
/* Check that this method will be callable when we are going from
* Java types to open types, for example when we are going from
* an MXBean proxy to the open types that it will be mapped to.
* The return type will be converted back to a Java type, so it
* must be "reconstructible". The parameters will be converted to
* open types, so if it is convertible at all there is no further
* check needed.
*/
void checkCallToOpen() {
try {
returnMapping.checkReconstructible();
} catch (InvalidObjectException e) {
throw new IllegalArgumentException(e);
}
}
String[] getOpenSignature() {
if (paramMappings.length == 0)
return noStrings;
String[] sig = new String[paramMappings.length];
for (int i = 0; i < paramMappings.length; i++)
sig[i] = paramMappings[i].getOpenClass().getName();
return sig;
}
final Object toOpenReturnValue(MXBeanLookup lookup, Object ret)
throws OpenDataException {
return returnMapping.toOpenValue(ret);
}
final Object fromOpenReturnValue(MXBeanLookup lookup, Object ret)
throws InvalidObjectException {
return returnMapping.fromOpenValue(ret);
}
final Object[] toOpenParameters(MXBeanLookup lookup, Object[] params)
throws OpenDataException {
if (paramConversionIsIdentity || params == null)
return params;
final Object[] oparams = new Object[params.length];
for (int i = 0; i < params.length; i++)
oparams[i] = paramMappings[i].toOpenValue(params[i]);
return oparams;
}
final Object[] fromOpenParameters(Object[] params)
throws InvalidObjectException {
if (paramConversionIsIdentity || params == null)
return params;
final Object[] jparams = new Object[params.length];
for (int i = 0; i < params.length; i++)
jparams[i] = paramMappings[i].fromOpenValue(params[i]);
return jparams;
}
final Object toOpenParameter(MXBeanLookup lookup,
Object param,
int paramNo)
throws OpenDataException {
return paramMappings[paramNo].toOpenValue(param);
}
final Object fromOpenParameter(MXBeanLookup lookup,
Object param,
int paramNo)
throws InvalidObjectException {
return paramMappings[paramNo].fromOpenValue(param);
}
Object invokeWithOpenReturn(MXBeanLookup lookup,
Object obj, Object[] params)
throws MBeanException, IllegalAccessException,
InvocationTargetException {
MXBeanLookup old = MXBeanLookup.getLookup();
try {
MXBeanLookup.setLookup(lookup);
return invokeWithOpenReturn(obj, params);
} finally {
MXBeanLookup.setLookup(old);
}
}
private Object invokeWithOpenReturn(Object obj, Object[] params)
throws MBeanException, IllegalAccessException,
InvocationTargetException {
final Object[] javaParams;
try {
javaParams = fromOpenParameters(params);
} catch (InvalidObjectException e) {
// probably can't happen
final String msg = methodName() + ": cannot convert parameters " +
"from open values: " + e;
throw new MBeanException(e, msg);
}
final Object javaReturn = MethodUtil.invoke(method, obj, javaParams);
try {
return returnMapping.toOpenValue(javaReturn);
} catch (OpenDataException e) {
// probably can't happen
final String msg = methodName() + ": cannot convert return " +
"value to open value: " + e;
throw new MBeanException(e, msg);
}
}
private String methodName() {
return method.getDeclaringClass() + "." + method.getName();
}
private ConvertingMethod(Method m) throws OpenDataException {
this.method = m;
MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT;
returnMapping =
mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
Type[] params = m.getGenericParameterTypes();
paramMappings = new MXBeanMapping[params.length];
boolean identity = true;
for (int i = 0; i < params.length; i++) {
paramMappings[i] = mappingFactory.mappingForType(params[i], mappingFactory);
identity &= DefaultMXBeanMappingFactory.isIdentity(paramMappings[i]);
}
paramConversionIsIdentity = identity;
}
private static final String[] noStrings = new String[0];
private final Method method;
private final MXBeanMapping returnMapping;
private final MXBeanMapping[] paramMappings;
private final boolean paramConversionIsIdentity;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.JMX;
public class DescriptorCache {
private DescriptorCache() {
}
static DescriptorCache getInstance() {
return instance;
}
public static DescriptorCache getInstance(JMX proof) {
if (proof != null)
return instance;
else
return null;
}
public ImmutableDescriptor get(ImmutableDescriptor descriptor) {
WeakReference<ImmutableDescriptor> wr = map.get(descriptor);
ImmutableDescriptor got = (wr == null) ? null : wr.get();
if (got != null)
return got;
map.put(descriptor, new WeakReference<ImmutableDescriptor>(descriptor));
return descriptor;
}
public ImmutableDescriptor union(Descriptor... descriptors) {
return get(ImmutableDescriptor.union(descriptors));
}
private final static DescriptorCache instance = new DescriptorCache();
private final WeakHashMap<ImmutableDescriptor,
WeakReference<ImmutableDescriptor>>
map = new WeakHashMap<ImmutableDescriptor,
WeakReference<ImmutableDescriptor>>();
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.ObjectName;
/**
* A dynamic MBean that wraps an underlying resource. A version of this
* interface might eventually appear in the public JMX API.
*
* @since 1.6
*/
public interface DynamicMBean2 extends DynamicMBean {
/**
* The resource corresponding to this MBean. This is the object whose
* class name should be reflected by the MBean's
* getMBeanInfo().getClassName() for example. For a "plain"
* DynamicMBean it will be "this". For an MBean that wraps another
* object, like javax.management.StandardMBean, it will be the wrapped
* object.
*/
public Object getResource();
/**
* The name of this MBean's class, as used by permission checks.
* This is typically equal to getResource().getClass().getName().
* This method is typically faster, sometimes much faster,
* than getMBeanInfo().getClassName(), but should return the same
* result.
*/
public String getClassName();
/**
* Additional registration hook. This method is called after
* {@link javax.management.MBeanRegistration#preRegister preRegister}.
* Unlike that method, if it throws an exception and the MBean implements
* {@code MBeanRegistration}, then {@link
* javax.management.MBeanRegistration#postRegister postRegister(false)}
* will be called on the MBean. This is the behavior that the MBean
* expects for a problem that does not come from its own preRegister
* method.
*/
public void preRegister2(MBeanServer mbs, ObjectName name)
throws Exception;
/**
* Additional registration hook. This method is called if preRegister
* and preRegister2 succeed, but then the MBean cannot be registered
* (for example because there is already another MBean of the same name).
*/
public void registerFailed();
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2002, 2004, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.security.PrivilegedAction;
/**
* Utility class to be used by the method <tt>AccessControler.doPrivileged</tt>
* to get a system property.
*
* @since 1.5
*/
public class GetPropertyAction implements PrivilegedAction<String> {
private final String key;
public GetPropertyAction(String key) {
this.key = key;
}
public String run() {
return System.getProperty(key);
}
}

View File

@@ -0,0 +1,816 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;
import javax.management.Descriptor;
import javax.management.DescriptorKey;
import javax.management.DynamicMBean;
import javax.management.ImmutableDescriptor;
import javax.management.MBeanInfo;
import javax.management.NotCompliantMBeanException;
import com.sun.jmx.remote.util.EnvHelp;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import javax.management.AttributeNotFoundException;
import javax.management.openmbean.CompositeData;
import sun.reflect.misc.MethodUtil;
import sun.reflect.misc.ReflectUtil;
/**
* This class contains the methods for performing all the tests needed to verify
* that a class represents a JMX compliant MBean.
*
* @since 1.5
*/
public class Introspector {
final public static boolean ALLOW_NONPUBLIC_MBEAN;
static {
String val = AccessController.doPrivileged(new GetPropertyAction("jdk.jmx.mbeans.allowNonPublic"));
ALLOW_NONPUBLIC_MBEAN = Boolean.parseBoolean(val);
}
/*
* ------------------------------------------
* PRIVATE CONSTRUCTORS
* ------------------------------------------
*/
// private constructor defined to "hide" the default public constructor
private Introspector() {
// ------------------------------
// ------------------------------
}
/*
* ------------------------------------------
* PUBLIC METHODS
* ------------------------------------------
*/
/**
* Tell whether a MBean of the given class is a Dynamic MBean.
* This method does nothing more than returning
* <pre>
* javax.management.DynamicMBean.class.isAssignableFrom(c)
* </pre>
* This method does not check for any JMX MBean compliance:
* <ul><li>If <code>true</code> is returned, then instances of
* <code>c</code> are DynamicMBean.</li>
* <li>If <code>false</code> is returned, then no further
* assumption can be made on instances of <code>c</code>.
* In particular, instances of <code>c</code> may, or may not
* be JMX standard MBeans.</li>
* </ul>
* @param c The class of the MBean under examination.
* @return <code>true</code> if instances of <code>c</code> are
* Dynamic MBeans, <code>false</code> otherwise.
*
**/
public static final boolean isDynamic(final Class<?> c) {
// Check if the MBean implements the DynamicMBean interface
return javax.management.DynamicMBean.class.isAssignableFrom(c);
}
/**
* Basic method for testing that a MBean of a given class can be
* instantiated by the MBean server.<p>
* This method checks that:
* <ul><li>The given class is a concrete class.</li>
* <li>The given class exposes at least one public constructor.</li>
* </ul>
* If these conditions are not met, throws a NotCompliantMBeanException.
* @param c The class of the MBean we want to create.
* @exception NotCompliantMBeanException if the MBean class makes it
* impossible to instantiate the MBean from within the
* MBeanServer.
*
**/
public static void testCreation(Class<?> c)
throws NotCompliantMBeanException {
// Check if the class is a concrete class
final int mods = c.getModifiers();
if (Modifier.isAbstract(mods) || Modifier.isInterface(mods)) {
throw new NotCompliantMBeanException("MBean class must be concrete");
}
// Check if the MBean has a public constructor
final Constructor<?>[] consList = c.getConstructors();
if (consList.length == 0) {
throw new NotCompliantMBeanException("MBean class must have public constructor");
}
}
public static void checkCompliance(Class<?> mbeanClass)
throws NotCompliantMBeanException {
// Is DynamicMBean?
//
if (DynamicMBean.class.isAssignableFrom(mbeanClass))
return;
// Is Standard MBean?
//
final Exception mbeanException;
try {
getStandardMBeanInterface(mbeanClass);
return;
} catch (NotCompliantMBeanException e) {
mbeanException = e;
}
// Is MXBean?
//
final Exception mxbeanException;
try {
getMXBeanInterface(mbeanClass);
return;
} catch (NotCompliantMBeanException e) {
mxbeanException = e;
}
final String msg =
"MBean class " + mbeanClass.getName() + " does not implement " +
"DynamicMBean, and neither follows the Standard MBean conventions (" +
mbeanException.toString() + ") nor the MXBean conventions (" +
mxbeanException.toString() + ")";
throw new NotCompliantMBeanException(msg);
}
public static <T> DynamicMBean makeDynamicMBean(T mbean)
throws NotCompliantMBeanException {
if (mbean instanceof DynamicMBean)
return (DynamicMBean) mbean;
final Class<?> mbeanClass = mbean.getClass();
Class<? super T> c = null;
try {
c = Util.cast(getStandardMBeanInterface(mbeanClass));
} catch (NotCompliantMBeanException e) {
// Ignore exception - we need to check whether
// mbean is an MXBean first.
}
if (c != null)
return new StandardMBeanSupport(mbean, c);
try {
c = Util.cast(getMXBeanInterface(mbeanClass));
} catch (NotCompliantMBeanException e) {
// Ignore exception - we cannot decide whether mbean was supposed
// to be an MBean or an MXBean. We will call checkCompliance()
// to generate the appropriate exception.
}
if (c != null)
return new MXBeanSupport(mbean, c);
checkCompliance(mbeanClass);
throw new NotCompliantMBeanException("Not compliant"); // not reached
}
/**
* Basic method for testing if a given class is a JMX compliant MBean.
*
* @param baseClass The class to be tested
*
* @return <code>null</code> if the MBean is a DynamicMBean,
* the computed {@link javax.management.MBeanInfo} otherwise.
* @exception NotCompliantMBeanException The specified class is not a
* JMX compliant MBean
*/
public static MBeanInfo testCompliance(Class<?> baseClass)
throws NotCompliantMBeanException {
// ------------------------------
// ------------------------------
// Check if the MBean implements the MBean or the Dynamic
// MBean interface
if (isDynamic(baseClass))
return null;
return testCompliance(baseClass, null);
}
/**
* Tests the given interface class for being a compliant MXBean interface.
* A compliant MXBean interface is any publicly accessible interface
* following the {@link MXBean} conventions.
* @param interfaceClass An interface class to test for the MXBean compliance
* @throws NotCompliantMBeanException Thrown when the tested interface
* is not public or contradicts the {@link MXBean} conventions.
*/
public static void testComplianceMXBeanInterface(Class<?> interfaceClass)
throws NotCompliantMBeanException {
MXBeanIntrospector.getInstance().getAnalyzer(interfaceClass);
}
/**
* Tests the given interface class for being a compliant MBean interface.
* A compliant MBean interface is any publicly accessible interface
* following the {@code MBean} conventions.
* @param interfaceClass An interface class to test for the MBean compliance
* @throws NotCompliantMBeanException Thrown when the tested interface
* is not public or contradicts the {@code MBean} conventions.
*/
public static void testComplianceMBeanInterface(Class<?> interfaceClass)
throws NotCompliantMBeanException{
StandardMBeanIntrospector.getInstance().getAnalyzer(interfaceClass);
}
/**
* Basic method for testing if a given class is a JMX compliant
* Standard MBean. This method is only called by the legacy code
* in com.sun.management.jmx.
*
* @param baseClass The class to be tested.
*
* @param mbeanInterface the MBean interface that the class implements,
* or null if the interface must be determined by introspection.
*
* @return the computed {@link javax.management.MBeanInfo}.
* @exception NotCompliantMBeanException The specified class is not a
* JMX compliant Standard MBean
*/
public static synchronized MBeanInfo
testCompliance(final Class<?> baseClass,
Class<?> mbeanInterface)
throws NotCompliantMBeanException {
if (mbeanInterface == null)
mbeanInterface = getStandardMBeanInterface(baseClass);
ReflectUtil.checkPackageAccess(mbeanInterface);
MBeanIntrospector<?> introspector = StandardMBeanIntrospector.getInstance();
return getClassMBeanInfo(introspector, baseClass, mbeanInterface);
}
private static <M> MBeanInfo
getClassMBeanInfo(MBeanIntrospector<M> introspector,
Class<?> baseClass, Class<?> mbeanInterface)
throws NotCompliantMBeanException {
PerInterface<M> perInterface = introspector.getPerInterface(mbeanInterface);
return introspector.getClassMBeanInfo(baseClass, perInterface);
}
/**
* Get the MBean interface implemented by a JMX Standard
* MBean class. This method is only called by the legacy
* code in "com.sun.management.jmx".
*
* @param baseClass The class to be tested.
*
* @return The MBean interface implemented by the MBean.
* Return <code>null</code> if the MBean is a DynamicMBean,
* or if no MBean interface is found.
*/
public static Class<?> getMBeanInterface(Class<?> baseClass) {
// Check if the given class implements the MBean interface
// or the Dynamic MBean interface
if (isDynamic(baseClass)) return null;
try {
return getStandardMBeanInterface(baseClass);
} catch (NotCompliantMBeanException e) {
return null;
}
}
/**
* Get the MBean interface implemented by a JMX Standard MBean class.
*
* @param baseClass The class to be tested.
*
* @return The MBean interface implemented by the Standard MBean.
*
* @throws NotCompliantMBeanException The specified class is
* not a JMX compliant Standard MBean.
*/
public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass)
throws NotCompliantMBeanException {
Class<? super T> current = baseClass;
Class<? super T> mbeanInterface = null;
while (current != null) {
mbeanInterface =
findMBeanInterface(current, current.getName());
if (mbeanInterface != null) break;
current = current.getSuperclass();
}
if (mbeanInterface != null) {
return mbeanInterface;
} else {
final String msg =
"Class " + baseClass.getName() +
" is not a JMX compliant Standard MBean";
throw new NotCompliantMBeanException(msg);
}
}
/**
* Get the MXBean interface implemented by a JMX MXBean class.
*
* @param baseClass The class to be tested.
*
* @return The MXBean interface implemented by the MXBean.
*
* @throws NotCompliantMBeanException The specified class is
* not a JMX compliant MXBean.
*/
public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass)
throws NotCompliantMBeanException {
try {
return MXBeanSupport.findMXBeanInterface(baseClass);
} catch (Exception e) {
throw throwException(baseClass,e);
}
}
/*
* ------------------------------------------
* PRIVATE METHODS
* ------------------------------------------
*/
/**
* Try to find the MBean interface corresponding to the class aName
* - i.e. <i>aName</i>MBean, from within aClass and its superclasses.
**/
private static <T> Class<? super T> findMBeanInterface(
Class<T> aClass, String aName) {
Class<? super T> current = aClass;
while (current != null) {
final Class<?>[] interfaces = current.getInterfaces();
final int len = interfaces.length;
for (int i=0;i<len;i++) {
Class<? super T> inter = Util.cast(interfaces[i]);
inter = implementsMBean(inter, aName);
if (inter != null) return inter;
}
current = current.getSuperclass();
}
return null;
}
public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
if (elmt == null)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
final Annotation[] annots = elmt.getAnnotations();
return descriptorForAnnotations(annots);
}
public static Descriptor descriptorForAnnotations(Annotation[] annots) {
if (annots.length == 0)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
Map<String, Object> descriptorMap = new HashMap<String, Object>();
for (Annotation a : annots) {
Class<? extends Annotation> c = a.annotationType();
Method[] elements = c.getMethods();
boolean packageAccess = false;
for (Method element : elements) {
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
if (key != null) {
String name = key.value();
Object value;
try {
// Avoid checking access more than once per annotation
if (!packageAccess) {
ReflectUtil.checkPackageAccess(c);
packageAccess = true;
}
value = MethodUtil.invoke(element, a, null);
} catch (RuntimeException e) {
// we don't expect this - except for possibly
// security exceptions?
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
// anyway...
//
throw e;
} catch (Exception e) {
// we don't expect this
throw new UndeclaredThrowableException(e);
}
value = annotationToField(value);
Object oldValue = descriptorMap.put(name, value);
if (oldValue != null && !equals(oldValue, value)) {
final String msg =
"Inconsistent values for descriptor field " + name +
" from annotations: " + value + " :: " + oldValue;
throw new IllegalArgumentException(msg);
}
}
}
}
if (descriptorMap.isEmpty())
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
else
return new ImmutableDescriptor(descriptorMap);
}
/**
* Throws a NotCompliantMBeanException or a SecurityException.
* @param notCompliant the class which was under examination
* @param cause the raeson why NotCompliantMBeanException should
* be thrown.
* @return nothing - this method always throw an exception.
* The return type makes it possible to write
* <pre> throw throwException(clazz,cause); </pre>
* @throws SecurityException - if cause is a SecurityException
* @throws NotCompliantMBeanException otherwise.
**/
static NotCompliantMBeanException throwException(Class<?> notCompliant,
Throwable cause)
throws NotCompliantMBeanException, SecurityException {
if (cause instanceof SecurityException)
throw (SecurityException) cause;
if (cause instanceof NotCompliantMBeanException)
throw (NotCompliantMBeanException)cause;
final String classname =
(notCompliant==null)?"null class":notCompliant.getName();
final String reason =
(cause==null)?"Not compliant":cause.getMessage();
final NotCompliantMBeanException res =
new NotCompliantMBeanException(classname+": "+reason);
res.initCause(cause);
throw res;
}
// Convert a value from an annotation element to a descriptor field value
// E.g. with @interface Foo {class value()} an annotation @Foo(String.class)
// will produce a Descriptor field value "java.lang.String"
private static Object annotationToField(Object x) {
// An annotation element cannot have a null value but never mind
if (x == null)
return null;
if (x instanceof Number || x instanceof String ||
x instanceof Character || x instanceof Boolean ||
x instanceof String[])
return x;
// Remaining possibilities: array of primitive (e.g. int[]),
// enum, class, array of enum or class.
Class<?> c = x.getClass();
if (c.isArray()) {
if (c.getComponentType().isPrimitive())
return x;
Object[] xx = (Object[]) x;
String[] ss = new String[xx.length];
for (int i = 0; i < xx.length; i++)
ss[i] = (String) annotationToField(xx[i]);
return ss;
}
if (x instanceof Class<?>)
return ((Class<?>) x).getName();
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.
// If it is indeed another annotation, then x will be a proxy
// with an unhelpful name like $Proxy2. So we extract the
// proxy's interface to use that in the exception message.
if (Proxy.isProxyClass(c))
c = c.getInterfaces()[0]; // array "can't be empty"
throw new IllegalArgumentException("Illegal type for annotation " +
"element using @DescriptorKey: " + c.getName());
}
// This must be consistent with the check for duplicate field values in
// ImmutableDescriptor.union. But we don't expect to be called very
// often so this inefficient check should be enough.
private static boolean equals(Object x, Object y) {
return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
}
/**
* Returns the XXMBean interface or null if no such interface exists
*
* @param c The interface to be tested
* @param clName The name of the class implementing this interface
*/
private static <T> Class<? super T> implementsMBean(Class<T> c, String clName) {
String clMBeanName = clName + "MBean";
if (c.getName().equals(clMBeanName)) {
return c;
}
Class<?>[] interfaces = c.getInterfaces();
for (int i = 0;i < interfaces.length; i++) {
if (interfaces[i].getName().equals(clMBeanName) &&
(Modifier.isPublic(interfaces[i].getModifiers()) ||
ALLOW_NONPUBLIC_MBEAN)) {
return Util.cast(interfaces[i]);
}
}
return null;
}
public static Object elementFromComplex(Object complex, String element)
throws AttributeNotFoundException {
try {
if (complex.getClass().isArray() && element.equals("length")) {
return Array.getLength(complex);
} else if (complex instanceof CompositeData) {
return ((CompositeData) complex).get(element);
} else {
// Java Beans introspection
//
Class<?> clazz = complex.getClass();
Method readMethod = null;
if (BeansHelper.isAvailable()) {
Object bi = BeansHelper.getBeanInfo(clazz);
Object[] pds = BeansHelper.getPropertyDescriptors(bi);
for (Object pd: pds) {
if (BeansHelper.getPropertyName(pd).equals(element)) {
readMethod = BeansHelper.getReadMethod(pd);
break;
}
}
} else {
// Java Beans not available so use simple introspection
// to locate method
readMethod = SimpleIntrospector.getReadMethod(clazz, element);
}
if (readMethod != null) {
ReflectUtil.checkPackageAccess(readMethod.getDeclaringClass());
return MethodUtil.invoke(readMethod, complex, new Class[0]);
}
throw new AttributeNotFoundException(
"Could not find the getter method for the property " +
element + " using the Java Beans introspector");
}
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
} catch (AttributeNotFoundException e) {
throw e;
} catch (Exception e) {
throw EnvHelp.initCause(
new AttributeNotFoundException(e.getMessage()), e);
}
}
/**
* A simple introspector that uses reflection to analyze a class and
* identify its "getter" methods. This class is intended for use only when
* Java Beans is not present (which implies that there isn't explicit
* information about the bean available).
*/
private static class SimpleIntrospector {
private SimpleIntrospector() { }
private static final String GET_METHOD_PREFIX = "get";
private static final String IS_METHOD_PREFIX = "is";
// cache to avoid repeated lookups
private static final Map<Class<?>,SoftReference<List<Method>>> cache =
Collections.synchronizedMap(
new WeakHashMap<Class<?>,SoftReference<List<Method>>> ());
/**
* Returns the list of methods cached for the given class, or {@code null}
* if not cached.
*/
private static List<Method> getCachedMethods(Class<?> clazz) {
// return cached methods if possible
SoftReference<List<Method>> ref = cache.get(clazz);
if (ref != null) {
List<Method> cached = ref.get();
if (cached != null)
return cached;
}
return null;
}
/**
* Returns {@code true} if the given method is a "getter" method (where
* "getter" method is a public method of the form getXXX or "boolean
* isXXX")
*/
static boolean isReadMethod(Method method) {
// ignore static methods
int modifiers = method.getModifiers();
if (Modifier.isStatic(modifiers))
return false;
String name = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
int paramCount = paramTypes.length;
if (paramCount == 0 && name.length() > 2) {
// boolean isXXX()
if (name.startsWith(IS_METHOD_PREFIX))
return (method.getReturnType() == boolean.class);
// getXXX()
if (name.length() > 3 && name.startsWith(GET_METHOD_PREFIX))
return (method.getReturnType() != void.class);
}
return false;
}
/**
* Returns the list of "getter" methods for the given class. The list
* is ordered so that isXXX methods appear before getXXX methods - this
* is for compatibility with the JavaBeans Introspector.
*/
static List<Method> getReadMethods(Class<?> clazz) {
// return cached result if available
List<Method> cachedResult = getCachedMethods(clazz);
if (cachedResult != null)
return cachedResult;
// get list of public methods, filtering out methods that have
// been overridden to return a more specific type.
List<Method> methods =
StandardMBeanIntrospector.getInstance().getMethods(clazz);
methods = MBeanAnalyzer.eliminateCovariantMethods(methods);
// filter out the non-getter methods
List<Method> result = new LinkedList<Method>();
for (Method m: methods) {
if (isReadMethod(m)) {
// favor isXXX over getXXX
if (m.getName().startsWith(IS_METHOD_PREFIX)) {
result.add(0, m);
} else {
result.add(m);
}
}
}
// add result to cache
cache.put(clazz, new SoftReference<List<Method>>(result));
return result;
}
/**
* Returns the "getter" to read the given property from the given class or
* {@code null} if no method is found.
*/
static Method getReadMethod(Class<?> clazz, String property) {
// first character in uppercase (compatibility with JavaBeans)
property = property.substring(0, 1).toUpperCase(Locale.ENGLISH) +
property.substring(1);
String getMethod = GET_METHOD_PREFIX + property;
String isMethod = IS_METHOD_PREFIX + property;
for (Method m: getReadMethods(clazz)) {
String name = m.getName();
if (name.equals(isMethod) || name.equals(getMethod)) {
return m;
}
}
return null;
}
}
/**
* A class that provides access to the JavaBeans Introspector and
* PropertyDescriptors without creating a static dependency on java.beans.
*/
private static class BeansHelper {
private static final Class<?> introspectorClass =
getClass("java.beans.Introspector");
private static final Class<?> beanInfoClass =
(introspectorClass == null) ? null : getClass("java.beans.BeanInfo");
private static final Class<?> getPropertyDescriptorClass =
(beanInfoClass == null) ? null : getClass("java.beans.PropertyDescriptor");
private static final Method getBeanInfo =
getMethod(introspectorClass, "getBeanInfo", Class.class);
private static final Method getPropertyDescriptors =
getMethod(beanInfoClass, "getPropertyDescriptors");
private static final Method getPropertyName =
getMethod(getPropertyDescriptorClass, "getName");
private static final Method getReadMethod =
getMethod(getPropertyDescriptorClass, "getReadMethod");
private static Class<?> getClass(String name) {
try {
return Class.forName(name, true, null);
} catch (ClassNotFoundException e) {
return null;
}
}
private static Method getMethod(Class<?> clazz,
String name,
Class<?>... paramTypes)
{
if (clazz != null) {
try {
return clazz.getMethod(name, paramTypes);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
} else {
return null;
}
}
private BeansHelper() { }
/**
* Returns {@code true} if java.beans is available.
*/
static boolean isAvailable() {
return introspectorClass != null;
}
/**
* Invokes java.beans.Introspector.getBeanInfo(Class)
*/
static Object getBeanInfo(Class<?> clazz) throws Exception {
try {
return getBeanInfo.invoke(null, clazz);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception)
throw (Exception)cause;
throw new AssertionError(e);
} catch (IllegalAccessException iae) {
throw new AssertionError(iae);
}
}
/**
* Invokes java.beans.BeanInfo.getPropertyDescriptors()
*/
static Object[] getPropertyDescriptors(Object bi) {
try {
return (Object[])getPropertyDescriptors.invoke(bi);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException)
throw (RuntimeException)cause;
throw new AssertionError(e);
} catch (IllegalAccessException iae) {
throw new AssertionError(iae);
}
}
/**
* Invokes java.beans.PropertyDescriptor.getName()
*/
static String getPropertyName(Object pd) {
try {
return (String)getPropertyName.invoke(pd);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException)
throw (RuntimeException)cause;
throw new AssertionError(e);
} catch (IllegalAccessException iae) {
throw new AssertionError(iae);
}
}
/**
* Invokes java.beans.PropertyDescriptor.getReadMethod()
*/
static Method getReadMethod(Object pd) {
try {
return (Method)getReadMethod.invoke(pd);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException)
throw (RuntimeException)cause;
throw new AssertionError(e);
} catch (IllegalAccessException iae) {
throw new AssertionError(iae);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerBuilder;
/**
* This class represents a builder that creates
* {@link javax.management.MBeanServer} implementations.
* The JMX {@link javax.management.MBeanServerFactory} allows
* for applications to provide their custom MBeanServer
* implementation. This class is not used when the whole Sun Reference JMX
* Implementation is used. However it may be used to substitute Sun
* MBeanServer implementation to another JMX implementation.
* <p>
* Contrarily to the default {@link javax.management.MBeanServerBuilder
* javax.management.MBeanServerBuilder} this MBeanServerBuilder returns
* MBeanServers on which
* {@link com.sun.jmx.interceptor.MBeanServerInterceptor}s are enabled.
*
* @since 1.5
*/
public class JmxMBeanServerBuilder extends MBeanServerBuilder {
/**
* This method creates a new MBeanServerDelegate for a new MBeanServer.
* When creating a new MBeanServer the
* {@link javax.management.MBeanServerFactory} first calls this method
* in order to create a new MBeanServerDelegate.
* <br>Then it calls
* <code>newMBeanServer(defaultDomain,outer,delegate)</code>
* passing the <var>delegate</var> that should be used by the MBeanServer
* implementation.
* <p>Note that the passed <var>delegate</var> might not be directly the
* MBeanServerDelegate that was returned by this method. It could
* be, for instance, a new object wrapping the previously
* returned object.
*
* @return A new {@link javax.management.MBeanServerDelegate}.
**/
public MBeanServerDelegate newMBeanServerDelegate() {
return JmxMBeanServer.newMBeanServerDelegate();
}
/**
* This method creates a new MBeanServer implementation object.
* When creating a new MBeanServer the
* {@link javax.management.MBeanServerFactory} first calls
* <code>newMBeanServerDelegate()</code> in order to obtain a new
* {@link javax.management.MBeanServerDelegate} for the new
* MBeanServer. Then it calls
* <code>newMBeanServer(defaultDomain,outer,delegate)</code>
* passing the <var>delegate</var> that should be used by the
* MBeanServer implementation.
* <p>Note that the passed <var>delegate</var> might not be directly the
* MBeanServerDelegate that was returned by this implementation. It could
* be, for instance, a new object wrapping the previously
* returned delegate.
* <p>The <var>outer</var> parameter is a pointer to the MBeanServer that
* should be passed to the {@link javax.management.MBeanRegistration}
* interface when registering MBeans inside the MBeanServer.
* If <var>outer</var> is <code>null</code>, then the MBeanServer
* implementation is free to use its own <code>this</code> pointer when
* invoking the {@link javax.management.MBeanRegistration} interface.
* <p>This makes it possible for a MBeanServer implementation to wrap
* another MBeanServer implementation, in order to implement, e.g,
* security checks, or to prevent access to the actual MBeanServer
* implementation by returning a pointer to a wrapping object.
* <p>
* This MBeanServerBuilder makes it possible to create MBeanServer
* which support {@link com.sun.jmx.interceptor.MBeanServerInterceptor}s.
*
* @param defaultDomain Default domain of the new MBeanServer.
* @param outer A pointer to the MBeanServer object that must be
* passed to the MBeans when invoking their
* {@link javax.management.MBeanRegistration} interface.
* @param delegate A pointer to the MBeanServerDelegate associated
* with the new MBeanServer. The new MBeanServer must register
* this MBean in its MBean repository.
*
* @return A new private implementation of an MBeanServer.
**/
public MBeanServer newMBeanServer(String defaultDomain,
MBeanServer outer,
MBeanServerDelegate delegate) {
return JmxMBeanServer.newMBeanServer(defaultDomain,outer,delegate,
true);
}
}

View File

@@ -0,0 +1,275 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.NotCompliantMBeanException;
/**
* <p>An analyzer for a given MBean interface. The analyzer can
* be for Standard MBeans or MXBeans, depending on the MBeanIntrospector
* passed at construction.
*
* <p>The analyzer can
* visit the attributes and operations of the interface, calling
* a caller-supplied visitor method for each one.</p>
*
* @param <M> Method or ConvertingMethod according as this is a
* Standard MBean or an MXBean.
*
* @since 1.6
*/
class MBeanAnalyzer<M> {
static interface MBeanVisitor<M> {
public void visitAttribute(String attributeName,
M getter,
M setter);
public void visitOperation(String operationName,
M operation);
}
void visit(MBeanVisitor<M> visitor) {
// visit attributes
for (Map.Entry<String, AttrMethods<M>> entry : attrMap.entrySet()) {
String name = entry.getKey();
AttrMethods<M> am = entry.getValue();
visitor.visitAttribute(name, am.getter, am.setter);
}
// visit operations
for (Map.Entry<String, List<M>> entry : opMap.entrySet()) {
for (M m : entry.getValue())
visitor.visitOperation(entry.getKey(), m);
}
}
/* Map op name to method */
private Map<String, List<M>> opMap = newInsertionOrderMap();
/* Map attr name to getter and/or setter */
private Map<String, AttrMethods<M>> attrMap = newInsertionOrderMap();
private static class AttrMethods<M> {
M getter;
M setter;
}
/**
* <p>Return an MBeanAnalyzer for the given MBean interface and
* MBeanIntrospector. Calling this method twice with the same
* parameters may return the same object or two different but
* equivalent objects.
*/
// Currently it's two different but equivalent objects. This only
// really impacts proxy generation. For MBean creation, the
// cached PerInterface object for an MBean interface means that
// an analyzer will not be recreated for a second MBean using the
// same interface.
static <M> MBeanAnalyzer<M> analyzer(Class<?> mbeanType,
MBeanIntrospector<M> introspector)
throws NotCompliantMBeanException {
return new MBeanAnalyzer<M>(mbeanType, introspector);
}
private MBeanAnalyzer(Class<?> mbeanType,
MBeanIntrospector<M> introspector)
throws NotCompliantMBeanException {
if (!mbeanType.isInterface()) {
throw new NotCompliantMBeanException("Not an interface: " +
mbeanType.getName());
} else if (!Modifier.isPublic(mbeanType.getModifiers()) &&
!Introspector.ALLOW_NONPUBLIC_MBEAN) {
throw new NotCompliantMBeanException("Interface is not public: " +
mbeanType.getName());
}
try {
initMaps(mbeanType, introspector);
} catch (Exception x) {
throw Introspector.throwException(mbeanType,x);
}
}
// Introspect the mbeanInterface and initialize this object's maps.
//
private void initMaps(Class<?> mbeanType,
MBeanIntrospector<M> introspector) throws Exception {
final List<Method> methods1 = introspector.getMethods(mbeanType);
final List<Method> methods = eliminateCovariantMethods(methods1);
/* Run through the methods to detect inconsistencies and to enable
us to give getter and setter together to visitAttribute. */
for (Method m : methods) {
final String name = m.getName();
final int nParams = m.getParameterTypes().length;
final M cm = introspector.mFrom(m);
String attrName = "";
if (name.startsWith("get"))
attrName = name.substring(3);
else if (name.startsWith("is")
&& m.getReturnType() == boolean.class)
attrName = name.substring(2);
if (attrName.length() != 0 && nParams == 0
&& m.getReturnType() != void.class) {
// It's a getter
// Check we don't have both isX and getX
AttrMethods<M> am = attrMap.get(attrName);
if (am == null)
am = new AttrMethods<M>();
else {
if (am.getter != null) {
final String msg = "Attribute " + attrName +
" has more than one getter";
throw new NotCompliantMBeanException(msg);
}
}
am.getter = cm;
attrMap.put(attrName, am);
} else if (name.startsWith("set") && name.length() > 3
&& nParams == 1 &&
m.getReturnType() == void.class) {
// It's a setter
attrName = name.substring(3);
AttrMethods<M> am = attrMap.get(attrName);
if (am == null)
am = new AttrMethods<M>();
else if (am.setter != null) {
final String msg = "Attribute " + attrName +
" has more than one setter";
throw new NotCompliantMBeanException(msg);
}
am.setter = cm;
attrMap.put(attrName, am);
} else {
// It's an operation
List<M> cms = opMap.get(name);
if (cms == null)
cms = newList();
cms.add(cm);
opMap.put(name, cms);
}
}
/* Check that getters and setters are consistent. */
for (Map.Entry<String, AttrMethods<M>> entry : attrMap.entrySet()) {
AttrMethods<M> am = entry.getValue();
if (!introspector.consistent(am.getter, am.setter)) {
final String msg = "Getter and setter for " + entry.getKey() +
" have inconsistent types";
throw new NotCompliantMBeanException(msg);
}
}
}
/**
* A comparator that defines a total order so that methods have the
* same name and identical signatures appear next to each others.
* The methods are sorted in such a way that methods which
* override each other will sit next to each other, with the
* overridden method first - e.g. Object getFoo() is placed before
* Integer getFoo(). This makes it possible to determine whether
* a method overrides another one simply by looking at the method(s)
* that precedes it in the list. (see eliminateCovariantMethods).
**/
private static class MethodOrder implements Comparator<Method> {
public int compare(Method a, Method b) {
final int cmp = a.getName().compareTo(b.getName());
if (cmp != 0) return cmp;
final Class<?>[] aparams = a.getParameterTypes();
final Class<?>[] bparams = b.getParameterTypes();
if (aparams.length != bparams.length)
return aparams.length - bparams.length;
if (!Arrays.equals(aparams, bparams)) {
return Arrays.toString(aparams).
compareTo(Arrays.toString(bparams));
}
final Class<?> aret = a.getReturnType();
final Class<?> bret = b.getReturnType();
if (aret == bret) return 0;
// Super type comes first: Object, Number, Integer
if (aret.isAssignableFrom(bret))
return -1;
return +1; // could assert bret.isAssignableFrom(aret)
}
public final static MethodOrder instance = new MethodOrder();
}
/* Eliminate methods that are overridden with a covariant return type.
Reflection will return both the original and the overriding method
but only the overriding one is of interest. We return the methods
in the same order they arrived in. This isn't required by the spec
but existing code may depend on it and users may be used to seeing
operations or attributes appear in a particular order.
Because of the way this method works, if the same Method appears
more than once in the given List then it will be completely deleted!
So don't do that. */
static List<Method>
eliminateCovariantMethods(List<Method> startMethods) {
// We are assuming that you never have very many methods with the
// same name, so it is OK to use algorithms that are quadratic
// in the number of methods with the same name.
final int len = startMethods.size();
final Method[] sorted = startMethods.toArray(new Method[len]);
Arrays.sort(sorted,MethodOrder.instance);
final Set<Method> overridden = newSet();
for (int i=1;i<len;i++) {
final Method m0 = sorted[i-1];
final Method m1 = sorted[i];
// Methods that don't have the same name can't override each other
if (!m0.getName().equals(m1.getName())) continue;
// Methods that have the same name and same signature override
// each other. In that case, the second method overrides the first,
// due to the way we have sorted them in MethodOrder.
if (Arrays.equals(m0.getParameterTypes(),
m1.getParameterTypes())) {
if (!overridden.add(m0))
throw new RuntimeException("Internal error: duplicate Method");
}
}
final List<Method> methods = newList(startMethods);
methods.removeAll(overridden);
return methods;
}
}

View File

@@ -0,0 +1,786 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permission;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.Map;
import java.util.logging.Level;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanPermission;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.ReflectionException;
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;
import sun.reflect.misc.ConstructorUtil;
import sun.reflect.misc.ReflectUtil;
/**
* Implements the MBeanInstantiator interface. Provides methods for
* instantiating objects, finding the class given its name and using
* different class loaders, deserializing objects in the context of a
* given class loader.
*
* @since 1.5
*/
public class MBeanInstantiator {
private final ModifiableClassLoaderRepository clr;
// private MetaData meta = null;
MBeanInstantiator(ModifiableClassLoaderRepository clr) {
this.clr = clr;
}
/**
* This methods tests if the MBean class makes it possible to
* 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 {
Introspector.testCreation(c);
}
/**
* Loads the class with the specified name using this object's
* Default Loader Repository.
**/
public Class<?> findClassWithDefaultLoaderRepository(String className)
throws ReflectionException {
Class<?> theClass;
if (className == null) {
throw new RuntimeOperationsException(new
IllegalArgumentException("The class name cannot be null"),
"Exception occurred during object instantiation");
}
ReflectUtil.checkPackageAccess(className);
try {
if (clr == null) throw new ClassNotFoundException(className);
theClass = clr.loadClass(className);
}
catch (ClassNotFoundException ee) {
throw new ReflectionException(ee,
"The MBean class could not be loaded by the default loader repository");
}
return theClass;
}
/**
* Gets the class for the specified class name using the MBean
* Interceptor's classloader
*/
public Class<?> findClass(String className, ClassLoader loader)
throws ReflectionException {
return loadClass(className,loader);
}
/**
* Gets the class for the specified class name using the specified
* class loader
*/
public Class<?> findClass(String className, ObjectName aLoader)
throws ReflectionException, InstanceNotFoundException {
if (aLoader == null)
throw new RuntimeOperationsException(new
IllegalArgumentException(), "Null loader passed in parameter");
// Retrieve the class loader from the repository
ClassLoader loader = null;
synchronized (this) {
loader = getClassLoader(aLoader);
}
if (loader == null) {
throw new InstanceNotFoundException("The loader named " +
aLoader + " is not registered in the MBeanServer");
}
return findClass(className,loader);
}
/**
* Return an array of Class corresponding to the given signature, using
* the specified class loader.
*/
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];
if (length == 0) return tab;
try {
for (int i= 0; i < length; i++) {
// Start handling primitive types (int. boolean and so
// forth)
//
final Class<?> primCla = primitiveClasses.get(signature[i]);
if (primCla != null) {
tab[i] = primCla;
continue;
}
ReflectUtil.checkPackageAccess(signature[i]);
// Ok we do not have a primitive type ! We need to build
// the signature of the method
//
if (aLoader != null) {
// We need to load the class through the class
// loader of the target object.
//
tab[i] = Class.forName(signature[i], false, aLoader);
} else {
// Load through the default class loader
//
tab[i] = findClass(signature[i],
this.getClass().getClassLoader());
}
}
} catch (ClassNotFoundException e) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
MBEANSERVER_LOGGER.logp(Level.FINEST,
MBeanInstantiator.class.getName(),
"findSignatureClasses",
"The parameter class could not be found", e);
}
throw new ReflectionException(e,
"The parameter class could not be found");
} catch (RuntimeException e) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
MBEANSERVER_LOGGER.logp(Level.FINEST,
MBeanInstantiator.class.getName(),
"findSignatureClasses",
"Unexpected exception", e);
}
throw e;
}
return tab;
}
/**
* 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)
throws ReflectionException, MBeanException {
checkMBeanPermission(theClass, null, null, "instantiate");
Object moi;
// ------------------------------
// ------------------------------
Constructor<?> cons = findConstructor(theClass, null);
if (cons == null) {
throw new ReflectionException(new
NoSuchMethodException("No such constructor"));
}
// Instantiate the new object
try {
ReflectUtil.checkPackageAccess(theClass);
ensureClassAccess(theClass);
moi= cons.newInstance();
} catch (InvocationTargetException e) {
// Wrap the exception.
Throwable t = e.getTargetException();
if (t instanceof RuntimeException) {
throw new RuntimeMBeanException((RuntimeException)t,
"RuntimeException thrown in the MBean's empty constructor");
} else if (t instanceof Error) {
throw new RuntimeErrorException((Error) t,
"Error thrown in the MBean's empty constructor");
} else {
throw new MBeanException((Exception) t,
"Exception thrown in the MBean's empty constructor");
}
} catch (NoSuchMethodError error) {
throw new ReflectionException(new
NoSuchMethodException("No constructor"),
"No such constructor");
} catch (InstantiationException e) {
throw new ReflectionException(e,
"Exception thrown trying to invoke the MBean's empty constructor");
} catch (IllegalAccessException e) {
throw new ReflectionException(e,
"Exception thrown trying to invoke the MBean's empty constructor");
} catch (IllegalArgumentException e) {
throw new ReflectionException(e,
"Exception thrown trying to invoke the MBean's empty constructor");
}
return moi;
}
/**
* Instantiates an object given its class, the parameters and
* signature of its constructor The call returns a reference to
* the newly created object.
*/
public Object instantiate(Class<?> theClass, Object params[],
String signature[], ClassLoader loader)
throws ReflectionException, MBeanException {
checkMBeanPermission(theClass, null, null, "instantiate");
// Instantiate the new object
// ------------------------------
// ------------------------------
final Class<?>[] tab;
Object moi;
try {
// Build the signature of the method
//
ClassLoader aLoader= theClass.getClassLoader();
// Build the signature of the method
//
tab =
((signature == null)?null:
findSignatureClasses(signature,aLoader));
}
// Exception IllegalArgumentException raised in Jdk1.1.8
catch (IllegalArgumentException e) {
throw new ReflectionException(e,
"The constructor parameter classes could not be loaded");
}
// Query the metadata service to get the right constructor
Constructor<?> cons = findConstructor(theClass, tab);
if (cons == null) {
throw new ReflectionException(new
NoSuchMethodException("No such constructor"));
}
try {
ReflectUtil.checkPackageAccess(theClass);
ensureClassAccess(theClass);
moi = cons.newInstance(params);
}
catch (NoSuchMethodError error) {
throw new ReflectionException(new
NoSuchMethodException("No such constructor found"),
"No such constructor" );
}
catch (InstantiationException e) {
throw new ReflectionException(e,
"Exception thrown trying to invoke the MBean's constructor");
}
catch (IllegalAccessException e) {
throw new ReflectionException(e,
"Exception thrown trying to invoke the MBean's constructor");
}
catch (InvocationTargetException e) {
// Wrap the exception.
Throwable th = e.getTargetException();
if (th instanceof RuntimeException) {
throw new RuntimeMBeanException((RuntimeException)th,
"RuntimeException thrown in the MBean's constructor");
} else if (th instanceof Error) {
throw new RuntimeErrorException((Error) th,
"Error thrown in the MBean's constructor");
} else {
throw new MBeanException((Exception) th,
"Exception thrown in the MBean's constructor");
}
}
return moi;
}
/**
* De-serializes a byte array in the context of a classloader.
*
* @param loader the classloader to use for de-serialization
* @param data The byte array to be de-sererialized.
*
* @return The de-serialized object stream.
*
* @exception OperationsException Any of the usual Input/Output related
* exceptions.
*/
public ObjectInputStream deserialize(ClassLoader loader, byte[] data)
throws OperationsException {
// Check parameter validity
if (data == null) {
throw new RuntimeOperationsException(new
IllegalArgumentException(), "Null data passed in parameter");
}
if (data.length == 0) {
throw new RuntimeOperationsException(new
IllegalArgumentException(), "Empty data passed in parameter");
}
// Object deserialization
ByteArrayInputStream bIn;
ObjectInputStream objIn;
bIn = new ByteArrayInputStream(data);
try {
objIn = new ObjectInputStreamWithLoader(bIn,loader);
} catch (IOException e) {
throw new OperationsException(
"An IOException occurred trying to de-serialize the data");
}
return objIn;
}
/**
* De-serializes a byte array in the context of a given MBean class loader.
* <P>The class loader is the one that loaded the class with name
* "className".
* <P>The name of the class loader to be used for loading the specified
* class is specified. If null, a default one has to be provided (for a
* MBean Server, its own class loader will be used).
*
* @param className The name of the class whose class loader should
* be used for the de-serialization.
* @param data The byte array to be de-sererialized.
* @param loaderName The name of the class loader to be used for loading
* the specified class. If null, a default one has to be provided (for a
* MBean Server, its own class loader will be used).
*
* @return The de-serialized object stream.
*
* @exception InstanceNotFoundException The specified class loader MBean is
* not found.
* @exception OperationsException Any of the usual Input/Output related
* exceptions.
* @exception ReflectionException The specified class could not be loaded
* by the specified class loader.
*/
public ObjectInputStream deserialize(String className,
ObjectName loaderName,
byte[] data,
ClassLoader loader)
throws InstanceNotFoundException,
OperationsException,
ReflectionException {
// Check parameter validity
if (data == null) {
throw new RuntimeOperationsException(new
IllegalArgumentException(), "Null data passed in parameter");
}
if (data.length == 0) {
throw new RuntimeOperationsException(new
IllegalArgumentException(), "Empty data passed in parameter");
}
if (className == null) {
throw new RuntimeOperationsException(new
IllegalArgumentException(), "Null className passed in parameter");
}
ReflectUtil.checkPackageAccess(className);
Class<?> theClass;
if (loaderName == null) {
// Load the class using the agent class loader
theClass = findClass(className, loader);
} else {
// Get the class loader MBean
try {
ClassLoader instance = null;
instance = getClassLoader(loaderName);
if (instance == null)
throw new ClassNotFoundException(className);
theClass = Class.forName(className, false, instance);
}
catch (ClassNotFoundException e) {
throw new ReflectionException(e,
"The MBean class could not be loaded by the " +
loaderName.toString() + " class loader");
}
}
// Object deserialization
ByteArrayInputStream bIn;
ObjectInputStream objIn;
bIn = new ByteArrayInputStream(data);
try {
objIn = new ObjectInputStreamWithLoader(bIn,
theClass.getClassLoader());
} catch (IOException e) {
throw new OperationsException(
"An IOException occurred trying to de-serialize the data");
}
return objIn;
}
/**
* Instantiates an object using the list of all class loaders registered
* in the MBean Interceptor
* (using its {@link javax.management.loading.ClassLoaderRepository}).
* <P>The object's class should have a public constructor.
* <P>It returns a reference to the newly created object.
* <P>The newly created object is not registered in the MBean Interceptor.
*
* @param className The class name of the object to be instantiated.
*
* @return The newly instantiated object.
*
* @exception ReflectionException Wraps a
* <CODE>java.lang.ClassNotFoundException</CODE> or the
* <CODE>java.lang.Exception</CODE> that occurred when trying to invoke the
* object's constructor.
* @exception MBeanException The constructor of the object has thrown an
* exception
* @exception RuntimeOperationsException Wraps a
* <CODE>java.lang.IllegalArgumentException</CODE>: the className passed in
* parameter is null.
*/
public Object instantiate(String className)
throws ReflectionException,
MBeanException {
return instantiate(className, (Object[]) null, (String[]) null, null);
}
/**
* Instantiates an object using the class Loader specified by its
* <CODE>ObjectName</CODE>.
* <P>If the loader name is null, a default one has to be provided (for a
* MBean Server, the ClassLoader that loaded it will be used).
* <P>The object's class should have a public constructor.
* <P>It returns a reference to the newly created object.
* <P>The newly created object is not registered in the MBean Interceptor.
*
* @param className The class name of the MBean to be instantiated.
* @param loaderName The object name of the class loader to be used.
*
* @return The newly instantiated object.
*
* @exception ReflectionException Wraps a
* <CODE>java.lang.ClassNotFoundException</CODE> or the
* <CODE>java.lang.Exception</CODE> that occurred when trying to invoke the
* object's constructor.
* @exception MBeanException The constructor of the object has thrown an
* exception.
* @exception InstanceNotFoundException The specified class loader is not
* registered in the MBeanServerInterceptor.
* @exception RuntimeOperationsException Wraps a
* <CODE>java.lang.IllegalArgumentException</CODE>: the className passed in
* parameter is null.
*/
public Object instantiate(String className, ObjectName loaderName,
ClassLoader loader)
throws ReflectionException, MBeanException,
InstanceNotFoundException {
return instantiate(className, loaderName, (Object[]) null,
(String[]) null, loader);
}
/**
* Instantiates an object using the list of all class loaders registered
* in the MBean server
* (using its {@link javax.management.loading.ClassLoaderRepository}).
* <P>The object's class should have a public constructor.
* <P>The call returns a reference to the newly created object.
* <P>The newly created object is not registered in the MBean Interceptor.
*
* @param className The class name of the object to be instantiated.
* @param params An array containing the parameters of the constructor to
* be invoked.
* @param signature An array containing the signature of the constructor to
* be invoked.
*
* @return The newly instantiated object.
*
* @exception ReflectionException Wraps a
* <CODE>java.lang.ClassNotFoundException</CODE> or the
* <CODE>java.lang.Exception</CODE> that occurred when trying to invoke the
* object's constructor.
* @exception MBeanException The constructor of the object has thrown an
* exception
* @exception RuntimeOperationsException Wraps a
* <CODE>java.lang.IllegalArgumentException</CODE>: the className passed in
* parameter is null.
*/
public Object instantiate(String className,
Object params[],
String signature[],
ClassLoader loader)
throws ReflectionException,
MBeanException {
Class<?> theClass = findClassWithDefaultLoaderRepository(className);
return instantiate(theClass, params, signature, loader);
}
/**
* Instantiates an object. The class loader to be used is identified by its
* object name.
* <P>If the object name of the loader is null, a default has to be
* provided (for example, for a MBean Server, the ClassLoader that loaded
* it will be used).
* <P>The object's class should have a public constructor.
* <P>The call returns a reference to the newly created object.
* <P>The newly created object is not registered in the MBean server.
*
* @param className The class name of the object to be instantiated.
* @param params An array containing the parameters of the constructor to
* be invoked.
* @param signature An array containing the signature of the constructor to
* be invoked.
* @param loaderName The object name of the class loader to be used.
*
* @return The newly instantiated object.
*
* @exception ReflectionException Wraps a
* <CODE>java.lang.ClassNotFoundException</CODE> or the
* <CODE>java.lang.Exception</CODE> that occurred when trying to invoke the
* object's constructor.
* @exception MBeanException The constructor of the object has thrown an
* exception
* @exception InstanceNotFoundException The specified class loader is not
* registered in the MBean Interceptor.
* @exception RuntimeOperationsException Wraps a
* <CODE>java.lang.IllegalArgumentException</CODE>: the className passed in
* parameter is null.
*/
public Object instantiate(String className,
ObjectName loaderName,
Object params[],
String signature[],
ClassLoader loader)
throws ReflectionException,
MBeanException,
InstanceNotFoundException {
// ------------------------------
// ------------------------------
Class<?> theClass;
if (loaderName == null) {
theClass = findClass(className, loader);
} else {
theClass = findClass(className, loaderName);
}
return instantiate(theClass, params, signature, loader);
}
/**
* Return the Default Loader Repository used by this instantiator object.
**/
public ModifiableClassLoaderRepository getClassLoaderRepository() {
checkMBeanPermission((String)null, null, null, "getClassLoaderRepository");
return clr;
}
/**
* 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)
throws ReflectionException {
Class<?> theClass;
if (className == null) {
throw new RuntimeOperationsException(new
IllegalArgumentException("The class name cannot be null"),
"Exception occurred during object instantiation");
}
ReflectUtil.checkPackageAccess(className);
try {
if (loader == null)
loader = MBeanInstantiator.class.getClassLoader();
if (loader != null) {
theClass = Class.forName(className, false, loader);
} else {
theClass = Class.forName(className);
}
} catch (ClassNotFoundException e) {
throw new ReflectionException(e,
"The MBean class could not be loaded");
}
return theClass;
}
/**
* Load the classes specified in the signature with the given loader,
* or with this object class 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];
if (length == 0) return tab;
try {
for (int i= 0; i < length; i++) {
// Start handling primitive types (int. boolean and so
// forth)
//
final Class<?> primCla = primitiveClasses.get(signature[i]);
if (primCla != null) {
tab[i] = primCla;
continue;
}
// Ok we do not have a primitive type ! We need to build
// the signature of the method
//
// We need to load the class through the class
// loader of the target object.
//
ReflectUtil.checkPackageAccess(signature[i]);
tab[i] = Class.forName(signature[i], false, aLoader);
}
} catch (ClassNotFoundException e) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
MBEANSERVER_LOGGER.logp(Level.FINEST,
MBeanInstantiator.class.getName(),
"findSignatureClasses",
"The parameter class could not be found", e);
}
throw new ReflectionException(e,
"The parameter class could not be found");
} catch (RuntimeException e) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
MBEANSERVER_LOGGER.logp(Level.FINEST,
MBeanInstantiator.class.getName(),
"findSignatureClasses",
"Unexpected exception", e);
}
throw e;
}
return tab;
}
private Constructor<?> findConstructor(Class<?> c, Class<?>[] params) {
try {
return ConstructorUtil.getConstructor(c, params);
} catch (Exception e) {
return null;
}
}
private static final Map<String, Class<?>> primitiveClasses = Util.newMap();
static {
for (Class<?> c : new Class<?>[] {byte.class, short.class, int.class,
long.class, float.class, double.class,
char.class, boolean.class})
primitiveClasses.put(c.getName(), c);
}
private static void checkMBeanPermission(Class<?> clazz,
String member,
ObjectName objectName,
String actions) {
if (clazz != null) {
checkMBeanPermission(clazz.getName(), member, objectName, actions);
}
}
private static void checkMBeanPermission(String classname,
String member,
ObjectName objectName,
String actions)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm = new MBeanPermission(classname,
member,
objectName,
actions);
sm.checkPermission(perm);
}
}
private static void ensureClassAccess(Class clazz)
throws IllegalAccessException
{
int mod = clazz.getModifiers();
if (!Modifier.isPublic(mod)) {
throw new IllegalAccessException("Class is not public and can't be instantiated");
}
}
private ClassLoader getClassLoader(final ObjectName name) {
if(clr == null){
return null;
}
// Restrict to getClassLoader permission only
Permissions permissions = new Permissions();
permissions.add(new MBeanPermission("*", null, name, "getClassLoader"));
ProtectionDomain protectionDomain = new ProtectionDomain(null, permissions);
ProtectionDomain[] domains = {protectionDomain};
AccessControlContext ctx = new AccessControlContext(domains);
ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return clr.getClassLoader(name);
}
}, ctx);
return loader;
}
}

View File

@@ -0,0 +1,471 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.WeakHashMap;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.ReflectionException;
import sun.reflect.misc.ReflectUtil;
/**
* An introspector for MBeans of a certain type. There is one instance
* of this class for Standard MBeans, and one for every MXBeanMappingFactory;
* these two cases correspond to the two concrete subclasses of this abstract
* class.
*
* @param <M> the representation of methods for this kind of MBean:
* Method for Standard MBeans, ConvertingMethod for MXBeans.
*
* @since 1.6
*/
/*
* Using a type parameter <M> allows us to deal with the fact that
* Method and ConvertingMethod have no useful common ancestor, on
* which we could call getName, getGenericReturnType, etc. A simpler approach
* would be to wrap every Method in an object that does have a common
* ancestor with ConvertingMethod. But that would mean an extra object
* for every Method in every Standard MBean interface.
*/
abstract class MBeanIntrospector<M> {
static final class PerInterfaceMap<M>
extends WeakHashMap<Class<?>, WeakReference<PerInterface<M>>> {}
/** The map from interface to PerInterface for this type of MBean. */
abstract PerInterfaceMap<M> getPerInterfaceMap();
/**
* The map from concrete implementation class and interface to
* MBeanInfo for this type of MBean.
*/
abstract MBeanInfoMap getMBeanInfoMap();
/** Make an interface analyzer for this type of MBean. */
abstract MBeanAnalyzer<M> getAnalyzer(Class<?> mbeanInterface)
throws NotCompliantMBeanException;
/** True if MBeans with this kind of introspector are MXBeans. */
abstract boolean isMXBean();
/** Find the M corresponding to the given Method. */
abstract M mFrom(Method m);
/** Get the name of this method. */
abstract String getName(M m);
/**
* Get the return type of this method. This is the return type
* of a method in a Java interface, so for MXBeans it is the
* declared Java type, not the mapped Open Type.
*/
abstract Type getGenericReturnType(M m);
/**
* Get the parameter types of this method in the Java interface
* it came from.
*/
abstract Type[] getGenericParameterTypes(M m);
/**
* Get the signature of this method as a caller would have to supply
* it in MBeanServer.invoke. For MXBeans, the named types will be
* the mapped Open Types for the parameters.
*/
abstract String[] getSignature(M m);
/**
* Check that this method is valid. For example, a method in an
* MXBean interface is not valid if one of its parameters cannot be
* mapped to an Open Type.
*/
abstract void checkMethod(M m);
/**
* Invoke the method with the given target and arguments.
*
* @param cookie Additional information about the target. For an
* MXBean, this is the MXBeanLookup associated with the MXBean.
*/
/*
* It would be cleaner if the type of the cookie were a
* type parameter to this class, but that would involve a lot of
* messy type parameter propagation just to avoid a couple of casts.
*/
abstract Object invokeM2(M m, Object target, Object[] args, Object cookie)
throws InvocationTargetException, IllegalAccessException,
MBeanException;
/**
* Test whether the given value is valid for the given parameter of this
* M.
*/
abstract boolean validParameter(M m, Object value, int paramNo,
Object cookie);
/**
* Construct an MBeanAttributeInfo for the given attribute based on the
* given getter and setter. One but not both of the getter and setter
* may be null.
*/
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
M getter, M setter);
/**
* Construct an MBeanOperationInfo for the given operation based on
* the M it was derived from.
*/
abstract MBeanOperationInfo getMBeanOperationInfo(String operationName,
M operation);
/**
* Get a Descriptor containing fields that MBeans of this kind will
* always have. For example, MXBeans will always have "mxbean=true".
*/
abstract Descriptor getBasicMBeanDescriptor();
/**
* Get a Descriptor containing additional fields beyond the ones
* from getBasicMBeanDescriptor that MBeans whose concrete class
* is resourceClass will always have.
*/
abstract Descriptor getMBeanDescriptor(Class<?> resourceClass);
/**
* Get the methods to be analyzed to build the MBean interface.
*/
final List<Method> getMethods(final Class<?> mbeanType) {
ReflectUtil.checkPackageAccess(mbeanType);
return Arrays.asList(mbeanType.getMethods());
}
final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
throws NotCompliantMBeanException {
PerInterfaceMap<M> map = getPerInterfaceMap();
synchronized (map) {
WeakReference<PerInterface<M>> wr = map.get(mbeanInterface);
PerInterface<M> pi = (wr == null) ? null : wr.get();
if (pi == null) {
try {
MBeanAnalyzer<M> analyzer = getAnalyzer(mbeanInterface);
MBeanInfo mbeanInfo =
makeInterfaceMBeanInfo(mbeanInterface, analyzer);
pi = new PerInterface<M>(mbeanInterface, this, analyzer,
mbeanInfo);
wr = new WeakReference<PerInterface<M>>(pi);
map.put(mbeanInterface, wr);
} catch (Exception x) {
throw Introspector.throwException(mbeanInterface,x);
}
}
return pi;
}
}
/**
* Make the MBeanInfo skeleton for the given MBean interface using
* the given analyzer. This will never be the MBeanInfo of any real
* MBean (because the getClassName() must be a concrete class), but
* its MBeanAttributeInfo[] and MBeanOperationInfo[] can be inserted
* into such an MBeanInfo, and its Descriptor can be the basis for
* the MBeanInfo's Descriptor.
*/
private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
MBeanAnalyzer<M> analyzer) {
final MBeanInfoMaker maker = new MBeanInfoMaker();
analyzer.visit(maker);
final String description =
"Information on the management interface of the MBean";
return maker.makeMBeanInfo(mbeanInterface, description);
}
/** True if the given getter and setter are consistent. */
final boolean consistent(M getter, M setter) {
return (getter == null || setter == null ||
getGenericReturnType(getter).equals(getGenericParameterTypes(setter)[0]));
}
/**
* Invoke the given M on the given target with the given args and cookie.
* Wrap exceptions appropriately.
*/
final Object invokeM(M m, Object target, Object[] args, Object cookie)
throws MBeanException, ReflectionException {
try {
return invokeM2(m, target, args, cookie);
} catch (InvocationTargetException e) {
unwrapInvocationTargetException(e);
throw new RuntimeException(e); // not reached
} catch (IllegalAccessException e) {
throw new ReflectionException(e, e.toString());
}
/* We do not catch and wrap RuntimeException or Error,
* because we're in a DynamicMBean, so the logic for DynamicMBeans
* will do the wrapping.
*/
}
/**
* Invoke the given setter on the given target with the given argument
* and cookie. Wrap exceptions appropriately.
*/
/* If the value is of the wrong type for the method we are about to
* invoke, we are supposed to throw an InvalidAttributeValueException.
* Rather than making the check always, we invoke the method, then
* if it throws an exception we check the type to see if that was
* what caused the exception. The assumption is that an exception
* from an invalid type will arise before any user method is ever
* called (either in reflection or in OpenConverter).
*/
final void invokeSetter(String name, M setter, Object target, Object arg,
Object cookie)
throws MBeanException, ReflectionException,
InvalidAttributeValueException {
try {
invokeM2(setter, target, new Object[] {arg}, cookie);
} catch (IllegalAccessException e) {
throw new ReflectionException(e, e.toString());
} catch (RuntimeException e) {
maybeInvalidParameter(name, setter, arg, cookie);
throw e;
} catch (InvocationTargetException e) {
maybeInvalidParameter(name, setter, arg, cookie);
unwrapInvocationTargetException(e);
}
}
private void maybeInvalidParameter(String name, M setter, Object arg,
Object cookie)
throws InvalidAttributeValueException {
if (!validParameter(setter, arg, 0, cookie)) {
final String msg =
"Invalid value for attribute " + name + ": " + arg;
throw new InvalidAttributeValueException(msg);
}
}
static boolean isValidParameter(Method m, Object value, int paramNo) {
Class<?> c = m.getParameterTypes()[paramNo];
try {
// Following is expensive but we only call this method to determine
// if an exception is due to an incompatible parameter type.
// Plain old c.isInstance doesn't work for primitive types.
Object a = Array.newInstance(c, 1);
Array.set(a, 0, value);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
private static void
unwrapInvocationTargetException(InvocationTargetException e)
throws MBeanException {
Throwable t = e.getCause();
if (t instanceof RuntimeException)
throw (RuntimeException) t;
else if (t instanceof Error)
throw (Error) t;
else
throw new MBeanException((Exception) t,
(t == null ? null : t.toString()));
}
/** A visitor that constructs the per-interface MBeanInfo. */
private class MBeanInfoMaker
implements MBeanAnalyzer.MBeanVisitor<M> {
public void visitAttribute(String attributeName,
M getter,
M setter) {
MBeanAttributeInfo mbai =
getMBeanAttributeInfo(attributeName, getter, setter);
attrs.add(mbai);
}
public void visitOperation(String operationName,
M operation) {
MBeanOperationInfo mboi =
getMBeanOperationInfo(operationName, operation);
ops.add(mboi);
}
/** Make an MBeanInfo based on the attributes and operations
* found in the interface. */
MBeanInfo makeMBeanInfo(Class<?> mbeanInterface,
String description) {
final MBeanAttributeInfo[] attrArray =
attrs.toArray(new MBeanAttributeInfo[0]);
final MBeanOperationInfo[] opArray =
ops.toArray(new MBeanOperationInfo[0]);
final String interfaceClassName =
"interfaceClassName=" + mbeanInterface.getName();
final Descriptor classNameDescriptor =
new ImmutableDescriptor(interfaceClassName);
final Descriptor mbeanDescriptor = getBasicMBeanDescriptor();
final Descriptor annotatedDescriptor =
Introspector.descriptorForElement(mbeanInterface);
final Descriptor descriptor =
DescriptorCache.getInstance().union(
classNameDescriptor,
mbeanDescriptor,
annotatedDescriptor);
return new MBeanInfo(mbeanInterface.getName(),
description,
attrArray,
null,
opArray,
null,
descriptor);
}
private final List<MBeanAttributeInfo> attrs = newList();
private final List<MBeanOperationInfo> ops = newList();
}
/*
* Looking up the MBeanInfo for a given base class (implementation class)
* is complicated by the fact that we may use the same base class with
* several different explicit MBean interfaces via the
* javax.management.StandardMBean class. It is further complicated
* by the fact that we have to be careful not to retain a strong reference
* to any Class object for fear we would prevent a ClassLoader from being
* garbage-collected. So we have a first lookup from the base class
* to a map for each interface that base class might specify giving
* the MBeanInfo constructed for that base class and interface.
*/
static class MBeanInfoMap
extends WeakHashMap<Class<?>, WeakHashMap<Class<?>, MBeanInfo>> {
}
/**
* Return the MBeanInfo for the given resource, based on the given
* per-interface data.
*/
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface) {
MBeanInfo mbi =
getClassMBeanInfo(resource.getClass(), perInterface);
MBeanNotificationInfo[] notifs = findNotifications(resource);
if (notifs == null || notifs.length == 0)
return mbi;
else {
return new MBeanInfo(mbi.getClassName(),
mbi.getDescription(),
mbi.getAttributes(),
mbi.getConstructors(),
mbi.getOperations(),
notifs,
mbi.getDescriptor());
}
}
/**
* Return the basic MBeanInfo for resources of the given class and
* per-interface data. This MBeanInfo might not be the final MBeanInfo
* for instances of the class, because if the class is a
* NotificationBroadcaster then each instance gets to decide what
* MBeanNotificationInfo[] to put in its own MBeanInfo.
*/
final MBeanInfo getClassMBeanInfo(Class<?> resourceClass,
PerInterface<M> perInterface) {
MBeanInfoMap map = getMBeanInfoMap();
synchronized (map) {
WeakHashMap<Class<?>, MBeanInfo> intfMap = map.get(resourceClass);
if (intfMap == null) {
intfMap = new WeakHashMap<Class<?>, MBeanInfo>();
map.put(resourceClass, intfMap);
}
Class<?> intfClass = perInterface.getMBeanInterface();
MBeanInfo mbi = intfMap.get(intfClass);
if (mbi == null) {
MBeanInfo imbi = perInterface.getMBeanInfo();
Descriptor descriptor =
ImmutableDescriptor.union(imbi.getDescriptor(),
getMBeanDescriptor(resourceClass));
mbi = new MBeanInfo(resourceClass.getName(),
imbi.getDescription(),
imbi.getAttributes(),
findConstructors(resourceClass),
imbi.getOperations(),
(MBeanNotificationInfo[]) null,
descriptor);
intfMap.put(intfClass, mbi);
}
return mbi;
}
}
static MBeanNotificationInfo[] findNotifications(Object moi) {
if (!(moi instanceof NotificationBroadcaster))
return null;
MBeanNotificationInfo[] mbn =
((NotificationBroadcaster) moi).getNotificationInfo();
if (mbn == null)
return null;
MBeanNotificationInfo[] result =
new MBeanNotificationInfo[mbn.length];
for (int i = 0; i < mbn.length; i++) {
MBeanNotificationInfo ni = mbn[i];
if (ni.getClass() != MBeanNotificationInfo.class)
ni = (MBeanNotificationInfo) ni.clone();
result[i] = ni;
}
return result;
}
private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
Constructor<?>[] cons = c.getConstructors();
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
for (int i = 0; i < cons.length; i++) {
final String descr = "Public constructor of the MBean";
mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
}
return mbc;
}
}

View File

@@ -0,0 +1,321 @@
/*
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.util.logging.Level;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
/**
* This class is the MBean implementation of the MBeanServerDelegate.
*
* @since 1.5
*/
final class MBeanServerDelegateImpl
extends MBeanServerDelegate
implements DynamicMBean, MBeanRegistration {
final private static String[] attributeNames = new String[] {
"MBeanServerId",
"SpecificationName",
"SpecificationVersion",
"SpecificationVendor",
"ImplementationName",
"ImplementationVersion",
"ImplementationVendor"
};
private static final MBeanAttributeInfo[] attributeInfos =
new MBeanAttributeInfo[] {
new MBeanAttributeInfo("MBeanServerId","java.lang.String",
"The MBean server agent identification",
true,false,false),
new MBeanAttributeInfo("SpecificationName","java.lang.String",
"The full name of the JMX specification "+
"implemented by this product.",
true,false,false),
new MBeanAttributeInfo("SpecificationVersion","java.lang.String",
"The version of the JMX specification "+
"implemented by this product.",
true,false,false),
new MBeanAttributeInfo("SpecificationVendor","java.lang.String",
"The vendor of the JMX specification "+
"implemented by this product.",
true,false,false),
new MBeanAttributeInfo("ImplementationName","java.lang.String",
"The JMX implementation name "+
"(the name of this product)",
true,false,false),
new MBeanAttributeInfo("ImplementationVersion","java.lang.String",
"The JMX implementation version "+
"(the version of this product).",
true,false,false),
new MBeanAttributeInfo("ImplementationVendor","java.lang.String",
"the JMX implementation vendor "+
"(the vendor of this product).",
true,false,false)
};
private final MBeanInfo delegateInfo;
public MBeanServerDelegateImpl () {
super();
delegateInfo =
new MBeanInfo("javax.management.MBeanServerDelegate",
"Represents the MBean server from the management "+
"point of view.",
MBeanServerDelegateImpl.attributeInfos, null,
null,getNotificationInfo());
}
final public ObjectName preRegister (MBeanServer server, ObjectName name)
throws java.lang.Exception {
if (name == null) return DELEGATE_NAME;
else return name;
}
final public void postRegister (Boolean registrationDone) {
}
final public void preDeregister()
throws java.lang.Exception {
throw new IllegalArgumentException(
"The MBeanServerDelegate MBean cannot be unregistered");
}
final public void postDeregister() {
}
/**
* Obtains the value of a specific attribute of the MBeanServerDelegate.
*
* @param attribute The name of the attribute to be retrieved
*
* @return The value of the attribute retrieved.
*
* @exception AttributeNotFoundException
* @exception MBeanException
* Wraps a <CODE>java.lang.Exception</CODE> thrown by the
* MBean's getter.
*/
public Object getAttribute(String attribute)
throws AttributeNotFoundException,
MBeanException, ReflectionException {
try {
// attribute must not be null
//
if (attribute == null)
throw new AttributeNotFoundException("null");
// Extract the requested attribute from file
//
if (attribute.equals("MBeanServerId"))
return getMBeanServerId();
else if (attribute.equals("SpecificationName"))
return getSpecificationName();
else if (attribute.equals("SpecificationVersion"))
return getSpecificationVersion();
else if (attribute.equals("SpecificationVendor"))
return getSpecificationVendor();
else if (attribute.equals("ImplementationName"))
return getImplementationName();
else if (attribute.equals("ImplementationVersion"))
return getImplementationVersion();
else if (attribute.equals("ImplementationVendor"))
return getImplementationVendor();
// Unknown attribute
//
else
throw new AttributeNotFoundException("null");
} catch (AttributeNotFoundException x) {
throw x;
} catch (JMRuntimeException j) {
throw j;
} catch (SecurityException s) {
throw s;
} catch (Exception x) {
throw new MBeanException(x,"Failed to get " + attribute);
}
}
/**
* This method always fail since all MBeanServerDelegateMBean attributes
* are read-only.
*
* @param attribute The identification of the attribute to
* be set and the value it is to be set to.
*
* @exception AttributeNotFoundException
*/
public void setAttribute(Attribute attribute)
throws AttributeNotFoundException, InvalidAttributeValueException,
MBeanException, ReflectionException {
// Now we will always fail:
// Either because the attribute is null or because it is not
// accessible (or does not exist).
//
final String attname = (attribute==null?null:attribute.getName());
if (attname == null) {
final RuntimeException r =
new IllegalArgumentException("Attribute name cannot be null");
throw new RuntimeOperationsException(r,
"Exception occurred trying to invoke the setter on the MBean");
}
// This is a hack: we call getAttribute in order to generate an
// AttributeNotFoundException if the attribute does not exist.
//
Object val = getAttribute(attname);
// If we reach this point, we know that the requested attribute
// exists. However, since all attributes are read-only, we throw
// an AttributeNotFoundException.
//
throw new AttributeNotFoundException(attname + " not accessible");
}
/**
* Makes it possible to get the values of several attributes of
* the MBeanServerDelegate.
*
* @param attributes A list of the attributes to be retrieved.
*
* @return The list of attributes retrieved.
*
*/
public AttributeList getAttributes(String[] attributes) {
// If attributes is null, the get all attributes.
//
final String[] attn = (attributes==null?attributeNames:attributes);
// Prepare the result list.
//
final int len = attn.length;
final AttributeList list = new AttributeList(len);
// Get each requested attribute.
//
for (int i=0;i<len;i++) {
try {
final Attribute a =
new Attribute(attn[i],getAttribute(attn[i]));
list.add(a);
} catch (Exception x) {
// Skip the attribute that couldn't be obtained.
//
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
MBEANSERVER_LOGGER.logp(Level.FINEST,
MBeanServerDelegateImpl.class.getName(),
"getAttributes",
"Attribute " + attn[i] + " not found");
}
}
}
// Finally return the result.
//
return list;
}
/**
* This method always return an empty list since all
* MBeanServerDelegateMBean attributes are read-only.
*
* @param attributes A list of attributes: The identification of the
* attributes to be set and the values they are to be set to.
*
* @return The list of attributes that were set, with their new values.
* In fact, this method always return an empty list since all
* MBeanServerDelegateMBean attributes are read-only.
*/
public AttributeList setAttributes(AttributeList attributes) {
return new AttributeList(0);
}
/**
* Always fails since the MBeanServerDelegate MBean has no operation.
*
* @param actionName The name of the action to be invoked.
* @param params An array containing the parameters to be set when the
* action is invoked.
* @param signature An array containing the signature of the action.
*
* @return The object returned by the action, which represents
* the result of invoking the action on the MBean specified.
*
* @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE>
* thrown by the MBean's invoked method.
* @exception ReflectionException Wraps a
* <CODE>java.lang.Exception</CODE> thrown while trying to invoke
* the method.
*/
public Object invoke(String actionName, Object params[],
String signature[])
throws MBeanException, ReflectionException {
// Check that operation name is not null.
//
if (actionName == null) {
final RuntimeException r =
new IllegalArgumentException("Operation name cannot be null");
throw new RuntimeOperationsException(r,
"Exception occurred trying to invoke the operation on the MBean");
}
throw new ReflectionException(
new NoSuchMethodException(actionName),
"The operation with name " + actionName +
" could not be found");
}
/**
* Provides the MBeanInfo describing the MBeanServerDelegate.
*
* @return The MBeanInfo describing the MBeanServerDelegate.
*
*/
public MBeanInfo getMBeanInfo() {
return delegateInfo;
}
}

View File

@@ -0,0 +1,276 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import com.sun.jmx.mbeanserver.MXBeanMappingFactory;
import sun.reflect.misc.ReflectUtil;
/**
* Base class for MBeans. There is one instance of this class for
* every Standard MBean and every MXBean. We try to limit the amount
* of information per instance so we can handle very large numbers of
* MBeans comfortably.
*
* @param <M> either Method or ConvertingMethod, for Standard MBeans
* and MXBeans respectively.
*
* @since 1.6
*/
/*
* We maintain a couple of caches to increase sharing between
* different MBeans of the same type and also to reduce creation time
* for the second and subsequent instances of the same type.
*
* The first cache maps from an MBean interface to a PerInterface
* object containing information parsed out of the interface. The
* interface is either a Standard MBean interface or an MXBean
* interface, and there is one cache for each case.
*
* The PerInterface includes an MBeanInfo. This contains the
* attributes and operations parsed out of the interface's methods,
* plus a basic Descriptor for the interface containing at least the
* interfaceClassName field and any fields derived from annotations on
* the interface. This MBeanInfo can never be the MBeanInfo for any
* actual MBean, because an MBeanInfo's getClassName() is the name of
* a concrete class and we don't know what the class will be.
* Furthermore a real MBeanInfo may need to add constructors and/or
* notifications to the MBeanInfo.
*
* The PerInterface also contains an MBeanDispatcher which is able to
* route getAttribute, setAttribute, and invoke to the appropriate
* method of the interface, including doing any necessary translation
* of parameters and return values for MXBeans.
*
* The PerInterface also contains the original Class for the interface.
*
* We need to be careful about references. When there are no MBeans
* with a given interface, there must not be any strong references to
* the interface Class. Otherwise it could never be garbage collected,
* and neither could its ClassLoader or any other classes loaded by
* its ClassLoader. Therefore the cache must wrap the PerInterface
* in a WeakReference. Each instance of MBeanSupport has a strong
* reference to its PerInterface, which prevents PerInterface instances
* from being garbage-collected prematurely.
*
* The second cache maps from a concrete class and an MBean interface
* that that class implements to the MBeanInfo for that class and
* interface. (The ability to specify an interface separately comes
* from the class StandardMBean. MBeans registered directly in the
* MBean Server will always have the same interface here.)
*
* The MBeanInfo in this second cache will be the MBeanInfo from the
* PerInterface cache for the given itnerface, but with the
* getClassName() having the concrete class's name, and the public
* constructors based on the concrete class's constructors. This
* MBeanInfo can be shared between all instances of the concrete class
* specifying the same interface, except instances that are
* NotificationBroadcasters. NotificationBroadcasters supply the
* MBeanNotificationInfo[] in the MBeanInfo based on the instance
* method NotificationBroadcaster.getNotificationInfo(), so two
* instances of the same concrete class do not necessarily have the
* same MBeanNotificationInfo[]. Currently we do not try to detect
* when they do, although it would probably be worthwhile doing that
* since it is a very common case.
*
* Standard MBeans additionally have the property that
* getNotificationInfo() must in principle be called every time
* getMBeanInfo() is called for the MBean, since the returned array is
* allowed to change over time. We attempt to reduce the cost of
* doing this by detecting when the Standard MBean is a subclass of
* NotificationBroadcasterSupport that does not override
* getNotificationInfo(), meaning that the MBeanNotificationInfo[] is
* the one that was supplied to the constructor. MXBeans do not have
* this problem because their getNotificationInfo() method is called
* only once.
*
*/
public abstract class MBeanSupport<M>
implements DynamicMBean2, MBeanRegistration {
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType)
throws NotCompliantMBeanException {
if (mbeanInterfaceType == null)
throw new NotCompliantMBeanException("Null MBean interface");
if (!mbeanInterfaceType.isInstance(resource)) {
final String msg =
"Resource class " + resource.getClass().getName() +
" is not an instance of " + mbeanInterfaceType.getName();
throw new NotCompliantMBeanException(msg);
}
ReflectUtil.checkPackageAccess(mbeanInterfaceType);
this.resource = resource;
MBeanIntrospector<M> introspector = getMBeanIntrospector();
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
}
/** Return the appropriate introspector for this type of MBean. */
abstract MBeanIntrospector<M> getMBeanIntrospector();
/**
* Return a cookie for this MBean. This cookie will be passed to
* MBean method invocations where it can supply additional information
* to the invocation. For example, with MXBeans it can be used to
* supply the MXBeanLookup context for resolving inter-MXBean references.
*/
abstract Object getCookie();
public final boolean isMXBean() {
return perInterface.isMXBean();
}
// Methods that javax.management.StandardMBean should call from its
// preRegister and postRegister, given that it is not supposed to
// call the contained object's preRegister etc methods even if it has them
public abstract void register(MBeanServer mbs, ObjectName name)
throws Exception;
public abstract void unregister();
public final ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception {
if (resource instanceof MBeanRegistration)
name = ((MBeanRegistration) resource).preRegister(server, name);
return name;
}
public final void preRegister2(MBeanServer server, ObjectName name)
throws Exception {
register(server, name);
}
public final void registerFailed() {
unregister();
}
public final void postRegister(Boolean registrationDone) {
if (resource instanceof MBeanRegistration)
((MBeanRegistration) resource).postRegister(registrationDone);
}
public final void preDeregister() throws Exception {
if (resource instanceof MBeanRegistration)
((MBeanRegistration) resource).preDeregister();
}
public final void postDeregister() {
// Undo any work from registration. We do this in postDeregister
// not preDeregister, because if the user preDeregister throws an
// exception then the MBean is not unregistered.
try {
unregister();
} finally {
if (resource instanceof MBeanRegistration)
((MBeanRegistration) resource).postDeregister();
}
}
public final Object getAttribute(String attribute)
throws AttributeNotFoundException,
MBeanException,
ReflectionException {
return perInterface.getAttribute(resource, attribute, getCookie());
}
public final AttributeList getAttributes(String[] attributes) {
final AttributeList result = new AttributeList(attributes.length);
for (String attrName : attributes) {
try {
final Object attrValue = getAttribute(attrName);
result.add(new Attribute(attrName, attrValue));
} catch (Exception e) {
// OK: attribute is not included in returned list, per spec
// XXX: log the exception
}
}
return result;
}
public final void setAttribute(Attribute attribute)
throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
final String name = attribute.getName();
final Object value = attribute.getValue();
perInterface.setAttribute(resource, name, value, getCookie());
}
public final AttributeList setAttributes(AttributeList attributes) {
final AttributeList result = new AttributeList(attributes.size());
for (Object attrObj : attributes) {
// We can't use AttributeList.asList because it has side-effects
Attribute attr = (Attribute) attrObj;
try {
setAttribute(attr);
result.add(new Attribute(attr.getName(), attr.getValue()));
} catch (Exception e) {
// OK: attribute is not included in returned list, per spec
// XXX: log the exception
}
}
return result;
}
public final Object invoke(String operation, Object[] params,
String[] signature)
throws MBeanException, ReflectionException {
return perInterface.invoke(resource, operation, params, signature,
getCookie());
}
// Overridden by StandardMBeanSupport
public MBeanInfo getMBeanInfo() {
return mbeanInfo;
}
public final String getClassName() {
return resource.getClass().getName();
}
public final Object getResource() {
return resource;
}
public final Class<?> getMBeanInterface() {
return perInterface.getMBeanInterface();
}
private final MBeanInfo mbeanInfo;
private final Object resource;
private final PerInterface<M> perInterface;
}

View File

@@ -0,0 +1,365 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import com.sun.jmx.mbeanserver.MBeanIntrospector.MBeanInfoMap;
import com.sun.jmx.mbeanserver.MBeanIntrospector.PerInterfaceMap;
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
import javax.management.openmbean.OpenMBeanParameterInfo;
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
import javax.management.openmbean.OpenType;
/**
* Introspector for MXBeans. There is exactly one instance of this class.
*
* @since 1.6
*/
class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
private static final MXBeanIntrospector instance = new MXBeanIntrospector();
static MXBeanIntrospector getInstance() {
return instance;
}
@Override
PerInterfaceMap<ConvertingMethod> getPerInterfaceMap() {
return perInterfaceMap;
}
@Override
MBeanInfoMap getMBeanInfoMap() {
return mbeanInfoMap;
}
@Override
MBeanAnalyzer<ConvertingMethod> getAnalyzer(Class<?> mbeanInterface)
throws NotCompliantMBeanException {
return MBeanAnalyzer.analyzer(mbeanInterface, this);
}
@Override
boolean isMXBean() {
return true;
}
@Override
ConvertingMethod mFrom(Method m) {
return ConvertingMethod.from(m);
}
@Override
String getName(ConvertingMethod m) {
return m.getName();
}
@Override
Type getGenericReturnType(ConvertingMethod m) {
return m.getGenericReturnType();
}
@Override
Type[] getGenericParameterTypes(ConvertingMethod m) {
return m.getGenericParameterTypes();
}
@Override
String[] getSignature(ConvertingMethod m) {
return m.getOpenSignature();
}
@Override
void checkMethod(ConvertingMethod m) {
m.checkCallFromOpen();
}
@Override
Object invokeM2(ConvertingMethod m, Object target, Object[] args,
Object cookie)
throws InvocationTargetException, IllegalAccessException,
MBeanException {
return m.invokeWithOpenReturn((MXBeanLookup) cookie, target, args);
}
@Override
boolean validParameter(ConvertingMethod m, Object value, int paramNo,
Object cookie) {
if (value == null) {
// Null is a valid value for all OpenTypes, even though
// OpenType.isValue(null) will return false. It can always be
// matched to the corresponding Java type, except when that
// type is primitive.
Type t = m.getGenericParameterTypes()[paramNo];
return (!(t instanceof Class<?>) || !((Class<?>) t).isPrimitive());
} else {
Object v;
try {
v = m.fromOpenParameter((MXBeanLookup) cookie, value, paramNo);
} catch (Exception e) {
// Ignore the exception and let MBeanIntrospector.invokeSetter()
// throw the initial exception.
return true;
}
return isValidParameter(m.getMethod(), v, paramNo);
}
}
@Override
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
ConvertingMethod getter, ConvertingMethod setter) {
final boolean isReadable = (getter != null);
final boolean isWritable = (setter != null);
final boolean isIs = isReadable && getName(getter).startsWith("is");
final String description = attributeName;
final OpenType<?> openType;
final Type originalType;
if (isReadable) {
openType = getter.getOpenReturnType();
originalType = getter.getGenericReturnType();
} else {
openType = setter.getOpenParameterTypes()[0];
originalType = setter.getGenericParameterTypes()[0];
}
Descriptor descriptor = typeDescriptor(openType, originalType);
if (isReadable) {
descriptor = ImmutableDescriptor.union(descriptor,
getter.getDescriptor());
}
if (isWritable) {
descriptor = ImmutableDescriptor.union(descriptor,
setter.getDescriptor());
}
final MBeanAttributeInfo ai;
if (canUseOpenInfo(originalType)) {
ai = new OpenMBeanAttributeInfoSupport(attributeName,
description,
openType,
isReadable,
isWritable,
isIs,
descriptor);
} else {
ai = new MBeanAttributeInfo(attributeName,
originalTypeString(originalType),
description,
isReadable,
isWritable,
isIs,
descriptor);
}
// could also consult annotations for defaultValue,
// minValue, maxValue, legalValues
return ai;
}
@Override
MBeanOperationInfo getMBeanOperationInfo(String operationName,
ConvertingMethod operation) {
final Method method = operation.getMethod();
final String description = operationName;
/* Ideally this would be an empty string, but
OMBOperationInfo constructor forbids that. Also, we
could consult an annotation to get a useful
description. */
final int impact = MBeanOperationInfo.UNKNOWN;
final OpenType<?> returnType = operation.getOpenReturnType();
final Type originalReturnType = operation.getGenericReturnType();
final OpenType<?>[] paramTypes = operation.getOpenParameterTypes();
final Type[] originalParamTypes = operation.getGenericParameterTypes();
final MBeanParameterInfo[] params =
new MBeanParameterInfo[paramTypes.length];
boolean openReturnType = canUseOpenInfo(originalReturnType);
boolean openParameterTypes = true;
Annotation[][] annots = method.getParameterAnnotations();
for (int i = 0; i < paramTypes.length; i++) {
final String paramName = "p" + i;
final String paramDescription = paramName;
final OpenType<?> openType = paramTypes[i];
final Type originalType = originalParamTypes[i];
Descriptor descriptor =
typeDescriptor(openType, originalType);
descriptor = ImmutableDescriptor.union(descriptor,
Introspector.descriptorForAnnotations(annots[i]));
final MBeanParameterInfo pi;
if (canUseOpenInfo(originalType)) {
pi = new OpenMBeanParameterInfoSupport(paramName,
paramDescription,
openType,
descriptor);
} else {
openParameterTypes = false;
pi = new MBeanParameterInfo(
paramName,
originalTypeString(originalType),
paramDescription,
descriptor);
}
params[i] = pi;
}
Descriptor descriptor =
typeDescriptor(returnType, originalReturnType);
descriptor = ImmutableDescriptor.union(descriptor,
Introspector.descriptorForElement(method));
final MBeanOperationInfo oi;
if (openReturnType && openParameterTypes) {
/* If the return value and all the parameters can be faithfully
* represented as OpenType then we return an OpenMBeanOperationInfo.
* If any of them is a primitive type, we can't. Compatibility
* with JSR 174 means that we must return an MBean*Info where
* the getType() is the primitive type, not its wrapped type as
* we would get with an OpenMBean*Info. The OpenType is available
* in the Descriptor in either case.
*/
final OpenMBeanParameterInfo[] oparams =
new OpenMBeanParameterInfo[params.length];
System.arraycopy(params, 0, oparams, 0, params.length);
oi = new OpenMBeanOperationInfoSupport(operationName,
description,
oparams,
returnType,
impact,
descriptor);
} else {
oi = new MBeanOperationInfo(operationName,
description,
params,
openReturnType ?
returnType.getClassName() :
originalTypeString(originalReturnType),
impact,
descriptor);
}
return oi;
}
@Override
Descriptor getBasicMBeanDescriptor() {
return new ImmutableDescriptor("mxbean=true",
"immutableInfo=true");
}
@Override
Descriptor getMBeanDescriptor(Class<?> resourceClass) {
/* We already have immutableInfo=true in the Descriptor
* included in the MBeanInfo for the MXBean interface. This
* method is being called for the MXBean *class* to add any
* new items beyond those in the interface Descriptor, which
* currently it does not.
*/
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
}
private static Descriptor typeDescriptor(OpenType<?> openType,
Type originalType) {
return new ImmutableDescriptor(
new String[] {"openType",
"originalType"},
new Object[] {openType,
originalTypeString(originalType)});
}
/**
* <p>True if this type can be faithfully represented in an
* OpenMBean*Info.</p>
*
* <p>Compatibility with JSR 174 means that primitive types must be
* represented by an MBean*Info whose getType() is the primitive type
* string, e.g. "int". If we used an OpenMBean*Info then this string
* would be the wrapped type, e.g. "java.lang.Integer".</p>
*
* <p>Compatibility with JMX 1.2 (including J2SE 5.0) means that arrays
* of primitive types cannot use an ArrayType representing an array of
* primitives, because that didn't exist in JMX 1.2.</p>
*/
private static boolean canUseOpenInfo(Type type) {
if (type instanceof GenericArrayType) {
return canUseOpenInfo(
((GenericArrayType) type).getGenericComponentType());
} else if (type instanceof Class<?> && ((Class<?>) type).isArray()) {
return canUseOpenInfo(
((Class<?>) type).getComponentType());
}
return (!(type instanceof Class<?> && ((Class<?>) type).isPrimitive()));
}
private static String originalTypeString(Type type) {
if (type instanceof Class<?>)
return ((Class<?>) type).getName();
else
return typeName(type);
}
static String typeName(Type type) {
if (type instanceof Class<?>) {
Class<?> c = (Class<?>) type;
if (c.isArray())
return typeName(c.getComponentType()) + "[]";
else
return c.getName();
} else if (type instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) type;
return typeName(gat.getGenericComponentType()) + "[]";
} else if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
StringBuilder sb = new StringBuilder();
sb.append(typeName(pt.getRawType())).append("<");
String sep = "";
for (Type t : pt.getActualTypeArguments()) {
sb.append(sep).append(typeName(t));
sep = ", ";
}
return sb.append(">").toString();
} else
return "???";
}
private final PerInterfaceMap<ConvertingMethod>
perInterfaceMap = new PerInterfaceMap<ConvertingMethod>();
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.util.Map;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import javax.management.InstanceAlreadyExistsException;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.openmbean.OpenDataException;
/**
* @since 1.6
*/
/*
* This class handles the mapping between MXBean references and
* ObjectNames. Consider an MXBean interface like this:
*
* public interface ModuleMXBean {
* ProductMXBean getProduct();
* void setProduct(ProductMXBean product);
* }
*
* This defines an attribute called "Product" whose originalType will
* be ProductMXBean and whose openType will be ObjectName. The
* mapping happens as follows.
*
* When the MXBean's getProduct method is called, it is supposed to
* return a reference to another MXBean, or a proxy for another
* MXBean. The MXBean layer has to convert this into an ObjectName.
* If it's a reference to another MXBean, it needs to be able to look
* up the name under which that MXBean has been registered in this
* MBeanServer; this is the purpose of the mxbeanToObjectName map. If
* it's a proxy, it can check that the MBeanServer matches and if so
* extract the ObjectName from the proxy.
*
* When the setProduct method is called on a proxy for this MXBean,
* the argument can be either an MXBean reference (only really logical
* if the proxy has a local MBeanServer) or another proxy. So the
* mapping logic is the same as for getProduct on the MXBean.
*
* When the MXBean's setProduct method is called, it needs to convert
* the ObjectName into an object implementing the ProductMXBean
* interface. We could have a lookup table that reverses
* mxbeanToObjectName, but this could violate the general JMX property
* that you cannot obtain a reference to an MBean object. So we
* always use a proxy for this. However we do have an
* objectNameToProxy map that allows us to reuse proxy instances.
*
* When the getProduct method is called on a proxy for this MXBean, it
* must convert the returned ObjectName into an instance of
* ProductMXBean. Again it can do this by making a proxy.
*
* From the above, it is clear that the logic for getX on an MXBean is
* the same as for setX on a proxy, and vice versa.
*/
public class MXBeanLookup {
private MXBeanLookup(MBeanServerConnection mbsc) {
this.mbsc = mbsc;
}
static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
synchronized (mbscToLookup) {
WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
if (lookup == null) {
lookup = new MXBeanLookup(mbsc);
mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
}
return lookup;
}
}
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
WeakReference<Object> wr = objectNameToProxy.get(name);
if (wr != null) {
Object proxy = wr.get();
if (type.isInstance(proxy))
return type.cast(proxy);
}
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
return proxy;
}
synchronized ObjectName mxbeanToObjectName(Object mxbean)
throws OpenDataException {
String wrong;
if (mxbean instanceof Proxy) {
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
if (ih instanceof MBeanServerInvocationHandler) {
MBeanServerInvocationHandler mbsih =
(MBeanServerInvocationHandler) ih;
if (mbsih.getMBeanServerConnection().equals(mbsc))
return mbsih.getObjectName();
else
wrong = "proxy for a different MBeanServer";
} else
wrong = "not a JMX proxy";
} else {
ObjectName name = mxbeanToObjectName.get(mxbean);
if (name != null)
return name;
wrong = "not an MXBean registered in this MBeanServer";
}
String s = (mxbean == null) ?
"null" : "object of type " + mxbean.getClass().getName();
throw new OpenDataException(
"Could not convert " + s + " to an ObjectName: " + wrong);
// Message will be strange if mxbean is null but it is not
// supposed to be.
}
synchronized void addReference(ObjectName name, Object mxbean)
throws InstanceAlreadyExistsException {
ObjectName existing = mxbeanToObjectName.get(mxbean);
if (existing != null) {
String multiname = AccessController.doPrivileged(
new GetPropertyAction("jmx.mxbean.multiname"));
if (!"true".equalsIgnoreCase(multiname)) {
throw new InstanceAlreadyExistsException(
"MXBean already registered with name " + existing);
}
}
mxbeanToObjectName.put(mxbean, name);
}
synchronized boolean removeReference(ObjectName name, Object mxbean) {
if (name.equals(mxbeanToObjectName.get(mxbean))) {
mxbeanToObjectName.remove(mxbean);
return true;
} else
return false;
/* removeReference can be called when the above condition fails,
* notably if you try to register the same MXBean twice.
*/
}
static MXBeanLookup getLookup() {
return currentLookup.get();
}
static void setLookup(MXBeanLookup lookup) {
currentLookup.set(lookup);
}
private static final ThreadLocal<MXBeanLookup> currentLookup =
new ThreadLocal<MXBeanLookup>();
private final MBeanServerConnection mbsc;
private final WeakIdentityHashMap<Object, ObjectName>
mxbeanToObjectName = WeakIdentityHashMap.make();
private final Map<ObjectName, WeakReference<Object>>
objectNameToProxy = newMap();
private static final WeakIdentityHashMap<MBeanServerConnection,
WeakReference<MXBeanLookup>>
mbscToLookup = WeakIdentityHashMap.make();
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.io.InvalidObjectException;
import java.lang.reflect.Type;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
/**
* <p>A custom mapping between Java types and Open types for use in MXBeans.
* To define such a mapping, subclass this class and define at least the
* {@link #fromOpenValue fromOpenValue} and {@link #toOpenValue toOpenValue}
* methods, and optionally the {@link #checkReconstructible} method.
* Then either use an {@link MXBeanMappingClass} annotation on your custom
* Java types, or include this MXBeanMapping in an
* {@link MXBeanMappingFactory}.</p>
*
* <p>For example, suppose we have a class {@code MyLinkedList}, which looks
* like this:</p>
*
* <pre>
* public class MyLinkedList {
* public MyLinkedList(String name, MyLinkedList next) {...}
* public String getName() {...}
* public MyLinkedList getNext() {...}
* }
* </pre>
*
* <p>This is not a valid type for MXBeans, because it contains a
* self-referential property "next" defined by the {@code getNext()}
* method. MXBeans do not support recursive types. So we would like
* to specify a mapping for {@code MyLinkedList} explicitly. When an
* MXBean interface contains {@code MyLinkedList}, that will be mapped
* into a {@code String[]}, which is a valid Open Type.</p>
*
* <p>To define this mapping, we first subclass {@code MXBeanMapping}:</p>
*
* <pre>
* public class MyLinkedListMapping extends MXBeanMapping {
* public MyLinkedListMapping(Type type) throws OpenDataException {
* super(MyLinkedList.class, ArrayType.getArrayType(SimpleType.STRING));
* if (type != MyLinkedList.class)
* throw new OpenDataException("Mapping only valid for MyLinkedList");
* }
*
* {@literal @Override}
* public Object fromOpenValue(Object openValue) throws InvalidObjectException {
* String[] array = (String[]) openValue;
* MyLinkedList list = null;
* for (int i = array.length - 1; i &gt;= 0; i--)
* list = new MyLinkedList(array[i], list);
* return list;
* }
*
* {@literal @Override}
* public Object toOpenValue(Object javaValue) throws OpenDataException {
* ArrayList&lt;String&gt; array = new ArrayList&lt;String&gt;();
* for (MyLinkedList list = (MyLinkedList) javaValue; list != null;
* list = list.getNext())
* array.add(list.getName());
* return array.toArray(new String[0]);
* }
* }
* </pre>
*
* <p>The call to the superclass constructor specifies what the
* original Java type is ({@code MyLinkedList.class}) and what Open
* Type it is mapped to ({@code
* ArrayType.getArrayType(SimpleType.STRING)}). The {@code
* fromOpenValue} method says how we go from the Open Type ({@code
* String[]}) to the Java type ({@code MyLinkedList}), and the {@code
* toOpenValue} method says how we go from the Java type to the Open
* Type.</p>
*
* <p>With this mapping defined, we can annotate the {@code MyLinkedList}
* class appropriately:</p>
*
* <pre>
* {@literal @MXBeanMappingClass}(MyLinkedListMapping.class)
* public class MyLinkedList {...}
* </pre>
*
* <p>Now we can use {@code MyLinkedList} in an MXBean interface and it
* will work.</p>
*
* <p>If we are unable to modify the {@code MyLinkedList} class,
* we can define an {@link MXBeanMappingFactory}. See the documentation
* of that class for further details.</p>
*
* @see <a href="../MXBean.html#custom">MXBean specification, section
* "Custom MXBean type mappings"</a>
*/
public abstract class MXBeanMapping {
private final Type javaType;
private final OpenType<?> openType;
private final Class<?> openClass;
/**
* <p>Construct a mapping between the given Java type and the given
* Open Type.</p>
*
* @param javaType the Java type (for example, {@code MyLinkedList}).
* @param openType the Open Type (for example, {@code
* ArrayType.getArrayType(SimpleType.STRING)})
*
* @throws NullPointerException if either argument is null.
*/
protected MXBeanMapping(Type javaType, OpenType<?> openType) {
if (javaType == null || openType == null)
throw new NullPointerException("Null argument");
this.javaType = javaType;
this.openType = openType;
this.openClass = makeOpenClass(javaType, openType);
}
/**
* <p>The Java type that was supplied to the constructor.</p>
* @return the Java type that was supplied to the constructor.
*/
public final Type getJavaType() {
return javaType;
}
/**
* <p>The Open Type that was supplied to the constructor.</p>
* @return the Open Type that was supplied to the constructor.
*/
public final OpenType<?> getOpenType() {
return openType;
}
/**
* <p>The Java class that corresponds to instances of the
* {@linkplain #getOpenType() Open Type} for this mapping.</p>
* @return the Java class that corresponds to instances of the
* Open Type for this mapping.
* @see OpenType#getClassName
*/
public final Class<?> getOpenClass() {
return openClass;
}
private static Class<?> makeOpenClass(Type javaType, OpenType<?> openType) {
if (javaType instanceof Class<?> && ((Class<?>) javaType).isPrimitive())
return (Class<?>) javaType;
try {
String className = openType.getClassName();
return Class.forName(className, false, MXBeanMapping.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e); // should not happen
}
}
/**
* <p>Convert an instance of the Open Type into the Java type.
* @param openValue the value to be converted.
* @return the converted value.
* @throws InvalidObjectException if the value cannot be converted.
*/
public abstract Object fromOpenValue(Object openValue)
throws InvalidObjectException;
/**
* <p>Convert an instance of the Java type into the Open Type.
* @param javaValue the value to be converted.
* @return the converted value.
* @throws OpenDataException if the value cannot be converted.
*/
public abstract Object toOpenValue(Object javaValue)
throws OpenDataException;
/**
* <p>Throw an appropriate InvalidObjectException if we will not
* be able to convert back from the open data to the original Java
* object. The {@link #fromOpenValue fromOpenValue} throws an
* exception if a given open data value cannot be converted. This
* method throws an exception if <em>no</em> open data values can
* be converted. The default implementation of this method never
* throws an exception. Subclasses can override it as
* appropriate.</p>
* @throws InvalidObjectException if {@code fromOpenValue} will throw
* an exception no matter what its argument is.
*/
public void checkReconstructible() throws InvalidObjectException {}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2007, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.openmbean.*;
import com.sun.jmx.mbeanserver.MXBeanMapping;
import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
import java.lang.reflect.Type;
/**
* <p>Defines how types are mapped for a given MXBean or set of MXBeans.
* An {@code MXBeanMappingFactory} can be specified either through the
* {@link MXBeanMappingFactoryClass} annotation, or through the
* {@link javax.management.JMX.MBeanOptions JMX.MBeanOptions} argument to a
* {@link javax.management.StandardMBean StandardMBean} constructor or MXBean
* proxy.</p>
*
* <p>An {@code MXBeanMappingFactory} must return an {@code MXBeanMapping}
* for any Java type that appears in the MXBeans that the factory is being
* used for. Usually it does that by handling any custom types, and
* forwarding everything else to the {@linkplain #DEFAULT default mapping
* factory}.</p>
*
* <p>Consider the {@code MyLinkedList} example from the {@link MXBeanMapping}
* documentation. If we are unable to change the {@code MyLinkedList} class
* to add an {@link MXBeanMappingClass} annotation, we could achieve the same
* effect by defining {@code MyLinkedListMappingFactory} as follows:</p>
*
* <pre>
* public class MyLinkedListMappingFactory extends MXBeanMappingFactory {
* public MyLinkedListMappingFactory() {}
*
* public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
* throws OpenDataException {
* if (t == MyLinkedList.class)
* return new MyLinkedListMapping(t);
* else
* return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);
* }
* }
* </pre>
*
* <p>The mapping factory handles only the {@code MyLinkedList} class.
* Every other type is forwarded to the default mapping factory.
* This includes types such as {@code MyLinkedList[]} and
* {@code List<MyLinkedList>}; the default mapping factory will recursively
* invoke {@code MyLinkedListMappingFactory} to map the contained
* {@code MyLinkedList} type.</p>
*
* <p>Once we have defined {@code MyLinkedListMappingFactory}, we can use
* it in an MXBean interface like this:</p>
*
* <pre>
* {@literal @MXBeanMappingFactoryClass}(MyLinkedListMappingFactory.class)
* public interface SomethingMXBean {
* public MyLinkedList getSomething();
* }
* </pre>
*
* <p>Alternatively we can annotate the package that {@code SomethingMXBean}
* appears in, or we can supply the factory to a {@link
* javax.management.StandardMBean StandardMBean} constructor or MXBean
* proxy.</p>
*
* @see <a href="../MXBean.html#custom">MXBean specification, section
* "Custom MXBean type mappings"</a>
*/
public abstract class MXBeanMappingFactory {
/**
* <p>Construct an instance of this class.</p>
*/
protected MXBeanMappingFactory() {}
/**
* <p>Mapping factory that applies the default rules for MXBean
* mappings, as described in the <a
* href="../MXBean.html#MXBean-spec">MXBean specification</a>.</p>
*/
public static final MXBeanMappingFactory DEFAULT =
new DefaultMXBeanMappingFactory();
/**
* <p>Return the mapping for the given Java type. Typically, a
* mapping factory will return mappings for types it handles, and
* forward other types to another mapping factory, most often
* the {@linkplain #DEFAULT default one}.</p>
* @param t the Java type to be mapped.
* @param f the original mapping factory that was consulted to do
* the mapping. A mapping factory should pass this parameter intact
* if it forwards a type to another mapping factory. In the example,
* this is how {@code MyLinkedListMappingFactory} works for types
* like {@code MyLinkedList[]} and {@code List<MyLinkedList>}.
* @return the mapping for the given type.
* @throws OpenDataException if this type cannot be mapped. This
* exception is appropriate if the factory is supposed to handle
* all types of this sort (for example, all linked lists), but
* cannot handle this particular type.
*/
public abstract MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
throws OpenDataException;
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.reflect.Method;
import java.util.Map;
import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
<p>Helper class for an {@link InvocationHandler} that forwards methods from an
MXBean interface to a named
MXBean in an MBean Server and handles translation between the
arbitrary Java types in the interface and the Open Types used
by the MXBean.</p>
@since 1.6
*/
public class MXBeanProxy {
public MXBeanProxy(Class<?> mxbeanInterface) {
if (mxbeanInterface == null)
throw new IllegalArgumentException("Null parameter");
final MBeanAnalyzer<ConvertingMethod> analyzer;
try {
analyzer =
MXBeanIntrospector.getInstance().getAnalyzer(mxbeanInterface);
} catch (NotCompliantMBeanException e) {
throw new IllegalArgumentException(e);
}
analyzer.visit(new Visitor());
}
private class Visitor
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod> {
public void visitAttribute(String attributeName,
ConvertingMethod getter,
ConvertingMethod setter) {
if (getter != null) {
getter.checkCallToOpen();
Method getterMethod = getter.getMethod();
handlerMap.put(getterMethod,
new GetHandler(attributeName, getter));
}
if (setter != null) {
// return type is void, no need for checkCallToOpen
Method setterMethod = setter.getMethod();
handlerMap.put(setterMethod,
new SetHandler(attributeName, setter));
}
}
public void visitOperation(String operationName,
ConvertingMethod operation) {
operation.checkCallToOpen();
Method operationMethod = operation.getMethod();
String[] sig = operation.getOpenSignature();
handlerMap.put(operationMethod,
new InvokeHandler(operationName, sig, operation));
}
}
private static abstract class Handler {
Handler(String name, ConvertingMethod cm) {
this.name = name;
this.convertingMethod = cm;
}
String getName() {
return name;
}
ConvertingMethod getConvertingMethod() {
return convertingMethod;
}
abstract Object invoke(MBeanServerConnection mbsc,
ObjectName name, Object[] args) throws Exception;
private final String name;
private final ConvertingMethod convertingMethod;
}
private static class GetHandler extends Handler {
GetHandler(String attributeName, ConvertingMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
assert(args == null || args.length == 0);
return mbsc.getAttribute(name, getName());
}
}
private static class SetHandler extends Handler {
SetHandler(String attributeName, ConvertingMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
assert(args.length == 1);
Attribute attr = new Attribute(getName(), args[0]);
mbsc.setAttribute(name, attr);
return null;
}
}
private static class InvokeHandler extends Handler {
InvokeHandler(String operationName, String[] signature,
ConvertingMethod cm) {
super(operationName, cm);
this.signature = signature;
}
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
return mbsc.invoke(name, getName(), args, signature);
}
private final String[] signature;
}
public Object invoke(MBeanServerConnection mbsc, ObjectName name,
Method method, Object[] args)
throws Throwable {
Handler handler = handlerMap.get(method);
ConvertingMethod cm = handler.getConvertingMethod();
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc);
MXBeanLookup oldLookup = MXBeanLookup.getLookup();
try {
MXBeanLookup.setLookup(lookup);
Object[] openArgs = cm.toOpenParameters(lookup, args);
Object result = handler.invoke(mbsc, name, openArgs);
return cm.fromOpenReturnValue(lookup, result);
} finally {
MXBeanLookup.setLookup(oldLookup);
}
}
private final Map<Method, Handler> handlerMap = newMap();
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.util.Iterator;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
* Base class for MXBeans.
*
* @since 1.6
*/
public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
/**
<p>Construct an MXBean that wraps the given resource using the
given MXBean interface.</p>
@param resource the underlying resource for the new MXBean.
@param mxbeanInterface the interface to be used to determine
the MXBean's management interface.
@param <T> a type parameter that allows the compiler to check
that {@code resource} implements {@code mxbeanInterface},
provided that {@code mxbeanInterface} is a class constant like
{@code SomeMXBean.class}.
@throws IllegalArgumentException if {@code resource} is null or
if it does not implement the class {@code mxbeanInterface} or if
that class is not a valid MXBean interface.
*/
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface)
throws NotCompliantMBeanException {
super(resource, mxbeanInterface);
}
@Override
MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() {
return MXBeanIntrospector.getInstance();
}
@Override
Object getCookie() {
return mxbeanLookup;
}
static <T> Class<? super T> findMXBeanInterface(Class<T> resourceClass) {
if (resourceClass == null)
throw new IllegalArgumentException("Null resource class");
final Set<Class<?>> intfs = transitiveInterfaces(resourceClass);
final Set<Class<?>> candidates = newSet();
for (Class<?> intf : intfs) {
if (JMX.isMXBeanInterface(intf))
candidates.add(intf);
}
reduce:
while (candidates.size() > 1) {
for (Class<?> intf : candidates) {
for (Iterator<Class<?>> it = candidates.iterator(); it.hasNext();
) {
final Class<?> intf2 = it.next();
if (intf != intf2 && intf2.isAssignableFrom(intf)) {
it.remove();
continue reduce;
}
}
}
final String msg =
"Class " + resourceClass.getName() + " implements more than " +
"one MXBean interface: " + candidates;
throw new IllegalArgumentException(msg);
}
if (candidates.iterator().hasNext()) {
return Util.cast(candidates.iterator().next());
} else {
final String msg =
"Class " + resourceClass.getName() +
" is not a JMX compliant MXBean";
throw new IllegalArgumentException(msg);
}
}
/* Return all interfaces inherited by this class, directly or
* indirectly through the parent class and interfaces.
*/
private static Set<Class<?>> transitiveInterfaces(Class<?> c) {
Set<Class<?>> set = newSet();
transitiveInterfaces(c, set);
return set;
}
private static void transitiveInterfaces(Class<?> c, Set<Class<?>> intfs) {
if (c == null)
return;
if (c.isInterface())
intfs.add(c);
transitiveInterfaces(c.getSuperclass(), intfs);
for (Class<?> sup : c.getInterfaces())
transitiveInterfaces(sup, intfs);
}
/*
* The sequence of events for tracking inter-MXBean references is
* relatively complicated. We use the magical preRegister2 method
* which the MBeanServer knows about. The steps during registration
* are:
* (1) Call user preRegister, if any. If exception, abandon.
* (2) Call preRegister2 and hence this register method. If exception,
* call postRegister(false) and abandon.
* (3) Try to register the MBean. If exception, call registerFailed()
* which will call the unregister method. (Also call postRegister(false).)
* (4) If we get this far, we can call postRegister(true).
*
* When we are wrapped in an instance of javax.management.StandardMBean,
* things are simpler. That class calls this method from its preRegister,
* and propagates any exception. There is no user preRegister in this case.
* If this method succeeds but registration subsequently fails,
* StandardMBean calls unregister from its postRegister(false) method.
*/
@Override
public void register(MBeanServer server, ObjectName name)
throws InstanceAlreadyExistsException {
if (name == null)
throw new IllegalArgumentException("Null object name");
// eventually we could have some logic to supply a default name
synchronized (lock) {
this.mxbeanLookup = MXBeanLookup.lookupFor(server);
this.mxbeanLookup.addReference(name, getResource());
this.objectName = name;
}
}
@Override
public void unregister() {
synchronized (lock) {
if (mxbeanLookup != null) {
if (mxbeanLookup.removeReference(objectName, getResource()))
objectName = null;
}
}
}
private final Object lock = new Object(); // for mxbeanLookup and objectName
private MXBeanLookup mxbeanLookup;
private ObjectName objectName;
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
// JMX import
import javax.management.ObjectName;
import javax.management.loading.ClassLoaderRepository;
/**
* This interface keeps the list of Class Loaders registered in the
* MBean Server.
* It provides the necessary methods to load classes using the
* registered Class Loaders, and to add/remove class loaders from the
* list.
*
* @since 1.5
*/
public interface ModifiableClassLoaderRepository
extends ClassLoaderRepository {
/**
* Add an anonymous ClassLoader to the repository.
**/
public void addClassLoader(ClassLoader loader);
/**
* Remove the specified ClassLoader to the repository.
* The class loader may or may not be anonymous.
**/
public void removeClassLoader(ClassLoader loader);
/**
* Add a named ClassLoader to the repository.
**/
public void addClassLoader(ObjectName name, ClassLoader loader);
/**
* Remove a named ClassLoader from the repository.
**/
public void removeClassLoader(ObjectName name);
/**
* Get a named ClassLoader from the repository.
**/
public ClassLoader getClassLoader(ObjectName name);
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.* ;
/**
* This class is used for storing a pair (name, object) where name is
* an object name and object is a reference to the object.
*
* @since 1.5
*/
public class NamedObject {
/**
* Object name.
*/
private final ObjectName name;
/**
* Object reference.
*/
private final DynamicMBean object;
/**
* Allows a named object to be created.
*
*@param objectName The object name of the object.
*@param object A reference to the object.
*/
public NamedObject(ObjectName objectName, DynamicMBean object) {
if (objectName.isPattern()) {
throw new RuntimeOperationsException(new IllegalArgumentException("Invalid name->"+ objectName.toString()));
}
this.name= objectName;
this.object= object;
}
/**
* Allows a named object to be created.
*
*@param objectName The string representation of the object name of the object.
*@param object A reference to the object.
*
*@exception MalformedObjectNameException The string passed does not have the format of a valid ObjectName
*/
public NamedObject(String objectName, DynamicMBean object) throws MalformedObjectNameException{
ObjectName objName= new ObjectName(objectName);
if (objName.isPattern()) {
throw new RuntimeOperationsException(new IllegalArgumentException("Invalid name->"+ objName.toString()));
}
this.name= objName;
this.object= object;
}
/**
* Compares the current object name with another object name.
*
* @param object The Named Object that the current object name is to be
* compared with.
*
* @return True if the two named objects are equal, otherwise false.
*/
public boolean equals(Object object) {
if (this == object) return true;
if (object == null) return false;
if (!(object instanceof NamedObject)) return false;
NamedObject no = (NamedObject) object;
return name.equals(no.getName());
}
/**
* Returns a hash code for this named object.
*
*/
public int hashCode() {
return name.hashCode();
}
/**
* Get the object name.
*/
public ObjectName getName() {
return name;
}
/**
* Get the object
*/
public DynamicMBean getObject() {
return object;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
// Java import
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import sun.reflect.misc.ReflectUtil;
/**
* This class deserializes an object in the context of a specific class loader.
*
* @since 1.5
*/
class ObjectInputStreamWithLoader extends ObjectInputStream {
private ClassLoader loader;
/**
* @exception IOException Signals that an I/O exception of some
* sort has occurred.
* @exception StreamCorruptedException The object stream is corrupt.
*/
public ObjectInputStreamWithLoader(InputStream in, ClassLoader theLoader)
throws IOException {
super(in);
this.loader = theLoader;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass aClass)
throws IOException, ClassNotFoundException {
if (loader == null) {
return super.resolveClass(aClass);
} else {
String name = aClass.getName();
ReflectUtil.checkPackageAccess(name);
// Query the class loader ...
return Class.forName(name, false, loader);
}
}
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.management.AttributeNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.ReflectionException;
import static com.sun.jmx.mbeanserver.Util.*;
/**
* Per-MBean-interface behavior. A single instance of this class can be shared
* by all MBeans of the same kind (Standard MBean or MXBean) that have the same
* MBean interface.
*
* @since 1.6
*/
final class PerInterface<M> {
PerInterface(Class<?> mbeanInterface, MBeanIntrospector<M> introspector,
MBeanAnalyzer<M> analyzer, MBeanInfo mbeanInfo) {
this.mbeanInterface = mbeanInterface;
this.introspector = introspector;
this.mbeanInfo = mbeanInfo;
analyzer.visit(new InitMaps());
}
Class<?> getMBeanInterface() {
return mbeanInterface;
}
MBeanInfo getMBeanInfo() {
return mbeanInfo;
}
boolean isMXBean() {
return introspector.isMXBean();
}
Object getAttribute(Object resource, String attribute, Object cookie)
throws AttributeNotFoundException,
MBeanException,
ReflectionException {
final M cm = getters.get(attribute);
if (cm == null) {
final String msg;
if (setters.containsKey(attribute))
msg = "Write-only attribute: " + attribute;
else
msg = "No such attribute: " + attribute;
throw new AttributeNotFoundException(msg);
}
return introspector.invokeM(cm, resource, (Object[]) null, cookie);
}
void setAttribute(Object resource, String attribute, Object value,
Object cookie)
throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
final M cm = setters.get(attribute);
if (cm == null) {
final String msg;
if (getters.containsKey(attribute))
msg = "Read-only attribute: " + attribute;
else
msg = "No such attribute: " + attribute;
throw new AttributeNotFoundException(msg);
}
introspector.invokeSetter(attribute, cm, resource, value, cookie);
}
Object invoke(Object resource, String operation, Object[] params,
String[] signature, Object cookie)
throws MBeanException, ReflectionException {
final List<MethodAndSig> list = ops.get(operation);
if (list == null) {
final String msg = "No such operation: " + operation;
return noSuchMethod(msg, resource, operation, params, signature,
cookie);
}
if (signature == null)
signature = new String[0];
MethodAndSig found = null;
for (MethodAndSig mas : list) {
if (Arrays.equals(mas.signature, signature)) {
found = mas;
break;
}
}
if (found == null) {
final String badSig = sigString(signature);
final String msg;
if (list.size() == 1) { // helpful exception message
msg = "Signature mismatch for operation " + operation +
": " + badSig + " should be " +
sigString(list.get(0).signature);
} else {
msg = "Operation " + operation + " exists but not with " +
"this signature: " + badSig;
}
return noSuchMethod(msg, resource, operation, params, signature,
cookie);
}
return introspector.invokeM(found.method, resource, params, cookie);
}
/*
* This method is called when invoke doesn't find the named method.
* Before throwing an exception, we check to see whether the
* jmx.invoke.getters property is set, and if so whether the method
* being invoked might be a getter or a setter. If so we invoke it
* and return the result. This is for compatibility
* with code based on JMX RI 1.0 or 1.1 which allowed invoking getters
* and setters. It is *not* recommended that new code use this feature.
*
* Since this method is either going to throw an exception or use
* functionality that is strongly discouraged, we consider that its
* performance is not very important.
*
* A simpler way to implement the functionality would be to add the getters
* and setters to the operations map when jmx.invoke.getters is set.
* However, that means that the property is consulted when an MBean
* interface is being introspected and not thereafter. Previously,
* the property was consulted on every invocation. So this simpler
* implementation could potentially break code that sets and unsets
* the property at different times.
*/
private Object noSuchMethod(String msg, Object resource, String operation,
Object[] params, String[] signature,
Object cookie)
throws MBeanException, ReflectionException {
// Construct the exception that we will probably throw
final NoSuchMethodException nsme =
new NoSuchMethodException(operation + sigString(signature));
final ReflectionException exception =
new ReflectionException(nsme, msg);
if (introspector.isMXBean())
throw exception; // No compatibility requirement here
// Is the compatibility property set?
GetPropertyAction act = new GetPropertyAction("jmx.invoke.getters");
String invokeGettersS;
try {
invokeGettersS = AccessController.doPrivileged(act);
} catch (Exception e) {
// We don't expect an exception here but if we get one then
// we'll simply assume that the property is not set.
invokeGettersS = null;
}
if (invokeGettersS == null)
throw exception;
int rest = 0;
Map<String, M> methods = null;
if (signature == null || signature.length == 0) {
if (operation.startsWith("get"))
rest = 3;
else if (operation.startsWith("is"))
rest = 2;
if (rest != 0)
methods = getters;
} else if (signature.length == 1 &&
operation.startsWith("set")) {
rest = 3;
methods = setters;
}
if (rest != 0) {
String attrName = operation.substring(rest);
M method = methods.get(attrName);
if (method != null && introspector.getName(method).equals(operation)) {
String[] msig = introspector.getSignature(method);
if ((signature == null && msig.length == 0) ||
Arrays.equals(signature, msig)) {
return introspector.invokeM(method, resource, params, cookie);
}
}
}
throw exception;
}
private String sigString(String[] signature) {
StringBuilder b = new StringBuilder("(");
if (signature != null) {
for (String s : signature) {
if (b.length() > 1)
b.append(", ");
b.append(s);
}
}
return b.append(")").toString();
}
/**
* Visitor that sets up the method maps (operations, getters, setters).
*/
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {
public void visitAttribute(String attributeName,
M getter,
M setter) {
if (getter != null) {
introspector.checkMethod(getter);
final Object old = getters.put(attributeName, getter);
assert(old == null);
}
if (setter != null) {
introspector.checkMethod(setter);
final Object old = setters.put(attributeName, setter);
assert(old == null);
}
}
public void visitOperation(String operationName,
M operation) {
introspector.checkMethod(operation);
final String[] sig = introspector.getSignature(operation);
final MethodAndSig mas = new MethodAndSig();
mas.method = operation;
mas.signature = sig;
List<MethodAndSig> list = ops.get(operationName);
if (list == null)
list = Collections.singletonList(mas);
else {
if (list.size() == 1)
list = newList(list);
list.add(mas);
}
ops.put(operationName, list);
}
}
private class MethodAndSig {
M method;
String[] signature;
}
private final Class<?> mbeanInterface;
private final MBeanIntrospector<M> introspector;
private final MBeanInfo mbeanInfo;
private final Map<String, M> getters = newMap();
private final Map<String, M> setters = newMap();
private final Map<String, List<MethodAndSig>> ops = newMap();
}

View File

@@ -0,0 +1,678 @@
/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import com.sun.jmx.defaults.ServiceName;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.Map;
import java.util.Set;
import javax.management.DynamicMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.RuntimeOperationsException;
/**
* This repository does not support persistency.
*
* @since 1.5
*/
public class Repository {
/**
* An interface that allows the caller to get some control
* over the registration.
* @see #addMBean
* @see #remove
*/
public interface RegistrationContext {
/**
* Called by {@link #addMBean}.
* Can throw a RuntimeOperationsException to cancel the
* registration.
*/
public void registering();
/**
* Called by {@link #remove}.
* Any exception thrown by this method will be ignored.
*/
public void unregistered();
}
// Private fields -------------------------------------------->
/**
* The structure for storing the objects is very basic.
* A Hashtable is used for storing the different domains
* For each domain, a hashtable contains the instances with
* canonical key property list string as key and named object
* aggregated from given object name and mbean instance as value.
*/
private final Map<String,Map<String,NamedObject>> domainTb;
/**
* Number of elements contained in the Repository
*/
private volatile int nbElements = 0;
/**
* Domain name of the server the repository is attached to.
* It is quicker to store the information in the repository rather
* than querying the framework each time the info is required.
*/
private final String domain;
/**
* We use a global reentrant read write lock to protect the repository.
* This seems safer and more efficient: we are using Maps of Maps,
* Guaranteing consistency while using Concurent objects at each level
* may be more difficult.
**/
private final ReentrantReadWriteLock lock;
// Private fields <=============================================
// Private methods --------------------------------------------->
/* This class is used to match an ObjectName against a pattern. */
private final static class ObjectNamePattern {
private final String[] keys;
private final String[] values;
private final String properties;
private final boolean isPropertyListPattern;
private final boolean isPropertyValuePattern;
/**
* The ObjectName pattern against which ObjectNames are matched.
**/
public final ObjectName pattern;
/**
* Builds a new ObjectNamePattern object from an ObjectName pattern.
* @param pattern The ObjectName pattern under examination.
**/
public ObjectNamePattern(ObjectName pattern) {
this(pattern.isPropertyListPattern(),
pattern.isPropertyValuePattern(),
pattern.getCanonicalKeyPropertyListString(),
pattern.getKeyPropertyList(),
pattern);
}
/**
* Builds a new ObjectNamePattern object from an ObjectName pattern
* constituents.
* @param propertyListPattern pattern.isPropertyListPattern().
* @param propertyValuePattern pattern.isPropertyValuePattern().
* @param canonicalProps pattern.getCanonicalKeyPropertyListString().
* @param keyPropertyList pattern.getKeyPropertyList().
* @param pattern The ObjectName pattern under examination.
**/
ObjectNamePattern(boolean propertyListPattern,
boolean propertyValuePattern,
String canonicalProps,
Map<String,String> keyPropertyList,
ObjectName pattern) {
this.isPropertyListPattern = propertyListPattern;
this.isPropertyValuePattern = propertyValuePattern;
this.properties = canonicalProps;
final int len = keyPropertyList.size();
this.keys = new String[len];
this.values = new String[len];
int i = 0;
for (Map.Entry<String,String> entry : keyPropertyList.entrySet()) {
keys[i] = entry.getKey();
values[i] = entry.getValue();
i++;
}
this.pattern = pattern;
}
/**
* Return true if the given ObjectName matches the ObjectName pattern
* for which this object has been built.
* WARNING: domain name is not considered here because it is supposed
* not to be wildcard when called. PropertyList is also
* supposed not to be zero-length.
* @param name The ObjectName we want to match against the pattern.
* @return true if <code>name</code> matches the pattern.
**/
public boolean matchKeys(ObjectName name) {
// If key property value pattern but not key property list
// pattern, then the number of key properties must be equal
//
if (isPropertyValuePattern &&
!isPropertyListPattern &&
(name.getKeyPropertyList().size() != keys.length))
return false;
// If key property value pattern or key property list pattern,
// then every property inside pattern should exist in name
//
if (isPropertyValuePattern || isPropertyListPattern) {
for (int i = keys.length - 1; i >= 0 ; i--) {
// Find value in given object name for key at current
// index in receiver
//
String v = name.getKeyProperty(keys[i]);
// Did we find a value for this key ?
//
if (v == null) return false;
// If this property is ok (same key, same value), go to next
//
if (isPropertyValuePattern &&
pattern.isPropertyValuePattern(keys[i])) {
// wildmatch key property values
// values[i] is the pattern;
// v is the string
if (Util.wildmatch(v,values[i]))
continue;
else
return false;
}
if (v.equals(values[i])) continue;
return false;
}
return true;
}
// If no pattern, then canonical names must be equal
//
final String p1 = name.getCanonicalKeyPropertyListString();
final String p2 = properties;
return (p1.equals(p2));
}
}
/**
* Add all the matching objects from the given hashtable in the
* result set for the given ObjectNamePattern
* Do not check whether the domains match (only check for matching
* key property lists - see <i>matchKeys()</i>)
**/
private void addAllMatching(final Map<String,NamedObject> moiTb,
final Set<NamedObject> result,
final ObjectNamePattern pattern) {
synchronized (moiTb) {
for (NamedObject no : moiTb.values()) {
final ObjectName on = no.getName();
// if all couples (property, value) are contained
if (pattern.matchKeys(on)) result.add(no);
}
}
}
private void addNewDomMoi(final DynamicMBean object,
final String dom,
final ObjectName name,
final RegistrationContext context) {
final Map<String,NamedObject> moiTb =
new HashMap<String,NamedObject>();
final String key = name.getCanonicalKeyPropertyListString();
addMoiToTb(object,name,key,moiTb,context);
domainTb.put(dom, moiTb);
nbElements++;
}
private void registering(RegistrationContext context) {
if (context == null) return;
try {
context.registering();
} catch (RuntimeOperationsException x) {
throw x;
} catch (RuntimeException x) {
throw new RuntimeOperationsException(x);
}
}
private void unregistering(RegistrationContext context, ObjectName name) {
if (context == null) return;
try {
context.unregistered();
} catch (Exception x) {
// shouldn't come here...
MBEANSERVER_LOGGER.log(Level.FINE,
"Unexpected exception while unregistering "+name,
x);
}
}
private void addMoiToTb(final DynamicMBean object,
final ObjectName name,
final String key,
final Map<String,NamedObject> moiTb,
final RegistrationContext context) {
registering(context);
moiTb.put(key,new NamedObject(name, object));
}
/**
* Retrieves the named object contained in repository
* from the given objectname.
*/
private NamedObject retrieveNamedObject(ObjectName name) {
// No patterns inside reposit
if (name.isPattern()) return null;
// Extract the domain name.
String dom = name.getDomain().intern();
// Default domain case
if (dom.length() == 0) {
dom = domain;
}
Map<String,NamedObject> moiTb = domainTb.get(dom);
if (moiTb == null) {
return null; // No domain containing registered object names
}
return moiTb.get(name.getCanonicalKeyPropertyListString());
}
// Private methods <=============================================
// Protected methods --------------------------------------------->
// Protected methods <=============================================
// Public methods --------------------------------------------->
/**
* Construct a new repository with the given default domain.
*/
public Repository(String domain) {
this(domain,true);
}
/**
* Construct a new repository with the given default domain.
*/
public Repository(String domain, boolean fairLock) {
lock = new ReentrantReadWriteLock(fairLock);
domainTb = new HashMap<String,Map<String,NamedObject>>(5);
if (domain != null && domain.length() != 0)
this.domain = domain.intern(); // we use == domain later on...
else
this.domain = ServiceName.DOMAIN;
// Creates a new hashtable for the default domain
domainTb.put(this.domain, new HashMap<String,NamedObject>());
}
/**
* Returns the list of domains in which any MBean is currently
* registered.
*
*/
public String[] getDomains() {
lock.readLock().lock();
final List<String> result;
try {
// Temporary list
result = new ArrayList<String>(domainTb.size());
for (Map.Entry<String,Map<String,NamedObject>> entry :
domainTb.entrySet()) {
// Skip domains that are in the table but have no
// MBean registered in them
// in particular the default domain may be like this
Map<String,NamedObject> t = entry.getValue();
if (t != null && t.size() != 0)
result.add(entry.getKey());
}
} finally {
lock.readLock().unlock();
}
// Make an array from result.
return result.toArray(new String[result.size()]);
}
/**
* Stores an MBean associated with its object name in the repository.
*
* @param object MBean to be stored in the repository.
* @param name MBean object name.
* @param context A registration context. If non null, the repository
* will call {@link RegistrationContext#registering()
* context.registering()} from within the repository
* lock, when it has determined that the {@code object}
* can be stored in the repository with that {@code name}.
* If {@link RegistrationContext#registering()
* context.registering()} throws an exception, the
* operation is abandonned, the MBean is not added to the
* repository, and a {@link RuntimeOperationsException}
* is thrown.
*/
public void addMBean(final DynamicMBean object, ObjectName name,
final RegistrationContext context)
throws InstanceAlreadyExistsException {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER, Repository.class.getName(),
"addMBean", "name = " + name);
}
// Extract the domain name.
String dom = name.getDomain().intern();
boolean to_default_domain = false;
// Set domain to default if domain is empty and not already set
if (dom.length() == 0)
name = Util.newObjectName(domain + name.toString());
// Do we have default domain ?
if (dom == domain) { // ES: OK (dom & domain are interned)
to_default_domain = true;
dom = domain;
} else {
to_default_domain = false;
}
// Validate name for an object
if (name.isPattern()) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Repository: cannot add mbean for " +
"pattern name " + name.toString()));
}
lock.writeLock().lock();
try {
// Domain cannot be JMImplementation if entry does not exist
if ( !to_default_domain &&
dom.equals("JMImplementation") &&
domainTb.containsKey("JMImplementation")) {
throw new RuntimeOperationsException(
new IllegalArgumentException(
"Repository: domain name cannot be JMImplementation"));
}
// If domain does not already exist, add it to the hash table
final Map<String,NamedObject> moiTb = domainTb.get(dom);
if (moiTb == null) {
addNewDomMoi(object, dom, name, context);
return;
} else {
// Add instance if not already present
String cstr = name.getCanonicalKeyPropertyListString();
NamedObject elmt= moiTb.get(cstr);
if (elmt != null) {
throw new InstanceAlreadyExistsException(name.toString());
} else {
nbElements++;
addMoiToTb(object,name,cstr,moiTb,context);
}
}
} finally {
lock.writeLock().unlock();
}
}
/**
* Checks whether an MBean of the name specified is already stored in
* the repository.
*
* @param name name of the MBean to find.
*
* @return true if the MBean is stored in the repository,
* false otherwise.
*/
public boolean contains(ObjectName name) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER, Repository.class.getName(),
"contains", " name = " + name);
}
lock.readLock().lock();
try {
return (retrieveNamedObject(name) != null);
} finally {
lock.readLock().unlock();
}
}
/**
* Retrieves the MBean of the name specified from the repository. The
* object name must match exactly.
*
* @param name name of the MBean to retrieve.
*
* @return The retrieved MBean if it is contained in the repository,
* null otherwise.
*/
public DynamicMBean retrieve(ObjectName name) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER, Repository.class.getName(),
"retrieve", "name = " + name);
}
// Calls internal retrieve method to get the named object
lock.readLock().lock();
try {
NamedObject no = retrieveNamedObject(name);
if (no == null) return null;
else return no.getObject();
} finally {
lock.readLock().unlock();
}
}
/**
* Selects and retrieves the list of MBeans whose names match the specified
* object name pattern and which match the specified query expression
* (optionally).
*
* @param pattern The name of the MBean(s) to retrieve - may be a specific
* object or a name pattern allowing multiple MBeans to be selected.
* @param query query expression to apply when selecting objects - this
* parameter will be ignored when the Repository Service does not
* support filtering.
*
* @return The list of MBeans selected. There may be zero, one or many
* MBeans returned in the set.
*/
public Set<NamedObject> query(ObjectName pattern, QueryExp query) {
final Set<NamedObject> result = new HashSet<NamedObject>();
// The following filter cases are considered:
// null, "", "*:*" : names in all domains
// ":*", ":[key=value],*" : names in defaultDomain
// "domain:*", "domain:[key=value],*" : names in the specified domain
// Surely one of the most frequent cases ... query on the whole world
ObjectName name;
if (pattern == null ||
pattern.getCanonicalName().length() == 0 ||
pattern.equals(ObjectName.WILDCARD))
name = ObjectName.WILDCARD;
else name = pattern;
lock.readLock().lock();
try {
// If pattern is not a pattern, retrieve this mbean !
if (!name.isPattern()) {
final NamedObject no = retrieveNamedObject(name);
if (no != null) result.add(no);
return result;
}
// All names in all domains
if (name == ObjectName.WILDCARD) {
for (Map<String,NamedObject> moiTb : domainTb.values()) {
result.addAll(moiTb.values());
}
return result;
}
final String canonical_key_property_list_string =
name.getCanonicalKeyPropertyListString();
final boolean allNames =
(canonical_key_property_list_string.length()==0);
final ObjectNamePattern namePattern =
(allNames?null:new ObjectNamePattern(name));
// All names in default domain
if (name.getDomain().length() == 0) {
final Map<String,NamedObject> moiTb = domainTb.get(domain);
if (allNames)
result.addAll(moiTb.values());
else
addAllMatching(moiTb, result, namePattern);
return result;
}
if (!name.isDomainPattern()) {
final Map<String,NamedObject> moiTb = domainTb.get(name.getDomain());
if (moiTb == null) return Collections.emptySet();
if (allNames)
result.addAll(moiTb.values());
else
addAllMatching(moiTb, result, namePattern);
return result;
}
// Pattern matching in the domain name (*, ?)
final String dom2Match = name.getDomain();
for (String dom : domainTb.keySet()) {
if (Util.wildmatch(dom, dom2Match)) {
final Map<String,NamedObject> moiTb = domainTb.get(dom);
if (allNames)
result.addAll(moiTb.values());
else
addAllMatching(moiTb, result, namePattern);
}
}
return result;
} finally {
lock.readLock().unlock();
}
}
/**
* Removes an MBean from the repository.
*
* @param name name of the MBean to remove.
* @param context A registration context. If non null, the repository
* will call {@link RegistrationContext#unregistered()
* context.unregistered()} from within the repository
* lock, just after the mbean associated with
* {@code name} is removed from the repository.
* If {@link RegistrationContext#unregistered()
* context.unregistered()} is not expected to throw any
* exception. If it does, the exception is logged
* and swallowed.
*
* @exception InstanceNotFoundException The MBean does not exist in
* the repository.
*/
public void remove(final ObjectName name,
final RegistrationContext context)
throws InstanceNotFoundException {
// Debugging stuff
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
MBEANSERVER_LOGGER.logp(Level.FINER, Repository.class.getName(),
"remove", "name = " + name);
}
// Extract domain name.
String dom= name.getDomain().intern();
// Default domain case
if (dom.length() == 0) dom = domain;
lock.writeLock().lock();
try {
// Find the domain subtable
final Map<String,NamedObject> moiTb = domainTb.get(dom);
if (moiTb == null) {
throw new InstanceNotFoundException(name.toString());
}
// Remove the corresponding element
if (moiTb.remove(name.getCanonicalKeyPropertyListString())==null) {
throw new InstanceNotFoundException(name.toString());
}
// We removed it !
nbElements--;
// No more object for this domain, we remove this domain hashtable
if (moiTb.isEmpty()) {
domainTb.remove(dom);
// set a new default domain table (always present)
// need to reinstantiate a hashtable because of possible
// big buckets array size inside table, never cleared,
// thus the new !
if (dom == domain) // ES: OK dom and domain are interned.
domainTb.put(domain, new HashMap<String,NamedObject>());
}
unregistering(context,name);
} finally {
lock.writeLock().unlock();
}
}
/**
* Gets the number of MBeans stored in the repository.
*
* @return Number of MBeans.
*/
public Integer getCount() {
return nbElements;
}
/**
* Gets the name of the domain currently used by default in the
* repository.
*
* @return A string giving the name of the default domain name.
*/
public String getDefaultDomain() {
return domain;
}
// Public methods <=============================================
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.loading.ClassLoaderRepository;
/**
* Fix security hole in ClassLoaderRepository. This class wraps
* the actual ClassLoaderRepository implementation so that
* only the methods from {@link javax.management.loading.ClassLoaderRepository}
* can be accessed (read-only).
*
* @since 1.5
*/
final class SecureClassLoaderRepository
implements ClassLoaderRepository {
private final ClassLoaderRepository clr;
/**
* Creates a new secure ClassLoaderRepository wrapping an
* unsecure implementation.
* @param clr Unsecure {@link ClassLoaderRepository} implementation
* to wrap.
**/
public SecureClassLoaderRepository(ClassLoaderRepository clr) {
this.clr=clr;
}
public final Class<?> loadClass(String className)
throws ClassNotFoundException {
return clr.loadClass(className);
}
public final Class<?> loadClassWithout(ClassLoader loader,
String className)
throws ClassNotFoundException {
return clr.loadClassWithout(loader,className);
}
public final Class<?> loadClassBefore(ClassLoader loader,
String className)
throws ClassNotFoundException {
return clr.loadClassBefore(loader,className);
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.WeakHashMap;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
import sun.reflect.misc.MethodUtil;
/**
* @since 1.6
*/
class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
private static final StandardMBeanIntrospector instance =
new StandardMBeanIntrospector();
static StandardMBeanIntrospector getInstance() {
return instance;
}
@Override
PerInterfaceMap<Method> getPerInterfaceMap() {
return perInterfaceMap;
}
@Override
MBeanInfoMap getMBeanInfoMap() {
return mbeanInfoMap;
}
@Override
MBeanAnalyzer<Method> getAnalyzer(Class<?> mbeanInterface)
throws NotCompliantMBeanException {
return MBeanAnalyzer.analyzer(mbeanInterface, this);
}
@Override
boolean isMXBean() {
return false;
}
@Override
Method mFrom(Method m) {
return m;
}
@Override
String getName(Method m) {
return m.getName();
}
@Override
Type getGenericReturnType(Method m) {
return m.getGenericReturnType();
}
@Override
Type[] getGenericParameterTypes(Method m) {
return m.getGenericParameterTypes();
}
@Override
String[] getSignature(Method m) {
Class<?>[] params = m.getParameterTypes();
String[] sig = new String[params.length];
for (int i = 0; i < params.length; i++)
sig[i] = params[i].getName();
return sig;
}
@Override
void checkMethod(Method m) {
}
@Override
Object invokeM2(Method m, Object target, Object[] args, Object cookie)
throws InvocationTargetException, IllegalAccessException,
MBeanException {
return MethodUtil.invoke(m, target, args);
}
@Override
boolean validParameter(Method m, Object value, int paramNo, Object cookie) {
return isValidParameter(m, value, paramNo);
}
@Override
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
Method getter, Method setter) {
final String description = "Attribute exposed for management";
try {
return new MBeanAttributeInfo(attributeName, description,
getter, setter);
} catch (IntrospectionException e) {
throw new RuntimeException(e); // should not happen
}
}
@Override
MBeanOperationInfo getMBeanOperationInfo(String operationName,
Method operation) {
final String description = "Operation exposed for management";
return new MBeanOperationInfo(description, operation);
}
@Override
Descriptor getBasicMBeanDescriptor() {
/* We don't bother saying mxbean=false, and we can't know whether
the info is immutable until we know whether the MBean class
(not interface) is a NotificationBroadcaster. */
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
}
@Override
Descriptor getMBeanDescriptor(Class<?> resourceClass) {
boolean immutable = isDefinitelyImmutableInfo(resourceClass);
return new ImmutableDescriptor("mxbean=false",
"immutableInfo=" + immutable);
}
/* Return true if and only if we can be sure that the given MBean implementation
* class has immutable MBeanInfo. A Standard MBean that is a
* NotificationBroadcaster is allowed to return different values at
* different times from its getNotificationInfo() method, which is when
* we might not know if it is immutable. But if it is a subclass of
* NotificationBroadcasterSupport and does not override
* getNotificationInfo(), then we know it won't change.
*/
static boolean isDefinitelyImmutableInfo(Class<?> implClass) {
if (!NotificationBroadcaster.class.isAssignableFrom(implClass))
return true;
synchronized (definitelyImmutable) {
Boolean immutable = definitelyImmutable.get(implClass);
if (immutable == null) {
final Class<NotificationBroadcasterSupport> nbs =
NotificationBroadcasterSupport.class;
if (nbs.isAssignableFrom(implClass)) {
try {
Method m = implClass.getMethod("getNotificationInfo");
immutable = (m.getDeclaringClass() == nbs);
} catch (Exception e) {
// Too bad, we'll say no for now.
return false;
}
} else
immutable = false;
definitelyImmutable.put(implClass, immutable);
}
return immutable;
}
}
private static final WeakHashMap<Class<?>, Boolean> definitelyImmutable =
new WeakHashMap<Class<?>, Boolean>();
private static final PerInterfaceMap<Method>
perInterfaceMap = new PerInterfaceMap<Method>();
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.reflect.Method;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
* Base class for Standard MBeans.
*
* @since 1.6
*/
public class StandardMBeanSupport extends MBeanSupport<Method> {
/**
* <p>Construct a Standard MBean that wraps the given resource using the
* given Standard MBean interface.</p>
*
* @param resource the underlying resource for the new MBean.
* @param mbeanInterfaceType the class or interface to be used to determine
* the MBean's management interface. An interface if this is a
* classic Standard MBean; a class if this is a {@code @ManagedResource}.
* @param <T> a type parameter that allows the compiler to check
* that {@code resource} implements {@code mbeanInterfaceType},
* provided that {@code mbeanInterfaceType} is a class constant like
* {@code SomeMBean.class}.
* @throws IllegalArgumentException if {@code resource} is null or
* if it does not implement the class {@code mbeanInterfaceType} or if
* that class is not a valid Standard MBean interface.
*/
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType)
throws NotCompliantMBeanException {
super(resource, mbeanInterfaceType);
}
@Override
MBeanIntrospector<Method> getMBeanIntrospector() {
return StandardMBeanIntrospector.getInstance();
}
@Override
Object getCookie() {
return null;
}
@Override
public void register(MBeanServer mbs, ObjectName name) {}
@Override
public void unregister() {}
/* Standard MBeans that are NotificationBroadcasters can return a different
* MBeanNotificationInfo[] every time getMBeanInfo() is called, so we have
* to reconstruct this MBeanInfo if necessary.
*/
@Override
public MBeanInfo getMBeanInfo() {
MBeanInfo mbi = super.getMBeanInfo();
Class<?> resourceClass = getResource().getClass();
if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
return mbi;
return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
mbi.getAttributes(), mbi.getConstructors(),
mbi.getOperations(),
MBeanIntrospector.findNotifications(getResource()),
mbi.getDescriptor());
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
/**
* Extends the MBeanServer interface to
* provide methods for getting the MetaData and MBeanServerInstantiator
* objects associated with an MBeanServer.
*
* @since 1.5
*/
public interface SunJmxMBeanServer
extends MBeanServer {
/**
* Return the MBeanInstantiator associated to this MBeanServer.
* @exception UnsupportedOperationException if
* {@link MBeanServerInterceptor}s
* are not enabled on this object.
* @see #interceptorsEnabled
*/
public MBeanInstantiator getMBeanInstantiator();
/**
* Tell whether {@link MBeanServerInterceptor}s are enabled on this
* object.
* @return <code>true</code> if {@link MBeanServerInterceptor}s are
* enabled.
* @see #getMBeanServerInterceptor
* @see #setMBeanServerInterceptor
* @see #getMBeanInstantiator
* @see com.sun.jmx.mbeanserver.JmxMBeanServerBuilder
**/
public boolean interceptorsEnabled();
/**
* Return the MBeanServerInterceptor.
* @exception UnsupportedOperationException if
* {@link MBeanServerInterceptor}s
* are not enabled on this object.
* @see #interceptorsEnabled
**/
public MBeanServer getMBeanServerInterceptor();
/**
* Set the MBeanServerInterceptor.
* @exception UnsupportedOperationException if
* {@link MBeanServerInterceptor}s
* are not enabled on this object.
* @see #interceptorsEnabled
**/
public void setMBeanServerInterceptor(MBeanServer interceptor);
/**
* <p>Return the MBeanServerDelegate representing the MBeanServer.
* Notifications can be sent from the MBean server delegate using
* the method {@link MBeanServerDelegate#sendNotification}
* in the returned object.</p>
*
*/
public MBeanServerDelegate getMBeanServerDelegate();
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
public class Util {
public static ObjectName newObjectName(String string) {
try {
return new ObjectName(string);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e);
}
}
static <K, V> Map<K, V> newMap() {
return new HashMap<K, V>();
}
static <K, V> Map<K, V> newSynchronizedMap() {
return Collections.synchronizedMap(Util.<K, V>newMap());
}
static <K, V> IdentityHashMap<K, V> newIdentityHashMap() {
return new IdentityHashMap<K, V>();
}
static <K, V> Map<K, V> newSynchronizedIdentityHashMap() {
Map<K, V> map = newIdentityHashMap();
return Collections.synchronizedMap(map);
}
static <K, V> SortedMap<K, V> newSortedMap() {
return new TreeMap<K, V>();
}
static <K, V> SortedMap<K, V> newSortedMap(Comparator<? super K> comp) {
return new TreeMap<K, V>(comp);
}
static <K, V> Map<K, V> newInsertionOrderMap() {
return new LinkedHashMap<K, V>();
}
static <E> Set<E> newSet() {
return new HashSet<E>();
}
static <E> Set<E> newSet(Collection<E> c) {
return new HashSet<E>(c);
}
static <E> List<E> newList() {
return new ArrayList<E>();
}
static <E> List<E> newList(Collection<E> c) {
return new ArrayList<E>(c);
}
/* This method can be used by code that is deliberately violating the
* allowed checked casts. Rather than marking the whole method containing
* the code with @SuppressWarnings, you can use a call to this method for
* the exact place where you need to escape the constraints. Typically
* you will "import static" this method and then write either
* X x = cast(y);
* or, if that doesn't work (e.g. X is a type variable)
* Util.<X>cast(y);
*/
@SuppressWarnings("unchecked")
public static <T> T cast(Object x) {
return (T) x;
}
/**
* Computes a descriptor hashcode from its names and values.
* @param names the sorted array of descriptor names.
* @param values the array of descriptor values.
* @return a hash code value, as described in {@link #hashCode(Descriptor)}
*/
public static int hashCode(String[] names, Object[] values) {
int hash = 0;
for (int i = 0; i < names.length; i++) {
Object v = values[i];
int h;
if (v == null) {
h = 0;
} else if (v instanceof Object[]) {
h = Arrays.deepHashCode((Object[]) v);
} else if (v.getClass().isArray()) {
h = Arrays.deepHashCode(new Object[]{v}) - 31;
// hashcode of a list containing just v is
// v.hashCode() + 31, see List.hashCode()
} else {
h = v.hashCode();
}
hash += names[i].toLowerCase().hashCode() ^ h;
}
return hash;
}
/** Match a part of a string against a shell-style pattern.
The only pattern characters recognized are <code>?</code>,
standing for any one character,
and <code>*</code>, standing for any string of
characters, including the empty string. For instance,
{@code wildmatch("sandwich","sa?d*ch",1,4,1,4)} will match
{@code "and"} against {@code "a?d"}.
@param str the string containing the sequence to match.
@param pat a string containing a pattern to match the sub string
against.
@param stri the index in the string at which matching should begin.
@param strend the index in the string at which the matching should
end.
@param pati the index in the pattern at which matching should begin.
@param patend the index in the pattern at which the matching should
end.
@return true if and only if the string matches the pattern.
*/
/* The algorithm is a classical one. We advance pointers in
parallel through str and pat. If we encounter a star in pat,
we remember its position and continue advancing. If at any
stage we get a mismatch between str and pat, we look to see if
there is a remembered star. If not, we fail. If so, we
retreat pat to just past that star and str to the position
after the last one we tried, and we let the match advance
again.
Even though there is only one remembered star position, the
algorithm works when there are several stars in the pattern.
When we encounter the second star, we forget the first one.
This is OK, because if we get to the second star in A*B*C
(where A etc are arbitrary strings), we have already seen AXB.
We're therefore setting up a match of *C against the remainder
of the string, which will match if that remainder looks like
YC, so the whole string looks like AXBYC.
*/
private static boolean wildmatch(final String str, final String pat,
int stri, final int strend, int pati, final int patend) {
// System.out.println("matching "+pat.substring(pati,patend)+
// " against "+str.substring(stri, strend));
int starstri; // index for backtrack if "*" attempt fails
int starpati; // index for backtrack if "*" attempt fails, +1
starstri = starpati = -1;
/* On each pass through this loop, we either advance pati,
or we backtrack pati and advance starstri. Since starstri
is only ever assigned from pati, the loop must terminate. */
while (true) {
if (pati < patend) {
final char patc = pat.charAt(pati);
switch (patc) {
case '?':
if (stri == strend)
break;
stri++;
pati++;
continue;
case '*':
pati++;
starpati = pati;
starstri = stri;
continue;
default:
if (stri < strend && str.charAt(stri) == patc) {
stri++;
pati++;
continue;
}
break;
}
} else if (stri == strend)
return true;
// Mismatched, can we backtrack to a "*"?
if (starpati < 0 || starstri == strend)
return false;
// Retry the match one position later in str
pati = starpati;
starstri++;
stri = starstri;
}
}
/** Match a string against a shell-style pattern. The only pattern
characters recognized are <code>?</code>, standing for any one
character, and <code>*</code>, standing for any string of
characters, including the empty string.
@param str the string to match.
@param pat the pattern to match the string against.
@return true if and only if the string matches the pattern.
*/
public static boolean wildmatch(String str, String pat) {
return wildmatch(str,pat,0,str.length(),0,pat.length());
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Map;
/**
* <p>A map where keys are compared using identity comparison (like
* IdentityHashMap) but where the presence of an object as a key in
* the map does not prevent it being garbage collected (like
* WeakHashMap). This class does not implement the Map interface
* because it is difficult to ensure correct semantics for iterators
* over the entrySet().</p>
*
* <p>Because we do not implement Map, we do not copy the questionable
* interface where you can call get(k) or remove(k) for any type of k,
* which of course can only have an effect if k is of type K.</p>
*
* <p>This map does not support null keys.</p>
*/
/*
* The approach
* is to wrap each key in a WeakReference and use the wrapped value as
* a key in an ordinary HashMap. The WeakReference has to be a
* subclass IdentityWeakReference (IWR) where two IWRs are equal if
* they refer to the same object. This enables us to find the entry
* again.
*/
class WeakIdentityHashMap<K, V> {
private WeakIdentityHashMap() {}
static <K, V> WeakIdentityHashMap<K, V> make() {
return new WeakIdentityHashMap<K, V>();
}
V get(K key) {
expunge();
WeakReference<K> keyref = makeReference(key);
return map.get(keyref);
}
public V put(K key, V value) {
expunge();
if (key == null)
throw new IllegalArgumentException("Null key");
WeakReference<K> keyref = makeReference(key, refQueue);
return map.put(keyref, value);
}
public V remove(K key) {
expunge();
WeakReference<K> keyref = makeReference(key);
return map.remove(keyref);
}
private void expunge() {
Reference<? extends K> ref;
while ((ref = refQueue.poll()) != null)
map.remove(ref);
}
private WeakReference<K> makeReference(K referent) {
return new IdentityWeakReference<K>(referent);
}
private WeakReference<K> makeReference(K referent, ReferenceQueue<K> q) {
return new IdentityWeakReference<K>(referent, q);
}
/**
* WeakReference where equals and hashCode are based on the
* referent. More precisely, two objects are equal if they are
* identical or if they both have the same non-null referent. The
* hashCode is the value the original referent had. Even if the
* referent is cleared, the hashCode remains. Thus, objects of
* this class can be used as keys in hash-based maps and sets.
*/
private static class IdentityWeakReference<T> extends WeakReference<T> {
IdentityWeakReference(T o) {
this(o, null);
}
IdentityWeakReference(T o, ReferenceQueue<T> q) {
super(o, q);
this.hashCode = (o == null) ? 0 : System.identityHashCode(o);
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof IdentityWeakReference<?>))
return false;
IdentityWeakReference<?> wr = (IdentityWeakReference<?>) o;
Object got = get();
return (got != null && got == wr.get());
}
public int hashCode() {
return hashCode;
}
private final int hashCode;
}
private Map<WeakReference<K>, V> map = newMap();
private ReferenceQueue<K> refQueue = new ReferenceQueue<K>();
}