feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
229
jdkSrc/jdk8/com/sun/jmx/mbeanserver/ConvertingMethod.java
Normal file
229
jdkSrc/jdk8/com/sun/jmx/mbeanserver/ConvertingMethod.java
Normal 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;
|
||||
}
|
||||
1541
jdkSrc/jdk8/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java
Normal file
1541
jdkSrc/jdk8/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java
Normal file
File diff suppressed because it is too large
Load Diff
67
jdkSrc/jdk8/com/sun/jmx/mbeanserver/DescriptorCache.java
Normal file
67
jdkSrc/jdk8/com/sun/jmx/mbeanserver/DescriptorCache.java
Normal 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>>();
|
||||
}
|
||||
77
jdkSrc/jdk8/com/sun/jmx/mbeanserver/DynamicMBean2.java
Normal file
77
jdkSrc/jdk8/com/sun/jmx/mbeanserver/DynamicMBean2.java
Normal 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();
|
||||
}
|
||||
46
jdkSrc/jdk8/com/sun/jmx/mbeanserver/GetPropertyAction.java
Normal file
46
jdkSrc/jdk8/com/sun/jmx/mbeanserver/GetPropertyAction.java
Normal 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);
|
||||
}
|
||||
}
|
||||
816
jdkSrc/jdk8/com/sun/jmx/mbeanserver/Introspector.java
Normal file
816
jdkSrc/jdk8/com/sun/jmx/mbeanserver/Introspector.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1522
jdkSrc/jdk8/com/sun/jmx/mbeanserver/JmxMBeanServer.java
Normal file
1522
jdkSrc/jdk8/com/sun/jmx/mbeanserver/JmxMBeanServer.java
Normal file
File diff suppressed because it is too large
Load Diff
114
jdkSrc/jdk8/com/sun/jmx/mbeanserver/JmxMBeanServerBuilder.java
Normal file
114
jdkSrc/jdk8/com/sun/jmx/mbeanserver/JmxMBeanServerBuilder.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
275
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanAnalyzer.java
Normal file
275
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanAnalyzer.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
786
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanInstantiator.java
Normal file
786
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanInstantiator.java
Normal 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;
|
||||
}
|
||||
}
|
||||
471
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanIntrospector.java
Normal file
471
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanIntrospector.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
321
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanServerDelegateImpl.java
Normal file
321
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanServerDelegateImpl.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
276
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanSupport.java
Normal file
276
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MBeanSupport.java
Normal 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;
|
||||
}
|
||||
365
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanIntrospector.java
Normal file
365
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanIntrospector.java
Normal 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();
|
||||
}
|
||||
188
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanLookup.java
Normal file
188
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanLookup.java
Normal 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();
|
||||
}
|
||||
210
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanMapping.java
Normal file
210
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanMapping.java
Normal 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 >= 0; i--)
|
||||
* list = new MyLinkedList(array[i], list);
|
||||
* return list;
|
||||
* }
|
||||
*
|
||||
* {@literal @Override}
|
||||
* public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
* ArrayList<String> array = new ArrayList<String>();
|
||||
* 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 {}
|
||||
}
|
||||
124
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanMappingFactory.java
Normal file
124
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanMappingFactory.java
Normal 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;
|
||||
}
|
||||
175
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanProxy.java
Normal file
175
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanProxy.java
Normal 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();
|
||||
}
|
||||
178
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanSupport.java
Normal file
178
jdkSrc/jdk8/com/sun/jmx/mbeanserver/MXBeanSupport.java
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
122
jdkSrc/jdk8/com/sun/jmx/mbeanserver/NamedObject.java
Normal file
122
jdkSrc/jdk8/com/sun/jmx/mbeanserver/NamedObject.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
280
jdkSrc/jdk8/com/sun/jmx/mbeanserver/PerInterface.java
Normal file
280
jdkSrc/jdk8/com/sun/jmx/mbeanserver/PerInterface.java
Normal 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();
|
||||
}
|
||||
678
jdkSrc/jdk8/com/sun/jmx/mbeanserver/Repository.java
Normal file
678
jdkSrc/jdk8/com/sun/jmx/mbeanserver/Repository.java
Normal 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 <=============================================
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
90
jdkSrc/jdk8/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java
Normal file
90
jdkSrc/jdk8/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java
Normal 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();
|
||||
|
||||
}
|
||||
241
jdkSrc/jdk8/com/sun/jmx/mbeanserver/Util.java
Normal file
241
jdkSrc/jdk8/com/sun/jmx/mbeanserver/Util.java
Normal 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());
|
||||
}
|
||||
}
|
||||
137
jdkSrc/jdk8/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java
Normal file
137
jdkSrc/jdk8/com/sun/jmx/mbeanserver/WeakIdentityHashMap.java
Normal 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>();
|
||||
}
|
||||
Reference in New Issue
Block a user