8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -0,0 +1,208 @@
/*
* Copyright (c) 1999, 2017, 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.defaults;
import java.lang.System.Logger;
/**
* This contains the property list defined for this
* JMX implementation.
*
*
* @since 1.5
*/
public class JmxProperties {
// private constructor defined to "hide" the default public constructor
private JmxProperties() {
}
// PUBLIC STATIC CONSTANTS
//------------------------
/**
* References the property that specifies the directory where
* the native libraries will be stored before the MLet Service
* loads them into memory.
* <p>
* Property Name: <B>jmx.mlet.library.dir</B>
*/
public static final String JMX_INITIAL_BUILDER =
"javax.management.builder.initial";
/**
* References the property that specifies the directory where
* the native libraries will be stored before the MLet Service
* loads them into memory.
* <p>
* Property Name: <B>jmx.mlet.library.dir</B>
*/
public static final String MLET_LIB_DIR = "jmx.mlet.library.dir";
/**
* References the property that specifies the full name of the JMX
* specification implemented by this product.
* <p>
* Property Name: <B>jmx.specification.name</B>
*/
public static final String JMX_SPEC_NAME = "jmx.specification.name";
/**
* References the property that specifies the version of the JMX
* specification implemented by this product.
* <p>
* Property Name: <B>jmx.specification.version</B>
*/
public static final String JMX_SPEC_VERSION = "jmx.specification.version";
/**
* References the property that specifies the vendor of the JMX
* specification implemented by this product.
* <p>
* Property Name: <B>jmx.specification.vendor</B>
*/
public static final String JMX_SPEC_VENDOR = "jmx.specification.vendor";
/**
* References the property that specifies the full name of this product
* implementing the JMX specification.
* <p>
* Property Name: <B>jmx.implementation.name</B>
*/
public static final String JMX_IMPL_NAME = "jmx.implementation.name";
/**
* References the property that specifies the name of the vendor of this
* product implementing the JMX specification.
* <p>
* Property Name: <B>jmx.implementation.vendor</B>
*/
public static final String JMX_IMPL_VENDOR = "jmx.implementation.vendor";
/**
* References the property that specifies the version of this product
* implementing the JMX specification.
* <p>
* Property Name: <B>jmx.implementation.version</B>
*/
public static final String JMX_IMPL_VERSION = "jmx.implementation.version";
/**
* Logger name for MBean Server information.
*/
public static final String MBEANSERVER_LOGGER_NAME =
"javax.management.mbeanserver";
/**
* Logger for MBean Server information.
*/
public static final Logger MBEANSERVER_LOGGER =
System.getLogger(MBEANSERVER_LOGGER_NAME);
/**
* Logger name for MLet service information.
*/
public static final String MLET_LOGGER_NAME =
"javax.management.mlet";
/**
* Logger for MLet service information.
*/
public static final Logger MLET_LOGGER =
System.getLogger(MLET_LOGGER_NAME);
/**
* Logger name for Monitor information.
*/
public static final String MONITOR_LOGGER_NAME =
"javax.management.monitor";
/**
* Logger for Monitor information.
*/
public static final Logger MONITOR_LOGGER =
System.getLogger(MONITOR_LOGGER_NAME);
/**
* Logger name for Timer information.
*/
public static final String TIMER_LOGGER_NAME =
"javax.management.timer";
/**
* Logger for Timer information.
*/
public static final Logger TIMER_LOGGER =
System.getLogger(TIMER_LOGGER_NAME);
/**
* Logger name for Event Management information.
*/
public static final String NOTIFICATION_LOGGER_NAME =
"javax.management.notification";
/**
* Logger for Event Management information.
*/
public static final Logger NOTIFICATION_LOGGER =
System.getLogger(NOTIFICATION_LOGGER_NAME);
/**
* Logger name for Relation Service.
*/
public static final String RELATION_LOGGER_NAME =
"javax.management.relation";
/**
* Logger for Relation Service.
*/
public static final Logger RELATION_LOGGER =
System.getLogger(RELATION_LOGGER_NAME);
/**
* Logger name for Model MBean.
*/
public static final String MODELMBEAN_LOGGER_NAME =
"javax.management.modelmbean";
/**
* Logger for Model MBean.
*/
public static final Logger MODELMBEAN_LOGGER =
System.getLogger(MODELMBEAN_LOGGER_NAME);
/**
* Logger name for all other JMX classes.
*/
public static final String MISC_LOGGER_NAME =
"javax.management.misc";
/**
* Logger for all other JMX classes.
*/
public static final Logger MISC_LOGGER =
System.getLogger(MISC_LOGGER_NAME);
}

View file

@ -0,0 +1,97 @@
/*
* 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.defaults;
/**
* Used for storing default values used by JMX services.
*
* @since 1.5
*/
public class ServiceName {
// private constructor defined to "hide" the default public constructor
private ServiceName() {
}
/**
* The object name of the MBeanServer delegate object
* <BR>
* The value is <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.
*/
public static final String DELEGATE =
"JMImplementation:type=MBeanServerDelegate" ;
/**
* The default key properties for registering the class loader of the
* MLet service.
* <BR>
* The value is <CODE>type=MLet</CODE>.
*/
public static final String MLET = "type=MLet";
/**
* The default domain.
* <BR>
* The value is <CODE>DefaultDomain</CODE>.
*/
public static final String DOMAIN = "DefaultDomain";
/**
* The name of the JMX specification implemented by this product.
* <BR>
* The value is <CODE>Java Management Extensions</CODE>.
*/
public static final String JMX_SPEC_NAME = "Java Management Extensions";
/**
* The version of the JMX specification implemented by this product.
* <BR>
* The value is <CODE>1.4</CODE>.
*/
public static final String JMX_SPEC_VERSION = "1.4";
/**
* The vendor of the JMX specification implemented by this product.
* <BR>
* The value is <CODE>Oracle Corporation</CODE>.
*/
public static final String JMX_SPEC_VENDOR = "Oracle Corporation";
/**
* The name of this product implementing the JMX specification.
* <BR>
* The value is <CODE>JMX</CODE>.
*/
public static final String JMX_IMPL_NAME = "JMX";
/**
* The name of the vendor of this product implementing the
* JMX specification.
* <BR>
* The value is <CODE>Oracle Corporation</CODE>.
*/
public static final String JMX_IMPL_VENDOR = "Oracle Corporation";
}

View file

@ -0,0 +1,33 @@
<html>
<head>
<title>jmx.defaults package</title>
<!--
Copyright (c) 2002, 2003, 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.
-->
</head>
<body bgcolor="white">
Provides specific classes to <B>Sun JMX Reference Implementation</B>.
</BODY>
</HTML>

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2002, 2016, 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.interceptor;
import java.io.ObjectInputStream;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.ReflectionException;
import javax.management.loading.ClassLoaderRepository;
/**
* <p>This interface specifies the behavior to be implemented by an
* MBean Server Interceptor. An MBean Server Interceptor has
* essentially the same interface as an MBean Server. An MBean Server
* forwards received requests to its default interceptor, which may
* handle them itself or forward them to other interceptors. The
* default interceptor may be changed via the {@link
* com.sun.jmx.mbeanserver.SunJmxMBeanServer#setMBeanServerInterceptor}
* method.</p>
*
* <p>The initial default interceptor provides the standard MBean
* Server behavior. It handles a collection of named MBeans, each
* represented by a Java object. A replacement default interceptor
* may build on this behavior, for instance by adding logging or
* security checks, before forwarding requests to the initial default
* interceptor. Or, it may route each request to one of a number of
* sub-interceptors, for instance based on the {@link ObjectName} in
* the request.</p>
*
* <p>An interceptor, default or not, need not implement MBeans as
* Java objects, in the way that the initial default interceptor does.
* It may instead implement <em>virtual MBeans</em>, which do not
* exist as Java objects when they are not in use. For example, these
* MBeans could be implemented by forwarding requests to a database,
* or to a remote MBean server, or by performing system calls to query
* or modify system resources.</p>
*
* @since 1.5
*/
public interface MBeanServerInterceptor extends MBeanServer {
/**
* This method should never be called.
* Usually hrows UnsupportedOperationException.
*/
public Object instantiate(String className)
throws ReflectionException, MBeanException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.
*/
public Object instantiate(String className, ObjectName loaderName)
throws ReflectionException, MBeanException,
InstanceNotFoundException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.
*/
public Object instantiate(String className, Object[] params,
String[] signature) throws ReflectionException, MBeanException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.
*/
public Object instantiate(String className, ObjectName loaderName,
Object[] params, String[] signature)
throws ReflectionException, MBeanException,
InstanceNotFoundException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.
*/
public ClassLoaderRepository getClassLoaderRepository();
}

View file

@ -0,0 +1,36 @@
<html>
<head>
<title>jmx.interceptor package</title>
<!--
Copyright (c) 2002, 2003, 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.
-->
</head>
<body bgcolor="white">
Provides specific classes to <B>Sun JMX Reference Implementation</B>.
<p><b>
This API is a Sun internal API and is subject to changes without notice.
</b></p>
</BODY>
</HTML>

View file

@ -0,0 +1,311 @@
/*
* Copyright (c) 2002, 2017, 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.lang.System.Logger.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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE,
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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE,
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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE, "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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE,
"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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE,
"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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE,
"loader = " + aloader + " class = " + className);
}
}
}
public final void addClassLoader(ClassLoader loader) {
add(null, loader);
}
public final void removeClassLoader(ClassLoader loader) {
remove(null, loader);
}
public final synchronized void addClassLoader(ObjectName name,
ClassLoader loader) {
loadersWithNames.put(name, loader);
if (!(loader instanceof PrivateClassLoader))
add(name, loader);
}
public final synchronized void removeClassLoader(ObjectName name) {
ClassLoader loader = loadersWithNames.remove(name);
if (!(loader instanceof PrivateClassLoader))
remove(name, loader);
}
public final ClassLoader getClassLoader(ObjectName name) {
ClassLoader instance = loadersWithNames.get(name);
if (instance != null) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm =
new MBeanPermission(instance.getClass().getName(),
null,
name,
"getClassLoader");
sm.checkPermission(perm);
}
}
return instance;
}
}

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.io.InvalidObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import javax.management.Descriptor;
import javax.management.MBeanException;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import sun.reflect.misc.MethodUtil;
final class ConvertingMethod {
static ConvertingMethod from(Method m) {
try {
return new ConvertingMethod(m);
} catch (OpenDataException ode) {
final String msg = "Method " + m.getDeclaringClass().getName() +
"." + m.getName() + " has parameter or return type that " +
"cannot be translated into an open type";
throw new IllegalArgumentException(msg, ode);
}
}
Method getMethod() {
return method;
}
Descriptor getDescriptor() {
return Introspector.descriptorForElement(method);
}
Type getGenericReturnType() {
return method.getGenericReturnType();
}
Type[] getGenericParameterTypes() {
return method.getGenericParameterTypes();
}
String getName() {
return method.getName();
}
OpenType<?> getOpenReturnType() {
return returnMapping.getOpenType();
}
OpenType<?>[] getOpenParameterTypes() {
final OpenType<?>[] types = new OpenType<?>[paramMappings.length];
for (int i = 0; i < paramMappings.length; i++)
types[i] = paramMappings[i].getOpenType();
return types;
}
/* Check that this method will be callable when we are going from
* open types to Java types, for example when we are going from
* an MXBean wrapper to the underlying resource.
* The parameters will be converted to
* Java types, so they must be "reconstructible". The return
* value will be converted to an Open Type, so if it is convertible
* at all there is no further check needed.
*/
void checkCallFromOpen() {
try {
for (MXBeanMapping paramConverter : paramMappings)
paramConverter.checkReconstructible();
} catch (InvalidObjectException e) {
throw new IllegalArgumentException(e);
}
}
/* Check that this method will be callable when we are going from
* Java types to open types, for example when we are going from
* an MXBean proxy to the open types that it will be mapped to.
* The return type will be converted back to a Java type, so it
* must be "reconstructible". The parameters will be converted to
* open types, so if it is convertible at all there is no further
* check needed.
*/
void checkCallToOpen() {
try {
returnMapping.checkReconstructible();
} catch (InvalidObjectException e) {
throw new IllegalArgumentException(e);
}
}
String[] getOpenSignature() {
if (paramMappings.length == 0)
return noStrings;
String[] sig = new String[paramMappings.length];
for (int i = 0; i < paramMappings.length; i++)
sig[i] = paramMappings[i].getOpenClass().getName();
return sig;
}
final Object toOpenReturnValue(MXBeanLookup lookup, Object ret)
throws OpenDataException {
return returnMapping.toOpenValue(ret);
}
final Object fromOpenReturnValue(MXBeanLookup lookup, Object ret)
throws InvalidObjectException {
return returnMapping.fromOpenValue(ret);
}
final Object[] toOpenParameters(MXBeanLookup lookup, Object[] params)
throws OpenDataException {
if (paramConversionIsIdentity || params == null)
return params;
final Object[] oparams = new Object[params.length];
for (int i = 0; i < params.length; i++)
oparams[i] = paramMappings[i].toOpenValue(params[i]);
return oparams;
}
final Object[] fromOpenParameters(Object[] params)
throws InvalidObjectException {
if (paramConversionIsIdentity || params == null)
return params;
final Object[] jparams = new Object[params.length];
for (int i = 0; i < params.length; i++)
jparams[i] = paramMappings[i].fromOpenValue(params[i]);
return jparams;
}
final Object toOpenParameter(MXBeanLookup lookup,
Object param,
int paramNo)
throws OpenDataException {
return paramMappings[paramNo].toOpenValue(param);
}
final Object fromOpenParameter(MXBeanLookup lookup,
Object param,
int paramNo)
throws InvalidObjectException {
return paramMappings[paramNo].fromOpenValue(param);
}
Object invokeWithOpenReturn(MXBeanLookup lookup,
Object obj, Object[] params)
throws MBeanException, IllegalAccessException,
InvocationTargetException {
MXBeanLookup old = MXBeanLookup.getLookup();
try {
MXBeanLookup.setLookup(lookup);
return invokeWithOpenReturn(obj, params);
} finally {
MXBeanLookup.setLookup(old);
}
}
private Object invokeWithOpenReturn(Object obj, Object[] params)
throws MBeanException, IllegalAccessException,
InvocationTargetException {
final Object[] javaParams;
try {
javaParams = fromOpenParameters(params);
} catch (InvalidObjectException e) {
// probably can't happen
final String msg = methodName() + ": cannot convert parameters " +
"from open values: " + e;
throw new MBeanException(e, msg);
}
final Object javaReturn = MethodUtil.invoke(method, obj, javaParams);
try {
return returnMapping.toOpenValue(javaReturn);
} catch (OpenDataException e) {
// probably can't happen
final String msg = methodName() + ": cannot convert return " +
"value to open value: " + e;
throw new MBeanException(e, msg);
}
}
private String methodName() {
return method.getDeclaringClass() + "." + method.getName();
}
private ConvertingMethod(Method m) throws OpenDataException {
this.method = m;
MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT;
returnMapping =
mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
Type[] params = m.getGenericParameterTypes();
paramMappings = new MXBeanMapping[params.length];
boolean identity = true;
for (int i = 0; i < params.length; i++) {
paramMappings[i] = mappingFactory.mappingForType(params[i], mappingFactory);
identity &= DefaultMXBeanMappingFactory.isIdentity(paramMappings[i]);
}
paramConversionIsIdentity = identity;
}
private static final String[] noStrings = new String[0];
private final Method method;
private final MXBeanMapping returnMapping;
private final MXBeanMapping[] paramMappings;
private final boolean paramConversionIsIdentity;
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.JMX;
public class DescriptorCache {
private DescriptorCache() {
}
static DescriptorCache getInstance() {
return instance;
}
public static DescriptorCache getInstance(JMX proof) {
if (proof != null)
return instance;
else
return null;
}
public ImmutableDescriptor get(ImmutableDescriptor descriptor) {
WeakReference<ImmutableDescriptor> wr = map.get(descriptor);
ImmutableDescriptor got = (wr == null) ? null : wr.get();
if (got != null)
return got;
map.put(descriptor, new WeakReference<ImmutableDescriptor>(descriptor));
return descriptor;
}
public ImmutableDescriptor union(Descriptor... descriptors) {
return get(ImmutableDescriptor.union(descriptors));
}
private final static DescriptorCache instance = new DescriptorCache();
private final WeakHashMap<ImmutableDescriptor,
WeakReference<ImmutableDescriptor>>
map = new WeakHashMap<ImmutableDescriptor,
WeakReference<ImmutableDescriptor>>();
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.ObjectName;
/**
* A dynamic MBean that wraps an underlying resource. A version of this
* interface might eventually appear in the public JMX API.
*
* @since 1.6
*/
public interface DynamicMBean2 extends DynamicMBean {
/**
* The resource corresponding to this MBean. This is the object whose
* class name should be reflected by the MBean's
* getMBeanInfo().getClassName() for example. For a "plain"
* DynamicMBean it will be "this". For an MBean that wraps another
* object, like javax.management.StandardMBean, it will be the wrapped
* object.
*/
public Object getResource();
/**
* The name of this MBean's class, as used by permission checks.
* This is typically equal to getResource().getClass().getName().
* This method is typically faster, sometimes much faster,
* than getMBeanInfo().getClassName(), but should return the same
* result.
*/
public String getClassName();
/**
* Additional registration hook. This method is called after
* {@link javax.management.MBeanRegistration#preRegister preRegister}.
* Unlike that method, if it throws an exception and the MBean implements
* {@code MBeanRegistration}, then {@link
* javax.management.MBeanRegistration#postRegister postRegister(false)}
* will be called on the MBean. This is the behavior that the MBean
* expects for a problem that does not come from its own preRegister
* method.
*/
public void preRegister2(MBeanServer mbs, ObjectName name)
throws Exception;
/**
* Additional registration hook. This method is called if preRegister
* and preRegister2 succeed, but then the MBean cannot be registered
* (for example because there is already another MBean of the same name).
*/
public void registerFailed();
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.security.PrivilegedAction;
/**
* Utility class to be used by the method {@code AccessControler.doPrivileged}
* to get a system property.
*
* @since 1.5
*/
public class GetPropertyAction implements PrivilegedAction<String> {
private final String key;
public GetPropertyAction(String key) {
this.key = key;
}
public String run() {
return System.getProperty(key);
}
}

View file

@ -0,0 +1,698 @@
/*
* Copyright (c) 1999, 2015, 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;
if (JavaBeansAccessor.isAvailable()) {
readMethod = JavaBeansAccessor.getReadMethod(clazz, element);
} 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) {
if (Character.isUpperCase(property.charAt(0))) {
// the property name must start with a lower-case letter
return null;
}
// first character after 'get/is' prefix must be 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;
}
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2015, 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.Constructor;
import java.lang.reflect.Method;
import jdk.internal.misc.JavaBeansAccess;
import jdk.internal.misc.SharedSecrets;
/**
* A centralized place for gaining access to java.beans related functionality -
* if available.
*/
class JavaBeansAccessor {
static {
// ensure that java.beans.Introspector is initialized (if present)
// it will fill in the SharedSecrets
try {
Class.forName("java.beans.Introspector", true,
JavaBeansAccessor.class.getClassLoader());
} catch (ClassNotFoundException ignore) { }
}
private static JavaBeansAccess getJavaBeansAccess() {
return SharedSecrets.getJavaBeansAccess();
}
static boolean isAvailable() {
return getJavaBeansAccess() != null;
}
/**
* Returns the getter method for a property of the given name
* @param clazz The JavaBeans class
* @param property The property name
* @return The resolved property getter name or null
* @throws Exception
*/
static Method getReadMethod(Class<?> clazz, String property) throws Exception {
JavaBeansAccess jba = getJavaBeansAccess();
return jba != null ? jba.getReadMethod(clazz, property) : null;
}
/**
* Return the <b>value</b> attribute of the associated
* <code>@ConstructorProperties</code> annotation if that is present.
* @param ctr The constructor to extract the annotation value from
* @return The {@code value} attribute of the <code>@ConstructorProperties</code>
* annotation or {@code null} if the constructor is not annotated by
* this annotation or the annotation is not accessible.
*/
static String[] getConstructorPropertiesValue(Constructor<?> ctr) {
JavaBeansAccess jba = getJavaBeansAccess();
return jba != null ? jba.getConstructorPropertiesValue(ctr) : null;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerBuilder;
/**
* This class represents a builder that creates
* {@link javax.management.MBeanServer} implementations.
* The JMX {@link javax.management.MBeanServerFactory} allows
* for applications to provide their custom MBeanServer
* implementation. This class is not used when the whole Sun Reference JMX
* Implementation is used. However it may be used to substitute Sun
* MBeanServer implementation to another JMX implementation.
* <p>
* Contrarily to the default {@link javax.management.MBeanServerBuilder
* javax.management.MBeanServerBuilder} this MBeanServerBuilder returns
* MBeanServers on which
* {@link com.sun.jmx.interceptor.MBeanServerInterceptor}s are enabled.
*
* @since 1.5
*/
public class JmxMBeanServerBuilder extends MBeanServerBuilder {
/**
* This method creates a new MBeanServerDelegate for a new MBeanServer.
* When creating a new MBeanServer the
* {@link javax.management.MBeanServerFactory} first calls this method
* in order to create a new MBeanServerDelegate.
* <br>Then it calls
* <code>newMBeanServer(defaultDomain,outer,delegate)</code>
* passing the <var>delegate</var> that should be used by the MBeanServer
* implementation.
* <p>Note that the passed <var>delegate</var> might not be directly the
* MBeanServerDelegate that was returned by this method. It could
* be, for instance, a new object wrapping the previously
* returned object.
*
* @return A new {@link javax.management.MBeanServerDelegate}.
**/
public MBeanServerDelegate newMBeanServerDelegate() {
return JmxMBeanServer.newMBeanServerDelegate();
}
/**
* This method creates a new MBeanServer implementation object.
* When creating a new MBeanServer the
* {@link javax.management.MBeanServerFactory} first calls
* <code>newMBeanServerDelegate()</code> in order to obtain a new
* {@link javax.management.MBeanServerDelegate} for the new
* MBeanServer. Then it calls
* <code>newMBeanServer(defaultDomain,outer,delegate)</code>
* passing the <var>delegate</var> that should be used by the
* MBeanServer implementation.
* <p>Note that the passed <var>delegate</var> might not be directly the
* MBeanServerDelegate that was returned by this implementation. It could
* be, for instance, a new object wrapping the previously
* returned delegate.
* <p>The <var>outer</var> parameter is a pointer to the MBeanServer that
* should be passed to the {@link javax.management.MBeanRegistration}
* interface when registering MBeans inside the MBeanServer.
* If <var>outer</var> is <code>null</code>, then the MBeanServer
* implementation is free to use its own <code>this</code> pointer when
* invoking the {@link javax.management.MBeanRegistration} interface.
* <p>This makes it possible for a MBeanServer implementation to wrap
* another MBeanServer implementation, in order to implement, e.g,
* security checks, or to prevent access to the actual MBeanServer
* implementation by returning a pointer to a wrapping object.
* <p>
* This MBeanServerBuilder makes it possible to create MBeanServer
* which support {@link com.sun.jmx.interceptor.MBeanServerInterceptor}s.
*
* @param defaultDomain Default domain of the new MBeanServer.
* @param outer A pointer to the MBeanServer object that must be
* passed to the MBeans when invoking their
* {@link javax.management.MBeanRegistration} interface.
* @param delegate A pointer to the MBeanServerDelegate associated
* with the new MBeanServer. The new MBeanServer must register
* this MBean in its MBean repository.
*
* @return A new private implementation of an MBeanServer.
**/
public MBeanServer newMBeanServer(String defaultDomain,
MBeanServer outer,
MBeanServerDelegate delegate) {
return JmxMBeanServer.newMBeanServer(defaultDomain,outer,delegate,
true);
}
}

View file

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

View file

@ -0,0 +1,778 @@
/*
* Copyright (c) 2000, 2017, 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.lang.System.Logger.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.DEBUG)) {
MBEANSERVER_LOGGER.log(Level.DEBUG,
"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.DEBUG)) {
MBEANSERVER_LOGGER.log(Level.DEBUG,
"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.DEBUG)) {
MBEANSERVER_LOGGER.log(Level.DEBUG,
"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.DEBUG)) {
MBEANSERVER_LOGGER.log(Level.DEBUG,
"Unexpected exception", e);
}
throw e;
}
return tab;
}
private Constructor<?> findConstructor(Class<?> c, Class<?>[] params) {
try {
return ConstructorUtil.getConstructor(c, params);
} catch (Exception e) {
return null;
}
}
private static final Map<String, Class<?>> primitiveClasses = Util.newMap();
static {
for (Class<?> c : new Class<?>[] {byte.class, short.class, int.class,
long.class, float.class, double.class,
char.class, boolean.class})
primitiveClasses.put(c.getName(), c);
}
private static void checkMBeanPermission(Class<?> clazz,
String member,
ObjectName objectName,
String actions) {
if (clazz != null) {
checkMBeanPermission(clazz.getName(), member, objectName, actions);
}
}
private static void checkMBeanPermission(String classname,
String member,
ObjectName objectName,
String actions)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm = new MBeanPermission(classname,
member,
objectName,
actions);
sm.checkPermission(perm);
}
}
private static void ensureClassAccess(Class<?> clazz)
throws IllegalAccessException
{
int mod = clazz.getModifiers();
if (!Modifier.isPublic(mod)) {
throw new IllegalAccessException("Class is not public and can't be instantiated");
}
}
private ClassLoader getClassLoader(final ObjectName name) {
if(clr == null){
return null;
}
// Restrict to getClassLoader permission only
Permissions permissions = new Permissions();
permissions.add(new MBeanPermission("*", null, name, "getClassLoader"));
ProtectionDomain protectionDomain = new ProtectionDomain(null, permissions);
ProtectionDomain[] domains = {protectionDomain};
AccessControlContext ctx = new AccessControlContext(domains);
ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return clr.getClassLoader(name);
}
}, ctx);
return loader;
}
}

View file

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

View file

@ -0,0 +1,319 @@
/*
* Copyright (c) 2002, 2017, 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.System.Logger.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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE,
"Attribute " + attn[i] + " not found");
}
}
}
// Finally return the result.
//
return list;
}
/**
* This method always return an empty list since all
* MBeanServerDelegateMBean attributes are read-only.
*
* @param attributes A list of attributes: The identification of the
* attributes to be set and the values they are to be set to.
*
* @return The list of attributes that were set, with their new values.
* In fact, this method always return an empty list since all
* MBeanServerDelegateMBean attributes are read-only.
*/
public AttributeList setAttributes(AttributeList attributes) {
return new AttributeList(0);
}
/**
* Always fails since the MBeanServerDelegate MBean has no operation.
*
* @param actionName The name of the action to be invoked.
* @param params An array containing the parameters to be set when the
* action is invoked.
* @param signature An array containing the signature of the action.
*
* @return The object returned by the action, which represents
* the result of invoking the action on the MBean specified.
*
* @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE>
* thrown by the MBean's invoked method.
* @exception ReflectionException Wraps a
* <CODE>java.lang.Exception</CODE> thrown while trying to invoke
* the method.
*/
public Object invoke(String actionName, Object params[],
String signature[])
throws MBeanException, ReflectionException {
// Check that operation name is not null.
//
if (actionName == null) {
final RuntimeException r =
new IllegalArgumentException("Operation name cannot be null");
throw new RuntimeOperationsException(r,
"Exception occurred trying to invoke the operation on the MBean");
}
throw new ReflectionException(
new NoSuchMethodException(actionName),
"The operation with name " + actionName +
" could not be found");
}
/**
* Provides the MBeanInfo describing the MBeanServerDelegate.
*
* @return The MBeanInfo describing the MBeanServerDelegate.
*
*/
public MBeanInfo getMBeanInfo() {
return delegateInfo;
}
}

View file

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

View file

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

View file

@ -0,0 +1,188 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.util.Map;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import javax.management.InstanceAlreadyExistsException;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.openmbean.OpenDataException;
/**
* @since 1.6
*/
/*
* This class handles the mapping between MXBean references and
* ObjectNames. Consider an MXBean interface like this:
*
* public interface ModuleMXBean {
* ProductMXBean getProduct();
* void setProduct(ProductMXBean product);
* }
*
* This defines an attribute called "Product" whose originalType will
* be ProductMXBean and whose openType will be ObjectName. The
* mapping happens as follows.
*
* When the MXBean's getProduct method is called, it is supposed to
* return a reference to another MXBean, or a proxy for another
* MXBean. The MXBean layer has to convert this into an ObjectName.
* If it's a reference to another MXBean, it needs to be able to look
* up the name under which that MXBean has been registered in this
* MBeanServer; this is the purpose of the mxbeanToObjectName map. If
* it's a proxy, it can check that the MBeanServer matches and if so
* extract the ObjectName from the proxy.
*
* When the setProduct method is called on a proxy for this MXBean,
* the argument can be either an MXBean reference (only really logical
* if the proxy has a local MBeanServer) or another proxy. So the
* mapping logic is the same as for getProduct on the MXBean.
*
* When the MXBean's setProduct method is called, it needs to convert
* the ObjectName into an object implementing the ProductMXBean
* interface. We could have a lookup table that reverses
* mxbeanToObjectName, but this could violate the general JMX property
* that you cannot obtain a reference to an MBean object. So we
* always use a proxy for this. However we do have an
* objectNameToProxy map that allows us to reuse proxy instances.
*
* When the getProduct method is called on a proxy for this MXBean, it
* must convert the returned ObjectName into an instance of
* ProductMXBean. Again it can do this by making a proxy.
*
* From the above, it is clear that the logic for getX on an MXBean is
* the same as for setX on a proxy, and vice versa.
*/
public class MXBeanLookup {
private MXBeanLookup(MBeanServerConnection mbsc) {
this.mbsc = mbsc;
}
static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
synchronized (mbscToLookup) {
WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
if (lookup == null) {
lookup = new MXBeanLookup(mbsc);
mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
}
return lookup;
}
}
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
WeakReference<Object> wr = objectNameToProxy.get(name);
if (wr != null) {
Object proxy = wr.get();
if (type.isInstance(proxy))
return type.cast(proxy);
}
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
return proxy;
}
synchronized ObjectName mxbeanToObjectName(Object mxbean)
throws OpenDataException {
String wrong;
if (mxbean instanceof Proxy) {
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
if (ih instanceof MBeanServerInvocationHandler) {
MBeanServerInvocationHandler mbsih =
(MBeanServerInvocationHandler) ih;
if (mbsih.getMBeanServerConnection().equals(mbsc))
return mbsih.getObjectName();
else
wrong = "proxy for a different MBeanServer";
} else
wrong = "not a JMX proxy";
} else {
ObjectName name = mxbeanToObjectName.get(mxbean);
if (name != null)
return name;
wrong = "not an MXBean registered in this MBeanServer";
}
String s = (mxbean == null) ?
"null" : "object of type " + mxbean.getClass().getName();
throw new OpenDataException(
"Could not convert " + s + " to an ObjectName: " + wrong);
// Message will be strange if mxbean is null but it is not
// supposed to be.
}
synchronized void addReference(ObjectName name, Object mxbean)
throws InstanceAlreadyExistsException {
ObjectName existing = mxbeanToObjectName.get(mxbean);
if (existing != null) {
String multiname = AccessController.doPrivileged(
new GetPropertyAction("jmx.mxbean.multiname"));
if (!"true".equalsIgnoreCase(multiname)) {
throw new InstanceAlreadyExistsException(
"MXBean already registered with name " + existing);
}
}
mxbeanToObjectName.put(mxbean, name);
}
synchronized boolean removeReference(ObjectName name, Object mxbean) {
if (name.equals(mxbeanToObjectName.get(mxbean))) {
mxbeanToObjectName.remove(mxbean);
return true;
} else
return false;
/* removeReference can be called when the above condition fails,
* notably if you try to register the same MXBean twice.
*/
}
static MXBeanLookup getLookup() {
return currentLookup.get();
}
static void setLookup(MXBeanLookup lookup) {
currentLookup.set(lookup);
}
private static final ThreadLocal<MXBeanLookup> currentLookup =
new ThreadLocal<MXBeanLookup>();
private final MBeanServerConnection mbsc;
private final WeakIdentityHashMap<Object, ObjectName>
mxbeanToObjectName = WeakIdentityHashMap.make();
private final Map<ObjectName, WeakReference<Object>>
objectNameToProxy = newMap();
private static final WeakIdentityHashMap<MBeanServerConnection,
WeakReference<MXBeanLookup>>
mbscToLookup = WeakIdentityHashMap.make();
}

View file

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

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.openmbean.*;
import com.sun.jmx.mbeanserver.MXBeanMapping;
import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
import java.lang.reflect.Type;
/**
* <p>Defines how types are mapped for a given MXBean or set of MXBeans.
* An {@code MXBeanMappingFactory} can be specified either through the
* {@link MXBeanMappingFactoryClass} annotation, or through the
* {@link javax.management.JMX.MBeanOptions JMX.MBeanOptions} argument to a
* {@link javax.management.StandardMBean StandardMBean} constructor or MXBean
* proxy.</p>
*
* <p>An {@code MXBeanMappingFactory} must return an {@code MXBeanMapping}
* for any Java type that appears in the MXBeans that the factory is being
* used for. Usually it does that by handling any custom types, and
* forwarding everything else to the {@linkplain #DEFAULT default mapping
* factory}.</p>
*
* <p>Consider the {@code MyLinkedList} example from the {@link MXBeanMapping}
* documentation. If we are unable to change the {@code MyLinkedList} class
* to add an {@link MXBeanMappingClass} annotation, we could achieve the same
* effect by defining {@code MyLinkedListMappingFactory} as follows:</p>
*
* <pre>
* public class MyLinkedListMappingFactory extends MXBeanMappingFactory {
* public MyLinkedListMappingFactory() {}
*
* public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
* throws OpenDataException {
* if (t == MyLinkedList.class)
* return new MyLinkedListMapping(t);
* else
* return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);
* }
* }
* </pre>
*
* <p>The mapping factory handles only the {@code MyLinkedList} class.
* Every other type is forwarded to the default mapping factory.
* This includes types such as {@code MyLinkedList[]} and
* {@code List<MyLinkedList>}; the default mapping factory will recursively
* invoke {@code MyLinkedListMappingFactory} to map the contained
* {@code MyLinkedList} type.</p>
*
* <p>Once we have defined {@code MyLinkedListMappingFactory}, we can use
* it in an MXBean interface like this:</p>
*
* <pre>
* {@literal @MXBeanMappingFactoryClass}(MyLinkedListMappingFactory.class)
* public interface SomethingMXBean {
* public MyLinkedList getSomething();
* }
* </pre>
*
* <p>Alternatively we can annotate the package that {@code SomethingMXBean}
* appears in, or we can supply the factory to a {@link
* javax.management.StandardMBean StandardMBean} constructor or MXBean
* proxy.</p>
*
* @see <a href="../MXBean.html#custom">MXBean specification, section
* "Custom MXBean type mappings"</a>
*/
public abstract class MXBeanMappingFactory {
/**
* <p>Construct an instance of this class.</p>
*/
protected MXBeanMappingFactory() {}
/**
* <p>Mapping factory that applies the default rules for MXBean
* mappings, as described in the <a
* href="../MXBean.html#MXBean-spec">MXBean specification</a>.</p>
*/
public static final MXBeanMappingFactory DEFAULT =
new DefaultMXBeanMappingFactory();
/**
* <p>Return the mapping for the given Java type. Typically, a
* mapping factory will return mappings for types it handles, and
* forward other types to another mapping factory, most often
* the {@linkplain #DEFAULT default one}.</p>
* @param t the Java type to be mapped.
* @param f the original mapping factory that was consulted to do
* the mapping. A mapping factory should pass this parameter intact
* if it forwards a type to another mapping factory. In the example,
* this is how {@code MyLinkedListMappingFactory} works for types
* like {@code MyLinkedList[]} and {@code List<MyLinkedList>}.
* @return the mapping for the given type.
* @throws OpenDataException if this type cannot be mapped. This
* exception is appropriate if the factory is supposed to handle
* all types of this sort (for example, all linked lists), but
* cannot handle this particular type.
*/
public abstract MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
throws OpenDataException;
}

View file

@ -0,0 +1,175 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.reflect.Method;
import java.util.Map;
import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
<p>Helper class for an {@link InvocationHandler} that forwards methods from an
MXBean interface to a named
MXBean in an MBean Server and handles translation between the
arbitrary Java types in the interface and the Open Types used
by the MXBean.</p>
@since 1.6
*/
public class MXBeanProxy {
public MXBeanProxy(Class<?> mxbeanInterface) {
if (mxbeanInterface == null)
throw new IllegalArgumentException("Null parameter");
final MBeanAnalyzer<ConvertingMethod> analyzer;
try {
analyzer =
MXBeanIntrospector.getInstance().getAnalyzer(mxbeanInterface);
} catch (NotCompliantMBeanException e) {
throw new IllegalArgumentException(e);
}
analyzer.visit(new Visitor());
}
private class Visitor
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod> {
public void visitAttribute(String attributeName,
ConvertingMethod getter,
ConvertingMethod setter) {
if (getter != null) {
getter.checkCallToOpen();
Method getterMethod = getter.getMethod();
handlerMap.put(getterMethod,
new GetHandler(attributeName, getter));
}
if (setter != null) {
// return type is void, no need for checkCallToOpen
Method setterMethod = setter.getMethod();
handlerMap.put(setterMethod,
new SetHandler(attributeName, setter));
}
}
public void visitOperation(String operationName,
ConvertingMethod operation) {
operation.checkCallToOpen();
Method operationMethod = operation.getMethod();
String[] sig = operation.getOpenSignature();
handlerMap.put(operationMethod,
new InvokeHandler(operationName, sig, operation));
}
}
private static abstract class Handler {
Handler(String name, ConvertingMethod cm) {
this.name = name;
this.convertingMethod = cm;
}
String getName() {
return name;
}
ConvertingMethod getConvertingMethod() {
return convertingMethod;
}
abstract Object invoke(MBeanServerConnection mbsc,
ObjectName name, Object[] args) throws Exception;
private final String name;
private final ConvertingMethod convertingMethod;
}
private static class GetHandler extends Handler {
GetHandler(String attributeName, ConvertingMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
assert(args == null || args.length == 0);
return mbsc.getAttribute(name, getName());
}
}
private static class SetHandler extends Handler {
SetHandler(String attributeName, ConvertingMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
assert(args.length == 1);
Attribute attr = new Attribute(getName(), args[0]);
mbsc.setAttribute(name, attr);
return null;
}
}
private static class InvokeHandler extends Handler {
InvokeHandler(String operationName, String[] signature,
ConvertingMethod cm) {
super(operationName, cm);
this.signature = signature;
}
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
return mbsc.invoke(name, getName(), args, signature);
}
private final String[] signature;
}
public Object invoke(MBeanServerConnection mbsc, ObjectName name,
Method method, Object[] args)
throws Throwable {
Handler handler = handlerMap.get(method);
ConvertingMethod cm = handler.getConvertingMethod();
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc);
MXBeanLookup oldLookup = MXBeanLookup.getLookup();
try {
MXBeanLookup.setLookup(lookup);
Object[] openArgs = cm.toOpenParameters(lookup, args);
Object result = handler.invoke(mbsc, name, openArgs);
return cm.fromOpenReturnValue(lookup, result);
} finally {
MXBeanLookup.setLookup(oldLookup);
}
}
private final Map<Method, Handler> handlerMap = newMap();
}

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.util.Iterator;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
* Base class for MXBeans.
*
* @since 1.6
*/
public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
/**
<p>Construct an MXBean that wraps the given resource using the
given MXBean interface.</p>
@param resource the underlying resource for the new MXBean.
@param mxbeanInterface the interface to be used to determine
the MXBean's management interface.
@param <T> a type parameter that allows the compiler to check
that {@code resource} implements {@code mxbeanInterface},
provided that {@code mxbeanInterface} is a class constant like
{@code SomeMXBean.class}.
@throws IllegalArgumentException if {@code resource} is null or
if it does not implement the class {@code mxbeanInterface} or if
that class is not a valid MXBean interface.
*/
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface)
throws NotCompliantMBeanException {
super(resource, mxbeanInterface);
}
@Override
MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() {
return MXBeanIntrospector.getInstance();
}
@Override
Object getCookie() {
return mxbeanLookup;
}
static <T> Class<? super T> findMXBeanInterface(Class<T> resourceClass) {
if (resourceClass == null)
throw new IllegalArgumentException("Null resource class");
final Set<Class<?>> intfs = transitiveInterfaces(resourceClass);
final Set<Class<?>> candidates = newSet();
for (Class<?> intf : intfs) {
if (JMX.isMXBeanInterface(intf))
candidates.add(intf);
}
reduce:
while (candidates.size() > 1) {
for (Class<?> intf : candidates) {
for (Iterator<Class<?>> it = candidates.iterator(); it.hasNext();
) {
final Class<?> intf2 = it.next();
if (intf != intf2 && intf2.isAssignableFrom(intf)) {
it.remove();
continue reduce;
}
}
}
final String msg =
"Class " + resourceClass.getName() + " implements more than " +
"one MXBean interface: " + candidates;
throw new IllegalArgumentException(msg);
}
if (candidates.iterator().hasNext()) {
return Util.cast(candidates.iterator().next());
} else {
final String msg =
"Class " + resourceClass.getName() +
" is not a JMX compliant MXBean";
throw new IllegalArgumentException(msg);
}
}
/* Return all interfaces inherited by this class, directly or
* indirectly through the parent class and interfaces.
*/
private static Set<Class<?>> transitiveInterfaces(Class<?> c) {
Set<Class<?>> set = newSet();
transitiveInterfaces(c, set);
return set;
}
private static void transitiveInterfaces(Class<?> c, Set<Class<?>> intfs) {
if (c == null)
return;
if (c.isInterface())
intfs.add(c);
transitiveInterfaces(c.getSuperclass(), intfs);
for (Class<?> sup : c.getInterfaces())
transitiveInterfaces(sup, intfs);
}
/*
* The sequence of events for tracking inter-MXBean references is
* relatively complicated. We use the magical preRegister2 method
* which the MBeanServer knows about. The steps during registration
* are:
* (1) Call user preRegister, if any. If exception, abandon.
* (2) Call preRegister2 and hence this register method. If exception,
* call postRegister(false) and abandon.
* (3) Try to register the MBean. If exception, call registerFailed()
* which will call the unregister method. (Also call postRegister(false).)
* (4) If we get this far, we can call postRegister(true).
*
* When we are wrapped in an instance of javax.management.StandardMBean,
* things are simpler. That class calls this method from its preRegister,
* and propagates any exception. There is no user preRegister in this case.
* If this method succeeds but registration subsequently fails,
* StandardMBean calls unregister from its postRegister(false) method.
*/
@Override
public void register(MBeanServer server, ObjectName name)
throws InstanceAlreadyExistsException {
if (name == null)
throw new IllegalArgumentException("Null object name");
// eventually we could have some logic to supply a default name
synchronized (lock) {
this.mxbeanLookup = MXBeanLookup.lookupFor(server);
this.mxbeanLookup.addReference(name, getResource());
this.objectName = name;
}
}
@Override
public void unregister() {
synchronized (lock) {
if (mxbeanLookup != null) {
if (mxbeanLookup.removeReference(objectName, getResource()))
objectName = null;
}
}
}
private final Object lock = new Object(); // for mxbeanLookup and objectName
private MXBeanLookup mxbeanLookup;
private ObjectName objectName;
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
// JMX import
import javax.management.ObjectName;
import javax.management.loading.ClassLoaderRepository;
/**
* This interface keeps the list of Class Loaders registered in the
* MBean Server.
* It provides the necessary methods to load classes using the
* registered Class Loaders, and to add/remove class loaders from the
* list.
*
* @since 1.5
*/
public interface ModifiableClassLoaderRepository
extends ClassLoaderRepository {
/**
* Add an anonymous ClassLoader to the repository.
**/
public void addClassLoader(ClassLoader loader);
/**
* Remove the specified ClassLoader to the repository.
* The class loader may or may not be anonymous.
**/
public void removeClassLoader(ClassLoader loader);
/**
* Add a named ClassLoader to the repository.
**/
public void addClassLoader(ObjectName name, ClassLoader loader);
/**
* Remove a named ClassLoader from the repository.
**/
public void removeClassLoader(ObjectName name);
/**
* Get a named ClassLoader from the repository.
**/
public ClassLoader getClassLoader(ObjectName name);
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.* ;
/**
* This class is used for storing a pair (name, object) where name is
* an object name and object is a reference to the object.
*
* @since 1.5
*/
public class NamedObject {
/**
* Object name.
*/
private final ObjectName name;
/**
* Object reference.
*/
private final DynamicMBean object;
/**
* Allows a named object to be created.
*
*@param objectName The object name of the object.
*@param object A reference to the object.
*/
public NamedObject(ObjectName objectName, DynamicMBean object) {
if (objectName.isPattern()) {
throw new RuntimeOperationsException(new IllegalArgumentException("Invalid name->"+ objectName.toString()));
}
this.name= objectName;
this.object= object;
}
/**
* Allows a named object to be created.
*
*@param objectName The string representation of the object name of the object.
*@param object A reference to the object.
*
*@exception MalformedObjectNameException The string passed does not have the format of a valid ObjectName
*/
public NamedObject(String objectName, DynamicMBean object) throws MalformedObjectNameException{
ObjectName objName= new ObjectName(objectName);
if (objName.isPattern()) {
throw new RuntimeOperationsException(new IllegalArgumentException("Invalid name->"+ objName.toString()));
}
this.name= objName;
this.object= object;
}
/**
* Compares the current object name with another object name.
*
* @param object The Named Object that the current object name is to be
* compared with.
*
* @return True if the two named objects are equal, otherwise false.
*/
public boolean equals(Object object) {
if (this == object) return true;
if (object == null) return false;
if (!(object instanceof NamedObject)) return false;
NamedObject no = (NamedObject) object;
return name.equals(no.getName());
}
/**
* Returns a hash code for this named object.
*
*/
public int hashCode() {
return name.hashCode();
}
/**
* Get the object name.
*/
public ObjectName getName() {
return name;
}
/**
* Get the object
*/
public DynamicMBean getObject() {
return object;
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
// Java import
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import sun.reflect.misc.ReflectUtil;
/**
* This class deserializes an object in the context of a specific class loader.
*
* @since 1.5
*/
class ObjectInputStreamWithLoader extends ObjectInputStream {
private ClassLoader loader;
/**
* @exception IOException Signals that an I/O exception of some
* sort has occurred.
* @exception StreamCorruptedException The object stream is corrupt.
*/
public ObjectInputStreamWithLoader(InputStream in, ClassLoader theLoader)
throws IOException {
super(in);
this.loader = theLoader;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass aClass)
throws IOException, ClassNotFoundException {
if (loader == null) {
return super.resolveClass(aClass);
} else {
String name = aClass.getName();
ReflectUtil.checkPackageAccess(name);
// Query the class loader ...
return Class.forName(name, false, loader);
}
}
}

View file

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

View file

@ -0,0 +1,674 @@
/*
* Copyright (c) 1999, 2017, 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.lang.System.Logger.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.DEBUG,
"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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE, "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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE, "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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE, "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.TRACE)) {
MBEANSERVER_LOGGER.log(Level.TRACE, "name = " + name);
}
// Extract domain name.
String dom= name.getDomain().intern();
// Default domain case
if (dom.length() == 0) dom = domain;
lock.writeLock().lock();
try {
// Find the domain subtable
final Map<String,NamedObject> moiTb = domainTb.get(dom);
if (moiTb == null) {
throw new InstanceNotFoundException(name.toString());
}
// Remove the corresponding element
if (moiTb.remove(name.getCanonicalKeyPropertyListString())==null) {
throw new InstanceNotFoundException(name.toString());
}
// We removed it !
nbElements--;
// No more object for this domain, we remove this domain hashtable
if (moiTb.isEmpty()) {
domainTb.remove(dom);
// set a new default domain table (always present)
// need to reinstantiate a hashtable because of possible
// big buckets array size inside table, never cleared,
// thus the new !
if (dom == domain) // ES: OK dom and domain are interned.
domainTb.put(domain, new HashMap<String,NamedObject>());
}
unregistering(context,name);
} finally {
lock.writeLock().unlock();
}
}
/**
* Gets the number of MBeans stored in the repository.
*
* @return Number of MBeans.
*/
public Integer getCount() {
return nbElements;
}
/**
* Gets the name of the domain currently used by default in the
* repository.
*
* @return A string giving the name of the default domain name.
*/
public String getDefaultDomain() {
return domain;
}
// Public methods <=============================================
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.loading.ClassLoaderRepository;
/**
* Fix security hole in ClassLoaderRepository. This class wraps
* the actual ClassLoaderRepository implementation so that
* only the methods from {@link javax.management.loading.ClassLoaderRepository}
* can be accessed (read-only).
*
* @since 1.5
*/
final class SecureClassLoaderRepository
implements ClassLoaderRepository {
private final ClassLoaderRepository clr;
/**
* Creates a new secure ClassLoaderRepository wrapping an
* unsecure implementation.
* @param clr Unsecure {@link ClassLoaderRepository} implementation
* to wrap.
**/
public SecureClassLoaderRepository(ClassLoaderRepository clr) {
this.clr=clr;
}
public final Class<?> loadClass(String className)
throws ClassNotFoundException {
return clr.loadClass(className);
}
public final Class<?> loadClassWithout(ClassLoader loader,
String className)
throws ClassNotFoundException {
return clr.loadClassWithout(loader,className);
}
public final Class<?> loadClassBefore(ClassLoader loader,
String className)
throws ClassNotFoundException {
return clr.loadClassBefore(loader,className);
}
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.WeakHashMap;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
import sun.reflect.misc.MethodUtil;
/**
* @since 1.6
*/
class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
private static final StandardMBeanIntrospector instance =
new StandardMBeanIntrospector();
static StandardMBeanIntrospector getInstance() {
return instance;
}
@Override
PerInterfaceMap<Method> getPerInterfaceMap() {
return perInterfaceMap;
}
@Override
MBeanInfoMap getMBeanInfoMap() {
return mbeanInfoMap;
}
@Override
MBeanAnalyzer<Method> getAnalyzer(Class<?> mbeanInterface)
throws NotCompliantMBeanException {
return MBeanAnalyzer.analyzer(mbeanInterface, this);
}
@Override
boolean isMXBean() {
return false;
}
@Override
Method mFrom(Method m) {
return m;
}
@Override
String getName(Method m) {
return m.getName();
}
@Override
Type getGenericReturnType(Method m) {
return m.getGenericReturnType();
}
@Override
Type[] getGenericParameterTypes(Method m) {
return m.getGenericParameterTypes();
}
@Override
String[] getSignature(Method m) {
Class<?>[] params = m.getParameterTypes();
String[] sig = new String[params.length];
for (int i = 0; i < params.length; i++)
sig[i] = params[i].getName();
return sig;
}
@Override
void checkMethod(Method m) {
}
@Override
Object invokeM2(Method m, Object target, Object[] args, Object cookie)
throws InvocationTargetException, IllegalAccessException,
MBeanException {
return MethodUtil.invoke(m, target, args);
}
@Override
boolean validParameter(Method m, Object value, int paramNo, Object cookie) {
return isValidParameter(m, value, paramNo);
}
@Override
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
Method getter, Method setter) {
final String description = "Attribute exposed for management";
try {
return new MBeanAttributeInfo(attributeName, description,
getter, setter);
} catch (IntrospectionException e) {
throw new RuntimeException(e); // should not happen
}
}
@Override
MBeanOperationInfo getMBeanOperationInfo(String operationName,
Method operation) {
final String description = "Operation exposed for management";
return new MBeanOperationInfo(description, operation);
}
@Override
Descriptor getBasicMBeanDescriptor() {
/* We don't bother saying mxbean=false, and we can't know whether
the info is immutable until we know whether the MBean class
(not interface) is a NotificationBroadcaster. */
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
}
@Override
Descriptor getMBeanDescriptor(Class<?> resourceClass) {
boolean immutable = isDefinitelyImmutableInfo(resourceClass);
return new ImmutableDescriptor("mxbean=false",
"immutableInfo=" + immutable);
}
/* Return true if and only if we can be sure that the given MBean implementation
* class has immutable MBeanInfo. A Standard MBean that is a
* NotificationBroadcaster is allowed to return different values at
* different times from its getNotificationInfo() method, which is when
* we might not know if it is immutable. But if it is a subclass of
* NotificationBroadcasterSupport and does not override
* getNotificationInfo(), then we know it won't change.
*/
static boolean isDefinitelyImmutableInfo(Class<?> implClass) {
if (!NotificationBroadcaster.class.isAssignableFrom(implClass))
return true;
synchronized (definitelyImmutable) {
Boolean immutable = definitelyImmutable.get(implClass);
if (immutable == null) {
final Class<NotificationBroadcasterSupport> nbs =
NotificationBroadcasterSupport.class;
if (nbs.isAssignableFrom(implClass)) {
try {
Method m = implClass.getMethod("getNotificationInfo");
immutable = (m.getDeclaringClass() == nbs);
} catch (Exception e) {
// Too bad, we'll say no for now.
return false;
}
} else
immutable = false;
definitelyImmutable.put(implClass, immutable);
}
return immutable;
}
}
private static final WeakHashMap<Class<?>, Boolean> definitelyImmutable =
new WeakHashMap<Class<?>, Boolean>();
private static final PerInterfaceMap<Method>
perInterfaceMap = new PerInterfaceMap<Method>();
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.reflect.Method;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
* Base class for Standard MBeans.
*
* @since 1.6
*/
public class StandardMBeanSupport extends MBeanSupport<Method> {
/**
* <p>Construct a Standard MBean that wraps the given resource using the
* given Standard MBean interface.</p>
*
* @param resource the underlying resource for the new MBean.
* @param mbeanInterfaceType the class or interface to be used to determine
* the MBean's management interface. An interface if this is a
* classic Standard MBean; a class if this is a {@code @ManagedResource}.
* @param <T> a type parameter that allows the compiler to check
* that {@code resource} implements {@code mbeanInterfaceType},
* provided that {@code mbeanInterfaceType} is a class constant like
* {@code SomeMBean.class}.
* @throws IllegalArgumentException if {@code resource} is null or
* if it does not implement the class {@code mbeanInterfaceType} or if
* that class is not a valid Standard MBean interface.
*/
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType)
throws NotCompliantMBeanException {
super(resource, mbeanInterfaceType);
}
@Override
MBeanIntrospector<Method> getMBeanIntrospector() {
return StandardMBeanIntrospector.getInstance();
}
@Override
Object getCookie() {
return null;
}
@Override
public void register(MBeanServer mbs, ObjectName name) {}
@Override
public void unregister() {}
/* Standard MBeans that are NotificationBroadcasters can return a different
* MBeanNotificationInfo[] every time getMBeanInfo() is called, so we have
* to reconstruct this MBeanInfo if necessary.
*/
@Override
public MBeanInfo getMBeanInfo() {
MBeanInfo mbi = super.getMBeanInfo();
Class<?> resourceClass = getResource().getClass();
if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
return mbi;
return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
mbi.getAttributes(), mbi.getConstructors(),
mbi.getOperations(),
MBeanIntrospector.findNotifications(getResource()),
mbi.getDescriptor());
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
/**
* Extends the MBeanServer interface to
* provide methods for getting the MetaData and MBeanServerInstantiator
* objects associated with an MBeanServer.
*
* @since 1.5
*/
public interface SunJmxMBeanServer
extends MBeanServer {
/**
* Return the MBeanInstantiator associated to this MBeanServer.
* @exception UnsupportedOperationException if
* {@link MBeanServerInterceptor}s
* are not enabled on this object.
* @see #interceptorsEnabled
*/
public MBeanInstantiator getMBeanInstantiator();
/**
* Tell whether {@link MBeanServerInterceptor}s are enabled on this
* object.
* @return <code>true</code> if {@link MBeanServerInterceptor}s are
* enabled.
* @see #getMBeanServerInterceptor
* @see #setMBeanServerInterceptor
* @see #getMBeanInstantiator
* @see com.sun.jmx.mbeanserver.JmxMBeanServerBuilder
**/
public boolean interceptorsEnabled();
/**
* Return the MBeanServerInterceptor.
* @exception UnsupportedOperationException if
* {@link MBeanServerInterceptor}s
* are not enabled on this object.
* @see #interceptorsEnabled
**/
public MBeanServer getMBeanServerInterceptor();
/**
* Set the MBeanServerInterceptor.
* @exception UnsupportedOperationException if
* {@link MBeanServerInterceptor}s
* are not enabled on this object.
* @see #interceptorsEnabled
**/
public void setMBeanServerInterceptor(MBeanServer interceptor);
/**
* <p>Return the MBeanServerDelegate representing the MBeanServer.
* Notifications can be sent from the MBean server delegate using
* the method {@link MBeanServerDelegate#sendNotification}
* in the returned object.</p>
*
*/
public MBeanServerDelegate getMBeanServerDelegate();
}

View file

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

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Map;
/**
* <p>A map where keys are compared using identity comparison (like
* IdentityHashMap) but where the presence of an object as a key in
* the map does not prevent it being garbage collected (like
* WeakHashMap). This class does not implement the Map interface
* because it is difficult to ensure correct semantics for iterators
* over the entrySet().</p>
*
* <p>Because we do not implement Map, we do not copy the questionable
* interface where you can call get(k) or remove(k) for any type of k,
* which of course can only have an effect if k is of type K.</p>
*
* <p>This map does not support null keys.</p>
*/
/*
* The approach
* is to wrap each key in a WeakReference and use the wrapped value as
* a key in an ordinary HashMap. The WeakReference has to be a
* subclass IdentityWeakReference (IWR) where two IWRs are equal if
* they refer to the same object. This enables us to find the entry
* again.
*/
class WeakIdentityHashMap<K, V> {
private WeakIdentityHashMap() {}
static <K, V> WeakIdentityHashMap<K, V> make() {
return new WeakIdentityHashMap<K, V>();
}
V get(K key) {
expunge();
WeakReference<K> keyref = makeReference(key);
return map.get(keyref);
}
public V put(K key, V value) {
expunge();
if (key == null)
throw new IllegalArgumentException("Null key");
WeakReference<K> keyref = makeReference(key, refQueue);
return map.put(keyref, value);
}
public V remove(K key) {
expunge();
WeakReference<K> keyref = makeReference(key);
return map.remove(keyref);
}
private void expunge() {
Reference<? extends K> ref;
while ((ref = refQueue.poll()) != null)
map.remove(ref);
}
private WeakReference<K> makeReference(K referent) {
return new IdentityWeakReference<K>(referent);
}
private WeakReference<K> makeReference(K referent, ReferenceQueue<K> q) {
return new IdentityWeakReference<K>(referent, q);
}
/**
* WeakReference where equals and hashCode are based on the
* referent. More precisely, two objects are equal if they are
* identical or if they both have the same non-null referent. The
* hashCode is the value the original referent had. Even if the
* referent is cleared, the hashCode remains. Thus, objects of
* this class can be used as keys in hash-based maps and sets.
*/
private static class IdentityWeakReference<T> extends WeakReference<T> {
IdentityWeakReference(T o) {
this(o, null);
}
IdentityWeakReference(T o, ReferenceQueue<T> q) {
super(o, q);
this.hashCode = (o == null) ? 0 : System.identityHashCode(o);
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof IdentityWeakReference<?>))
return false;
IdentityWeakReference<?> wr = (IdentityWeakReference<?>) o;
Object got = get();
return (got != null && got == wr.get());
}
public int hashCode() {
return hashCode;
}
private final int hashCode;
}
private Map<WeakReference<K>, V> map = newMap();
private ReferenceQueue<K> refQueue = new ReferenceQueue<K>();
}

View file

@ -0,0 +1,33 @@
<html>
<head>
<title>jmx.mbeanserver package</title>
<!--
Copyright (c) 1999, 2003, 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.
-->
</head>
<body bgcolor="white">
Provides specific classes to <B>Sun JMX Reference Implementation</B>.
</BODY>
</HTML>

View file

@ -0,0 +1,852 @@
/*
* Copyright (c) 2003, 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.remote.internal;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.HashMap;
import java.util.Map;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationFilter;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.QueryEval;
import javax.management.QueryExp;
import javax.management.remote.NotificationResult;
import javax.management.remote.TargetedNotification;
import com.sun.jmx.remote.util.EnvHelp;
import com.sun.jmx.remote.util.ClassLogger;
/** A circular buffer of notifications received from an MBean server. */
/*
There is one instance of ArrayNotificationBuffer for every
MBeanServer object that has an attached ConnectorServer. Then, for
every ConnectorServer attached to a given MBeanServer, there is an
instance of the inner class ShareBuffer. So for example with two
ConnectorServers it looks like this:
ConnectorServer1 -> ShareBuffer1 -\
}-> ArrayNotificationBuffer
ConnectorServer2 -> ShareBuffer2 -/ |
|
v
MBeanServer
The ArrayNotificationBuffer has a circular buffer of
NamedNotification objects. Each ConnectorServer defines a
notification buffer size, and this size is recorded by the
corresponding ShareBuffer. The buffer size of the
ArrayNotificationBuffer is the maximum of all of its ShareBuffers.
When a ShareBuffer is added or removed, the ArrayNotificationBuffer
size is adjusted accordingly.
An ArrayNotificationBuffer also has a BufferListener (which is a
NotificationListener) registered on every NotificationBroadcaster
MBean in the MBeanServer to which it is attached. The cost of this
potentially large set of listeners is the principal motivation for
sharing the ArrayNotificationBuffer between ConnectorServers, and
also the reason that we are careful to discard the
ArrayNotificationBuffer (and its BufferListeners) when there are no
longer any ConnectorServers using it.
The synchronization of this class is inherently complex. In an attempt
to limit the complexity, we use just two locks:
- globalLock controls access to the mapping between an MBeanServer
and its ArrayNotificationBuffer and to the set of ShareBuffers for
each ArrayNotificationBuffer.
- the instance lock of each ArrayNotificationBuffer controls access
to the array of notifications, including its size, and to the
dispose flag of the ArrayNotificationBuffer. The wait/notify
mechanism is used to indicate changes to the array.
If both locks are held at the same time, the globalLock must be
taken first.
Since adding or removing a BufferListener to an MBean can involve
calling user code, we are careful not to hold any locks while it is
done.
*/
public class ArrayNotificationBuffer implements NotificationBuffer {
private boolean disposed = false;
// FACTORY STUFF, INCLUDING SHARING
private static final Object globalLock = new Object();
private static final
HashMap<MBeanServer,ArrayNotificationBuffer> mbsToBuffer =
new HashMap<MBeanServer,ArrayNotificationBuffer>(1);
private final Collection<ShareBuffer> sharers = new HashSet<ShareBuffer>(1);
public static NotificationBuffer getNotificationBuffer(
MBeanServer mbs, Map<String, ?> env) {
if (env == null)
env = Collections.emptyMap();
//Find out queue size
int queueSize = EnvHelp.getNotifBufferSize(env);
ArrayNotificationBuffer buf;
boolean create;
NotificationBuffer sharer;
synchronized (globalLock) {
buf = mbsToBuffer.get(mbs);
create = (buf == null);
if (create) {
buf = new ArrayNotificationBuffer(mbs, queueSize);
mbsToBuffer.put(mbs, buf);
}
sharer = buf.new ShareBuffer(queueSize);
}
/* We avoid holding any locks while calling createListeners.
* This prevents possible deadlocks involving user code, but
* does mean that a second ConnectorServer created and started
* in this window will return before all the listeners are ready,
* which could lead to surprising behaviour. The alternative
* would be to block the second ConnectorServer until the first
* one has finished adding all the listeners, but that would then
* be subject to deadlock.
*/
if (create)
buf.createListeners();
return sharer;
}
/* Ensure that this buffer is no longer the one that will be returned by
* getNotificationBuffer. This method is idempotent - calling it more
* than once has no effect beyond that of calling it once.
*/
static void removeNotificationBuffer(MBeanServer mbs) {
synchronized (globalLock) {
mbsToBuffer.remove(mbs);
}
}
void addSharer(ShareBuffer sharer) {
synchronized (globalLock) {
synchronized (this) {
if (sharer.getSize() > queueSize)
resize(sharer.getSize());
}
sharers.add(sharer);
}
}
private void removeSharer(ShareBuffer sharer) {
boolean empty;
synchronized (globalLock) {
sharers.remove(sharer);
empty = sharers.isEmpty();
if (empty)
removeNotificationBuffer(mBeanServer);
else {
int max = 0;
for (ShareBuffer buf : sharers) {
int bufsize = buf.getSize();
if (bufsize > max)
max = bufsize;
}
if (max < queueSize)
resize(max);
}
}
if (empty) {
synchronized (this) {
disposed = true;
// Notify potential waiting fetchNotification call
notifyAll();
}
destroyListeners();
}
}
private synchronized void resize(int newSize) {
if (newSize == queueSize)
return;
while (queue.size() > newSize)
dropNotification();
queue.resize(newSize);
queueSize = newSize;
}
private class ShareBuffer implements NotificationBuffer {
ShareBuffer(int size) {
this.size = size;
addSharer(this);
}
public NotificationResult
fetchNotifications(NotificationBufferFilter filter,
long startSequenceNumber,
long timeout,
int maxNotifications)
throws InterruptedException {
NotificationBuffer buf = ArrayNotificationBuffer.this;
return buf.fetchNotifications(filter, startSequenceNumber,
timeout, maxNotifications);
}
public void dispose() {
ArrayNotificationBuffer.this.removeSharer(this);
}
int getSize() {
return size;
}
private final int size;
}
// ARRAYNOTIFICATIONBUFFER IMPLEMENTATION
private ArrayNotificationBuffer(MBeanServer mbs, int queueSize) {
if (logger.traceOn())
logger.trace("Constructor", "queueSize=" + queueSize);
if (mbs == null || queueSize < 1)
throw new IllegalArgumentException("Bad args");
this.mBeanServer = mbs;
this.queueSize = queueSize;
this.queue = new ArrayQueue<NamedNotification>(queueSize);
this.earliestSequenceNumber = System.currentTimeMillis();
this.nextSequenceNumber = this.earliestSequenceNumber;
logger.trace("Constructor", "ends");
}
private synchronized boolean isDisposed() {
return disposed;
}
// We no longer support calling this method from outside.
// The JDK doesn't contain any such calls and users are not
// supposed to be accessing this class.
public void dispose() {
throw new UnsupportedOperationException();
}
/**
* <p>Fetch notifications that match the given listeners.</p>
*
* <p>The operation only considers notifications with a sequence
* number at least <code>startSequenceNumber</code>. It will take
* no longer than <code>timeout</code>, and will return no more
* than <code>maxNotifications</code> different notifications.</p>
*
* <p>If there are no notifications matching the criteria, the
* operation will block until one arrives, subject to the
* timeout.</p>
*
* @param filter an object that will add notifications to a
* {@code List<TargetedNotification>} if they match the current
* listeners with their filters.
* @param startSequenceNumber the first sequence number to
* consider.
* @param timeout the maximum time to wait. May be 0 to indicate
* not to wait if there are no notifications.
* @param maxNotifications the maximum number of notifications to
* return. May be 0 to indicate a wait for eligible notifications
* that will return a usable <code>nextSequenceNumber</code>. The
* {@link TargetedNotification} array in the returned {@link
* NotificationResult} may contain more than this number of
* elements but will not contain more than this number of
* different notifications.
*/
public NotificationResult
fetchNotifications(NotificationBufferFilter filter,
long startSequenceNumber,
long timeout,
int maxNotifications)
throws InterruptedException {
logger.trace("fetchNotifications", "starts");
if (startSequenceNumber < 0 || isDisposed()) {
synchronized(this) {
return new NotificationResult(earliestSequenceNumber(),
nextSequenceNumber(),
new TargetedNotification[0]);
}
}
// Check arg validity
if (filter == null
|| startSequenceNumber < 0 || timeout < 0
|| maxNotifications < 0) {
logger.trace("fetchNotifications", "Bad args");
throw new IllegalArgumentException("Bad args to fetch");
}
if (logger.debugOn()) {
logger.trace("fetchNotifications",
"filter=" + filter + "; startSeq=" +
startSequenceNumber + "; timeout=" + timeout +
"; max=" + maxNotifications);
}
if (startSequenceNumber > nextSequenceNumber()) {
final String msg = "Start sequence number too big: " +
startSequenceNumber + " > " + nextSequenceNumber();
logger.trace("fetchNotifications", msg);
throw new IllegalArgumentException(msg);
}
/* Determine the end time corresponding to the timeout value.
Caller may legitimately supply Long.MAX_VALUE to indicate no
timeout. In that case the addition will overflow and produce
a negative end time. Set end time to Long.MAX_VALUE in that
case. We assume System.currentTimeMillis() is positive. */
long endTime = System.currentTimeMillis() + timeout;
if (endTime < 0) // overflow
endTime = Long.MAX_VALUE;
if (logger.debugOn())
logger.debug("fetchNotifications", "endTime=" + endTime);
/* We set earliestSeq the first time through the loop. If we
set it here, notifications could be dropped before we
started examining them, so earliestSeq might not correspond
to the earliest notification we examined. */
long earliestSeq = -1;
long nextSeq = startSequenceNumber;
List<TargetedNotification> notifs =
new ArrayList<TargetedNotification>();
/* On exit from this loop, notifs, earliestSeq, and nextSeq must
all be correct values for the returned NotificationResult. */
while (true) {
logger.debug("fetchNotifications", "main loop starts");
NamedNotification candidate;
/* Get the next available notification regardless of filters,
or wait for one to arrive if there is none. */
synchronized (this) {
/* First time through. The current earliestSequenceNumber
is the first one we could have examined. */
if (earliestSeq < 0) {
earliestSeq = earliestSequenceNumber();
if (logger.debugOn()) {
logger.debug("fetchNotifications",
"earliestSeq=" + earliestSeq);
}
if (nextSeq < earliestSeq) {
nextSeq = earliestSeq;
logger.debug("fetchNotifications",
"nextSeq=earliestSeq");
}
} else
earliestSeq = earliestSequenceNumber();
/* If many notifications have been dropped since the
last time through, nextSeq could now be earlier
than the current earliest. If so, notifications
may have been lost and we return now so the caller
can see this next time it calls. */
if (nextSeq < earliestSeq) {
logger.trace("fetchNotifications",
"nextSeq=" + nextSeq + " < " + "earliestSeq=" +
earliestSeq + " so may have lost notifs");
break;
}
if (nextSeq < nextSequenceNumber()) {
candidate = notificationAt(nextSeq);
// Skip security check if NotificationBufferFilter is not overloaded
if (!(filter instanceof ServerNotifForwarder.NotifForwarderBufferFilter)) {
try {
ServerNotifForwarder.checkMBeanPermission(this.mBeanServer,
candidate.getObjectName(),"addNotificationListener");
} catch (InstanceNotFoundException | SecurityException e) {
if (logger.debugOn()) {
logger.debug("fetchNotifications", "candidate: " + candidate + " skipped. exception " + e);
}
++nextSeq;
continue;
}
}
if (logger.debugOn()) {
logger.debug("fetchNotifications", "candidate: " +
candidate);
logger.debug("fetchNotifications", "nextSeq now " +
nextSeq);
}
} else {
/* nextSeq is the largest sequence number. If we
already got notifications, return them now.
Otherwise wait for some to arrive, with
timeout. */
if (notifs.size() > 0) {
logger.debug("fetchNotifications",
"no more notifs but have some so don't wait");
break;
}
long toWait = endTime - System.currentTimeMillis();
if (toWait <= 0) {
logger.debug("fetchNotifications", "timeout");
break;
}
/* dispose called */
if (isDisposed()) {
if (logger.debugOn())
logger.debug("fetchNotifications",
"dispose callled, no wait");
return new NotificationResult(earliestSequenceNumber(),
nextSequenceNumber(),
new TargetedNotification[0]);
}
if (logger.debugOn())
logger.debug("fetchNotifications",
"wait(" + toWait + ")");
wait(toWait);
continue;
}
}
/* We have a candidate notification. See if it matches
our filters. We do this outside the synchronized block
so we don't hold up everyone accessing the buffer
(including notification senders) while we evaluate
potentially slow filters. */
ObjectName name = candidate.getObjectName();
Notification notif = candidate.getNotification();
List<TargetedNotification> matchedNotifs =
new ArrayList<TargetedNotification>();
logger.debug("fetchNotifications",
"applying filter to candidate");
filter.apply(matchedNotifs, name, notif);
if (matchedNotifs.size() > 0) {
/* We only check the max size now, so that our
returned nextSeq is as large as possible. This
prevents the caller from thinking it missed
interesting notifications when in fact we knew they
weren't. */
if (maxNotifications <= 0) {
logger.debug("fetchNotifications",
"reached maxNotifications");
break;
}
--maxNotifications;
if (logger.debugOn())
logger.debug("fetchNotifications", "add: " +
matchedNotifs);
notifs.addAll(matchedNotifs);
}
++nextSeq;
} // end while
/* Construct and return the result. */
int nnotifs = notifs.size();
TargetedNotification[] resultNotifs =
new TargetedNotification[nnotifs];
notifs.toArray(resultNotifs);
NotificationResult nr =
new NotificationResult(earliestSeq, nextSeq, resultNotifs);
if (logger.debugOn())
logger.debug("fetchNotifications", nr.toString());
logger.trace("fetchNotifications", "ends");
return nr;
}
synchronized long earliestSequenceNumber() {
return earliestSequenceNumber;
}
synchronized long nextSequenceNumber() {
return nextSequenceNumber;
}
synchronized void addNotification(NamedNotification notif) {
if (logger.traceOn())
logger.trace("addNotification", notif.toString());
while (queue.size() >= queueSize) {
dropNotification();
if (logger.debugOn()) {
logger.debug("addNotification",
"dropped oldest notif, earliestSeq=" +
earliestSequenceNumber);
}
}
queue.add(notif);
nextSequenceNumber++;
if (logger.debugOn())
logger.debug("addNotification", "nextSeq=" + nextSequenceNumber);
notifyAll();
}
private void dropNotification() {
queue.remove(0);
earliestSequenceNumber++;
}
synchronized NamedNotification notificationAt(long seqNo) {
long index = seqNo - earliestSequenceNumber;
if (index < 0 || index > Integer.MAX_VALUE) {
final String msg = "Bad sequence number: " + seqNo + " (earliest "
+ earliestSequenceNumber + ")";
logger.trace("notificationAt", msg);
throw new IllegalArgumentException(msg);
}
return queue.get((int) index);
}
private static class NamedNotification {
NamedNotification(ObjectName sender, Notification notif) {
this.sender = sender;
this.notification = notif;
}
ObjectName getObjectName() {
return sender;
}
Notification getNotification() {
return notification;
}
public String toString() {
return "NamedNotification(" + sender + ", " + notification + ")";
}
private final ObjectName sender;
private final Notification notification;
}
/*
* Add our listener to every NotificationBroadcaster MBean
* currently in the MBean server and to every
* NotificationBroadcaster later created.
*
* It would be really nice if we could just do
* mbs.addNotificationListener(new ObjectName("*:*"), ...);
* Definitely something for the next version of JMX.
*
* There is a nasty race condition that we must handle. We
* first register for MBean-creation notifications so we can add
* listeners to new MBeans, then we query the existing MBeans to
* add listeners to them. The problem is that a new MBean could
* arrive after we register for creations but before the query has
* completed. Then we could see the MBean both in the query and
* in an MBean-creation notification, and we would end up
* registering our listener twice.
*
* To solve this problem, we arrange for new MBeans that arrive
* while the query is being done to be added to the Set createdDuringQuery
* and we do not add a listener immediately. When the query is done,
* we atomically turn off the addition of new names to createdDuringQuery
* and add all the names that were there to the result of the query.
* Since we are dealing with Sets, the result is the same whether or not
* the newly-created MBean was included in the query result.
*
* It is important not to hold any locks during the operation of adding
* listeners to MBeans. An MBean's addNotificationListener can be
* arbitrary user code, and this could deadlock with any locks we hold
* (see bug 6239400). The corollary is that we must not do any operations
* in this method or the methods it calls that require locks.
*/
private void createListeners() {
logger.debug("createListeners", "starts");
synchronized (this) {
createdDuringQuery = new HashSet<ObjectName>();
}
try {
addNotificationListener(MBeanServerDelegate.DELEGATE_NAME,
creationListener, creationFilter, null);
logger.debug("createListeners", "added creationListener");
} catch (Exception e) {
final String msg = "Can't add listener to MBean server delegate: ";
RuntimeException re = new IllegalArgumentException(msg + e);
EnvHelp.initCause(re, e);
logger.fine("createListeners", msg + e);
logger.debug("createListeners", e);
throw re;
}
/* Spec doesn't say whether Set returned by QueryNames can be modified
so we clone it. */
Set<ObjectName> names = queryNames(null, broadcasterQuery);
names = new HashSet<ObjectName>(names);
synchronized (this) {
names.addAll(createdDuringQuery);
createdDuringQuery = null;
}
for (ObjectName name : names)
addBufferListener(name);
logger.debug("createListeners", "ends");
}
private void addBufferListener(ObjectName name) {
checkNoLocks();
if (logger.debugOn())
logger.debug("addBufferListener", name.toString());
try {
addNotificationListener(name, bufferListener, null, name);
} catch (Exception e) {
logger.trace("addBufferListener", e);
/* This can happen if the MBean was unregistered just
after the query. Or user NotificationBroadcaster might
throw unexpected exception. */
}
}
private void removeBufferListener(ObjectName name) {
checkNoLocks();
if (logger.debugOn())
logger.debug("removeBufferListener", name.toString());
try {
removeNotificationListener(name, bufferListener);
} catch (Exception e) {
logger.trace("removeBufferListener", e);
}
}
private void addNotificationListener(final ObjectName name,
final NotificationListener listener,
final NotificationFilter filter,
final Object handback)
throws Exception {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws InstanceNotFoundException {
mBeanServer.addNotificationListener(name,
listener,
filter,
handback);
return null;
}
});
} catch (Exception e) {
throw extractException(e);
}
}
private void removeNotificationListener(final ObjectName name,
final NotificationListener listener)
throws Exception {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
mBeanServer.removeNotificationListener(name, listener);
return null;
}
});
} catch (Exception e) {
throw extractException(e);
}
}
private Set<ObjectName> queryNames(final ObjectName name,
final QueryExp query) {
PrivilegedAction<Set<ObjectName>> act =
new PrivilegedAction<Set<ObjectName>>() {
public Set<ObjectName> run() {
return mBeanServer.queryNames(name, query);
}
};
try {
return AccessController.doPrivileged(act);
} catch (RuntimeException e) {
logger.fine("queryNames", "Failed to query names: " + e);
logger.debug("queryNames", e);
throw e;
}
}
private static boolean isInstanceOf(final MBeanServer mbs,
final ObjectName name,
final String className) {
PrivilegedExceptionAction<Boolean> act =
new PrivilegedExceptionAction<Boolean>() {
public Boolean run() throws InstanceNotFoundException {
return mbs.isInstanceOf(name, className);
}
};
try {
return AccessController.doPrivileged(act);
} catch (Exception e) {
logger.fine("isInstanceOf", "failed: " + e);
logger.debug("isInstanceOf", e);
return false;
}
}
/* This method must not be synchronized. See the comment on the
* createListeners method.
*
* The notification could arrive after our buffer has been destroyed
* or even during its destruction. So we always add our listener
* (without synchronization), then we check if the buffer has been
* destroyed and if so remove the listener we just added.
*/
private void createdNotification(MBeanServerNotification n) {
final String shouldEqual =
MBeanServerNotification.REGISTRATION_NOTIFICATION;
if (!n.getType().equals(shouldEqual)) {
logger.warning("createNotification", "bad type: " + n.getType());
return;
}
ObjectName name = n.getMBeanName();
if (logger.debugOn())
logger.debug("createdNotification", "for: " + name);
synchronized (this) {
if (createdDuringQuery != null) {
createdDuringQuery.add(name);
return;
}
}
if (isInstanceOf(mBeanServer, name, broadcasterClass)) {
addBufferListener(name);
if (isDisposed())
removeBufferListener(name);
}
}
private class BufferListener implements NotificationListener {
public void handleNotification(Notification notif, Object handback) {
if (logger.debugOn()) {
logger.debug("BufferListener.handleNotification",
"notif=" + notif + "; handback=" + handback);
}
ObjectName name = (ObjectName) handback;
addNotification(new NamedNotification(name, notif));
}
}
private final NotificationListener bufferListener = new BufferListener();
private static class BroadcasterQuery
extends QueryEval implements QueryExp {
private static final long serialVersionUID = 7378487660587592048L;
public boolean apply(final ObjectName name) {
final MBeanServer mbs = QueryEval.getMBeanServer();
return isInstanceOf(mbs, name, broadcasterClass);
}
}
private static final QueryExp broadcasterQuery = new BroadcasterQuery();
private static final NotificationFilter creationFilter;
static {
NotificationFilterSupport nfs = new NotificationFilterSupport();
nfs.enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
creationFilter = nfs;
}
private final NotificationListener creationListener =
new NotificationListener() {
public void handleNotification(Notification notif,
Object handback) {
logger.debug("creationListener", "handleNotification called");
createdNotification((MBeanServerNotification) notif);
}
};
private void destroyListeners() {
checkNoLocks();
logger.debug("destroyListeners", "starts");
try {
removeNotificationListener(MBeanServerDelegate.DELEGATE_NAME,
creationListener);
} catch (Exception e) {
logger.warning("remove listener from MBeanServer delegate", e);
}
Set<ObjectName> names = queryNames(null, broadcasterQuery);
for (final ObjectName name : names) {
if (logger.debugOn())
logger.debug("destroyListeners",
"remove listener from " + name);
removeBufferListener(name);
}
logger.debug("destroyListeners", "ends");
}
private void checkNoLocks() {
if (Thread.holdsLock(this) || Thread.holdsLock(globalLock))
logger.warning("checkNoLocks", "lock protocol violation");
}
/**
* Iterate until we extract the real exception
* from a stack of PrivilegedActionExceptions.
*/
private static Exception extractException(Exception e) {
while (e instanceof PrivilegedActionException) {
e = ((PrivilegedActionException)e).getException();
}
return e;
}
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc",
"ArrayNotificationBuffer");
private final MBeanServer mBeanServer;
private final ArrayQueue<NamedNotification> queue;
private int queueSize;
private long earliestSequenceNumber;
private long nextSequenceNumber;
private Set<ObjectName> createdDuringQuery;
static final String broadcasterClass =
NotificationBroadcaster.class.getName();
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2003, 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.remote.internal;
import java.util.AbstractList;
import java.util.Iterator;
public class ArrayQueue<T> extends AbstractList<T> {
public ArrayQueue(int capacity) {
this.capacity = capacity + 1;
this.queue = newArray(capacity + 1);
this.head = 0;
this.tail = 0;
}
public void resize(int newcapacity) {
int size = size();
if (newcapacity < size)
throw new IndexOutOfBoundsException("Resizing would lose data");
newcapacity++;
if (newcapacity == this.capacity)
return;
T[] newqueue = newArray(newcapacity);
for (int i = 0; i < size; i++)
newqueue[i] = get(i);
this.capacity = newcapacity;
this.queue = newqueue;
this.head = 0;
this.tail = size;
}
@SuppressWarnings("unchecked")
private T[] newArray(int size) {
return (T[]) new Object[size];
}
public boolean add(T o) {
queue[tail] = o;
int newtail = (tail + 1) % capacity;
if (newtail == head)
throw new IndexOutOfBoundsException("Queue full");
tail = newtail;
return true; // we did add something
}
public T remove(int i) {
if (i != 0)
throw new IllegalArgumentException("Can only remove head of queue");
if (head == tail)
throw new IndexOutOfBoundsException("Queue empty");
T removed = queue[head];
queue[head] = null;
head = (head + 1) % capacity;
return removed;
}
public T get(int i) {
int size = size();
if (i < 0 || i >= size) {
final String msg = "Index " + i + ", queue size " + size;
throw new IndexOutOfBoundsException(msg);
}
int index = (head + i) % capacity;
return queue[index];
}
public int size() {
// Can't use % here because it's not mod: -3 % 2 is -1, not +1.
int diff = tail - head;
if (diff < 0)
diff += capacity;
return diff;
}
private int capacity;
private T[] queue;
private int head;
private int tail;
}

View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 2003, 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.remote.internal;
import java.io.IOException;
import java.io.InterruptedIOException;
import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
public abstract class ClientCommunicatorAdmin {
private static volatile long threadNo = 1;
public ClientCommunicatorAdmin(long period) {
this.period = period;
if (period > 0) {
checker = new Checker();
Thread t = new Thread(null,
checker,
"JMX client heartbeat " + (++threadNo),
0,
false);
t.setDaemon(true);
t.start();
} else
checker = null;
}
/**
* Called by a client to inform of getting an IOException.
*/
public void gotIOException (IOException ioe) throws IOException {
restart(ioe);
}
/**
* Called by this class to check a client connection.
*/
protected abstract void checkConnection() throws IOException;
/**
* Tells a client to re-start again.
*/
protected abstract void doStart() throws IOException;
/**
* Tells a client to stop because failing to call checkConnection.
*/
protected abstract void doStop();
/**
* Terminates this object.
*/
public void terminate() {
synchronized(lock) {
if (state == TERMINATED) {
return;
}
state = TERMINATED;
lock.notifyAll();
if (checker != null)
checker.stop();
}
}
private void restart(IOException ioe) throws IOException {
// check state
synchronized(lock) {
if (state == TERMINATED) {
throw new IOException("The client has been closed.");
} else if (state == FAILED) { // already failed to re-start by another thread
throw ioe;
} else if (state == RE_CONNECTING) {
// restart process has been called by another thread
// we need to wait
while(state == RE_CONNECTING) {
try {
lock.wait();
} catch (InterruptedException ire) {
// be asked to give up
InterruptedIOException iioe = new InterruptedIOException(ire.toString());
EnvHelp.initCause(iioe, ire);
throw iioe;
}
}
if (state == TERMINATED) {
throw new IOException("The client has been closed.");
} else if (state != CONNECTED) {
// restarted is failed by another thread
throw ioe;
}
return;
} else {
state = RE_CONNECTING;
lock.notifyAll();
}
}
// re-starting
try {
doStart();
synchronized(lock) {
if (state == TERMINATED) {
throw new IOException("The client has been closed.");
}
state = CONNECTED;
lock.notifyAll();
}
return;
} catch (Exception e) {
logger.warning("restart", "Failed to restart: " + e);
logger.debug("restart",e);
synchronized(lock) {
if (state == TERMINATED) {
throw new IOException("The client has been closed.");
}
state = FAILED;
lock.notifyAll();
}
try {
doStop();
} catch (Exception eee) {
// OK.
// We know there is a problem.
}
terminate();
throw ioe;
}
}
// --------------------------------------------------------------
// private varaibles
// --------------------------------------------------------------
private class Checker implements Runnable {
public void run() {
myThread = Thread.currentThread();
while (state != TERMINATED && !myThread.isInterrupted()) {
try {
Thread.sleep(period);
} catch (InterruptedException ire) {
// OK.
// We will check the state at the following steps
}
if (state == TERMINATED || myThread.isInterrupted()) {
break;
}
try {
checkConnection();
} catch (Exception e) {
synchronized(lock) {
if (state == TERMINATED || myThread.isInterrupted()) {
break;
}
}
e = (Exception)EnvHelp.getCause(e);
if (e instanceof IOException &&
!(e instanceof InterruptedIOException)) {
try {
gotIOException((IOException)e);
} catch (Exception ee) {
logger.warning("Checker-run",
"Failed to check connection: "+ e);
logger.warning("Checker-run", "stopping");
logger.debug("Checker-run",e);
break;
}
} else {
logger.warning("Checker-run",
"Failed to check the connection: " + e);
logger.debug("Checker-run",e);
// XXX stop checking?
break;
}
}
}
if (logger.traceOn()) {
logger.trace("Checker-run", "Finished.");
}
}
private void stop() {
if (myThread != null && myThread != Thread.currentThread()) {
myThread.interrupt();
}
}
private Thread myThread;
}
// --------------------------------------------------------------
// private variables
// --------------------------------------------------------------
private final Checker checker;
private long period;
// state
private final static int CONNECTED = 0;
private final static int RE_CONNECTING = 1;
private final static int FAILED = 2;
private final static int TERMINATED = 3;
private int state = CONNECTED;
private final int[] lock = new int[0];
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc",
"ClientCommunicatorAdmin");
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2003, 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.remote.internal;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.security.auth.Subject;
/**
* <p>An identified listener. A listener has an Integer id that is
* unique per connector server. It selects notifications based on the
* ObjectName of the originator and an optional
* NotificationFilter.</p>
*/
public class ClientListenerInfo {
public ClientListenerInfo(Integer listenerID,
ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback,
Subject delegationSubject) {
this.listenerID = listenerID;
this.name = name;
this.listener = listener;
this.filter = filter;
this.handback = handback;
this.delegationSubject = delegationSubject;
}
public ObjectName getObjectName() {
return name;
}
public Integer getListenerID() {
return listenerID;
}
public NotificationFilter getNotificationFilter() {
return filter;
}
public NotificationListener getListener() {
return listener;
}
public Object getHandback() {
return handback;
}
public Subject getDelegationSubject() {
return delegationSubject;
}
public boolean sameAs(ObjectName name) {
return (getObjectName().equals(name));
}
public boolean sameAs(ObjectName name, NotificationListener listener) {
return ( getObjectName().equals(name) &&
getListener() == listener);
}
public boolean sameAs(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) {
return ( getObjectName().equals(name) &&
getListener() == listener &&
getNotificationFilter() == filter &&
getHandback() == handback);
}
private final ObjectName name;
private final Integer listenerID;
private final NotificationFilter filter;
private final NotificationListener listener;
private final Object handback;
private final Subject delegationSubject;
}

View file

@ -0,0 +1,971 @@
/*
* Copyright (c) 2002, 2016, 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.remote.internal;
import java.io.IOException;
import java.io.NotSerializableException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.NotificationFilter;
import javax.management.ObjectName;
import javax.management.MBeanServerNotification;
import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.remote.NotificationResult;
import javax.management.remote.TargetedNotification;
import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.concurrent.RejectedExecutionException;
public abstract class ClientNotifForwarder {
private final AccessControlContext acc;
public ClientNotifForwarder(Map<String, ?> env) {
this(null, env);
}
private static int threadId;
/* An Executor that allows at most one executing and one pending
Runnable. It uses at most one thread -- as soon as there is
no pending Runnable the thread can exit. Another thread is
created as soon as there is a new pending Runnable. This
Executor is adapted for use in a situation where each Runnable
usually schedules up another Runnable. On return from the
first one, the second one is immediately executed. So this
just becomes a complicated way to write a while loop, but with
the advantage that you can replace it with another Executor,
for instance one that you are using to execute a bunch of other
unrelated work.
You might expect that a java.util.concurrent.ThreadPoolExecutor
with corePoolSize=0 and maximumPoolSize=1 would have the same
behavior, but it does not. A ThreadPoolExecutor only creates
a new thread when a new task is submitted and the number of
existing threads is < corePoolSize. This can never happen when
corePoolSize=0, so new threads are never created. Surprising,
but there you are.
*/
private static class LinearExecutor implements Executor {
public synchronized void execute(Runnable command) {
if (this.command != null)
throw new IllegalArgumentException("More than one command");
this.command = command;
if (thread == null) {
thread = new Thread(
null,
()-> {
while (true) {
Runnable r;
synchronized (LinearExecutor.this) {
if (LinearExecutor.this.command == null) {
thread = null;
return;
} else {
r = LinearExecutor.this.command;
LinearExecutor.this.command = null;
}
}
r.run();
}
},
"ClientNotifForwarder-" + ++threadId,
0,
false
);
thread.setDaemon(true);
thread.start();
}
}
private Runnable command;
private Thread thread;
}
public ClientNotifForwarder(ClassLoader defaultClassLoader, Map<String, ?> env) {
maxNotifications = EnvHelp.getMaxFetchNotifNumber(env);
timeout = EnvHelp.getFetchTimeout(env);
/* You can supply an Executor in which the remote call to
fetchNotifications will be made. The Executor's execute
method reschedules another task, so you must not use
an Executor that executes tasks in the caller's thread. */
Executor ex = (Executor)
env.get("jmx.remote.x.fetch.notifications.executor");
if (ex == null)
ex = new LinearExecutor();
else if (logger.traceOn())
logger.trace("ClientNotifForwarder", "executor is " + ex);
this.defaultClassLoader = defaultClassLoader;
this.executor = ex;
this.acc = AccessController.getContext();
}
/**
* Called to fetch notifications from a server.
*/
abstract protected NotificationResult fetchNotifs(long clientSequenceNumber,
int maxNotifications,
long timeout)
throws IOException, ClassNotFoundException;
abstract protected Integer addListenerForMBeanRemovedNotif()
throws IOException, InstanceNotFoundException;
abstract protected void removeListenerForMBeanRemovedNotif(Integer id)
throws IOException, InstanceNotFoundException,
ListenerNotFoundException;
/**
* Used to send out a notification about lost notifs
*/
abstract protected void lostNotifs(String message, long number);
public synchronized void addNotificationListener(Integer listenerID,
ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback,
Subject delegationSubject)
throws IOException, InstanceNotFoundException {
if (logger.traceOn()) {
logger.trace("addNotificationListener",
"Add the listener "+listener+" at "+name);
}
infoList.put(listenerID,
new ClientListenerInfo(listenerID,
name,
listener,
filter,
handback,
delegationSubject));
init(false);
}
public synchronized Integer[]
getListenerIds(ObjectName name,
NotificationListener listener)
throws ListenerNotFoundException, IOException {
List<Integer> ids = new ArrayList<Integer>();
List<ClientListenerInfo> values =
new ArrayList<ClientListenerInfo>(infoList.values());
for (int i=values.size()-1; i>=0; i--) {
ClientListenerInfo li = values.get(i);
if (li.sameAs(name, listener)) {
ids.add(li.getListenerID());
}
}
if (ids.isEmpty())
throw new ListenerNotFoundException("Listener not found");
return ids.toArray(new Integer[0]);
}
public synchronized Integer
getListenerId(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws ListenerNotFoundException, IOException {
Integer id = null;
List<ClientListenerInfo> values =
new ArrayList<ClientListenerInfo>(infoList.values());
for (int i=values.size()-1; i>=0; i--) {
ClientListenerInfo li = values.get(i);
if (li.sameAs(name, listener, filter, handback)) {
id=li.getListenerID();
break;
}
}
if (id == null)
throw new ListenerNotFoundException("Listener not found");
return id;
}
public synchronized Integer[]
removeNotificationListener(ObjectName name,
NotificationListener listener)
throws ListenerNotFoundException, IOException {
beforeRemove();
if (logger.traceOn()) {
logger.trace("removeNotificationListener",
"Remove the listener "+listener+" from "+name);
}
Integer[] liIds = getListenerIds(name, listener);
for (int i = 0; i < liIds.length; i++) {
infoList.remove(liIds[i]);
}
return liIds;
}
public synchronized Integer
removeNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws ListenerNotFoundException, IOException {
if (logger.traceOn()) {
logger.trace("removeNotificationListener",
"Remove the listener "+listener+" from "+name);
}
beforeRemove();
Integer liId = getListenerId(name, listener,
filter, handback);
infoList.remove(liId);
return liId;
}
public synchronized Integer[] removeNotificationListener(ObjectName name) {
if (logger.traceOn()) {
logger.trace("removeNotificationListener",
"Remove all listeners registered at "+name);
}
List<Integer> ids = new ArrayList<Integer>();
List<ClientListenerInfo> values =
new ArrayList<ClientListenerInfo>(infoList.values());
for (int i=values.size()-1; i>=0; i--) {
ClientListenerInfo li = values.get(i);
if (li.sameAs(name)) {
ids.add(li.getListenerID());
infoList.remove(li.getListenerID());
}
}
return ids.toArray(new Integer[0]);
}
/*
* Called when a connector is doing reconnection. Like <code>postReconnection</code>,
* this method is intended to be called only by a client connector:
* <code>RMIConnector</code> and <code>ClientIntermediary</code>.
* Call this method will set the flag beingReconnection to <code>true</code>,
* and the thread used to fetch notifis will be stopped, a new thread can be
* created only after the method <code>postReconnection</code> is called.
*
* It is caller's responsiblity to not re-call this method before calling
* <code>postReconnection</code>.
*/
public synchronized ClientListenerInfo[] preReconnection() throws IOException {
if (state == TERMINATED || beingReconnected) { // should never
throw new IOException("Illegal state.");
}
final ClientListenerInfo[] tmp =
infoList.values().toArray(new ClientListenerInfo[0]);
beingReconnected = true;
infoList.clear();
return tmp;
}
/**
* Called after reconnection is finished.
* This method is intended to be called only by a client connector:
* <code>RMIConnector</code> and <code>ClientIntermediary</code>.
*/
public synchronized void postReconnection(ClientListenerInfo[] listenerInfos)
throws IOException {
if (state == TERMINATED) {
return;
}
while (state == STOPPING) {
try {
wait();
} catch (InterruptedException ire) {
IOException ioe = new IOException(ire.toString());
EnvHelp.initCause(ioe, ire);
throw ioe;
}
}
final boolean trace = logger.traceOn();
final int len = listenerInfos.length;
for (int i=0; i<len; i++) {
if (trace) {
logger.trace("addNotificationListeners",
"Add a listener at "+
listenerInfos[i].getListenerID());
}
infoList.put(listenerInfos[i].getListenerID(), listenerInfos[i]);
}
beingReconnected = false;
notifyAll();
if (currentFetchThread == Thread.currentThread() ||
state == STARTING || state == STARTED) { // doing or waiting reconnection
// only update mbeanRemovedNotifID
try {
mbeanRemovedNotifID = addListenerForMBeanRemovedNotif();
} catch (Exception e) {
final String msg =
"Failed to register a listener to the mbean " +
"server: the client will not do clean when an MBean " +
"is unregistered";
if (logger.traceOn()) {
logger.trace("init", msg, e);
}
}
} else {
while (state == STOPPING) {
try {
wait();
} catch (InterruptedException ire) {
IOException ioe = new IOException(ire.toString());
EnvHelp.initCause(ioe, ire);
throw ioe;
}
}
if (listenerInfos.length > 0) { // old listeners are re-added
init(true); // not update clientSequenceNumber
} else if (infoList.size() > 0) { // only new listeners added during reconnection
init(false); // need update clientSequenceNumber
}
}
}
public synchronized void terminate() {
if (state == TERMINATED) {
return;
}
if (logger.traceOn()) {
logger.trace("terminate", "Terminating...");
}
if (state == STARTED) {
infoList.clear();
}
setState(TERMINATED);
}
// -------------------------------------------------
// private classes
// -------------------------------------------------
//
private class NotifFetcher implements Runnable {
private volatile boolean alreadyLogged = false;
private void logOnce(String msg, SecurityException x) {
if (alreadyLogged) return;
// Log only once.
logger.config("setContextClassLoader",msg);
if (x != null) logger.fine("setContextClassLoader", x);
alreadyLogged = true;
}
// Set new context class loader, returns previous one.
private final ClassLoader setContextClassLoader(final ClassLoader loader) {
final AccessControlContext ctxt = ClientNotifForwarder.this.acc;
// if ctxt is null, log a config message and throw a
// SecurityException.
if (ctxt == null) {
logOnce("AccessControlContext must not be null.",null);
throw new SecurityException("AccessControlContext must not be null");
}
return AccessController.doPrivileged(
new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
try {
// get context class loader - may throw
// SecurityException - though unlikely.
final ClassLoader previous =
Thread.currentThread().getContextClassLoader();
// if nothing needs to be done, break here...
if (loader == previous) return previous;
// reset context class loader - may throw
// SecurityException
Thread.currentThread().setContextClassLoader(loader);
return previous;
} catch (SecurityException x) {
logOnce("Permission to set ContextClassLoader missing. " +
"Notifications will not be dispatched. " +
"Please check your Java policy configuration: " +
x, x);
throw x;
}
}
}, ctxt);
}
public void run() {
final ClassLoader previous;
if (defaultClassLoader != null) {
previous = setContextClassLoader(defaultClassLoader);
} else {
previous = null;
}
try {
doRun();
} finally {
if (defaultClassLoader != null) {
setContextClassLoader(previous);
}
}
}
private void doRun() {
synchronized (ClientNotifForwarder.this) {
currentFetchThread = Thread.currentThread();
if (state == STARTING) {
setState(STARTED);
}
}
NotificationResult nr = null;
if (!shouldStop() && (nr = fetchNotifs()) != null) {
// nr == null means got exception
final TargetedNotification[] notifs =
nr.getTargetedNotifications();
final int len = notifs.length;
final Map<Integer, ClientListenerInfo> listeners;
final Integer myListenerID;
long missed = 0;
synchronized(ClientNotifForwarder.this) {
// check sequence number.
//
if (clientSequenceNumber >= 0) {
missed = nr.getEarliestSequenceNumber() -
clientSequenceNumber;
}
clientSequenceNumber = nr.getNextSequenceNumber();
listeners = new HashMap<Integer, ClientListenerInfo>();
for (int i = 0 ; i < len ; i++) {
final TargetedNotification tn = notifs[i];
final Integer listenerID = tn.getListenerID();
// check if an mbean unregistration notif
if (!listenerID.equals(mbeanRemovedNotifID)) {
final ClientListenerInfo li = infoList.get(listenerID);
if (li != null) {
listeners.put(listenerID, li);
}
continue;
}
final Notification notif = tn.getNotification();
final String unreg =
MBeanServerNotification.UNREGISTRATION_NOTIFICATION;
if (notif instanceof MBeanServerNotification &&
notif.getType().equals(unreg)) {
MBeanServerNotification mbsn =
(MBeanServerNotification) notif;
ObjectName name = mbsn.getMBeanName();
removeNotificationListener(name);
}
}
myListenerID = mbeanRemovedNotifID;
}
if (missed > 0) {
final String msg =
"May have lost up to " + missed +
" notification" + (missed == 1 ? "" : "s");
lostNotifs(msg, missed);
logger.trace("NotifFetcher.run", msg);
}
// forward
for (int i = 0 ; i < len ; i++) {
final TargetedNotification tn = notifs[i];
dispatchNotification(tn,myListenerID,listeners);
}
}
synchronized (ClientNotifForwarder.this) {
currentFetchThread = null;
}
if (nr == null) {
if (logger.traceOn()) {
logger.trace("NotifFetcher-run",
"Recieved null object as notifs, stops fetching because the "
+ "notification server is terminated.");
}
}
if (nr == null || shouldStop()) {
// tell that the thread is REALLY stopped
setState(STOPPED);
try {
removeListenerForMBeanRemovedNotif(mbeanRemovedNotifID);
} catch (Exception e) {
if (logger.traceOn()) {
logger.trace("NotifFetcher-run",
"removeListenerForMBeanRemovedNotif", e);
}
}
} else {
try {
executor.execute(this);
} catch (Exception e) {
if (isRejectedExecutionException(e)) {
// We reached here because the executor was shutdown.
// If executor was supplied by client, then it was shutdown
// abruptly or JMXConnector was shutdown along with executor
// while this thread was suspended at L564.
if (!(executor instanceof LinearExecutor)) {
// Spawn new executor that will do cleanup if JMXConnector is closed
// or keep notif system running otherwise
executor = new LinearExecutor();
executor.execute(this);
}
} else {
throw e;
}
}
}
}
private boolean isRejectedExecutionException(Exception e) {
Throwable cause = e;
while (cause != null) {
if (cause instanceof RejectedExecutionException) {
return true;
}
cause = cause.getCause();
}
return false;
}
void dispatchNotification(TargetedNotification tn,
Integer myListenerID,
Map<Integer, ClientListenerInfo> listeners) {
final Notification notif = tn.getNotification();
final Integer listenerID = tn.getListenerID();
if (listenerID.equals(myListenerID)) return;
final ClientListenerInfo li = listeners.get(listenerID);
if (li == null) {
logger.trace("NotifFetcher.dispatch",
"Listener ID not in map");
return;
}
NotificationListener l = li.getListener();
Object h = li.getHandback();
try {
l.handleNotification(notif, h);
} catch (RuntimeException e) {
final String msg =
"Failed to forward a notification " +
"to a listener";
logger.trace("NotifFetcher-run", msg, e);
}
}
private NotificationResult fetchNotifs() {
try {
NotificationResult nr = ClientNotifForwarder.this.
fetchNotifs(clientSequenceNumber,maxNotifications,
timeout);
if (logger.traceOn()) {
logger.trace("NotifFetcher-run",
"Got notifications from the server: "+nr);
}
return nr;
} catch (ClassNotFoundException | NotSerializableException e) {
logger.trace("NotifFetcher.fetchNotifs", e);
return fetchOneNotif();
} catch (IOException ioe) {
if (!shouldStop()) {
logger.error("NotifFetcher-run",
"Failed to fetch notification, " +
"stopping thread. Error is: " + ioe, ioe);
logger.debug("NotifFetcher-run",ioe);
}
// no more fetching
return null;
}
}
/* Fetch one notification when we suspect that it might be a
notification that we can't deserialize (because of a
missing class). First we ask for 0 notifications with 0
timeout. This allows us to skip sequence numbers for
notifications that don't match our filters. Then we ask
for one notification. If that produces a
ClassNotFoundException, NotSerializableException or
UnmarshalException, we increase our sequence number and ask again.
Eventually we will either get a successful notification, or a
return with 0 notifications. In either case we can return a
NotificationResult. This algorithm works (albeit less
well) even if the server implementation doesn't optimize a
request for 0 notifications to skip sequence numbers for
notifications that don't match our filters.
If we had at least one
ClassNotFoundException/NotSerializableException/UnmarshalException,
then we must emit a JMXConnectionNotification.LOST_NOTIFS.
*/
private NotificationResult fetchOneNotif() {
ClientNotifForwarder cnf = ClientNotifForwarder.this;
long startSequenceNumber = clientSequenceNumber;
int notFoundCount = 0;
NotificationResult result = null;
long firstEarliest = -1;
while (result == null && !shouldStop()) {
NotificationResult nr;
try {
// 0 notifs to update startSequenceNumber
nr = cnf.fetchNotifs(startSequenceNumber, 0, 0L);
} catch (ClassNotFoundException e) {
logger.warning("NotifFetcher.fetchOneNotif",
"Impossible exception: " + e);
logger.debug("NotifFetcher.fetchOneNotif",e);
return null;
} catch (IOException e) {
if (!shouldStop())
logger.trace("NotifFetcher.fetchOneNotif", e);
return null;
}
if (shouldStop() || nr == null)
return null;
startSequenceNumber = nr.getNextSequenceNumber();
if (firstEarliest < 0)
firstEarliest = nr.getEarliestSequenceNumber();
try {
// 1 notif to skip possible missing class
result = cnf.fetchNotifs(startSequenceNumber, 1, 0L);
} catch (ClassNotFoundException | NotSerializableException e) {
logger.warning("NotifFetcher.fetchOneNotif",
"Failed to deserialize a notification: "+e.toString());
if (logger.traceOn()) {
logger.trace("NotifFetcher.fetchOneNotif",
"Failed to deserialize a notification.", e);
}
notFoundCount++;
startSequenceNumber++;
} catch (Exception e) {
if (!shouldStop())
logger.trace("NotifFetcher.fetchOneNotif", e);
return null;
}
}
if (notFoundCount > 0) {
final String msg =
"Dropped " + notFoundCount + " notification" +
(notFoundCount == 1 ? "" : "s") +
" because classes were missing locally or incompatible";
lostNotifs(msg, notFoundCount);
// Even if result.getEarliestSequenceNumber() is now greater than
// it was initially, meaning some notifs have been dropped
// from the buffer, we don't want the caller to see that
// because it is then likely to renotify about the lost notifs.
// So we put back the first value of earliestSequenceNumber
// that we saw.
if (result != null) {
result = new NotificationResult(
firstEarliest, result.getNextSequenceNumber(),
result.getTargetedNotifications());
}
}
return result;
}
private boolean shouldStop() {
synchronized (ClientNotifForwarder.this) {
if (state != STARTED) {
return true;
} else if (infoList.size() == 0) {
// no more listener, stop fetching
setState(STOPPING);
return true;
}
return false;
}
}
}
// -------------------------------------------------
// private methods
// -------------------------------------------------
private synchronized void setState(int newState) {
if (state == TERMINATED) {
return;
}
state = newState;
this.notifyAll();
}
/*
* Called to decide whether need to start a thread for fetching notifs.
* <P>The parameter reconnected will decide whether to initilize the clientSequenceNumber,
* initilaizing the clientSequenceNumber means to ignore all notifications arrived before.
* If it is reconnected, we will not initialize in order to get all notifications arrived
* during the reconnection. It may cause the newly registered listeners to receive some
* notifications arrived before its registray.
*/
private synchronized void init(boolean reconnected) throws IOException {
switch (state) {
case STARTED:
return;
case STARTING:
return;
case TERMINATED:
throw new IOException("The ClientNotifForwarder has been terminated.");
case STOPPING:
if (beingReconnected == true) {
// wait for another thread to do, which is doing reconnection
return;
}
while (state == STOPPING) { // make sure only one fetching thread.
try {
wait();
} catch (InterruptedException ire) {
IOException ioe = new IOException(ire.toString());
EnvHelp.initCause(ioe, ire);
throw ioe;
}
}
// re-call this method to check the state again,
// the state can be other value like TERMINATED.
init(reconnected);
return;
case STOPPED:
if (beingReconnected == true) {
// wait for another thread to do, which is doing reconnection
return;
}
if (logger.traceOn()) {
logger.trace("init", "Initializing...");
}
// init the clientSequenceNumber if not reconnected.
if (!reconnected) {
try {
NotificationResult nr = fetchNotifs(-1, 0, 0);
if (state != STOPPED) { // JDK-8038940
// reconnection must happen during
// fetchNotifs(-1, 0, 0), and a new
// thread takes over the fetching job
return;
}
clientSequenceNumber = nr.getNextSequenceNumber();
} catch (ClassNotFoundException e) {
// can't happen
logger.warning("init", "Impossible exception: "+ e);
logger.debug("init",e);
}
}
// for cleaning
try {
mbeanRemovedNotifID = addListenerForMBeanRemovedNotif();
} catch (Exception e) {
final String msg =
"Failed to register a listener to the mbean " +
"server: the client will not do clean when an MBean " +
"is unregistered";
if (logger.traceOn()) {
logger.trace("init", msg, e);
}
}
setState(STARTING);
// start fetching
executor.execute(new NotifFetcher());
return;
default:
// should not
throw new IOException("Unknown state.");
}
}
/**
* Import: should not remove a listener during reconnection, the reconnection
* needs to change the listener list and that will possibly make removal fail.
*/
private synchronized void beforeRemove() throws IOException {
while (beingReconnected) {
if (state == TERMINATED) {
throw new IOException("Terminated.");
}
try {
wait();
} catch (InterruptedException ire) {
IOException ioe = new IOException(ire.toString());
EnvHelp.initCause(ioe, ire);
throw ioe;
}
}
if (state == TERMINATED) {
throw new IOException("Terminated.");
}
}
// -------------------------------------------------
// private variables
// -------------------------------------------------
private final ClassLoader defaultClassLoader;
private Executor executor;
private final Map<Integer, ClientListenerInfo> infoList =
new HashMap<Integer, ClientListenerInfo>();
// notif stuff
private long clientSequenceNumber = -1;
private final int maxNotifications;
private final long timeout;
private Integer mbeanRemovedNotifID = null;
private Thread currentFetchThread;
// state
/**
* This state means that a thread is being created for fetching and forwarding notifications.
*/
private static final int STARTING = 0;
/**
* This state tells that a thread has been started for fetching and forwarding notifications.
*/
private static final int STARTED = 1;
/**
* This state means that the fetching thread is informed to stop.
*/
private static final int STOPPING = 2;
/**
* This state means that the fetching thread is already stopped.
*/
private static final int STOPPED = 3;
/**
* This state means that this object is terminated and no more thread will be created
* for fetching notifications.
*/
private static final int TERMINATED = 4;
private int state = STOPPED;
/**
* This variable is used to tell whether a connector (RMIConnector or ClientIntermediary)
* is doing reconnection.
* This variable will be set to true by the method <code>preReconnection</code>, and set
* to false by <code>postReconnection</code>.
* When beingReconnected == true, no thread will be created for fetching notifications.
*/
private boolean beingReconnected = false;
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc",
"ClientNotifForwarder");
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2003, 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.remote.internal;
import java.util.Set;
import javax.management.remote.NotificationResult;
import javax.management.remote.TargetedNotification;
/** A buffer of notifications received from an MBean server. */
public interface NotificationBuffer {
/**
* <p>Fetch notifications that match the given listeners.</p>
*
* <p>The operation only considers notifications with a sequence
* number at least <code>startSequenceNumber</code>. It will take
* no longer than <code>timeout</code>, and will return no more
* than <code>maxNotifications</code> different notifications.</p>
*
* <p>If there are no notifications matching the criteria, the
* operation will block until one arrives, subject to the
* timeout.</p>
*
* @param filter an object that will add notifications to a
* {@code List<TargetedNotification>} if they match the current
* listeners with their filters.
* @param startSequenceNumber the first sequence number to
* consider.
* @param timeout the maximum time to wait. May be 0 to indicate
* not to wait if there are no notifications.
* @param maxNotifications the maximum number of notifications to
* return. May be 0 to indicate a wait for eligible notifications
* that will return a usable <code>nextSequenceNumber</code>. The
* {@link TargetedNotification} array in the returned {@link
* NotificationResult} may contain more than this number of
* elements but will not contain more than this number of
* different notifications.
*/
public NotificationResult
fetchNotifications(NotificationBufferFilter filter,
long startSequenceNumber,
long timeout,
int maxNotifications)
throws InterruptedException;
/**
* <p>Discard this buffer.</p>
*/
public void dispose();
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 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.remote.internal;
import java.util.List;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.management.remote.TargetedNotification;
public interface NotificationBufferFilter {
/**
* Add the given notification coming from the given MBean to the list
* iff it matches this filter's rules.
*/
public void apply(List<TargetedNotification> targetedNotifs,
ObjectName source, Notification notif);
}

View file

@ -0,0 +1,235 @@
/*
* Copyright (c) 2003, 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.remote.internal;
import com.sun.jmx.remote.util.ClassLogger;
public abstract class ServerCommunicatorAdmin {
public ServerCommunicatorAdmin(long timeout) {
if (logger.traceOn()) {
logger.trace("Constructor",
"Creates a new ServerCommunicatorAdmin object "+
"with the timeout "+timeout);
}
this.timeout = timeout;
timestamp = 0;
if (timeout < Long.MAX_VALUE) {
Runnable timeoutTask = new Timeout();
final Thread t = new Thread(null,
timeoutTask,
"JMX-Server-Admin-Timeout",
0,
false);
t.setName("JMX server connection timeout " + t.getId());
// If you change this name you will need to change a unit test
// (NoServerTimeoutTest)
t.setDaemon(true);
t.start();
}
}
/**
* Tells that a new request message is received.
* A caller of this method should always call the method
* <code>rspOutgoing</code> to inform that a response is sent out
* for the received request.
* @return the value of the termination flag:
* true if the connection is already being terminated,
* false otherwise.
*/
public boolean reqIncoming() {
if (logger.traceOn()) {
logger.trace("reqIncoming", "Receive a new request.");
}
synchronized(lock) {
if (terminated) {
logger.warning("reqIncoming",
"The server has decided to close " +
"this client connection.");
}
++currentJobs;
return terminated;
}
}
/**
* Tells that a response is sent out for a received request.
* @return the value of the termination flag:
* true if the connection is already being terminated,
* false otherwise.
*/
public boolean rspOutgoing() {
if (logger.traceOn()) {
logger.trace("reqIncoming", "Finish a request.");
}
synchronized(lock) {
if (--currentJobs == 0) {
timestamp = System.currentTimeMillis();
logtime("Admin: Timestamp=",timestamp);
// tells the adminor to restart waiting with timeout
lock.notify();
}
return terminated;
}
}
/**
* Called by this class to tell an implementation to do stop.
*/
protected abstract void doStop();
/**
* Terminates this object.
* Called only by outside, so do not need to call doStop
*/
public void terminate() {
if (logger.traceOn()) {
logger.trace("terminate",
"terminate the ServerCommunicatorAdmin object.");
}
synchronized(lock) {
if (terminated) {
return;
}
terminated = true;
// tell Timeout to terminate
lock.notify();
}
}
// --------------------------------------------------------------
// private classes
// --------------------------------------------------------------
private class Timeout implements Runnable {
public void run() {
boolean stopping = false;
synchronized(lock) {
if (timestamp == 0) timestamp = System.currentTimeMillis();
logtime("Admin: timeout=",timeout);
logtime("Admin: Timestamp=",timestamp);
while(!terminated) {
try {
// wait until there is no more job
while(!terminated && currentJobs != 0) {
if (logger.traceOn()) {
logger.trace("Timeout-run",
"Waiting without timeout.");
}
lock.wait();
}
if (terminated) return;
final long remaining =
timeout - (System.currentTimeMillis() - timestamp);
logtime("Admin: remaining timeout=",remaining);
if (remaining > 0) {
if (logger.traceOn()) {
logger.trace("Timeout-run",
"Waiting with timeout: "+
remaining + " ms remaining");
}
lock.wait(remaining);
}
if (currentJobs > 0) continue;
final long elapsed =
System.currentTimeMillis() - timestamp;
logtime("Admin: elapsed=",elapsed);
if (!terminated && elapsed > timeout) {
if (logger.traceOn()) {
logger.trace("Timeout-run",
"timeout elapsed");
}
logtime("Admin: timeout elapsed! "+
elapsed+">",timeout);
// stopping
terminated = true;
stopping = true;
break;
}
} catch (InterruptedException ire) {
logger.warning("Timeout-run","Unexpected Exception: "+
ire);
logger.debug("Timeout-run",ire);
return;
}
}
}
if (stopping) {
if (logger.traceOn()) {
logger.trace("Timeout-run", "Call the doStop.");
}
doStop();
}
}
}
private void logtime(String desc,long time) {
timelogger.trace("synchro",desc+time);
}
// --------------------------------------------------------------
// private variables
// --------------------------------------------------------------
private long timestamp;
private final int[] lock = new int[0];
private int currentJobs = 0;
private long timeout;
// state issue
private boolean terminated = false;
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc",
"ServerCommunicatorAdmin");
private static final ClassLogger timelogger =
new ClassLogger("javax.management.remote.timeout",
"ServerCommunicatorAdmin");
}

View file

@ -0,0 +1,506 @@
/*
* 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.remote.internal;
import com.sun.jmx.remote.security.NotificationAccessController;
import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanPermission;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationFilter;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.NotificationResult;
import javax.management.remote.TargetedNotification;
import javax.management.MalformedObjectNameException;
import javax.security.auth.Subject;
public class ServerNotifForwarder {
public ServerNotifForwarder(MBeanServer mbeanServer,
Map<String, ?> env,
NotificationBuffer notifBuffer,
String connectionId) {
this.mbeanServer = mbeanServer;
this.notifBuffer = notifBuffer;
this.connectionId = connectionId;
connectionTimeout = EnvHelp.getServerConnectionTimeout(env);
String stringBoolean = (String) env.get("jmx.remote.x.check.notification.emission");
checkNotificationEmission = EnvHelp.computeBooleanFromString( stringBoolean );
notificationAccessController =
EnvHelp.getNotificationAccessController(env);
}
public Integer addNotificationListener(final ObjectName name,
final NotificationFilter filter)
throws InstanceNotFoundException, IOException {
if (logger.traceOn()) {
logger.trace("addNotificationListener",
"Add a listener at " + name);
}
checkState();
// Explicitly check MBeanPermission for addNotificationListener
//
checkMBeanPermission(name, "addNotificationListener");
if (notificationAccessController != null) {
notificationAccessController.addNotificationListener(
connectionId, name, getSubject());
}
try {
boolean instanceOf =
AccessController.doPrivileged(
new PrivilegedExceptionAction<Boolean>() {
public Boolean run() throws InstanceNotFoundException {
return mbeanServer.isInstanceOf(name, broadcasterClass);
}
});
if (!instanceOf) {
throw new IllegalArgumentException("The specified MBean [" +
name + "] is not a " +
"NotificationBroadcaster " +
"object.");
}
} catch (PrivilegedActionException e) {
throw (InstanceNotFoundException) extractException(e);
}
final Integer id = getListenerID();
// 6238731: set the default domain if no domain is set.
ObjectName nn = name;
if (name.getDomain() == null || name.getDomain().equals("")) {
try {
nn = ObjectName.getInstance(mbeanServer.getDefaultDomain(),
name.getKeyPropertyList());
} catch (MalformedObjectNameException mfoe) {
// impossible, but...
IOException ioe = new IOException(mfoe.getMessage());
ioe.initCause(mfoe);
throw ioe;
}
}
synchronized (listenerMap) {
IdAndFilter idaf = new IdAndFilter(id, filter);
Set<IdAndFilter> set = listenerMap.get(nn);
// Tread carefully because if set.size() == 1 it may be the
// Collections.singleton we make here, which is unmodifiable.
if (set == null)
set = Collections.singleton(idaf);
else {
if (set.size() == 1)
set = new HashSet<IdAndFilter>(set);
set.add(idaf);
}
listenerMap.put(nn, set);
}
return id;
}
public void removeNotificationListener(ObjectName name,
Integer[] listenerIDs)
throws Exception {
if (logger.traceOn()) {
logger.trace("removeNotificationListener",
"Remove some listeners from " + name);
}
checkState();
// Explicitly check MBeanPermission for removeNotificationListener
//
checkMBeanPermission(name, "removeNotificationListener");
if (notificationAccessController != null) {
notificationAccessController.removeNotificationListener(
connectionId, name, getSubject());
}
Exception re = null;
for (int i = 0 ; i < listenerIDs.length ; i++) {
try {
removeNotificationListener(name, listenerIDs[i]);
} catch (Exception e) {
// Give back the first exception
//
if (re != null) {
re = e;
}
}
}
if (re != null) {
throw re;
}
}
public void removeNotificationListener(ObjectName name, Integer listenerID)
throws
InstanceNotFoundException,
ListenerNotFoundException,
IOException {
if (logger.traceOn()) {
logger.trace("removeNotificationListener",
"Remove the listener " + listenerID + " from " + name);
}
checkState();
if (name != null && !name.isPattern()) {
if (!mbeanServer.isRegistered(name)) {
throw new InstanceNotFoundException("The MBean " + name +
" is not registered.");
}
}
synchronized (listenerMap) {
// Tread carefully because if set.size() == 1 it may be a
// Collections.singleton, which is unmodifiable.
Set<IdAndFilter> set = listenerMap.get(name);
IdAndFilter idaf = new IdAndFilter(listenerID, null);
if (set == null || !set.contains(idaf))
throw new ListenerNotFoundException("Listener not found");
if (set.size() == 1)
listenerMap.remove(name);
else
set.remove(idaf);
}
}
/* This is the object that will apply our filtering to candidate
* notifications. First of all, if there are no listeners for the
* ObjectName that the notification is coming from, we go no further.
* Then, for each listener, we must apply the corresponding filter (if any)
* and ignore the listener if the filter rejects. Finally, we apply
* some access checks which may also reject the listener.
*
* A given notification may trigger several listeners on the same MBean,
* which is why listenerMap is a Map<ObjectName, Set<IdAndFilter>> and
* why we add the found notifications to a supplied List rather than
* just returning a boolean.
*/
private final NotifForwarderBufferFilter bufferFilter = new NotifForwarderBufferFilter();
final class NotifForwarderBufferFilter implements NotificationBufferFilter {
public void apply(List<TargetedNotification> targetedNotifs,
ObjectName source, Notification notif) {
// We proceed in two stages here, to avoid holding the listenerMap
// lock while invoking the filters (which are user code).
final IdAndFilter[] candidates;
synchronized (listenerMap) {
final Set<IdAndFilter> set = listenerMap.get(source);
if (set == null) {
logger.debug("bufferFilter", "no listeners for this name");
return;
}
candidates = new IdAndFilter[set.size()];
set.toArray(candidates);
}
// We don't synchronize on targetedNotifs, because it is a local
// variable of our caller and no other thread can see it.
for (IdAndFilter idaf : candidates) {
final NotificationFilter nf = idaf.getFilter();
if (nf == null || nf.isNotificationEnabled(notif)) {
logger.debug("bufferFilter", "filter matches");
final TargetedNotification tn =
new TargetedNotification(notif, idaf.getId());
if (allowNotificationEmission(source, tn))
targetedNotifs.add(tn);
}
}
}
};
public NotificationResult fetchNotifs(long startSequenceNumber,
long timeout,
int maxNotifications) {
if (logger.traceOn()) {
logger.trace("fetchNotifs", "Fetching notifications, the " +
"startSequenceNumber is " + startSequenceNumber +
", the timeout is " + timeout +
", the maxNotifications is " + maxNotifications);
}
NotificationResult nr;
final long t = Math.min(connectionTimeout, timeout);
try {
nr = notifBuffer.fetchNotifications(bufferFilter,
startSequenceNumber,
t, maxNotifications);
snoopOnUnregister(nr);
} catch (InterruptedException ire) {
nr = new NotificationResult(0L, 0L, new TargetedNotification[0]);
}
if (logger.traceOn()) {
logger.trace("fetchNotifs", "Forwarding the notifs: "+nr);
}
return nr;
}
// The standard RMI connector client will register a listener on the MBeanServerDelegate
// in order to be told when MBeans are unregistered. We snoop on fetched notifications
// so that we can know too, and remove the corresponding entry from the listenerMap.
// See 6957378.
private void snoopOnUnregister(NotificationResult nr) {
List<IdAndFilter> copy = null;
synchronized (listenerMap) {
Set<IdAndFilter> delegateSet = listenerMap.get(MBeanServerDelegate.DELEGATE_NAME);
if (delegateSet == null || delegateSet.isEmpty()) {
return;
}
copy = new ArrayList<>(delegateSet);
}
for (TargetedNotification tn : nr.getTargetedNotifications()) {
Integer id = tn.getListenerID();
for (IdAndFilter idaf : copy) {
if (idaf.id == id) {
// This is a notification from the MBeanServerDelegate.
Notification n = tn.getNotification();
if (n instanceof MBeanServerNotification &&
n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
MBeanServerNotification mbsn = (MBeanServerNotification) n;
ObjectName gone = mbsn.getMBeanName();
synchronized (listenerMap) {
listenerMap.remove(gone);
}
}
}
}
}
}
public void terminate() {
if (logger.traceOn()) {
logger.trace("terminate", "Be called.");
}
synchronized(terminationLock) {
if (terminated) {
return;
}
terminated = true;
synchronized(listenerMap) {
listenerMap.clear();
}
}
if (logger.traceOn()) {
logger.trace("terminate", "Terminated.");
}
}
//----------------
// PRIVATE METHODS
//----------------
private Subject getSubject() {
return Subject.getSubject(AccessController.getContext());
}
private void checkState() throws IOException {
synchronized(terminationLock) {
if (terminated) {
throw new IOException("The connection has been terminated.");
}
}
}
private Integer getListenerID() {
synchronized(listenerCounterLock) {
return listenerCounter++;
}
}
/**
* Explicitly check the MBeanPermission for
* the current access control context.
*/
public final void checkMBeanPermission(
final ObjectName name, final String actions)
throws InstanceNotFoundException, SecurityException {
checkMBeanPermission(mbeanServer,name,actions);
}
static void checkMBeanPermission(
final MBeanServer mbs, final ObjectName name, final String actions)
throws InstanceNotFoundException, SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
AccessControlContext acc = AccessController.getContext();
ObjectInstance oi;
try {
oi = AccessController.doPrivileged(
new PrivilegedExceptionAction<ObjectInstance>() {
public ObjectInstance run()
throws InstanceNotFoundException {
return mbs.getObjectInstance(name);
}
});
} catch (PrivilegedActionException e) {
throw (InstanceNotFoundException) extractException(e);
}
String classname = oi.getClassName();
MBeanPermission perm = new MBeanPermission(
classname,
null,
name,
actions);
sm.checkPermission(perm, acc);
}
}
/**
* Check if the caller has the right to get the following notifications.
*/
private boolean allowNotificationEmission(ObjectName name,
TargetedNotification tn) {
try {
if (checkNotificationEmission) {
checkMBeanPermission(name, "addNotificationListener");
}
if (notificationAccessController != null) {
notificationAccessController.fetchNotification(
connectionId, name, tn.getNotification(), getSubject());
}
return true;
} catch (SecurityException e) {
if (logger.debugOn()) {
logger.debug("fetchNotifs", "Notification " +
tn.getNotification() + " not forwarded: the " +
"caller didn't have the required access rights");
}
return false;
} catch (Exception e) {
if (logger.debugOn()) {
logger.debug("fetchNotifs", "Notification " +
tn.getNotification() + " not forwarded: " +
"got an unexpected exception: " + e);
}
return false;
}
}
/**
* Iterate until we extract the real exception
* from a stack of PrivilegedActionExceptions.
*/
private static Exception extractException(Exception e) {
while (e instanceof PrivilegedActionException) {
e = ((PrivilegedActionException)e).getException();
}
return e;
}
private static class IdAndFilter {
private Integer id;
private NotificationFilter filter;
IdAndFilter(Integer id, NotificationFilter filter) {
this.id = id;
this.filter = filter;
}
Integer getId() {
return this.id;
}
NotificationFilter getFilter() {
return this.filter;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return ((o instanceof IdAndFilter) &&
((IdAndFilter) o).getId().equals(getId()));
}
}
//------------------
// PRIVATE VARIABLES
//------------------
private MBeanServer mbeanServer;
private final String connectionId;
private final long connectionTimeout;
private static int listenerCounter = 0;
private final static int[] listenerCounterLock = new int[0];
private NotificationBuffer notifBuffer;
private final Map<ObjectName, Set<IdAndFilter>> listenerMap =
new HashMap<ObjectName, Set<IdAndFilter>>();
private boolean terminated = false;
private final int[] terminationLock = new int[0];
static final String broadcasterClass =
NotificationBroadcaster.class.getName();
private final boolean checkNotificationEmission;
private final NotificationAccessController notificationAccessController;
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc", "ServerNotifForwarder");
}

View file

@ -0,0 +1,37 @@
<html>
<head>
<title>JMX Remote API - Sun RI Internal Classes</title>
<!--
Copyright (c) 2003, 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.
-->
</head>
<body bgcolor="white">
<p>This package contains some classes used internally by the
Sun implementation of JMX Connectors to push and pull
notifications.
</p>
</body>
</html>

View file

@ -0,0 +1,570 @@
/*
* Copyright (c) 2004, 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.remote.security;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.mbeanserver.Util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilePermission;
import java.io.IOException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;
import javax.management.remote.JMXPrincipal;
import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
/**
* This {@link LoginModule} performs file-based authentication.
*
* <p> A supplied username and password is verified against the
* corresponding user credentials stored in a designated password file.
* If successful then a new {@link JMXPrincipal} is created with the
* user's name and it is associated with the current {@link Subject}.
* Such principals may be identified and granted management privileges in
* the access control file for JMX remote management or in a Java security
* policy.
*
* <p> The password file comprises a list of key-value pairs as specified in
* {@link Properties}. The key represents a user's name and the value is its
* associated cleartext password. By default, the following password file is
* used:
* <pre>
* ${java.home}/conf/management/jmxremote.password
* </pre>
* A different password file can be specified via the <code>passwordFile</code>
* configuration option.
*
* <p> This module recognizes the following <code>Configuration</code> options:
* <dl>
* <dt> <code>passwordFile</code> </dt>
* <dd> the path to an alternative password file. It is used instead of
* the default password file.</dd>
*
* <dt> <code>useFirstPass</code> </dt>
* <dd> if <code>true</code>, this module retrieves the username and password
* from the module's shared state, using "javax.security.auth.login.name"
* and "javax.security.auth.login.password" as the respective keys. The
* retrieved values are used for authentication. If authentication fails,
* no attempt for a retry is made, and the failure is reported back to
* the calling application.</dd>
*
* <dt> <code>tryFirstPass</code> </dt>
* <dd> if <code>true</code>, this module retrieves the username and password
* from the module's shared state, using "javax.security.auth.login.name"
* and "javax.security.auth.login.password" as the respective keys. The
* retrieved values are used for authentication. If authentication fails,
* the module uses the CallbackHandler to retrieve a new username and
* password, and another attempt to authenticate is made. If the
* authentication fails, the failure is reported back to the calling
* application.</dd>
*
* <dt> <code>storePass</code> </dt>
* <dd> if <code>true</code>, this module stores the username and password
* obtained from the CallbackHandler in the module's shared state, using
* "javax.security.auth.login.name" and
* "javax.security.auth.login.password" as the respective keys. This is
* not performed if existing values already exist for the username and
* password in the shared state, or if authentication fails.</dd>
*
* <dt> <code>clearPass</code> </dt>
* <dd> if <code>true</code>, this module clears the username and password
* stored in the module's shared state after both phases of authentication
* (login and commit) have completed.</dd>
* </dl>
*/
public class FileLoginModule implements LoginModule {
private static final String PASSWORD_FILE_NAME = "jmxremote.password";
// Location of the default password file
private static final String DEFAULT_PASSWORD_FILE_NAME =
AccessController.doPrivileged(new GetPropertyAction("java.home")) +
File.separatorChar + "conf" +
File.separatorChar + "management" + File.separatorChar +
PASSWORD_FILE_NAME;
// Key to retrieve the stored username
private static final String USERNAME_KEY =
"javax.security.auth.login.name";
// Key to retrieve the stored password
private static final String PASSWORD_KEY =
"javax.security.auth.login.password";
// Log messages
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc", "FileLoginModule");
// Configurable options
private boolean useFirstPass = false;
private boolean tryFirstPass = false;
private boolean storePass = false;
private boolean clearPass = false;
// Authentication status
private boolean succeeded = false;
private boolean commitSucceeded = false;
// Supplied username and password
private String username;
private char[] password;
private JMXPrincipal user;
// Initial state
private Subject subject;
private CallbackHandler callbackHandler;
private Map<String, Object> sharedState;
private Map<String, ?> options;
private String passwordFile;
private String passwordFileDisplayName;
private boolean userSuppliedPasswordFile;
private boolean hasJavaHomePermission;
private Properties userCredentials;
/**
* Initialize this <code>LoginModule</code>.
*
* @param subject the <code>Subject</code> to be authenticated.
* @param callbackHandler a <code>CallbackHandler</code> to acquire the
* user's name and password.
* @param sharedState shared <code>LoginModule</code> state.
* @param options options specified in the login
* <code>Configuration</code> for this particular
* <code>LoginModule</code>.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String,?> sharedState,
Map<String,?> options)
{
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = Util.cast(sharedState);
this.options = options;
// initialize any configured options
tryFirstPass =
"true".equalsIgnoreCase((String)options.get("tryFirstPass"));
useFirstPass =
"true".equalsIgnoreCase((String)options.get("useFirstPass"));
storePass =
"true".equalsIgnoreCase((String)options.get("storePass"));
clearPass =
"true".equalsIgnoreCase((String)options.get("clearPass"));
passwordFile = (String)options.get("passwordFile");
passwordFileDisplayName = passwordFile;
userSuppliedPasswordFile = true;
// set the location of the password file
if (passwordFile == null) {
passwordFile = DEFAULT_PASSWORD_FILE_NAME;
userSuppliedPasswordFile = false;
try {
System.getProperty("java.home");
hasJavaHomePermission = true;
passwordFileDisplayName = passwordFile;
} catch (SecurityException e) {
hasJavaHomePermission = false;
passwordFileDisplayName = PASSWORD_FILE_NAME;
}
}
}
/**
* Begin user authentication (Authentication Phase 1).
*
* <p> Acquire the user's name and password and verify them against
* the corresponding credentials from the password file.
*
* @return true always, since this <code>LoginModule</code>
* should not be ignored.
* @exception FailedLoginException if the authentication fails.
* @exception LoginException if this <code>LoginModule</code>
* is unable to perform the authentication.
*/
public boolean login() throws LoginException {
try {
loadPasswordFile();
} catch (IOException ioe) {
LoginException le = new LoginException(
"Error: unable to load the password file: " +
passwordFileDisplayName);
throw EnvHelp.initCause(le, ioe);
}
if (userCredentials == null) {
throw new LoginException
("Error: unable to locate the users' credentials.");
}
if (logger.debugOn()) {
logger.debug("login",
"Using password file: " + passwordFileDisplayName);
}
// attempt the authentication
if (tryFirstPass) {
try {
// attempt the authentication by getting the
// username and password from shared state
attemptAuthentication(true);
// authentication succeeded
succeeded = true;
if (logger.debugOn()) {
logger.debug("login",
"Authentication using cached password has succeeded");
}
return true;
} catch (LoginException le) {
// authentication failed -- try again below by prompting
cleanState();
logger.debug("login",
"Authentication using cached password has failed");
}
} else if (useFirstPass) {
try {
// attempt the authentication by getting the
// username and password from shared state
attemptAuthentication(true);
// authentication succeeded
succeeded = true;
if (logger.debugOn()) {
logger.debug("login",
"Authentication using cached password has succeeded");
}
return true;
} catch (LoginException le) {
// authentication failed
cleanState();
logger.debug("login",
"Authentication using cached password has failed");
throw le;
}
}
if (logger.debugOn()) {
logger.debug("login", "Acquiring password");
}
// attempt the authentication using the supplied username and password
try {
attemptAuthentication(false);
// authentication succeeded
succeeded = true;
if (logger.debugOn()) {
logger.debug("login", "Authentication has succeeded");
}
return true;
} catch (LoginException le) {
cleanState();
logger.debug("login", "Authentication has failed");
throw le;
}
}
/**
* Complete user authentication (Authentication Phase 2).
*
* <p> This method is called if the LoginContext's
* overall authentication has succeeded
* (all the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
* LoginModules have succeeded).
*
* <p> If this LoginModule's own authentication attempt
* succeeded (checked by retrieving the private state saved by the
* <code>login</code> method), then this method associates a
* <code>JMXPrincipal</code> with the <code>Subject</code> located in the
* <code>LoginModule</code>. If this LoginModule's own
* authentication attempted failed, then this method removes
* any state that was originally saved.
*
* @exception LoginException if the commit fails
* @return true if this LoginModule's own login and commit
* attempts succeeded, or false otherwise.
*/
public boolean commit() throws LoginException {
if (succeeded == false) {
return false;
} else {
if (subject.isReadOnly()) {
cleanState();
throw new LoginException("Subject is read-only");
}
// add Principals to the Subject
if (!subject.getPrincipals().contains(user)) {
subject.getPrincipals().add(user);
}
if (logger.debugOn()) {
logger.debug("commit",
"Authentication has completed successfully");
}
}
// in any case, clean out state
cleanState();
commitSucceeded = true;
return true;
}
/**
* Abort user authentication (Authentication Phase 2).
*
* <p> This method is called if the LoginContext's overall authentication
* failed (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
* LoginModules did not succeed).
*
* <p> If this LoginModule's own authentication attempt
* succeeded (checked by retrieving the private state saved by the
* <code>login</code> and <code>commit</code> methods),
* then this method cleans up any state that was originally saved.
*
* @exception LoginException if the abort fails.
* @return false if this LoginModule's own login and/or commit attempts
* failed, and true otherwise.
*/
public boolean abort() throws LoginException {
if (logger.debugOn()) {
logger.debug("abort",
"Authentication has not completed successfully");
}
if (succeeded == false) {
return false;
} else if (succeeded == true && commitSucceeded == false) {
// Clean out state
succeeded = false;
cleanState();
user = null;
} else {
// overall authentication succeeded and commit succeeded,
// but someone else's commit failed
logout();
}
return true;
}
/**
* Logout a user.
*
* <p> This method removes the Principals
* that were added by the <code>commit</code> method.
*
* @exception LoginException if the logout fails.
* @return true in all cases since this <code>LoginModule</code>
* should not be ignored.
*/
public boolean logout() throws LoginException {
if (subject.isReadOnly()) {
cleanState();
throw new LoginException ("Subject is read-only");
}
subject.getPrincipals().remove(user);
// clean out state
cleanState();
succeeded = false;
commitSucceeded = false;
user = null;
if (logger.debugOn()) {
logger.debug("logout", "Subject is being logged out");
}
return true;
}
/**
* Attempt authentication
*
* @param usePasswdFromSharedState a flag to tell this method whether
* to retrieve the password from the sharedState.
*/
@SuppressWarnings("unchecked") // sharedState used as Map<String,Object>
private void attemptAuthentication(boolean usePasswdFromSharedState)
throws LoginException {
// get the username and password
getUsernamePassword(usePasswdFromSharedState);
String localPassword;
// userCredentials is initialized in login()
if (((localPassword = userCredentials.getProperty(username)) == null) ||
(! localPassword.equals(new String(password)))) {
// username not found or passwords do not match
if (logger.debugOn()) {
logger.debug("login", "Invalid username or password");
}
throw new FailedLoginException("Invalid username or password");
}
// Save the username and password in the shared state
// only if authentication succeeded
if (storePass &&
!sharedState.containsKey(USERNAME_KEY) &&
!sharedState.containsKey(PASSWORD_KEY)) {
sharedState.put(USERNAME_KEY, username);
sharedState.put(PASSWORD_KEY, password);
}
// Create a new user principal
user = new JMXPrincipal(username);
if (logger.debugOn()) {
logger.debug("login",
"User '" + username + "' successfully validated");
}
}
/*
* Read the password file.
*/
private void loadPasswordFile() throws IOException {
FileInputStream fis;
try {
fis = new FileInputStream(passwordFile);
} catch (SecurityException e) {
if (userSuppliedPasswordFile || hasJavaHomePermission) {
throw e;
} else {
final FilePermission fp =
new FilePermission(passwordFileDisplayName, "read");
AccessControlException ace = new AccessControlException(
"access denied " + fp.toString());
ace.setStackTrace(e.getStackTrace());
throw ace;
}
}
try {
final BufferedInputStream bis = new BufferedInputStream(fis);
try {
userCredentials = new Properties();
userCredentials.load(bis);
} finally {
bis.close();
}
} finally {
fis.close();
}
}
/**
* Get the username and password.
* This method does not return any value.
* Instead, it sets global name and password variables.
*
* <p> Also note that this method will set the username and password
* values in the shared state in case subsequent LoginModules
* want to use them via use/tryFirstPass.
*
* @param usePasswdFromSharedState boolean that tells this method whether
* to retrieve the password from the sharedState.
*/
private void getUsernamePassword(boolean usePasswdFromSharedState)
throws LoginException {
if (usePasswdFromSharedState) {
// use the password saved by the first module in the stack
username = (String)sharedState.get(USERNAME_KEY);
password = (char[])sharedState.get(PASSWORD_KEY);
return;
}
// acquire username and password
if (callbackHandler == null)
throw new LoginException("Error: no CallbackHandler available " +
"to garner authentication information from the user");
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("username");
callbacks[1] = new PasswordCallback("password", false);
try {
callbackHandler.handle(callbacks);
username = ((NameCallback)callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0,
password, 0, tmpPassword.length);
((PasswordCallback)callbacks[1]).clearPassword();
} catch (IOException ioe) {
LoginException le = new LoginException(ioe.toString());
throw EnvHelp.initCause(le, ioe);
} catch (UnsupportedCallbackException uce) {
LoginException le = new LoginException(
"Error: " + uce.getCallback().toString() +
" not available to garner authentication " +
"information from the user");
throw EnvHelp.initCause(le, uce);
}
}
/**
* Clean out state because of a failed authentication attempt
*/
private void cleanState() {
username = null;
if (password != null) {
Arrays.fill(password, ' ');
password = null;
}
if (clearPass) {
sharedState.remove(USERNAME_KEY);
sharedState.remove(PASSWORD_KEY);
}
}
}

View file

@ -0,0 +1,346 @@
/*
* Copyright (c) 2004, 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.remote.security;
import java.io.IOException;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.management.remote.JMXPrincipal;
import javax.management.remote.JMXAuthenticator;
import javax.security.auth.AuthPermission;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
/**
* <p>This class represents a
* <a href="{@docRoot}/../guide/security/jaas/JAASRefGuide.html">JAAS</a>
* based implementation of the {@link JMXAuthenticator} interface.</p>
*
* <p>Authentication is performed by passing the supplied user's credentials
* to one or more authentication mechanisms ({@link LoginModule}) for
* verification. An authentication mechanism acquires the user's credentials
* by calling {@link NameCallback} and/or {@link PasswordCallback}.
* If authentication is successful then an authenticated {@link Subject}
* filled in with a {@link Principal} is returned. Authorization checks
* will then be performed based on this <code>Subject</code>.</p>
*
* <p>By default, a single file-based authentication mechanism
* {@link FileLoginModule} is configured (<code>FileLoginConfig</code>).</p>
*
* <p>To override the default configuration use the
* <code>com.sun.management.jmxremote.login.config</code> management property
* described in the JRE/conf/management/management.properties file.
* Set this property to the name of a JAAS configuration entry and ensure that
* the entry is loaded by the installed {@link Configuration}. In addition,
* ensure that the authentication mechanisms specified in the entry acquire
* the user's credentials by calling {@link NameCallback} and
* {@link PasswordCallback} and that they return a {@link Subject} filled-in
* with a {@link Principal}, for those users that are successfully
* authenticated.</p>
*/
public final class JMXPluggableAuthenticator implements JMXAuthenticator {
/**
* Creates an instance of <code>JMXPluggableAuthenticator</code>
* and initializes it with a {@link LoginContext}.
*
* @param env the environment containing configuration properties for the
* authenticator. Can be null, which is equivalent to an empty
* Map.
* @exception SecurityException if the authentication mechanism cannot be
* initialized.
*/
public JMXPluggableAuthenticator(Map<?, ?> env) {
String loginConfigName = null;
String passwordFile = null;
if (env != null) {
loginConfigName = (String) env.get(LOGIN_CONFIG_PROP);
passwordFile = (String) env.get(PASSWORD_FILE_PROP);
}
try {
if (loginConfigName != null) {
// use the supplied JAAS login configuration
loginContext =
new LoginContext(loginConfigName, new JMXCallbackHandler());
} else {
// use the default JAAS login configuration (file-based)
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new AuthPermission("createLoginContext." +
LOGIN_CONFIG_NAME));
}
final String pf = passwordFile;
try {
loginContext = AccessController.doPrivileged(
new PrivilegedExceptionAction<LoginContext>() {
public LoginContext run() throws LoginException {
return new LoginContext(
LOGIN_CONFIG_NAME,
null,
new JMXCallbackHandler(),
new FileLoginConfig(pf));
}
});
} catch (PrivilegedActionException pae) {
throw (LoginException) pae.getException();
}
}
} catch (LoginException le) {
authenticationFailure("authenticate", le);
} catch (SecurityException se) {
authenticationFailure("authenticate", se);
}
}
/**
* Authenticate the <code>MBeanServerConnection</code> client
* with the given client credentials.
*
* @param credentials the user-defined credentials to be passed in
* to the server in order to authenticate the user before creating
* the <code>MBeanServerConnection</code>. This parameter must
* be a two-element <code>String[]</code> containing the client's
* username and password in that order.
*
* @return the authenticated subject containing a
* <code>JMXPrincipal(username)</code>.
*
* @exception SecurityException if the server cannot authenticate the user
* with the provided credentials.
*/
public Subject authenticate(Object credentials) {
// Verify that credentials is of type String[].
//
if (!(credentials instanceof String[])) {
// Special case for null so we get a more informative message
if (credentials == null)
authenticationFailure("authenticate", "Credentials required");
final String message =
"Credentials should be String[] instead of " +
credentials.getClass().getName();
authenticationFailure("authenticate", message);
}
// Verify that the array contains two elements.
//
final String[] aCredentials = (String[]) credentials;
if (aCredentials.length != 2) {
final String message =
"Credentials should have 2 elements not " +
aCredentials.length;
authenticationFailure("authenticate", message);
}
// Verify that username exists and the associated
// password matches the one supplied by the client.
//
username = aCredentials[0];
password = aCredentials[1];
if (username == null || password == null) {
final String message = "Username or password is null";
authenticationFailure("authenticate", message);
}
// Perform authentication
try {
loginContext.login();
final Subject subject = loginContext.getSubject();
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
subject.setReadOnly();
return null;
}
});
return subject;
} catch (LoginException le) {
authenticationFailure("authenticate", le);
}
return null;
}
private static void authenticationFailure(String method, String message)
throws SecurityException {
final String msg = "Authentication failed! " + message;
final SecurityException e = new SecurityException(msg);
logException(method, msg, e);
throw e;
}
private static void authenticationFailure(String method,
Exception exception)
throws SecurityException {
String msg;
SecurityException se;
if (exception instanceof SecurityException) {
msg = exception.getMessage();
se = (SecurityException) exception;
} else {
msg = "Authentication failed! " + exception.getMessage();
final SecurityException e = new SecurityException(msg);
EnvHelp.initCause(e, exception);
se = e;
}
logException(method, msg, se);
throw se;
}
private static void logException(String method,
String message,
Exception e) {
if (logger.traceOn()) {
logger.trace(method, message);
}
if (logger.debugOn()) {
logger.debug(method, e);
}
}
private LoginContext loginContext;
private String username;
private String password;
private static final String LOGIN_CONFIG_PROP =
"jmx.remote.x.login.config";
private static final String LOGIN_CONFIG_NAME = "JMXPluggableAuthenticator";
private static final String PASSWORD_FILE_PROP =
"jmx.remote.x.password.file";
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc", LOGIN_CONFIG_NAME);
/**
* This callback handler supplies the username and password (which was
* originally supplied by the JMX user) to the JAAS login module performing
* the authentication. No interactive user prompting is required because the
* credentials are already available to this class (via its enclosing class).
*/
private final class JMXCallbackHandler implements CallbackHandler {
/**
* Sets the username and password in the appropriate Callback object.
*/
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
((NameCallback)callbacks[i]).setName(username);
} else if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback)callbacks[i])
.setPassword(password.toCharArray());
} else {
throw new UnsupportedCallbackException
(callbacks[i], "Unrecognized Callback");
}
}
}
}
/**
* This class defines the JAAS configuration for file-based authentication.
* It is equivalent to the following textual configuration entry:
* <pre>
* JMXPluggableAuthenticator {
* com.sun.jmx.remote.security.FileLoginModule required;
* };
* </pre>
*/
private static class FileLoginConfig extends Configuration {
// The JAAS configuration for file-based authentication
private AppConfigurationEntry[] entries;
// The classname of the login module for file-based authentication
private static final String FILE_LOGIN_MODULE =
FileLoginModule.class.getName();
// The option that identifies the password file to use
private static final String PASSWORD_FILE_OPTION = "passwordFile";
/**
* Creates an instance of <code>FileLoginConfig</code>
*
* @param passwordFile A filepath that identifies the password file to use.
* If null then the default password file is used.
*/
public FileLoginConfig(String passwordFile) {
Map<String, String> options;
if (passwordFile != null) {
options = new HashMap<String, String>(1);
options.put(PASSWORD_FILE_OPTION, passwordFile);
} else {
options = Collections.emptyMap();
}
entries = new AppConfigurationEntry[] {
new AppConfigurationEntry(FILE_LOGIN_MODULE,
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
options)
};
}
/**
* Gets the JAAS configuration for file-based authentication
*/
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
return name.equals(LOGIN_CONFIG_NAME) ? entries : null;
}
/**
* Refreshes the configuration.
*/
public void refresh() {
// the configuration is fixed
}
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2003, 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.remote.security;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.ProtectionDomain;
import javax.security.auth.Subject;
import javax.security.auth.SubjectDomainCombiner;
/**
* <p>This class represents an extension to the {@link SubjectDomainCombiner}
* and is used to add a new {@link ProtectionDomain}, comprised of a null
* codesource/signers and an empty permission set, to the access control
* context with which this combiner is combined.</p>
*
* <p>When the {@link #combine} method is called the {@link ProtectionDomain}
* is augmented with the permissions granted to the set of principals present
* in the supplied {@link Subject}.</p>
*/
public class JMXSubjectDomainCombiner extends SubjectDomainCombiner {
public JMXSubjectDomainCombiner(Subject s) {
super(s);
}
public ProtectionDomain[] combine(ProtectionDomain[] current,
ProtectionDomain[] assigned) {
// Add a new ProtectionDomain with the null codesource/signers, and
// the empty permission set, to the end of the array containing the
// 'current' protections domains, i.e. the ones that will be augmented
// with the permissions granted to the set of principals present in
// the supplied subject.
//
ProtectionDomain[] newCurrent;
if (current == null || current.length == 0) {
newCurrent = new ProtectionDomain[1];
newCurrent[0] = pdNoPerms;
} else {
newCurrent = new ProtectionDomain[current.length + 1];
for (int i = 0; i < current.length; i++) {
newCurrent[i] = current[i];
}
newCurrent[current.length] = pdNoPerms;
}
return super.combine(newCurrent, assigned);
}
/**
* A null CodeSource.
*/
private static final CodeSource nullCodeSource =
new CodeSource(null, (java.security.cert.Certificate[]) null);
/**
* A ProtectionDomain with a null CodeSource and an empty permission set.
*/
private static final ProtectionDomain pdNoPerms =
new ProtectionDomain(nullCodeSource, new Permissions(), null, null);
/**
* Get the current AccessControlContext combined with the supplied subject.
*/
public static AccessControlContext getContext(Subject subject) {
return new AccessControlContext(AccessController.getContext(),
new JMXSubjectDomainCombiner(subject));
}
/**
* Get the AccessControlContext of the domain combiner created with
* the supplied subject, i.e. an AccessControlContext with the domain
* combiner created with the supplied subject and where the caller's
* context has been removed.
*/
public static AccessControlContext
getDomainCombinerContext(Subject subject) {
return new AccessControlContext(
new AccessControlContext(new ProtectionDomain[0]),
new JMXSubjectDomainCombiner(subject));
}
}

View file

@ -0,0 +1,665 @@
/*
* Copyright (c) 2003, 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.remote.security;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import java.io.ObjectInputStream;
import java.security.AccessController;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.InstanceAlreadyExistsException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import javax.management.loading.ClassLoaderRepository;
import javax.management.remote.MBeanServerForwarder;
/**
* <p>An object of this class implements the MBeanServer interface
* and, for each of its methods, calls an appropriate checking method
* and then forwards the request to a wrapped MBeanServer object. The
* checking method may throw a RuntimeException if the operation is
* not allowed; in this case the request is not forwarded to the
* wrapped object.</p>
*
* <p>A typical use of this class is to insert it between a connector server
* such as the RMI connector and the MBeanServer with which the connector
* is associated. Requests from the connector client can then be filtered
* and those operations that are not allowed, or not allowed in a particular
* context, can be rejected by throwing a <code>SecurityException</code>
* in the corresponding <code>check*</code> method.</p>
*
* <p>This is an abstract class, because in its implementation none of
* the checking methods does anything. To be useful, it must be
* subclassed and at least one of the checking methods overridden to
* do some checking. Some or all of the MBeanServer methods may also
* be overridden, for instance if the default checking behavior is
* inappropriate.</p>
*
* <p>If there is no SecurityManager, then the access controller will refuse
* to create an MBean that is a ClassLoader, which includes MLets, or to
* execute the method addURL on an MBean that is an MLet. This prevents
* people from opening security holes unintentionally. Otherwise, it
* would not be obvious that granting write access grants the ability to
* download and execute arbitrary code in the target MBean server. Advanced
* users who do want the ability to use MLets are presumably advanced enough
* to handle policy files and security managers.</p>
*/
public abstract class MBeanServerAccessController
implements MBeanServerForwarder {
public MBeanServer getMBeanServer() {
return mbs;
}
public void setMBeanServer(MBeanServer mbs) {
if (mbs == null)
throw new IllegalArgumentException("Null MBeanServer");
if (this.mbs != null)
throw new IllegalArgumentException("MBeanServer object already " +
"initialized");
this.mbs = mbs;
}
/**
* Check if the caller can do read operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
protected abstract void checkRead();
/**
* Check if the caller can do write operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
protected abstract void checkWrite();
/**
* Check if the caller can create the named class. The default
* implementation of this method calls {@link #checkWrite()}.
*/
protected void checkCreate(String className) {
checkWrite();
}
/**
* Check if the caller can unregister the named MBean. The default
* implementation of this method calls {@link #checkWrite()}.
*/
protected void checkUnregister(ObjectName name) {
checkWrite();
}
//--------------------------------------------
//--------------------------------------------
//
// Implementation of the MBeanServer interface
//
//--------------------------------------------
//--------------------------------------------
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public void addNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException {
checkRead();
getMBeanServer().addNotificationListener(name, listener,
filter, handback);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public void addNotificationListener(ObjectName name,
ObjectName listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException {
checkRead();
getMBeanServer().addNotificationListener(name, listener,
filter, handback);
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className, ObjectName name)
throws
ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException {
checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className);
checkClassLoader(object);
return getMBeanServer().registerMBean(object, name);
} else {
return getMBeanServer().createMBean(className, name);
}
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className, ObjectName name,
Object params[], String signature[])
throws
ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException {
checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className,
params,
signature);
checkClassLoader(object);
return getMBeanServer().registerMBean(object, name);
} else {
return getMBeanServer().createMBean(className, name,
params, signature);
}
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className,
ObjectName name,
ObjectName loaderName)
throws
ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className,
loaderName);
checkClassLoader(object);
return getMBeanServer().registerMBean(object, name);
} else {
return getMBeanServer().createMBean(className, name, loaderName);
}
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className,
ObjectName name,
ObjectName loaderName,
Object params[],
String signature[])
throws
ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className,
loaderName,
params,
signature);
checkClassLoader(object);
return getMBeanServer().registerMBean(object, name);
} else {
return getMBeanServer().createMBean(className, name, loaderName,
params, signature);
}
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
@Deprecated
public ObjectInputStream deserialize(ObjectName name, byte[] data)
throws InstanceNotFoundException, OperationsException {
checkRead();
return getMBeanServer().deserialize(name, data);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
@Deprecated
public ObjectInputStream deserialize(String className, byte[] data)
throws OperationsException, ReflectionException {
checkRead();
return getMBeanServer().deserialize(className, data);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
@Deprecated
public ObjectInputStream deserialize(String className,
ObjectName loaderName,
byte[] data)
throws
InstanceNotFoundException,
OperationsException,
ReflectionException {
checkRead();
return getMBeanServer().deserialize(className, loaderName, data);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public Object getAttribute(ObjectName name, String attribute)
throws
MBeanException,
AttributeNotFoundException,
InstanceNotFoundException,
ReflectionException {
checkRead();
return getMBeanServer().getAttribute(name, attribute);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException {
checkRead();
return getMBeanServer().getAttributes(name, attributes);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public ClassLoader getClassLoader(ObjectName loaderName)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().getClassLoader(loaderName);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().getClassLoaderFor(mbeanName);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public ClassLoaderRepository getClassLoaderRepository() {
checkRead();
return getMBeanServer().getClassLoaderRepository();
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public String getDefaultDomain() {
checkRead();
return getMBeanServer().getDefaultDomain();
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public String[] getDomains() {
checkRead();
return getMBeanServer().getDomains();
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public Integer getMBeanCount() {
checkRead();
return getMBeanServer().getMBeanCount();
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public MBeanInfo getMBeanInfo(ObjectName name)
throws
InstanceNotFoundException,
IntrospectionException,
ReflectionException {
checkRead();
return getMBeanServer().getMBeanInfo(name);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().getObjectInstance(name);
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className)
throws ReflectionException, MBeanException {
checkCreate(className);
return getMBeanServer().instantiate(className);
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className,
Object params[],
String signature[])
throws ReflectionException, MBeanException {
checkCreate(className);
return getMBeanServer().instantiate(className, params, signature);
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className, ObjectName loaderName)
throws ReflectionException, MBeanException, InstanceNotFoundException {
checkCreate(className);
return getMBeanServer().instantiate(className, loaderName);
}
/**
* Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className, ObjectName loaderName,
Object params[], String signature[])
throws ReflectionException, MBeanException, InstanceNotFoundException {
checkCreate(className);
return getMBeanServer().instantiate(className, loaderName,
params, signature);
}
/**
* Call <code>checkWrite()</code>, then forward this method to the
* wrapped object.
*/
public Object invoke(ObjectName name, String operationName,
Object params[], String signature[])
throws
InstanceNotFoundException,
MBeanException,
ReflectionException {
checkWrite();
checkMLetMethods(name, operationName);
return getMBeanServer().invoke(name, operationName, params, signature);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().isInstanceOf(name, className);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public boolean isRegistered(ObjectName name) {
checkRead();
return getMBeanServer().isRegistered(name);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
checkRead();
return getMBeanServer().queryMBeans(name, query);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
checkRead();
return getMBeanServer().queryNames(name, query);
}
/**
* Call <code>checkWrite()</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance registerMBean(Object object, ObjectName name)
throws
InstanceAlreadyExistsException,
MBeanRegistrationException,
NotCompliantMBeanException {
checkWrite();
return getMBeanServer().registerMBean(object, name);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public void removeNotificationListener(ObjectName name,
NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException {
checkRead();
getMBeanServer().removeNotificationListener(name, listener);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public void removeNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException, ListenerNotFoundException {
checkRead();
getMBeanServer().removeNotificationListener(name, listener,
filter, handback);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public void removeNotificationListener(ObjectName name,
ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException {
checkRead();
getMBeanServer().removeNotificationListener(name, listener);
}
/**
* Call <code>checkRead()</code>, then forward this method to the
* wrapped object.
*/
public void removeNotificationListener(ObjectName name,
ObjectName listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException, ListenerNotFoundException {
checkRead();
getMBeanServer().removeNotificationListener(name, listener,
filter, handback);
}
/**
* Call <code>checkWrite()</code>, then forward this method to the
* wrapped object.
*/
public void setAttribute(ObjectName name, Attribute attribute)
throws
InstanceNotFoundException,
AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
checkWrite();
getMBeanServer().setAttribute(name, attribute);
}
/**
* Call <code>checkWrite()</code>, then forward this method to the
* wrapped object.
*/
public AttributeList setAttributes(ObjectName name,
AttributeList attributes)
throws InstanceNotFoundException, ReflectionException {
checkWrite();
return getMBeanServer().setAttributes(name, attributes);
}
/**
* Call <code>checkUnregister()</code>, then forward this method to the
* wrapped object.
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException {
checkUnregister(name);
getMBeanServer().unregisterMBean(name);
}
//----------------
// PRIVATE METHODS
//----------------
private void checkClassLoader(Object object) {
if (object instanceof ClassLoader)
throw new SecurityException("Access denied! Creating an " +
"MBean that is a ClassLoader " +
"is forbidden unless a security " +
"manager is installed.");
}
private void checkMLetMethods(ObjectName name, String operation)
throws InstanceNotFoundException {
// Check if security manager installed
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return;
}
// Check for addURL and getMBeansFromURL methods
if (!operation.equals("addURL") &&
!operation.equals("getMBeansFromURL")) {
return;
}
// Check if MBean is instance of MLet
if (!getMBeanServer().isInstanceOf(name,
"javax.management.loading.MLet")) {
return;
}
// Throw security exception
if (operation.equals("addURL")) { // addURL
throw new SecurityException("Access denied! MLet method addURL " +
"cannot be invoked unless a security manager is installed.");
} else { // getMBeansFromURL
// Whether or not calling getMBeansFromURL is allowed is controlled
// by the value of the "jmx.remote.x.mlet.allow.getMBeansFromURL"
// system property. If the value of this property is true, calling
// the MLet's getMBeansFromURL method is allowed. The default value
// for this property is false.
final String propName = "jmx.remote.x.mlet.allow.getMBeansFromURL";
GetPropertyAction propAction = new GetPropertyAction(propName);
String propValue = AccessController.doPrivileged(propAction);
boolean allowGetMBeansFromURL = "true".equalsIgnoreCase(propValue);
if (!allowGetMBeansFromURL) {
throw new SecurityException("Access denied! MLet method " +
"getMBeansFromURL cannot be invoked unless a " +
"security manager is installed or the system property " +
"-Djmx.remote.x.mlet.allow.getMBeansFromURL=true " +
"is specified.");
}
}
}
//------------------
// PRIVATE VARIABLES
//------------------
private MBeanServer mbs;
}

View file

@ -0,0 +1,544 @@
/*
* Copyright (c) 2003, 2014, 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.remote.security;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.security.auth.Subject;
/**
* <p>An object of this class implements the MBeanServerAccessController
* interface and, for each of its methods, calls an appropriate checking
* method and then forwards the request to a wrapped MBeanServer object.
* The checking method may throw a SecurityException if the operation is
* not allowed; in this case the request is not forwarded to the
* wrapped object.</p>
*
* <p>This class implements the {@link #checkRead()}, {@link #checkWrite()},
* {@link #checkCreate(String)}, and {@link #checkUnregister(ObjectName)}
* methods based on an access level properties file containing username/access
* level pairs. The set of username/access level pairs is passed either as a
* filename which denotes a properties file on disk, or directly as an instance
* of the {@link Properties} class. In both cases, the name of each property
* represents a username, and the value of the property is the associated access
* level. Thus, any given username either does not exist in the properties or
* has exactly one access level. The same access level can be shared by several
* usernames.</p>
*
* <p>The supported access level values are {@code readonly} and
* {@code readwrite}. The {@code readwrite} access level can be
* qualified by one or more <i>clauses</i>, where each clause looks
* like <code>create <i>classNamePattern</i></code> or {@code
* unregister}. For example:</p>
*
* <pre>
* monitorRole readonly
* controlRole readwrite \
* create javax.management.timer.*,javax.management.monitor.* \
* unregister
* </pre>
*
* <p>(The continuation lines with {@code \} come from the parser for
* Properties files.)</p>
*/
public class MBeanServerFileAccessController
extends MBeanServerAccessController {
static final String READONLY = "readonly";
static final String READWRITE = "readwrite";
static final String CREATE = "create";
static final String UNREGISTER = "unregister";
private enum AccessType {READ, WRITE, CREATE, UNREGISTER};
private static class Access {
final boolean write;
final String[] createPatterns;
private boolean unregister;
Access(boolean write, boolean unregister, List<String> createPatternList) {
this.write = write;
int npats = (createPatternList == null) ? 0 : createPatternList.size();
if (npats == 0)
this.createPatterns = NO_STRINGS;
else
this.createPatterns = createPatternList.toArray(new String[npats]);
this.unregister = unregister;
}
private final String[] NO_STRINGS = new String[0];
}
/**
* <p>Create a new MBeanServerAccessController that forwards all the
* MBeanServer requests to the MBeanServer set by invoking the {@link
* #setMBeanServer} method after doing access checks based on read and
* write permissions.</p>
*
* <p>This instance is initialized from the specified properties file.</p>
*
* @param accessFileName name of the file which denotes a properties
* file on disk containing the username/access level entries.
*
* @exception IOException if the file does not exist, is a
* directory rather than a regular file, or for some other
* reason cannot be opened for reading.
*
* @exception IllegalArgumentException if any of the supplied access
* level values differs from "readonly" or "readwrite".
*/
public MBeanServerFileAccessController(String accessFileName)
throws IOException {
super();
this.accessFileName = accessFileName;
Properties props = propertiesFromFile(accessFileName);
parseProperties(props);
}
/**
* <p>Create a new MBeanServerAccessController that forwards all the
* MBeanServer requests to <code>mbs</code> after doing access checks
* based on read and write permissions.</p>
*
* <p>This instance is initialized from the specified properties file.</p>
*
* @param accessFileName name of the file which denotes a properties
* file on disk containing the username/access level entries.
*
* @param mbs the MBeanServer object to which requests will be forwarded.
*
* @exception IOException if the file does not exist, is a
* directory rather than a regular file, or for some other
* reason cannot be opened for reading.
*
* @exception IllegalArgumentException if any of the supplied access
* level values differs from "readonly" or "readwrite".
*/
public MBeanServerFileAccessController(String accessFileName,
MBeanServer mbs)
throws IOException {
this(accessFileName);
setMBeanServer(mbs);
}
/**
* <p>Create a new MBeanServerAccessController that forwards all the
* MBeanServer requests to the MBeanServer set by invoking the {@link
* #setMBeanServer} method after doing access checks based on read and
* write permissions.</p>
*
* <p>This instance is initialized from the specified properties
* instance. This constructor makes a copy of the properties
* instance and it is the copy that is consulted to check the
* username and access level of an incoming connection. The
* original properties object can be modified without affecting
* the copy. If the {@link #refresh} method is then called, the
* <code>MBeanServerFileAccessController</code> will make a new
* copy of the properties object at that time.</p>
*
* @param accessFileProps properties list containing the username/access
* level entries.
*
* @exception IllegalArgumentException if <code>accessFileProps</code> is
* <code>null</code> or if any of the supplied access level values differs
* from "readonly" or "readwrite".
*/
public MBeanServerFileAccessController(Properties accessFileProps)
throws IOException {
super();
if (accessFileProps == null)
throw new IllegalArgumentException("Null properties");
originalProps = accessFileProps;
parseProperties(accessFileProps);
}
/**
* <p>Create a new MBeanServerAccessController that forwards all the
* MBeanServer requests to the MBeanServer set by invoking the {@link
* #setMBeanServer} method after doing access checks based on read and
* write permissions.</p>
*
* <p>This instance is initialized from the specified properties
* instance. This constructor makes a copy of the properties
* instance and it is the copy that is consulted to check the
* username and access level of an incoming connection. The
* original properties object can be modified without affecting
* the copy. If the {@link #refresh} method is then called, the
* <code>MBeanServerFileAccessController</code> will make a new
* copy of the properties object at that time.</p>
*
* @param accessFileProps properties list containing the username/access
* level entries.
*
* @param mbs the MBeanServer object to which requests will be forwarded.
*
* @exception IllegalArgumentException if <code>accessFileProps</code> is
* <code>null</code> or if any of the supplied access level values differs
* from "readonly" or "readwrite".
*/
public MBeanServerFileAccessController(Properties accessFileProps,
MBeanServer mbs)
throws IOException {
this(accessFileProps);
setMBeanServer(mbs);
}
/**
* Check if the caller can do read operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
@Override
public void checkRead() {
checkAccess(AccessType.READ, null);
}
/**
* Check if the caller can do write operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
@Override
public void checkWrite() {
checkAccess(AccessType.WRITE, null);
}
/**
* Check if the caller can create MBeans or instances of the given class.
* This method does nothing if so, otherwise throws SecurityException.
*/
@Override
public void checkCreate(String className) {
checkAccess(AccessType.CREATE, className);
}
/**
* Check if the caller can do unregister operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
@Override
public void checkUnregister(ObjectName name) {
checkAccess(AccessType.UNREGISTER, null);
}
/**
* <p>Refresh the set of username/access level entries.</p>
*
* <p>If this instance was created using the
* {@link #MBeanServerFileAccessController(String)} or
* {@link #MBeanServerFileAccessController(String,MBeanServer)}
* constructors to specify a file from which the entries are read,
* the file is re-read.</p>
*
* <p>If this instance was created using the
* {@link #MBeanServerFileAccessController(Properties)} or
* {@link #MBeanServerFileAccessController(Properties,MBeanServer)}
* constructors then a new copy of the <code>Properties</code> object
* is made.</p>
*
* @exception IOException if the file does not exist, is a
* directory rather than a regular file, or for some other
* reason cannot be opened for reading.
*
* @exception IllegalArgumentException if any of the supplied access
* level values differs from "readonly" or "readwrite".
*/
public synchronized void refresh() throws IOException {
Properties props;
if (accessFileName == null)
props = originalProps;
else
props = propertiesFromFile(accessFileName);
parseProperties(props);
}
private static Properties propertiesFromFile(String fname)
throws IOException {
FileInputStream fin = new FileInputStream(fname);
try {
Properties p = new Properties();
p.load(fin);
return p;
} finally {
fin.close();
}
}
private synchronized void checkAccess(AccessType requiredAccess, String arg) {
final AccessControlContext acc = AccessController.getContext();
final Subject s =
AccessController.doPrivileged(new PrivilegedAction<Subject>() {
public Subject run() {
return Subject.getSubject(acc);
}
});
if (s == null) return; /* security has not been enabled */
final Set<Principal> principals = s.getPrincipals();
String newPropertyValue = null;
for (Iterator<Principal> i = principals.iterator(); i.hasNext(); ) {
final Principal p = i.next();
Access access = accessMap.get(p.getName());
if (access != null) {
boolean ok;
switch (requiredAccess) {
case READ:
ok = true; // all access entries imply read
break;
case WRITE:
ok = access.write;
break;
case UNREGISTER:
ok = access.unregister;
if (!ok && access.write)
newPropertyValue = "unregister";
break;
case CREATE:
ok = checkCreateAccess(access, arg);
if (!ok && access.write)
newPropertyValue = "create " + arg;
break;
default:
throw new AssertionError();
}
if (ok)
return;
}
}
SecurityException se = new SecurityException("Access denied! Invalid " +
"access level for requested MBeanServer operation.");
// Add some more information to help people with deployments that
// worked before we required explicit create clauses. We're not giving
// any information to the bad guys, other than that the access control
// is based on a file, which they could have worked out from the stack
// trace anyway.
if (newPropertyValue != null) {
SecurityException se2 = new SecurityException("Access property " +
"for this identity should be similar to: " + READWRITE +
" " + newPropertyValue);
se.initCause(se2);
}
throw se;
}
private static boolean checkCreateAccess(Access access, String className) {
for (String classNamePattern : access.createPatterns) {
if (classNameMatch(classNamePattern, className))
return true;
}
return false;
}
private static boolean classNameMatch(String pattern, String className) {
// We studiously avoided regexes when parsing the properties file,
// because that is done whenever the VM is started with the
// appropriate -Dcom.sun.management options, even if nobody ever
// creates an MBean. We don't want to incur the overhead of loading
// all the regex code whenever those options are specified, but if we
// get as far as here then the VM is already running and somebody is
// doing the very unusual operation of remotely creating an MBean.
// Because that operation is so unusual, we don't try to optimize
// by hand-matching or by caching compiled Pattern objects.
StringBuilder sb = new StringBuilder();
StringTokenizer stok = new StringTokenizer(pattern, "*", true);
while (stok.hasMoreTokens()) {
String tok = stok.nextToken();
if (tok.equals("*"))
sb.append("[^.]*");
else
sb.append(Pattern.quote(tok));
}
return className.matches(sb.toString());
}
private void parseProperties(Properties props) {
this.accessMap = new HashMap<String, Access>();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String identity = (String) entry.getKey();
String accessString = (String) entry.getValue();
Access access = Parser.parseAccess(identity, accessString);
accessMap.put(identity, access);
}
}
private static class Parser {
private final static int EOS = -1; // pseudo-codepoint "end of string"
static {
assert !Character.isWhitespace(EOS);
}
private final String identity; // just for better error messages
private final String s; // the string we're parsing
private final int len; // s.length()
private int i;
private int c;
// At any point, either c is s.codePointAt(i), or i == len and
// c is EOS. We use int rather than char because it is conceivable
// (if unlikely) that a classname in a create clause might contain
// "supplementary characters", the ones that don't fit in the original
// 16 bits for Unicode.
private Parser(String identity, String s) {
this.identity = identity;
this.s = s;
this.len = s.length();
this.i = 0;
if (i < len)
this.c = s.codePointAt(i);
else
this.c = EOS;
}
static Access parseAccess(String identity, String s) {
return new Parser(identity, s).parseAccess();
}
private Access parseAccess() {
skipSpace();
String type = parseWord();
Access access;
if (type.equals(READONLY))
access = new Access(false, false, null);
else if (type.equals(READWRITE))
access = parseReadWrite();
else {
throw syntax("Expected " + READONLY + " or " + READWRITE +
": " + type);
}
if (c != EOS)
throw syntax("Extra text at end of line");
return access;
}
private Access parseReadWrite() {
List<String> createClasses = new ArrayList<String>();
boolean unregister = false;
while (true) {
skipSpace();
if (c == EOS)
break;
String type = parseWord();
if (type.equals(UNREGISTER))
unregister = true;
else if (type.equals(CREATE))
parseCreate(createClasses);
else
throw syntax("Unrecognized keyword " + type);
}
return new Access(true, unregister, createClasses);
}
private void parseCreate(List<String> createClasses) {
while (true) {
skipSpace();
createClasses.add(parseClassName());
skipSpace();
if (c == ',')
next();
else
break;
}
}
private String parseClassName() {
// We don't check that classname components begin with suitable
// characters (so we accept 1.2.3 for example). This means that
// there are only two states, which we can call dotOK and !dotOK
// according as a dot (.) is legal or not. Initially we're in
// !dotOK since a classname can't start with a dot; after a dot
// we're in !dotOK again; and after any other characters we're in
// dotOK. The classname is only accepted if we end in dotOK,
// so we reject an empty name or a name that ends with a dot.
final int start = i;
boolean dotOK = false;
while (true) {
if (c == '.') {
if (!dotOK)
throw syntax("Bad . in class name");
dotOK = false;
} else if (c == '*' || Character.isJavaIdentifierPart(c))
dotOK = true;
else
break;
next();
}
String className = s.substring(start, i);
if (!dotOK)
throw syntax("Bad class name " + className);
return className;
}
// Advance c and i to the next character, unless already at EOS.
private void next() {
if (c != EOS) {
i += Character.charCount(c);
if (i < len)
c = s.codePointAt(i);
else
c = EOS;
}
}
private void skipSpace() {
while (Character.isWhitespace(c))
next();
}
private String parseWord() {
skipSpace();
if (c == EOS)
throw syntax("Expected word at end of line");
final int start = i;
while (c != EOS && !Character.isWhitespace(c))
next();
String word = s.substring(start, i);
skipSpace();
return word;
}
private IllegalArgumentException syntax(String msg) {
return new IllegalArgumentException(
msg + " [" + identity + " " + s + "]");
}
}
private Map<String, Access> accessMap;
private Properties originalProps;
private String accessFileName;
}

View file

@ -0,0 +1,110 @@
/*
* 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.remote.security;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.security.auth.Subject;
/**
* <p>This interface allows to control remote access to the
* {@code addNotificationListener} and {@code removeNotificationListener}
* methods when the notification listener parameter is of type
* {@code NotificationListener} and also allows to control remote access
* to the notifications being forwarded to the interested remote listeners.</p>
*
* <p>An implementation of this interface can be supplied to a
* {@code JMXConnectorServer} in the environment map through the
* {@code com.sun.jmx.remote.notification.access.controller}
* environment map property.</p>
*
* @since 1.6
*/
public interface NotificationAccessController {
/**
* This method is called when a remote
* {@link javax.management.remote.JMXConnector} invokes the method
* {@link javax.management.MBeanServerConnection#addNotificationListener(ObjectName,NotificationListener,NotificationFilter,Object)}.
*
* @param connectionId the {@code connectionId} of the remote client
* adding the listener.
* @param name the name of the MBean where the listener is to be added.
* @param subject the authenticated subject representing the remote client.
*
* @throws SecurityException if the remote client with the supplied
* authenticated subject does not have the rights to add a listener
* to the supplied MBean.
*/
public void addNotificationListener(String connectionId,
ObjectName name,
Subject subject)
throws SecurityException;
/**
* This method is called when a remote
* {@link javax.management.remote.JMXConnector} invokes the method
* {@link javax.management.MBeanServerConnection#removeNotificationListener(ObjectName,NotificationListener)}
* or the method
* {@link javax.management.MBeanServerConnection#removeNotificationListener(ObjectName,NotificationListener,NotificationFilter,Object)}.
*
* @param connectionId the {@code connectionId} of the remote client
* removing the listener.
* @param name the name of the MBean where the listener is to be removed.
* @param subject the authenticated subject representing the remote client.
*
* @throws SecurityException if the remote client with the supplied
* authenticated subject does not have the rights to remove a listener
* from the supplied MBean.
*/
public void removeNotificationListener(String connectionId,
ObjectName name,
Subject subject)
throws SecurityException;
/**
* This method is called before the
* {@link javax.management.remote.JMXConnectorServer}
* forwards the notification to the interested remote
* listener represented by the authenticated subject.
*
* @param connectionId the {@code connectionId} of the remote client
* receiving the notification.
* @param name the name of the MBean forwarding the notification.
* @param notification the notification to be forwarded to the interested
* remote listener.
* @param subject the authenticated subject representing the remote client.
*
* @throws SecurityException if the remote client with
* the supplied authenticated subject does not have the
* rights to receive the notification.
*/
public void fetchNotification(String connectionId,
ObjectName name,
Notification notification,
Subject subject)
throws SecurityException;
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2003, 2014, 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.remote.security;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.Permission;
import java.security.Principal;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.management.remote.SubjectDelegationPermission;
import java.util.*;
public class SubjectDelegator {
/* Return the AccessControlContext appropriate to execute an
operation on behalf of the delegatedSubject. If the
authenticatedAccessControlContext does not have permission to
delegate to that subject, throw SecurityException. */
public AccessControlContext
delegatedContext(AccessControlContext authenticatedACC,
Subject delegatedSubject,
boolean removeCallerContext)
throws SecurityException {
if (System.getSecurityManager() != null && authenticatedACC == null) {
throw new SecurityException("Illegal AccessControlContext: null");
}
// Check if the subject delegation permission allows the
// authenticated subject to assume the identity of each
// principal in the delegated subject
//
Collection<Principal> ps = getSubjectPrincipals(delegatedSubject);
final Collection<Permission> permissions = new ArrayList<>(ps.size());
for(Principal p : ps) {
final String pname = p.getClass().getName() + "." + p.getName();
permissions.add(new SubjectDelegationPermission(pname));
}
PrivilegedAction<Void> action =
new PrivilegedAction<Void>() {
public Void run() {
for (Permission sdp : permissions) {
AccessController.checkPermission(sdp);
}
return null;
}
};
AccessController.doPrivileged(action, authenticatedACC);
return getDelegatedAcc(delegatedSubject, removeCallerContext);
}
private AccessControlContext getDelegatedAcc(Subject delegatedSubject, boolean removeCallerContext) {
if (removeCallerContext) {
return JMXSubjectDomainCombiner.getDomainCombinerContext(delegatedSubject);
} else {
return JMXSubjectDomainCombiner.getContext(delegatedSubject);
}
}
/**
* Check if the connector server creator can assume the identity of each
* principal in the authenticated subject, i.e. check if the connector
* server creator codebase contains a subject delegation permission for
* each principal present in the authenticated subject.
*
* @return {@code true} if the connector server creator can delegate to all
* the authenticated principals in the subject. Otherwise, {@code false}.
*/
public static synchronized boolean
checkRemoveCallerContext(Subject subject) {
try {
for (Principal p : getSubjectPrincipals(subject)) {
final String pname =
p.getClass().getName() + "." + p.getName();
final Permission sdp =
new SubjectDelegationPermission(pname);
AccessController.checkPermission(sdp);
}
} catch (SecurityException e) {
return false;
}
return true;
}
/**
* Retrieves the {@linkplain Subject} principals
* @param subject The subject
* @return If the {@code Subject} is immutable it will return the principals directly.
* If the {@code Subject} is mutable it will create an unmodifiable copy.
*/
private static Collection<Principal> getSubjectPrincipals(Subject subject) {
if (subject.isReadOnly()) {
return subject.getPrincipals();
}
List<Principal> principals = Arrays.asList(subject.getPrincipals().toArray(new Principal[0]));
return Collections.unmodifiableList(principals);
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2003, 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.remote.util;
import javax.management.loading.ClassLoaderRepository;
public class ClassLoaderWithRepository extends ClassLoader {
public ClassLoaderWithRepository(ClassLoaderRepository clr,
ClassLoader cl2) {
if (clr == null) throw new
IllegalArgumentException("Null ClassLoaderRepository object.");
repository = clr;
this.cl2 = cl2;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> cls;
try {
cls = repository.loadClass(name);
} catch (ClassNotFoundException cne) {
if (cl2 != null) {
return cl2.loadClass(name);
} else {
throw cne;
}
}
if(!cls.getName().equals(name)){
if (cl2 != null) {
return cl2.loadClass(name);
} else {
throw new ClassNotFoundException(name);
}
}
return cls;
}
private ClassLoaderRepository repository;
private ClassLoader cl2;
}

View file

@ -0,0 +1,212 @@
/*
* Copyright (c) 2003, 2017, 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.remote.util;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ResourceBundle;
public class ClassLogger implements System.Logger {
private final String className;
private final Logger logger;
public ClassLogger(String subsystem, String className) {
logger = System.getLogger(subsystem);
this.className = className;
}
public final boolean traceOn() {
return logger.isLoggable(Level.TRACE);
}
public final boolean debugOn() {
return logger.isLoggable(Level.DEBUG);
}
public final boolean warningOn() {
return logger.isLoggable(Level.WARNING);
}
public final boolean infoOn() {
return logger.isLoggable(Level.INFO);
}
public final boolean configOn() {
return logger.isLoggable(Level.DEBUG);
}
public final boolean fineOn() {
return logger.isLoggable(Level.DEBUG);
}
public final boolean finerOn() {
return logger.isLoggable(Level.TRACE);
}
public final boolean finestOn() {
return logger.isLoggable(Level.TRACE);
}
public final void debug(String func, String msg) {
logger.log(Level.DEBUG, msg);
}
public final void debug(String func, Throwable t) {
logger.log(Level.DEBUG, className + "::" + func, t);
}
public final void debug(String func, String msg, Throwable t) {
logger.log(Level.DEBUG, msg, t);
}
public final void trace(String func, String msg) {
logger.log(Level.TRACE, msg);
}
public final void trace(String func, Throwable t) {
logger.log(Level.TRACE, className + "::" + func, t);
}
public final void trace(String func, String msg, Throwable t) {
logger.log(Level.TRACE, msg, t);
}
public final void error(String func, String msg) {
logger.log(Level.ERROR, msg);
}
public final void error(String func, Throwable t) {
logger.log(Level.ERROR, className + "::" + func, t);
}
public final void error(String func, String msg, Throwable t) {
logger.log(Level.ERROR, msg, t);
}
public final void finest(String func, String msg) {
logger.log(Level.TRACE, msg);
}
public final void finest(String func, Throwable t) {
logger.log(Level.TRACE, className + "::" + func, t);
}
public final void finest(String func, String msg, Throwable t) {
logger.log(Level.TRACE, msg, t);
}
public final void finer(String func, String msg) {
logger.log(Level.TRACE, msg);
}
public final void finer(String func, Throwable t) {
logger.log(Level.TRACE, className + "::" + func, t);
}
public final void finer(String func, String msg, Throwable t) {
logger.log(Level.DEBUG, msg, t);
}
public final void fine(String func, String msg) {
logger.log(Level.DEBUG, msg);
}
public final void fine(String func, Throwable t) {
logger.log(Level.DEBUG, className + "::" + func, t);
}
public final void fine(String func, String msg, Throwable t) {
logger.log(Level.DEBUG, msg, t);
}
public final void config(String func, String msg) {
logger.log(Level.DEBUG, msg);
}
public final void config(String func, Throwable t) {
logger.log(Level.DEBUG, className + "::" + func, t);
}
public final void config(String func, String msg, Throwable t) {
logger.log(Level.DEBUG, msg, t);
}
public final void info(String func, String msg) {
logger.log(Level.INFO, msg);
}
public final void info(String func, Throwable t) {
logger.log(Level.INFO, className + "::" + func, t);
}
public final void info(String func, String msg, Throwable t) {
logger.log(Level.INFO, msg, t);
}
public final void warning(String func, String msg) {
logger.log(Level.WARNING, msg);
}
public final void warning(String func, Throwable t) {
logger.log(Level.WARNING, className + "::" + func, t);
}
public final void warning(String func, String msg, Throwable t) {
logger.log(Level.WARNING, msg, t);
}
public final void severe(String func, String msg) {
logger.log(Level.ERROR, msg);
}
public final void severe(String func, Throwable t) {
logger.log(Level.ERROR, className + "::" + func, t);
}
public final void severe(String func, String msg, Throwable t) {
logger.log(Level.ERROR, msg, t);
}
public final String getName() {
return logger.getName();
}
public final boolean isLoggable(Level level) {
return logger.isLoggable(level);
}
public final void log(Level level, ResourceBundle bundle, String msg,
Throwable thrown) {
logger.log(level, bundle, msg, thrown);
}
public final void log(Level level, ResourceBundle bundle, String format,
Object... params) {
logger.log(level, bundle, format, params);
}
}

View file

@ -0,0 +1,767 @@
/*
* Copyright (c) 2003, 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.remote.util;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.security.AccessController;
import javax.management.ObjectName;
import javax.management.MBeanServer;
import javax.management.InstanceNotFoundException;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServerFactory;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.remote.security.NotificationAccessController;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorServer;
public class EnvHelp {
/**
* Name of the attribute that specifies a default class loader
* object.
* The value associated with this attribute is a ClassLoader object.
*/
private static final String DEFAULT_CLASS_LOADER =
JMXConnectorFactory.DEFAULT_CLASS_LOADER;
/**
* Name of the attribute that specifies a default class loader
* ObjectName.
* The value associated with this attribute is an ObjectName object.
*/
private static final String DEFAULT_CLASS_LOADER_NAME =
JMXConnectorServerFactory.DEFAULT_CLASS_LOADER_NAME;
/**
* Get the Connector Server default class loader.
* <p>
* Returns:
* <ul>
* <li>
* The ClassLoader object found in <var>env</var> for
* <code>jmx.remote.default.class.loader</code>, if any.
* </li>
* <li>
* The ClassLoader pointed to by the ObjectName found in
* <var>env</var> for <code>jmx.remote.default.class.loader.name</code>,
* and registered in <var>mbs</var> if any.
* </li>
* <li>
* The current thread's context classloader otherwise.
* </li>
* </ul>
*
* @param env Environment attributes.
* @param mbs The MBeanServer for which the connector server provides
* remote access.
*
* @return the connector server's default class loader.
*
* @exception IllegalArgumentException if one of the following is true:
* <ul>
* <li>both
* <code>jmx.remote.default.class.loader</code> and
* <code>jmx.remote.default.class.loader.name</code> are specified,
* </li>
* <li>or
* <code>jmx.remote.default.class.loader</code> is not
* an instance of {@link ClassLoader},
* </li>
* <li>or
* <code>jmx.remote.default.class.loader.name</code> is not
* an instance of {@link ObjectName},
* </li>
* <li>or
* <code>jmx.remote.default.class.loader.name</code> is specified
* but <var>mbs</var> is null.
* </li>
* </ul>
* @exception InstanceNotFoundException if
* <code>jmx.remote.default.class.loader.name</code> is specified
* and the ClassLoader MBean is not found in <var>mbs</var>.
*/
public static ClassLoader resolveServerClassLoader(Map<String, ?> env,
MBeanServer mbs)
throws InstanceNotFoundException {
if (env == null)
return Thread.currentThread().getContextClassLoader();
Object loader = env.get(DEFAULT_CLASS_LOADER);
Object name = env.get(DEFAULT_CLASS_LOADER_NAME);
if (loader != null && name != null) {
final String msg = "Only one of " +
DEFAULT_CLASS_LOADER + " or " +
DEFAULT_CLASS_LOADER_NAME +
" should be specified.";
throw new IllegalArgumentException(msg);
}
if (loader == null && name == null)
return Thread.currentThread().getContextClassLoader();
if (loader != null) {
if (loader instanceof ClassLoader) {
return (ClassLoader) loader;
} else {
final String msg =
"ClassLoader object is not an instance of " +
ClassLoader.class.getName() + " : " +
loader.getClass().getName();
throw new IllegalArgumentException(msg);
}
}
ObjectName on;
if (name instanceof ObjectName) {
on = (ObjectName) name;
} else {
final String msg =
"ClassLoader name is not an instance of " +
ObjectName.class.getName() + " : " +
name.getClass().getName();
throw new IllegalArgumentException(msg);
}
if (mbs == null)
throw new IllegalArgumentException("Null MBeanServer object");
return mbs.getClassLoader(on);
}
/**
* Get the Connector Client default class loader.
* <p>
* Returns:
* <ul>
* <li>
* The ClassLoader object found in <var>env</var> for
* <code>jmx.remote.default.class.loader</code>, if any.
* </li>
* <li>The {@code Thread.currentThread().getContextClassLoader()}
* otherwise.
* </li>
* </ul>
* <p>
* Usually a Connector Client will call
* <pre>
* ClassLoader dcl = EnvHelp.resolveClientClassLoader(env);
* </pre>
* in its <code>connect(Map env)</code> method.
*
* @return The connector client default class loader.
*
* @exception IllegalArgumentException if
* <code>jmx.remote.default.class.loader</code> is specified
* and is not an instance of {@link ClassLoader}.
*/
public static ClassLoader resolveClientClassLoader(Map<String, ?> env) {
if (env == null)
return Thread.currentThread().getContextClassLoader();
Object loader = env.get(DEFAULT_CLASS_LOADER);
if (loader == null)
return Thread.currentThread().getContextClassLoader();
if (loader instanceof ClassLoader) {
return (ClassLoader) loader;
} else {
final String msg =
"ClassLoader object is not an instance of " +
ClassLoader.class.getName() + " : " +
loader.getClass().getName();
throw new IllegalArgumentException(msg);
}
}
/**
* Initialize the cause field of a {@code Throwable} object.
*
* @param throwable The {@code Throwable} on which the cause is set.
* @param cause The cause to set on the supplied {@code Throwable}.
* @return the {@code Throwable} with the cause field initialized.
*/
public static <T extends Throwable> T initCause(T throwable,
Throwable cause) {
throwable.initCause(cause);
return throwable;
}
/**
* Returns the cause field of a {@code Throwable} object.
* The cause field can be got only if <var>t</var> has an
* {@link Throwable#getCause()} method (JDK Version {@literal >=} 1.4)
* @param t {@code Throwable} on which the cause must be set.
* @return the cause if getCause() succeeded and the got value is not
* null, otherwise return the <var>t</var>.
*/
public static Throwable getCause(Throwable t) {
Throwable ret = t;
try {
java.lang.reflect.Method getCause =
t.getClass().getMethod("getCause", (Class<?>[]) null);
ret = (Throwable)getCause.invoke(t, (Object[]) null);
} catch (Exception e) {
// OK.
// it must be older than 1.4.
}
return (ret != null) ? ret: t;
}
/**
* Name of the attribute that specifies the size of a notification
* buffer for a connector server. The default value is 1000.
*/
public static final String BUFFER_SIZE_PROPERTY =
"jmx.remote.x.notification.buffer.size";
/**
* Returns the size of a notification buffer for a connector server.
* The default value is 1000.
*/
public static int getNotifBufferSize(Map<String, ?> env) {
int defaultQueueSize = 1000; // default value
// keep it for the compability for the fix:
// 6174229: Environment parameter should be notification.buffer.size
// instead of buffer.size
final String oldP = "jmx.remote.x.buffer.size";
// the default value re-specified in the system
try {
GetPropertyAction act = new GetPropertyAction(BUFFER_SIZE_PROPERTY);
String s = AccessController.doPrivileged(act);
if (s != null) {
defaultQueueSize = Integer.parseInt(s);
} else { // try the old one
act = new GetPropertyAction(oldP);
s = AccessController.doPrivileged(act);
if (s != null) {
defaultQueueSize = Integer.parseInt(s);
}
}
} catch (RuntimeException e) {
logger.warning("getNotifBufferSize",
"Can't use System property "+
BUFFER_SIZE_PROPERTY+ ": " + e);
logger.debug("getNotifBufferSize", e);
}
int queueSize = defaultQueueSize;
try {
if (env.containsKey(BUFFER_SIZE_PROPERTY)) {
queueSize = (int)EnvHelp.getIntegerAttribute(env,BUFFER_SIZE_PROPERTY,
defaultQueueSize,0,
Integer.MAX_VALUE);
} else { // try the old one
queueSize = (int)EnvHelp.getIntegerAttribute(env,oldP,
defaultQueueSize,0,
Integer.MAX_VALUE);
}
} catch (RuntimeException e) {
logger.warning("getNotifBufferSize",
"Can't determine queuesize (using default): "+
e);
logger.debug("getNotifBufferSize", e);
}
return queueSize;
}
/**
* Name of the attribute that specifies the maximum number of
* notifications that a client will fetch from its server. The
* value associated with this attribute should be an
* {@code Integer} object. The default value is 1000.
*/
public static final String MAX_FETCH_NOTIFS =
"jmx.remote.x.notification.fetch.max";
/**
* Returns the maximum notification number which a client will
* fetch every time.
*/
public static int getMaxFetchNotifNumber(Map<String, ?> env) {
return (int) getIntegerAttribute(env, MAX_FETCH_NOTIFS, 1000, 1,
Integer.MAX_VALUE);
}
/**
* Name of the attribute that specifies the timeout for a
* client to fetch notifications from its server. The value
* associated with this attribute should be a <code>Long</code>
* object. The default value is 60000 milliseconds.
*/
public static final String FETCH_TIMEOUT =
"jmx.remote.x.notification.fetch.timeout";
/**
* Returns the timeout for a client to fetch notifications.
*/
public static long getFetchTimeout(Map<String, ?> env) {
return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
Long.MAX_VALUE);
}
/**
* Name of the attribute that specifies an object that will check
* accesses to add/removeNotificationListener and also attempts to
* receive notifications. The value associated with this attribute
* should be a <code>NotificationAccessController</code> object.
* The default value is null.
* <p>
* This field is not public because of its com.sun dependency.
*/
public static final String NOTIF_ACCESS_CONTROLLER =
"com.sun.jmx.remote.notification.access.controller";
public static NotificationAccessController getNotificationAccessController(
Map<String, ?> env) {
return (env == null) ? null :
(NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
}
/**
* Get an integer-valued attribute with name <code>name</code>
* from <code>env</code>. If <code>env</code> is null, or does
* not contain an entry for <code>name</code>, return
* <code>defaultValue</code>. The value may be a Number, or it
* may be a String that is parsable as a long. It must be at
* least <code>minValue</code> and at most<code>maxValue</code>.
*
* @throws IllegalArgumentException if <code>env</code> contains
* an entry for <code>name</code> but it does not meet the
* constraints above.
*/
public static long getIntegerAttribute(Map<String, ?> env, String name,
long defaultValue, long minValue,
long maxValue) {
final Object o;
if (env == null || (o = env.get(name)) == null)
return defaultValue;
final long result;
if (o instanceof Number)
result = ((Number) o).longValue();
else if (o instanceof String) {
result = Long.parseLong((String) o);
/* May throw a NumberFormatException, which is an
IllegalArgumentException. */
} else {
final String msg =
"Attribute " + name + " value must be Integer or String: " + o;
throw new IllegalArgumentException(msg);
}
if (result < minValue) {
final String msg =
"Attribute " + name + " value must be at least " + minValue +
": " + result;
throw new IllegalArgumentException(msg);
}
if (result > maxValue) {
final String msg =
"Attribute " + name + " value must be at most " + maxValue +
": " + result;
throw new IllegalArgumentException(msg);
}
return result;
}
public static final String DEFAULT_ORB="java.naming.corba.orb";
/* Check that all attributes have a key that is a String.
Could make further checks, e.g. appropriate types for attributes. */
public static void checkAttributes(Map<?, ?> attributes) {
for (Object key : attributes.keySet()) {
if (!(key instanceof String)) {
final String msg =
"Attributes contain key that is not a string: " + key;
throw new IllegalArgumentException(msg);
}
}
}
/* Return a writable map containing only those attributes that are
serializable, and that are not hidden by
jmx.remote.x.hidden.attributes or the default list of hidden
attributes. */
public static <V> Map<String, V> filterAttributes(Map<String, V> attributes) {
if (logger.traceOn()) {
logger.trace("filterAttributes", "starts");
}
SortedMap<String, V> map = new TreeMap<String, V>(attributes);
purgeUnserializable(map.values());
hideAttributes(map);
return map;
}
/**
* Remove from the given Collection any element that is not a
* serializable object.
*/
private static void purgeUnserializable(Collection<?> objects) {
logger.trace("purgeUnserializable", "starts");
ObjectOutputStream oos = null;
int i = 0;
for (Iterator<?> it = objects.iterator(); it.hasNext(); i++) {
Object v = it.next();
if (v == null || v instanceof String) {
if (logger.traceOn()) {
logger.trace("purgeUnserializable",
"Value trivially serializable: " + v);
}
continue;
}
try {
if (oos == null)
oos = new ObjectOutputStream(new SinkOutputStream());
oos.writeObject(v);
if (logger.traceOn()) {
logger.trace("purgeUnserializable",
"Value serializable: " + v);
}
} catch (IOException e) {
if (logger.traceOn()) {
logger.trace("purgeUnserializable",
"Value not serializable: " + v + ": " +
e);
}
it.remove();
oos = null; // ObjectOutputStream invalid after exception
}
}
}
/**
* The value of this attribute, if present, is a string specifying
* what other attributes should not appear in
* JMXConnectorServer.getAttributes(). It is a space-separated
* list of attribute patterns, where each pattern is either an
* attribute name, or an attribute prefix followed by a "*"
* character. The "*" has no special significance anywhere except
* at the end of a pattern. By default, this list is added to the
* list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which
* uses the same format). If the value of this attribute begins
* with an "=", then the remainder of the string defines the
* complete list of attribute patterns.
*/
public static final String HIDDEN_ATTRIBUTES =
"jmx.remote.x.hidden.attributes";
/**
* Default list of attributes not to show.
* @see #HIDDEN_ATTRIBUTES
*/
/* This list is copied directly from the spec, plus
java.naming.security.*. Most of the attributes here would have
been eliminated from the map anyway because they are typically
not serializable. But just in case they are, we list them here
to conform to the spec. */
public static final String DEFAULT_HIDDEN_ATTRIBUTES =
"java.naming.security.* " +
"jmx.remote.authenticator " +
"jmx.remote.context " +
"jmx.remote.default.class.loader " +
"jmx.remote.message.connection.server " +
"jmx.remote.object.wrapping " +
"jmx.remote.rmi.client.socket.factory " +
"jmx.remote.rmi.server.socket.factory " +
"jmx.remote.sasl.callback.handler " +
"jmx.remote.tls.socket.factory " +
"jmx.remote.x.access.file " +
"jmx.remote.x.password.file ";
private static final SortedSet<String> defaultHiddenStrings =
new TreeSet<String>();
private static final SortedSet<String> defaultHiddenPrefixes =
new TreeSet<String>();
private static void hideAttributes(SortedMap<String, ?> map) {
if (map.isEmpty())
return;
final SortedSet<String> hiddenStrings;
final SortedSet<String> hiddenPrefixes;
String hide = (String) map.get(HIDDEN_ATTRIBUTES);
if (hide != null) {
if (hide.startsWith("="))
hide = hide.substring(1);
else
hide += " " + DEFAULT_HIDDEN_ATTRIBUTES;
hiddenStrings = new TreeSet<String>();
hiddenPrefixes = new TreeSet<String>();
parseHiddenAttributes(hide, hiddenStrings, hiddenPrefixes);
} else {
hide = DEFAULT_HIDDEN_ATTRIBUTES;
synchronized (defaultHiddenStrings) {
if (defaultHiddenStrings.isEmpty()) {
parseHiddenAttributes(hide,
defaultHiddenStrings,
defaultHiddenPrefixes);
}
hiddenStrings = defaultHiddenStrings;
hiddenPrefixes = defaultHiddenPrefixes;
}
}
/* Construct a string that is greater than any key in the map.
Setting a string-to-match or a prefix-to-match to this string
guarantees that we will never call next() on the corresponding
iterator. */
String sentinelKey = map.lastKey() + "X";
Iterator<String> keyIterator = map.keySet().iterator();
Iterator<String> stringIterator = hiddenStrings.iterator();
Iterator<String> prefixIterator = hiddenPrefixes.iterator();
String nextString;
if (stringIterator.hasNext())
nextString = stringIterator.next();
else
nextString = sentinelKey;
String nextPrefix;
if (prefixIterator.hasNext())
nextPrefix = prefixIterator.next();
else
nextPrefix = sentinelKey;
/* Read each key in sorted order and, if it matches a string
or prefix, remove it. */
keys:
while (keyIterator.hasNext()) {
String key = keyIterator.next();
/* Continue through string-match values until we find one
that is either greater than the current key, or equal
to it. In the latter case, remove the key. */
int cmp = +1;
while ((cmp = nextString.compareTo(key)) < 0) {
if (stringIterator.hasNext())
nextString = stringIterator.next();
else
nextString = sentinelKey;
}
if (cmp == 0) {
keyIterator.remove();
continue keys;
}
/* Continue through the prefix values until we find one
that is either greater than the current key, or a
prefix of it. In the latter case, remove the key. */
while (nextPrefix.compareTo(key) <= 0) {
if (key.startsWith(nextPrefix)) {
keyIterator.remove();
continue keys;
}
if (prefixIterator.hasNext())
nextPrefix = prefixIterator.next();
else
nextPrefix = sentinelKey;
}
}
}
private static void parseHiddenAttributes(String hide,
SortedSet<String> hiddenStrings,
SortedSet<String> hiddenPrefixes) {
final StringTokenizer tok = new StringTokenizer(hide);
while (tok.hasMoreTokens()) {
String s = tok.nextToken();
if (s.endsWith("*"))
hiddenPrefixes.add(s.substring(0, s.length() - 1));
else
hiddenStrings.add(s);
}
}
/**
* Name of the attribute that specifies the timeout to keep a
* server side connection after answering last client request.
* The default value is 120000 milliseconds.
*/
public static final String SERVER_CONNECTION_TIMEOUT =
"jmx.remote.x.server.connection.timeout";
/**
* Returns the server side connection timeout.
*/
public static long getServerConnectionTimeout(Map<String, ?> env) {
return getIntegerAttribute(env, SERVER_CONNECTION_TIMEOUT, 120000L,
0, Long.MAX_VALUE);
}
/**
* Name of the attribute that specifies the period in
* millisecond for a client to check its connection. The default
* value is 60000 milliseconds.
*/
public static final String CLIENT_CONNECTION_CHECK_PERIOD =
"jmx.remote.x.client.connection.check.period";
/**
* Returns the client connection check period.
*/
public static long getConnectionCheckPeriod(Map<String, ?> env) {
return getIntegerAttribute(env, CLIENT_CONNECTION_CHECK_PERIOD, 60000L,
0, Long.MAX_VALUE);
}
/**
* Computes a boolean value from a string value retrieved from a
* property in the given map.
*
* @param stringBoolean the string value that must be converted
* into a boolean value.
*
* @return
* <ul>
* <li>{@code false} if {@code stringBoolean} is {@code null}</li>
* <li>{@code false} if
* {@code stringBoolean.equalsIgnoreCase("false")}
* is {@code true}</li>
* <li>{@code true} if
* {@code stringBoolean.equalsIgnoreCase("true")}
* is {@code true}</li>
* </ul>
*
* @throws IllegalArgumentException if
* {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and
* {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are
* {@code false}.
*/
public static boolean computeBooleanFromString(String stringBoolean) {
// returns a default value of 'false' if no property is found...
return computeBooleanFromString(stringBoolean,false);
}
/**
* Computes a boolean value from a string value retrieved from a
* property in the given map.
*
* @param stringBoolean the string value that must be converted
* into a boolean value.
* @param defaultValue a default value to return in case no property
* was defined.
*
* @return
* <ul>
* <li>{@code defaultValue} if {@code stringBoolean}
* is {@code null}</li>
* <li>{@code false} if
* {@code stringBoolean.equalsIgnoreCase("false")}
* is {@code true}</li>
* <li>{@code true} if
* {@code stringBoolean.equalsIgnoreCase("true")}
* is {@code true}</li>
* </ul>
*
* @throws IllegalArgumentException if
* {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and
* {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are
* {@code false}.
*/
public static boolean computeBooleanFromString( String stringBoolean, boolean defaultValue) {
if (stringBoolean == null)
return defaultValue;
else if (stringBoolean.equalsIgnoreCase("true"))
return true;
else if (stringBoolean.equalsIgnoreCase("false"))
return false;
else
throw new IllegalArgumentException(
"Property value must be \"true\" or \"false\" instead of \"" +
stringBoolean + "\"");
}
/**
* Converts a map into a valid hash table, i.e.
* it removes all the 'null' values from the map.
*/
public static <K, V> Hashtable<K, V> mapToHashtable(Map<K, V> map) {
HashMap<K, V> m = new HashMap<K, V>(map);
if (m.containsKey(null)) m.remove(null);
for (Iterator<?> i = m.values().iterator(); i.hasNext(); )
if (i.next() == null) i.remove();
return new Hashtable<K, V>(m);
}
/**
* Name of the attribute that specifies whether a connector server
* should not prevent the VM from exiting
*/
public static final String JMX_SERVER_DAEMON = "jmx.remote.x.daemon";
/**
* Returns true if {@value JMX_SERVER_DAEMON} is specified in the {@code env}
* as a key and its value is a String and it is equal to true ignoring case.
*
* @param env
* @return
*/
public static boolean isServerDaemon(Map<String, ?> env) {
return (env != null) &&
("true".equalsIgnoreCase((String)env.get(JMX_SERVER_DAEMON)));
}
private static final class SinkOutputStream extends OutputStream {
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
}
private static final ClassLogger logger =
new ClassLogger("javax.management.remote.misc", "EnvHelp");
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2003, 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.remote.util;
import sun.reflect.misc.ReflectUtil;
public class OrderClassLoaders extends ClassLoader {
public OrderClassLoaders(ClassLoader cl1, ClassLoader cl2) {
super(cl1);
this.cl2 = cl2;
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
ReflectUtil.checkPackageAccess(name);
try {
return super.loadClass(name, resolve);
} catch (ClassNotFoundException cne) {
if (cl2 != null) {
return cl2.loadClass(name);
} else {
throw cne;
}
}
}
private ClassLoader cl2;
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2007, 2011, 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 java.lang.management;
/**
* The management interface for a buffer pool, for example a pool of
* {@link java.nio.ByteBuffer#allocateDirect direct} or {@link
* java.nio.MappedByteBuffer mapped} buffers.
*
* <p> A class implementing this interface is an
* {@link javax.management.MXBean}. A Java
* virtual machine has one or more implementations of this interface. The {@link
* java.lang.management.ManagementFactory#getPlatformMXBeans getPlatformMXBeans}
* method can be used to obtain the list of {@code BufferPoolMXBean} objects
* representing the management interfaces for pools of buffers as follows:
* <pre>
* List&lt;BufferPoolMXBean&gt; pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
* </pre>
*
* <p> The management interfaces are also registered with the platform {@link
* javax.management.MBeanServer MBeanServer}. The {@link
* javax.management.ObjectName ObjectName} that uniquely identifies the
* management interface within the {@code MBeanServer} takes the form:
* <pre>
* java.nio:type=BufferPool,name=<i>pool name</i>
* </pre>
* where <em>pool name</em> is the {@link #getName name} of the buffer pool.
*
* @since 1.7
*/
public interface BufferPoolMXBean extends PlatformManagedObject {
/**
* Returns the name representing this buffer pool.
*
* @return The name of this buffer pool.
*/
String getName();
/**
* Returns an estimate of the number of buffers in the pool.
*
* @return An estimate of the number of buffers in this pool
*/
long getCount();
/**
* Returns an estimate of the total capacity of the buffers in this pool.
* A buffer's capacity is the number of elements it contains and the value
* returned by this method is an estimate of the total capacity of buffers
* in the pool in bytes.
*
* @return An estimate of the total capacity of the buffers in this pool
* in bytes
*/
long getTotalCapacity();
/**
* Returns an estimate of the memory that the Java virtual machine is using
* for this buffer pool. The value returned by this method may differ
* from the estimate of the total {@link #getTotalCapacity capacity} of
* the buffers in this pool. This difference is explained by alignment,
* memory allocator, and other implementation specific reasons.
*
* @return An estimate of the memory that the Java virtual machine is using
* for this buffer pool in bytes, or {@code -1L} if an estimate of
* the memory usage is not available
*/
long getMemoryUsed();
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
/**
* The management interface for the class loading system of
* the Java virtual machine.
*
* <p> A Java virtual machine has a single instance of the implementation
* class of this interface. This instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getClassLoadingMXBean} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer}.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* the class loading system within an {@code MBeanServer} is:
* <blockquote>
* {@link ManagementFactory#CLASS_LOADING_MXBEAN_NAME
* java.lang:type=ClassLoading}
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface ClassLoadingMXBean extends PlatformManagedObject {
/**
* Returns the total number of classes that have been loaded since
* the Java virtual machine has started execution.
*
* @return the total number of classes loaded.
*
*/
public long getTotalLoadedClassCount();
/**
* Returns the number of classes that are currently loaded in the
* Java virtual machine.
*
* @return the number of currently loaded classes.
*/
public int getLoadedClassCount();
/**
* Returns the total number of classes unloaded since the Java virtual machine
* has started execution.
*
* @return the total number of unloaded classes.
*/
public long getUnloadedClassCount();
/**
* Tests if the verbose output for the class loading system is enabled.
*
* @return {@code true} if the verbose output for the class loading
* system is enabled; {@code false} otherwise.
*/
public boolean isVerbose();
/**
* Enables or disables the verbose output for the class loading
* system. The verbose output information and the output stream
* to which the verbose information is emitted are implementation
* dependent. Typically, a Java virtual machine implementation
* prints a message each time a class file is loaded.
*
* <p>This method can be called by multiple threads concurrently.
* Each invocation of this method enables or disables the verbose
* output globally.
*
* @param value {@code true} to enable the verbose output;
* {@code false} to disable.
*
* @exception java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*/
public void setVerbose(boolean value);
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
/**
* The management interface for the compilation system of
* the Java virtual machine.
*
* <p> A Java virtual machine has a single instance of the implementation
* class of this interface. This instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getCompilationMXBean} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* the compilation system within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#COMPILATION_MXBEAN_NAME
* java.lang:type=Compilation}
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface CompilationMXBean extends PlatformManagedObject {
/**
* Returns the name of the Just-in-time (JIT) compiler.
*
* @return the name of the JIT compiler.
*/
public java.lang.String getName();
/**
* Tests if the Java virtual machine supports the monitoring of
* compilation time.
*
* @return {@code true} if the monitoring of compilation time is
* supported; {@code false} otherwise.
*/
public boolean isCompilationTimeMonitoringSupported();
/**
* Returns the approximate accumulated elapsed time (in milliseconds)
* spent in compilation.
* If multiple threads are used for compilation, this value is
* summation of the approximate time that each thread spent in compilation.
*
* <p>This method is optionally supported by the platform.
* A Java virtual machine implementation may not support the compilation
* time monitoring. The {@link #isCompilationTimeMonitoringSupported}
* method can be used to determine if the Java virtual machine
* supports this operation.
*
* <p> This value does not indicate the level of performance of
* the Java virtual machine and is not intended for performance comparisons
* of different virtual machine implementations.
* The implementations may have different definitions and different
* measurements of the compilation time.
*
* @return Compilation time in milliseconds
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support
* this operation.
*
*/
public long getTotalCompilationTime();
}

View file

@ -0,0 +1,470 @@
/*
* Copyright (c) 2015, 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 java.lang.management;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.management.ObjectName;
import sun.management.ManagementFactoryHelper;
import sun.management.spi.PlatformMBeanProvider;
class DefaultPlatformMBeanProvider extends PlatformMBeanProvider {
private final List<PlatformComponent<?>> mxbeanList;
DefaultPlatformMBeanProvider() {
mxbeanList = Collections.unmodifiableList(init());
}
@Override
public List<PlatformComponent<?>> getPlatformComponentList() {
return mxbeanList;
}
private List<PlatformComponent<?>> init() {
ArrayList<PlatformComponent<?>> initMBeanList = new ArrayList<>();
/**
* Class loading system of the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<ClassLoadingMXBean>() {
private final Set<String> classLoadingInterfaceNames =
Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.ClassLoadingMXBean"));
@Override
public Set<Class<? extends ClassLoadingMXBean>> mbeanInterfaces() {
return Collections.singleton(ClassLoadingMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return classLoadingInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.CLASS_LOADING_MXBEAN_NAME;
}
@Override
public Map<String, ClassLoadingMXBean> nameToMBeanMap() {
return Collections.singletonMap(
ManagementFactory.CLASS_LOADING_MXBEAN_NAME,
ManagementFactoryHelper.getClassLoadingMXBean());
}
});
/**
* Compilation system of the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<CompilationMXBean>() {
private final Set<String> compilationMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.CompilationMXBean"));
@Override
public Set<Class<? extends CompilationMXBean>> mbeanInterfaces() {
return Collections.singleton(CompilationMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return compilationMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.COMPILATION_MXBEAN_NAME;
}
@Override
public Map<String, CompilationMXBean> nameToMBeanMap() {
CompilationMXBean m = ManagementFactoryHelper.getCompilationMXBean();
if (m == null) {
return Collections.emptyMap();
} else {
return Collections.singletonMap(
ManagementFactory.COMPILATION_MXBEAN_NAME,
ManagementFactoryHelper.getCompilationMXBean());
}
}
});
/**
* Memory system of the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<MemoryMXBean>() {
private final Set<String> memoryMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.MemoryMXBean"));
@Override
public Set<Class<? extends MemoryMXBean>> mbeanInterfaces() {
return Collections.singleton(MemoryMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return memoryMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.MEMORY_MXBEAN_NAME;
}
@Override
public Map<String, MemoryMXBean> nameToMBeanMap() {
return Collections.singletonMap(
ManagementFactory.MEMORY_MXBEAN_NAME,
ManagementFactoryHelper.getMemoryMXBean());
}
});
/**
* Garbage Collector in the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<MemoryManagerMXBean>() {
private final Set<String> garbageCollectorMXBeanInterfaceNames
= Collections.unmodifiableSet(
Stream.of("java.lang.management.MemoryManagerMXBean",
"java.lang.management.GarbageCollectorMXBean")
.collect(Collectors.toSet()));
@Override
public Set<Class<? extends MemoryManagerMXBean>> mbeanInterfaces() {
return Stream.of(MemoryManagerMXBean.class,
GarbageCollectorMXBean.class).collect(Collectors.toSet());
}
@Override
public Set<String> mbeanInterfaceNames() {
return garbageCollectorMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",name=*";
}
@Override
public boolean isSingleton() {
return false; // zero or more instances
}
@Override
public Map<String, MemoryManagerMXBean> nameToMBeanMap() {
List<GarbageCollectorMXBean> list
= ManagementFactoryHelper.getGarbageCollectorMXBeans();
Map<String, MemoryManagerMXBean> map;
if (list.isEmpty()) {
map = Collections.emptyMap();
} else {
map = new HashMap<>(list.size());
for (MemoryManagerMXBean gcm : list) {
map.put(gcm.getObjectName().getCanonicalName(),
gcm);
}
}
return map;
}
});
/**
* Memory manager in the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<MemoryManagerMXBean>() {
private final Set<String> memoryManagerMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.MemoryManagerMXBean"));
@Override
public Set<Class<? extends MemoryManagerMXBean>> mbeanInterfaces() {
return Collections.singleton(MemoryManagerMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return memoryManagerMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE + ",name=*";
}
@Override
public boolean isSingleton() {
return false; // zero or more instances
}
@Override
public Map<String, MemoryManagerMXBean> nameToMBeanMap() {
List<MemoryManagerMXBean> list
= ManagementFactoryHelper.getMemoryManagerMXBeans();
return list.stream()
.filter(this::isMemoryManager)
.collect(Collectors.toMap(
pmo -> pmo.getObjectName().getCanonicalName(), Function.identity()));
}
// ManagementFactoryHelper.getMemoryManagerMXBeans() returns all
// memory managers - we need to filter out those that do not match
// the pattern for which we are registered
private boolean isMemoryManager(MemoryManagerMXBean mbean) {
final ObjectName name = mbean.getObjectName();
return ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE.startsWith(name.getDomain())
&& ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE.contains(
"type="+name.getKeyProperty("type"));
}
});
/**
* Memory pool in the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<MemoryPoolMXBean>() {
private final Set<String> memoryPoolMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.MemoryPoolMXBean"));
@Override
public Set<Class<? extends MemoryPoolMXBean>> mbeanInterfaces() {
return Collections.singleton(MemoryPoolMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return memoryPoolMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",name=*";
}
@Override
public boolean isSingleton() {
return false; // zero or more instances
}
@Override
public Map<String, MemoryPoolMXBean> nameToMBeanMap() {
List<MemoryPoolMXBean> list
= ManagementFactoryHelper.getMemoryPoolMXBeans();
Map<String, MemoryPoolMXBean> map;
if (list.isEmpty()) {
map = Collections.<String, MemoryPoolMXBean>emptyMap();
} else {
map = new HashMap<>(list.size());
for (MemoryPoolMXBean mpm : list) {
map.put(mpm.getObjectName().getCanonicalName(),
mpm);
}
}
return map;
}
});
/**
* Runtime system of the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<RuntimeMXBean>() {
private final Set<String> runtimeMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.RuntimeMXBean"));
@Override
public Set<Class<? extends RuntimeMXBean>> mbeanInterfaces() {
return Collections.singleton(RuntimeMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return runtimeMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.RUNTIME_MXBEAN_NAME;
}
@Override
public Map<String, RuntimeMXBean> nameToMBeanMap() {
return Collections.singletonMap(
ManagementFactory.RUNTIME_MXBEAN_NAME,
ManagementFactoryHelper.getRuntimeMXBean());
}
});
/**
* Threading system of the Java virtual machine.
*/
initMBeanList.add(new PlatformComponent<ThreadMXBean>() {
private final Set<String> threadMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.ThreadMXBean"));
@Override
public Set<Class<? extends ThreadMXBean>> mbeanInterfaces() {
return Collections.singleton(ThreadMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return threadMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.THREAD_MXBEAN_NAME;
}
@Override
public Map<String, ThreadMXBean> nameToMBeanMap() {
return Collections.singletonMap(
ManagementFactory.THREAD_MXBEAN_NAME,
ManagementFactoryHelper.getThreadMXBean());
}
});
if (ManagementFactoryHelper.isPlatformLoggingMXBeanAvailable()) {
/**
* Logging facility.
*/
initMBeanList.add(new PlatformComponent<PlatformLoggingMXBean>() {
private final Set<String> platformLoggingMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.PlatformLoggingMXBean"));
@Override
public Set<Class<? extends PlatformLoggingMXBean>> mbeanInterfaces() {
return Collections.singleton(PlatformLoggingMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return platformLoggingMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return "java.util.logging:type=Logging";
}
@Override
public Map<String, PlatformLoggingMXBean> nameToMBeanMap() {
return Collections.singletonMap(
"java.util.logging:type=Logging",
ManagementFactoryHelper.getPlatformLoggingMXBean());
}
});
}
/**
* Buffer pools.
*/
initMBeanList.add(new PlatformComponent<BufferPoolMXBean>() {
private final Set<String> bufferPoolMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.BufferPoolMXBean"));
@Override
public Set<Class<? extends BufferPoolMXBean>> mbeanInterfaces() {
return Collections.singleton(BufferPoolMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return bufferPoolMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return "java.nio:type=BufferPool,name=*";
}
@Override
public boolean isSingleton() {
return false; // zero or more instances
}
@Override
public Map<String, BufferPoolMXBean> nameToMBeanMap() {
List<BufferPoolMXBean> list
= ManagementFactoryHelper.getBufferPoolMXBeans();
Map<String, BufferPoolMXBean> map;
if (list.isEmpty()) {
map = Collections.<String, BufferPoolMXBean>emptyMap();
} else {
map = new HashMap<>(list.size());
list.stream()
.forEach(mbean -> map.put(mbean.getObjectName().getCanonicalName(),mbean));
}
return map;
}
});
/**
* OperatingSystemMXBean
*/
initMBeanList.add(new PlatformComponent<OperatingSystemMXBean>() {
private final Set<String> operatingSystemMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.OperatingSystemMXBean"));
@Override
public Set<Class<? extends OperatingSystemMXBean>> mbeanInterfaces() {
return Collections.singleton(OperatingSystemMXBean.class);
}
@Override
public Set<String> mbeanInterfaceNames() {
return operatingSystemMXBeanInterfaceNames;
}
@Override
public String getObjectNamePattern() {
return ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME;
}
@Override
public Map<String, OperatingSystemMXBean> nameToMBeanMap() {
return Collections.singletonMap(
ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME,
ManagementFactoryHelper.getOperatingSystemMXBean());
}
});
initMBeanList.trimToSize();
return initMBeanList;
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
/**
* The management interface for the garbage collection of
* the Java virtual machine. Garbage collection is the process
* that the Java virtual machine uses to find and reclaim unreachable
* objects to free up memory space. A garbage collector is one type of
* {@link MemoryManagerMXBean memory manager}.
*
* <p> A Java virtual machine may have one or more instances of
* the implementation class of this interface.
* An instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getGarbageCollectorMXBeans} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* a garbage collector within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE
* java.lang:type=GarbageCollector}{@code ,name=}<i>collector's name</i>
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* A platform usually includes additional platform-dependent information
* specific to a garbage collection algorithm for monitoring.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see MemoryMXBean
*
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface GarbageCollectorMXBean extends MemoryManagerMXBean {
/**
* Returns the total number of collections that have occurred.
* This method returns {@code -1} if the collection count is undefined for
* this collector.
*
* @return the total number of collections that have occurred.
*/
public long getCollectionCount();
/**
* Returns the approximate accumulated collection elapsed time
* in milliseconds. This method returns {@code -1} if the collection
* elapsed time is undefined for this collector.
* <p>
* The Java virtual machine implementation may use a high resolution
* timer to measure the elapsed time. This method may return the
* same value even if the collection count has been incremented
* if the collection elapsed time is very short.
*
* @return the approximate accumulated collection elapsed time
* in milliseconds.
*/
public long getCollectionTime();
}

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2005, 2017, 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 java.lang.management;
import javax.management.openmbean.CompositeData;
import java.util.concurrent.locks.*;
import sun.management.LockInfoCompositeData;
/**
* Information about a <em>lock</em>. A lock can be a built-in object monitor,
* an <em>ownable synchronizer</em>, or the {@link Condition Condition}
* object associated with synchronizers.
* <p>
* <a id="OwnableSynchronizer">An ownable synchronizer</a> is
* a synchronizer that may be exclusively owned by a thread and uses
* {@link AbstractOwnableSynchronizer AbstractOwnableSynchronizer}
* (or its subclass) to implement its synchronization property.
* {@link ReentrantLock ReentrantLock} and the write-lock (but not
* the read-lock) of {@link ReentrantReadWriteLock ReentrantReadWriteLock} are
* two examples of ownable synchronizers provided by the platform.
*
* <h3><a id="MappedType">MXBean Mapping</a></h3>
* {@code LockInfo} is mapped to a {@link CompositeData CompositeData}
* as specified in the {@link #from from} method.
*
* @see java.util.concurrent.locks.AbstractOwnableSynchronizer
* @see java.util.concurrent.locks.Condition
*
* @author Mandy Chung
* @since 1.6
*/
public class LockInfo {
private String className;
private int identityHashCode;
/**
* Constructs a {@code LockInfo} object.
*
* @param className the fully qualified name of the class of the lock object.
* @param identityHashCode the {@link System#identityHashCode
* identity hash code} of the lock object.
*/
public LockInfo(String className, int identityHashCode) {
if (className == null) {
throw new NullPointerException("Parameter className cannot be null");
}
this.className = className;
this.identityHashCode = identityHashCode;
}
/**
* package-private constructors
*/
LockInfo(Object lock) {
this.className = lock.getClass().getName();
this.identityHashCode = System.identityHashCode(lock);
}
/**
* Returns the fully qualified name of the class of the lock object.
*
* @return the fully qualified name of the class of the lock object.
*/
public String getClassName() {
return className;
}
/**
* Returns the identity hash code of the lock object
* returned from the {@link System#identityHashCode} method.
*
* @return the identity hash code of the lock object.
*/
public int getIdentityHashCode() {
return identityHashCode;
}
/**
* Returns a {@code LockInfo} object represented by the
* given {@code CompositeData}.
* The given {@code CompositeData} must contain the following attributes:
* <table class="striped" style="margin-left:2em;">
* <caption style="display:none">The attributes and the types the given CompositeData contains</caption>
* <thead style="text-align:left">
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">className</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">identityHashCode</th>
* <td>{@code java.lang.Integer}</td>
* </tr>
* </tbody>
* </table>
*
* @param cd {@code CompositeData} representing a {@code LockInfo}
*
* @throws IllegalArgumentException if {@code cd} does not
* represent a {@code LockInfo} with the attributes described
* above.
* @return a {@code LockInfo} object represented
* by {@code cd} if {@code cd} is not {@code null};
* {@code null} otherwise.
*
* @since 1.8
*/
public static LockInfo from(CompositeData cd) {
if (cd == null) {
return null;
}
if (cd instanceof LockInfoCompositeData) {
return ((LockInfoCompositeData) cd).getLockInfo();
} else {
return LockInfoCompositeData.toLockInfo(cd);
}
}
/**
* Returns a string representation of a lock. The returned
* string representation consists of the name of the class of the
* lock object, the at-sign character `@', and the unsigned
* hexadecimal representation of the <em>identity</em> hash code
* of the object. This method returns a string equals to the value of:
* <blockquote>
* <pre>
* lock.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(lock))
* </pre></blockquote>
* where {@code lock} is the lock object.
*
* @return the string representation of a lock.
*/
public String toString() {
return className + '@' + Integer.toHexString(identityHashCode);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2003, 2017, 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 java.lang.management;
/**
* The permission which the SecurityManager will check when code
* that is running with a SecurityManager calls methods defined
* in the management interface for the Java platform.
* <P>
* The following table
* provides a summary description of what the permission allows,
* and discusses the risks of granting code the permission.
*
* <table class="striped">
* <caption style="display:none">Table shows permission target name, what the permission allows, and associated risks</caption>
* <thead>
* <tr>
* <th scope="col">Permission Target Name</th>
* <th scope="col">What the Permission Allows</th>
* <th scope="col">Risks of Allowing this Permission</th>
* </tr>
* </thead>
* <tbody style="text=align:left">
*
* <tr>
* <th scope="row">control</th>
* <td>Ability to control the runtime characteristics of the Java virtual
* machine, for example, enabling and disabling the verbose output for
* the class loading or memory system, setting the threshold of a memory
* pool, and enabling and disabling the thread contention monitoring
* support. Some actions controlled by this permission can disclose
* information about the running application, like the -verbose:class
* flag.
* </td>
* <td>This allows an attacker to control the runtime characteristics
* of the Java virtual machine and cause the system to misbehave. An
* attacker can also access some information related to the running
* application.
* </td>
* </tr>
* <tr>
* <th scope="row">monitor</th>
* <td>Ability to retrieve runtime information about
* the Java virtual machine such as thread
* stack trace, a list of all loaded class names, and input arguments
* to the Java virtual machine.</td>
* <td>This allows malicious code to monitor runtime information and
* uncover vulnerabilities.</td>
* </tr>
*
* </tbody>
* </table>
*
* <p>
* Programmers do not normally create ManagementPermission objects directly.
* Instead they are created by the security policy code based on reading
* the security policy file.
*
* @author Mandy Chung
* @since 1.5
*
* @see java.security.BasicPermission
* @see java.security.Permission
* @see java.security.Permissions
* @see java.security.PermissionCollection
* @see java.lang.SecurityManager
*
*/
public final class ManagementPermission extends java.security.BasicPermission {
private static final long serialVersionUID = 1897496590799378737L;
/**
* Constructs a ManagementPermission with the specified name.
*
* @param name Permission name. Must be either "monitor" or "control".
*
* @throws NullPointerException if <code>name</code> is <code>null</code>.
* @throws IllegalArgumentException if <code>name</code> is empty or invalid.
*/
public ManagementPermission(String name) {
super(name);
if (!name.equals("control") && !name.equals("monitor")) {
throw new IllegalArgumentException("name: " + name);
}
}
/**
* Constructs a new ManagementPermission object.
*
* @param name Permission name. Must be either "monitor" or "control".
* @param actions Must be either null or the empty string.
*
* @throws NullPointerException if <code>name</code> is <code>null</code>.
* @throws IllegalArgumentException if <code>name</code> is empty or
* if arguments are invalid.
*/
public ManagementPermission(String name, String actions)
throws IllegalArgumentException {
super(name);
if (!name.equals("control") && !name.equals("monitor")) {
throw new IllegalArgumentException("name: " + name);
}
if (actions != null && actions.length() > 0) {
throw new IllegalArgumentException("actions: " + actions);
}
}
}

View file

@ -0,0 +1,304 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
import javax.management.openmbean.CompositeData;
/**
* The management interface for the memory system of
* the Java virtual machine.
*
* <p> A Java virtual machine has a single instance of the implementation
* class of this interface. This instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getMemoryMXBean} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* the memory system within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#MEMORY_MXBEAN_NAME
* java.lang:type=Memory}
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* <h3> Memory </h3>
* The memory system of the Java virtual machine manages
* the following kinds of memory:
*
* <h3> 1. Heap </h3>
* The Java virtual machine has a <i>heap</i> that is the runtime
* data area from which memory for all class instances and arrays
* are allocated. It is created at the Java virtual machine start-up.
* Heap memory for objects is reclaimed by an automatic memory management
* system which is known as a <i>garbage collector</i>.
*
* <p>The heap may be of a fixed size or may be expanded and shrunk.
* The memory for the heap does not need to be contiguous.
*
* <h3> 2. Non-Heap Memory</h3>
* The Java virtual machine manages memory other than the heap
* (referred as <i>non-heap memory</i>).
*
* <p> The Java virtual machine has a <i>method area</i> that is shared
* among all threads.
* The method area belongs to non-heap memory. It stores per-class structures
* such as a runtime constant pool, field and method data, and the code for
* methods and constructors. It is created at the Java virtual machine
* start-up.
*
* <p> The method area is logically part of the heap but a Java virtual
* machine implementation may choose not to either garbage collect
* or compact it. Similar to the heap, the method area may be of a
* fixed size or may be expanded and shrunk. The memory for the
* method area does not need to be contiguous.
*
* <p>In addition to the method area, a Java virtual machine
* implementation may require memory for internal processing or
* optimization which also belongs to non-heap memory.
* For example, the JIT compiler requires memory for storing the native
* machine code translated from the Java virtual machine code for
* high performance.
*
* <h3>Memory Pools and Memory Managers</h3>
* {@link MemoryPoolMXBean Memory pools} and
* {@link MemoryManagerMXBean memory managers} are the abstract entities
* that monitor and manage the memory system
* of the Java virtual machine.
*
* <p>A memory pool represents a memory area that the Java virtual machine
* manages. The Java virtual machine has at least one memory pool
* and it may create or remove memory pools during execution.
* A memory pool can belong to either the heap or the non-heap memory.
*
* <p>A memory manager is responsible for managing one or more memory pools.
* The garbage collector is one type of memory manager responsible
* for reclaiming memory occupied by unreachable objects. A Java virtual
* machine may have one or more memory managers. It may
* add or remove memory managers during execution.
* A memory pool can be managed by more than one memory manager.
*
* <h3>Memory Usage Monitoring</h3>
*
* Memory usage is a very important monitoring attribute for the memory system.
* The memory usage, for example, could indicate:
* <ul>
* <li>the memory usage of an application,</li>
* <li>the workload being imposed on the automatic memory management system,</li>
* <li>potential memory leakage.</li>
* </ul>
*
* <p>
* The memory usage can be monitored in three ways:
* <ul>
* <li>Polling</li>
* <li>Usage Threshold Notification</li>
* <li>Collection Usage Threshold Notification</li>
* </ul>
*
* Details are specified in the {@link MemoryPoolMXBean} interface.
*
* <p>The memory usage monitoring mechanism is intended for load-balancing
* or workload distribution use. For example, an application would stop
* receiving any new workload when its memory usage exceeds a
* certain threshold. It is not intended for an application to detect
* and recover from a low memory condition.
*
* <h3>Notifications</h3>
*
* <p>This {@code MemoryMXBean} is a
* {@link javax.management.NotificationEmitter NotificationEmitter}
* that emits two types of memory {@link javax.management.Notification
* notifications} if any one of the memory pools
* supports a <a href="MemoryPoolMXBean.html#UsageThreshold">usage threshold</a>
* or a <a href="MemoryPoolMXBean.html#CollectionThreshold">collection usage
* threshold</a> which can be determined by calling the
* {@link MemoryPoolMXBean#isUsageThresholdSupported} and
* {@link MemoryPoolMXBean#isCollectionUsageThresholdSupported} methods.
* <ul>
* <li>{@link MemoryNotificationInfo#MEMORY_THRESHOLD_EXCEEDED
* usage threshold exceeded notification} - for notifying that
* the memory usage of a memory pool is increased and has reached
* or exceeded its
* <a href="MemoryPoolMXBean.html#UsageThreshold"> usage threshold</a> value.
* </li>
* <li>{@link MemoryNotificationInfo#MEMORY_COLLECTION_THRESHOLD_EXCEEDED
* collection usage threshold exceeded notification} - for notifying that
* the memory usage of a memory pool is greater than or equal to its
* <a href="MemoryPoolMXBean.html#CollectionThreshold">
* collection usage threshold</a> after the Java virtual machine
* has expended effort in recycling unused objects in that
* memory pool.</li>
* </ul>
*
* <p>
* The notification emitted is a {@link javax.management.Notification}
* instance whose {@link javax.management.Notification#setUserData
* user data} is set to a {@link CompositeData CompositeData}
* that represents a {@link MemoryNotificationInfo} object
* containing information about the memory pool when the notification
* was constructed. The {@code CompositeData} contains the attributes
* as described in {@link MemoryNotificationInfo#from
* MemoryNotificationInfo}.
*
* <hr>
* <h3>NotificationEmitter</h3>
* The {@code MemoryMXBean} object returned by
* {@link ManagementFactory#getMemoryMXBean} implements
* the {@link javax.management.NotificationEmitter NotificationEmitter}
* interface that allows a listener to be registered within the
* {@code MemoryMXBean} as a notification listener.
*
* Below is an example code that registers a {@code MyListener} to handle
* notification emitted by the {@code MemoryMXBean}.
*
* <blockquote><pre>
* class MyListener implements javax.management.NotificationListener {
* public void handleNotification(Notification notif, Object handback) {
* // handle notification
* ....
* }
* }
*
* MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
* NotificationEmitter emitter = (NotificationEmitter) mbean;
* MyListener listener = new MyListener();
* emitter.addNotificationListener(listener, null, null);
* </pre></blockquote>
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface MemoryMXBean extends PlatformManagedObject {
/**
* Returns the approximate number of objects for which
* finalization is pending.
*
* @return the approximate number objects for which finalization
* is pending.
*/
public int getObjectPendingFinalizationCount();
/**
* Returns the current memory usage of the heap that
* is used for object allocation. The heap consists
* of one or more memory pools. The {@code used}
* and {@code committed} size of the returned memory
* usage is the sum of those values of all heap memory pools
* whereas the {@code init} and {@code max} size of the
* returned memory usage represents the setting of the heap
* memory which may not be the sum of those of all heap
* memory pools.
* <p>
* The amount of used memory in the returned memory usage
* is the amount of memory occupied by both live objects
* and garbage objects that have not been collected, if any.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code MemoryUsage} is
* {@code CompositeData} with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} object representing
* the heap memory usage.
*/
public MemoryUsage getHeapMemoryUsage();
/**
* Returns the current memory usage of non-heap memory that
* is used by the Java virtual machine.
* The non-heap memory consists of one or more memory pools.
* The {@code used} and {@code committed} size of the
* returned memory usage is the sum of those values of
* all non-heap memory pools whereas the {@code init}
* and {@code max} size of the returned memory usage
* represents the setting of the non-heap
* memory which may not be the sum of those of all non-heap
* memory pools.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code MemoryUsage} is
* {@code CompositeData} with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} object representing
* the non-heap memory usage.
*/
public MemoryUsage getNonHeapMemoryUsage();
/**
* Tests if verbose output for the memory system is enabled.
*
* @return {@code true} if verbose output for the memory
* system is enabled; {@code false} otherwise.
*/
public boolean isVerbose();
/**
* Enables or disables verbose output for the memory
* system. The verbose output information and the output stream
* to which the verbose information is emitted are implementation
* dependent. Typically, a Java virtual machine implementation
* prints a message whenever it frees memory at garbage collection.
*
* <p>
* Each invocation of this method enables or disables verbose
* output globally.
*
* @param value {@code true} to enable verbose output;
* {@code false} to disable.
*
* @exception java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*/
public void setVerbose(boolean value);
/**
* Runs the garbage collector.
* The call <code>gc()</code> is effectively equivalent to the
* call:
* <blockquote><pre>
* System.gc()
* </pre></blockquote>
*
* @see java.lang.System#gc()
*/
public void gc();
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
/**
* The management interface for a memory manager.
* A memory manager manages one or more memory pools of the
* Java virtual machine.
*
* <p> A Java virtual machine has one or more memory managers.
* An instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getMemoryManagerMXBeans} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* a memory manager within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE
* java.lang:type=MemoryManager}{@code ,name=}<i>manager's name</i>
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see MemoryMXBean
*
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface MemoryManagerMXBean extends PlatformManagedObject {
/**
* Returns the name representing this memory manager.
*
* @return the name of this memory manager.
*/
public String getName();
/**
* Tests if this memory manager is valid in the Java virtual
* machine. A memory manager becomes invalid once the Java virtual
* machine removes it from the memory system.
*
* @return {@code true} if the memory manager is valid in the
* Java virtual machine;
* {@code false} otherwise.
*/
public boolean isValid();
/**
* Returns the name of memory pools that this memory manager manages.
*
* @return an array of {@code String} objects, each is
* the name of a memory pool that this memory manager manages.
*/
public String[] getMemoryPoolNames();
}

View file

@ -0,0 +1,259 @@
/*
* Copyright (c) 2003, 2017, 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 java.lang.management;
import javax.management.openmbean.CompositeData;
import sun.management.MemoryNotifInfoCompositeData;
/**
* The information about a memory notification.
*
* <p>
* A memory notification is emitted by {@link MemoryMXBean}
* when the Java virtual machine detects that the memory usage
* of a memory pool is exceeding a threshold value.
* The notification emitted will contain the memory notification
* information about the detected condition:
* <ul>
* <li>The name of the memory pool.</li>
* <li>The memory usage of the memory pool when the notification
* was constructed.</li>
* <li>The number of times that the memory usage has crossed
* a threshold when the notification was constructed.
* For usage threshold notifications, this count will be the
* {@link MemoryPoolMXBean#getUsageThresholdCount usage threshold
* count}. For collection threshold notifications,
* this count will be the
* {@link MemoryPoolMXBean#getCollectionUsageThresholdCount
* collection usage threshold count}.
* </li>
* </ul>
*
* <p>
* A {@link CompositeData CompositeData} representing
* the {@code MemoryNotificationInfo} object
* is stored in the
* {@link javax.management.Notification#setUserData user data}
* of a {@link javax.management.Notification notification}.
* The {@link #from from} method is provided to convert from
* a {@code CompositeData} to a {@code MemoryNotificationInfo}
* object. For example:
*
* <blockquote><pre>
* Notification notif;
*
* // receive the notification emitted by MemoryMXBean and set to notif
* ...
*
* String notifType = notif.getType();
* if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) ||
* notifType.equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) {
* // retrieve the memory notification information
* CompositeData cd = (CompositeData) notif.getUserData();
* MemoryNotificationInfo info = MemoryNotificationInfo.from(cd);
* ....
* }
* </pre></blockquote>
*
* <p>
* The types of notifications emitted by {@code MemoryMXBean} are:
* <ul>
* <li>A {@link #MEMORY_THRESHOLD_EXCEEDED
* usage threshold exceeded notification}.
* <br>This notification will be emitted when
* the memory usage of a memory pool is increased and has reached
* or exceeded its
* <a href="MemoryPoolMXBean.html#UsageThreshold"> usage threshold</a> value.
* Subsequent crossing of the usage threshold value does not cause
* further notification until the memory usage has returned
* to become less than the usage threshold value.
* </li>
* <li>A {@link #MEMORY_COLLECTION_THRESHOLD_EXCEEDED
* collection usage threshold exceeded notification}.
* <br>This notification will be emitted when
* the memory usage of a memory pool is greater than or equal to its
* <a href="MemoryPoolMXBean.html#CollectionThreshold">
* collection usage threshold</a> after the Java virtual machine
* has expended effort in recycling unused objects in that
* memory pool.</li>
* </ul>
*
* @author Mandy Chung
* @since 1.5
*
*/
public class MemoryNotificationInfo {
private final String poolName;
private final MemoryUsage usage;
private final long count;
/**
* Notification type denoting that
* the memory usage of a memory pool has
* reached or exceeded its
* <a href="MemoryPoolMXBean.html#UsageThreshold"> usage threshold</a> value.
* This notification is emitted by {@link MemoryMXBean}.
* Subsequent crossing of the usage threshold value does not cause
* further notification until the memory usage has returned
* to become less than the usage threshold value.
* The value of this notification type is
* {@code java.management.memory.threshold.exceeded}.
*/
public static final String MEMORY_THRESHOLD_EXCEEDED =
"java.management.memory.threshold.exceeded";
/**
* Notification type denoting that
* the memory usage of a memory pool is greater than or equal to its
* <a href="MemoryPoolMXBean.html#CollectionThreshold">
* collection usage threshold</a> after the Java virtual machine
* has expended effort in recycling unused objects in that
* memory pool.
* This notification is emitted by {@link MemoryMXBean}.
* The value of this notification type is
* {@code java.management.memory.collection.threshold.exceeded}.
*/
public static final String MEMORY_COLLECTION_THRESHOLD_EXCEEDED =
"java.management.memory.collection.threshold.exceeded";
/**
* Constructs a {@code MemoryNotificationInfo} object.
*
* @param poolName The name of the memory pool which triggers this notification.
* @param usage Memory usage of the memory pool.
* @param count The threshold crossing count.
*/
public MemoryNotificationInfo(String poolName,
MemoryUsage usage,
long count) {
if (poolName == null) {
throw new NullPointerException("Null poolName");
}
if (usage == null) {
throw new NullPointerException("Null usage");
}
this.poolName = poolName;
this.usage = usage;
this.count = count;
}
MemoryNotificationInfo(CompositeData cd) {
MemoryNotifInfoCompositeData.validateCompositeData(cd);
this.poolName = MemoryNotifInfoCompositeData.getPoolName(cd);
this.usage = MemoryNotifInfoCompositeData.getUsage(cd);
this.count = MemoryNotifInfoCompositeData.getCount(cd);
}
/**
* Returns the name of the memory pool that triggers this notification.
* The memory pool usage has crossed a threshold.
*
* @return the name of the memory pool that triggers this notification.
*/
public String getPoolName() {
return poolName;
}
/**
* Returns the memory usage of the memory pool
* when this notification was constructed.
*
* @return the memory usage of the memory pool
* when this notification was constructed.
*/
public MemoryUsage getUsage() {
return usage;
}
/**
* Returns the number of times that the memory usage has crossed
* a threshold when the notification was constructed.
* For usage threshold notifications, this count will be the
* {@link MemoryPoolMXBean#getUsageThresholdCount threshold
* count}. For collection threshold notifications,
* this count will be the
* {@link MemoryPoolMXBean#getCollectionUsageThresholdCount
* collection usage threshold count}.
*
* @return the number of times that the memory usage has crossed
* a threshold when the notification was constructed.
*/
public long getCount() {
return count;
}
/**
* Returns a {@code MemoryNotificationInfo} object represented by the
* given {@code CompositeData}.
* The given {@code CompositeData} must contain
* the following attributes:
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and the types the given CompositeData contains</caption>
* <thead>
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">poolName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">usage</th>
* <td>{@code javax.management.openmbean.CompositeData}</td>
* </tr>
* <tr>
* <th scope="row">count</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* </tbody>
* </table>
*
* @param cd {@code CompositeData} representing a
* {@code MemoryNotificationInfo}
*
* @throws IllegalArgumentException if {@code cd} does not
* represent a {@code MemoryNotificationInfo} object.
*
* @return a {@code MemoryNotificationInfo} object represented
* by {@code cd} if {@code cd} is not {@code null};
* {@code null} otherwise.
*/
public static MemoryNotificationInfo from(CompositeData cd) {
if (cd == null) {
return null;
}
if (cd instanceof MemoryNotifInfoCompositeData) {
return ((MemoryNotifInfoCompositeData) cd).getMemoryNotifInfo();
} else {
return new MemoryNotificationInfo(cd);
}
}
}

View file

@ -0,0 +1,643 @@
/*
* Copyright (c) 2003, 2017, 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 java.lang.management;
/**
* The management interface for a memory pool. A memory pool
* represents the memory resource managed by the Java virtual machine
* and is managed by one or more {@link MemoryManagerMXBean memory managers}.
*
* <p> A Java virtual machine has one or more instances of the
* implementation class of this interface. An instance
* implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getMemoryPoolMXBeans} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* a memory pool within an {@code MBeanServer} is:
* <blockquote>
* {@link ManagementFactory#MEMORY_POOL_MXBEAN_DOMAIN_TYPE
* java.lang:type=MemoryPool}{@code ,name=}<i>pool's name</i>
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* <h3>Memory Type</h3>
* <p>The Java virtual machine has a heap for object allocation and also
* maintains non-heap memory for the method area and the Java virtual
* machine execution. The Java virtual machine can have one or more
* memory pools. Each memory pool represents a memory area
* of one of the following types:
* <ul>
* <li>{@link MemoryType#HEAP heap}</li>
* <li>{@link MemoryType#NON_HEAP non-heap}</li>
* </ul>
*
* <h3>Memory Usage Monitoring</h3>
*
* A memory pool has the following attributes:
* <ul>
* <li><a href="#Usage">Memory usage</a></li>
* <li><a href="#PeakUsage">Peak memory usage</a></li>
* <li><a href="#UsageThreshold">Usage Threshold</a></li>
* <li><a href="#CollectionThreshold">Collection Usage Threshold</a>
* (only supported by some <em>garbage-collected</em> memory pools)</li>
* </ul>
*
* <h3><a id="Usage">1. Memory Usage</a></h3>
*
* The {@link #getUsage} method provides an estimate
* of the current usage of a memory pool.
* For a garbage-collected memory pool, the amount of used memory
* includes the memory occupied by all objects in the pool
* including both <em>reachable</em> and <em>unreachable</em> objects.
*
* <p>In general, this method is a lightweight operation for getting
* an approximate memory usage. For some memory pools, for example,
* when objects are not packed contiguously, this method may be
* an expensive operation that requires some computation to determine
* the current memory usage. An implementation should document when
* this is the case.
*
* <h3><a id="PeakUsage">2. Peak Memory Usage</a></h3>
*
* The Java virtual machine maintains the peak memory usage of a memory
* pool since the virtual machine was started or the peak was reset.
* The peak memory usage is returned by the {@link #getPeakUsage} method
* and reset by calling the {@link #resetPeakUsage} method.
*
* <h3><a id="UsageThreshold">3. Usage Threshold</a></h3>
*
* Each memory pool has a manageable attribute
* called the <i>usage threshold</i> which has a default value supplied
* by the Java virtual machine. The default value is platform-dependent.
* The usage threshold can be set via the
* {@link #setUsageThreshold setUsageThreshold} method.
* If the threshold is set to a positive value, the usage threshold crossing
* checking is enabled in this memory pool.
* If the usage threshold is set to zero, usage
* threshold crossing checking on this memory pool is disabled.
* The {@link MemoryPoolMXBean#isUsageThresholdSupported} method can
* be used to determine if this functionality is supported.
* <p>
* A Java virtual machine performs usage threshold crossing checking on a
* memory pool basis at its best appropriate time, typically,
* at garbage collection time.
* Each memory pool maintains a {@link #getUsageThresholdCount
* usage threshold count} that will get incremented
* every time when the Java virtual machine
* detects that the memory pool usage is crossing the threshold.
* <p>
* This manageable usage threshold attribute is designed for monitoring the
* increasing trend of memory usage with low overhead.
* Usage threshold may not be appropriate for some memory pools.
* For example, a generational garbage collector, a common garbage collection
* algorithm used in many Java virtual machine implementations,
* manages two or more generations segregating objects by age.
* Most of the objects are allocated in
* the <em>youngest generation</em> (say a nursery memory pool).
* The nursery memory pool is designed to be filled up and
* collecting the nursery memory pool will free most of its memory space
* since it is expected to contain mostly short-lived objects
* and mostly are unreachable at garbage collection time.
* In this case, it is more appropriate for the nursery memory pool
* not to support a usage threshold. In addition,
* if the cost of an object allocation
* in one memory pool is very low (for example, just atomic pointer exchange),
* the Java virtual machine would probably not support the usage threshold
* for that memory pool since the overhead in comparing the usage with
* the threshold is higher than the cost of object allocation.
*
* <p>
* The memory usage of the system can be monitored using
* <a href="#Polling">polling</a> or
* <a href="#ThresholdNotification">threshold notification</a> mechanisms.
*
* <ol type="a">
* <li><a id="Polling"><b>Polling</b></a>
* <p>
* An application can continuously monitor its memory usage
* by calling either the {@link #getUsage} method for all
* memory pools or the {@link #isUsageThresholdExceeded} method
* for those memory pools that support a usage threshold.
* Below is example code that has a thread dedicated for
* task distribution and processing. At every interval,
* it will determine if it should receive and process new tasks based
* on its memory usage. If the memory usage exceeds its usage threshold,
* it will redistribute all outstanding tasks to other VMs and
* stop receiving new tasks until the memory usage returns
* below its usage threshold.
*
* <pre>
* // Assume the usage threshold is supported for this pool.
* // Set the threshold to myThreshold above which no new tasks
* // should be taken.
* pool.setUsageThreshold(myThreshold);
* ....
*
* boolean lowMemory = false;
* while (true) {
* if (pool.isUsageThresholdExceeded()) {
* // potential low memory, so redistribute tasks to other VMs
* lowMemory = true;
* redistributeTasks();
* // stop receiving new tasks
* stopReceivingTasks();
* } else {
* if (lowMemory) {
* // resume receiving tasks
* lowMemory = false;
* resumeReceivingTasks();
* }
* // processing outstanding task
* ...
* }
* // sleep for sometime
* try {
* Thread.sleep(sometime);
* } catch (InterruptedException e) {
* ...
* }
* }
* </pre>
*
* <hr>
* The above example does not differentiate the case where
* the memory usage has temporarily dropped below the usage threshold
* from the case where the memory usage remains above the threshold
* between two iterations. The usage threshold count returned by
* the {@link #getUsageThresholdCount} method
* can be used to determine
* if the memory usage has returned below the threshold
* between two polls.
* <p>
* Below shows another example that takes some action if a
* memory pool is under low memory and ignores the memory usage
* changes during the action processing time.
*
* <pre>
* // Assume the usage threshold is supported for this pool.
* // Set the threshold to myThreshold which determines if
* // the application will take some action under low memory condition.
* pool.setUsageThreshold(myThreshold);
*
* int prevCrossingCount = 0;
* while (true) {
* // A busy loop to detect when the memory usage
* // has exceeded the threshold.
* while (!pool.isUsageThresholdExceeded() ||
* pool.getUsageThresholdCount() == prevCrossingCount) {
* try {
* Thread.sleep(sometime)
* } catch (InterruptException e) {
* ....
* }
* }
*
* // Do some processing such as check for memory usage
* // and issue a warning
* ....
*
* // Gets the current threshold count. The busy loop will then
* // ignore any crossing of threshold happens during the processing.
* prevCrossingCount = pool.getUsageThresholdCount();
* }
* </pre><hr>
* </li>
* <li><a id="ThresholdNotification"><b>Usage Threshold Notifications</b></a>
* <p>
* Usage threshold notification will be emitted by {@link MemoryMXBean}.
* When the Java virtual machine detects that the memory usage of
* a memory pool has reached or exceeded the usage threshold
* the virtual machine will trigger the {@code MemoryMXBean} to emit an
* {@link MemoryNotificationInfo#MEMORY_THRESHOLD_EXCEEDED
* usage threshold exceeded notification}.
* Another usage threshold exceeded notification will not be
* generated until the usage has fallen below the threshold and
* then exceeded it again.
* <p>
* Below is an example code implementing the same logic as the
* first example above but using the usage threshold notification
* mechanism to detect low memory conditions instead of polling.
* In this example code, upon receiving notification, the notification
* listener notifies another thread to perform the actual action
* such as to redistribute outstanding tasks, stop receiving tasks,
* or resume receiving tasks.
* The {@code handleNotification} method should be designed to
* do a very minimal amount of work and return without delay to avoid
* causing delay in delivering subsequent notifications. Time-consuming
* actions should be performed by a separate thread.
* The notification listener may be invoked by multiple threads
* concurrently; so the tasks performed by the listener
* should be properly synchronized.
*
* <pre>
* class MyListener implements javax.management.NotificationListener {
* public void handleNotification(Notification notification, Object handback) {
* String notifType = notification.getType();
* if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
* // potential low memory, notify another thread
* // to redistribute outstanding tasks to other VMs
* // and stop receiving new tasks.
* lowMemory = true;
* notifyAnotherThread(lowMemory);
* }
* }
* }
*
* // Register MyListener with MemoryMXBean
* MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
* NotificationEmitter emitter = (NotificationEmitter) mbean;
* MyListener listener = new MyListener();
* emitter.addNotificationListener(listener, null, null);
*
* // Assume this pool supports a usage threshold.
* // Set the threshold to myThreshold above which no new tasks
* // should be taken.
* pool.setUsageThreshold(myThreshold);
*
* // Usage threshold detection is enabled and notification will be
* // handled by MyListener. Continue for other processing.
* ....
*
* </pre>
* <hr>
* <p>
* There is no guarantee about when the {@code MemoryMXBean} will emit
* a threshold notification and when the notification will be delivered.
* When a notification listener is invoked, the memory usage of
* the memory pool may have crossed the usage threshold more
* than once.
* The {@link MemoryNotificationInfo#getCount} method returns the number
* of times that the memory usage has crossed the usage threshold
* at the point in time when the notification was constructed.
* It can be compared with the current usage threshold count returned
* by the {@link #getUsageThresholdCount} method to determine if
* such situation has occurred.
* </li>
* </ol>
*
* <h3><a id="CollectionThreshold">4. Collection Usage Threshold</a></h3>
*
* Collection usage threshold is a manageable attribute only applicable
* to some garbage-collected memory pools.
* After a Java virtual machine has expended effort in reclaiming memory
* space by recycling unused objects in a memory pool at garbage collection
* time, some number of bytes in the memory pools that are garbaged
* collected will still be in use. The collection usage threshold
* allows a value to be set for this number of bytes such
* that if the threshold is exceeded,
* a {@link MemoryNotificationInfo#MEMORY_THRESHOLD_EXCEEDED
* collection usage threshold exceeded notification}
* will be emitted by the {@link MemoryMXBean}.
* In addition, the {@link #getCollectionUsageThresholdCount
* collection usage threshold count} will then be incremented.
*
* <p>
* The {@link MemoryPoolMXBean#isCollectionUsageThresholdSupported} method can
* be used to determine if this functionality is supported.
*
* <p>
* A Java virtual machine performs collection usage threshold checking
* on a memory pool basis. This checking is enabled if the collection
* usage threshold is set to a positive value.
* If the collection usage threshold is set to zero, this checking
* is disabled on this memory pool. Default value is zero.
* The Java virtual machine performs the collection usage threshold
* checking at garbage collection time.
*
* <p>
* Some garbage-collected memory pools may
* choose not to support the collection usage threshold. For example,
* a memory pool is only managed by a continuous concurrent garbage
* collector. Objects can be allocated in this memory pool by some thread
* while the unused objects are reclaimed by the concurrent garbage
* collector simultaneously. Unless there is a well-defined
* garbage collection time which is the best appropriate time
* to check the memory usage, the collection usage threshold should not
* be supported.
*
* <p>
* The collection usage threshold is designed for monitoring the memory usage
* after the Java virtual machine has expended effort in reclaiming
* memory space. The collection usage could also be monitored
* by the polling and threshold notification mechanism
* described above for the <a href="#UsageThreshold">usage threshold</a>
* in a similar fashion.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface MemoryPoolMXBean extends PlatformManagedObject {
/**
* Returns the name representing this memory pool.
*
* @return the name of this memory pool.
*/
public String getName();
/**
* Returns the type of this memory pool.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code MemoryType} is {@code String}
* and the value is the name of the {@code MemoryType}.
*
* @return the type of this memory pool.
*/
public MemoryType getType();
/**
* Returns an estimate of the memory usage of this memory pool.
* This method returns {@code null}
* if this memory pool is not valid (i.e. no longer exists).
*
* <p>
* This method requests the Java virtual machine to make
* a best-effort estimate of the current memory usage of this
* memory pool. For some memory pools, this method may be an
* expensive operation that requires some computation to determine
* the estimate. An implementation should document when
* this is the case.
*
* <p>This method is designed for use in monitoring system
* memory usage and detecting low memory condition.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code MemoryUsage} is
* {@code CompositeData} with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} object; or {@code null} if
* this pool not valid.
*/
public MemoryUsage getUsage();
/**
* Returns the peak memory usage of this memory pool since the
* Java virtual machine was started or since the peak was reset.
* This method returns {@code null}
* if this memory pool is not valid (i.e. no longer exists).
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code MemoryUsage} is
* {@code CompositeData} with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} object representing the peak
* memory usage; or {@code null} if this pool is not valid.
*
*/
public MemoryUsage getPeakUsage();
/**
* Resets the peak memory usage statistic of this memory pool
* to the current memory usage.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*/
public void resetPeakUsage();
/**
* Tests if this memory pool is valid in the Java virtual
* machine. A memory pool becomes invalid once the Java virtual
* machine removes it from the memory system.
*
* @return {@code true} if the memory pool is valid in the running
* Java virtual machine;
* {@code false} otherwise.
*/
public boolean isValid();
/**
* Returns the name of memory managers that manages this memory pool.
* Each memory pool will be managed by at least one memory manager.
*
* @return an array of {@code String} objects, each is the name of
* a memory manager managing this memory pool.
*/
public String[] getMemoryManagerNames();
/**
* Returns the usage threshold value of this memory pool in bytes.
* Each memory pool has a platform-dependent default threshold value.
* The current usage threshold can be changed via the
* {@link #setUsageThreshold setUsageThreshold} method.
*
* @return the usage threshold value of this memory pool in bytes.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a usage threshold.
*
* @see #isUsageThresholdSupported
*/
public long getUsageThreshold();
/**
* Sets the threshold of this memory pool to the given {@code threshold}
* value if this memory pool supports the usage threshold.
* The usage threshold crossing checking is enabled in this memory pool
* if the threshold is set to a positive value.
* The usage threshold crossing checking is disabled
* if it is set to zero.
*
* @param threshold the new threshold value in bytes. Must be non-negative.
*
* @throws IllegalArgumentException if {@code threshold} is negative
* or greater than the maximum amount of memory for
* this memory pool if defined.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a usage threshold.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*
* @see #isUsageThresholdSupported
* @see <a href="#UsageThreshold">Usage threshold</a>
*/
public void setUsageThreshold(long threshold);
/**
* Tests if the memory usage of this memory pool
* reaches or exceeds its usage threshold value.
*
* @return {@code true} if the memory usage of
* this memory pool reaches or exceeds the threshold value;
* {@code false} otherwise.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a usage threshold.
*/
public boolean isUsageThresholdExceeded();
/**
* Returns the number of times that the memory usage has crossed
* the usage threshold.
*
* @return the number of times that the memory usage
* has crossed its usage threshold value.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a usage threshold.
*/
public long getUsageThresholdCount();
/**
* Tests if this memory pool supports usage threshold.
*
* @return {@code true} if this memory pool supports usage threshold;
* {@code false} otherwise.
*/
public boolean isUsageThresholdSupported();
/**
* Returns the collection usage threshold value of this memory pool
* in bytes. The default value is zero. The collection usage
* threshold can be changed via the
* {@link #setCollectionUsageThreshold setCollectionUsageThreshold} method.
*
* @return the collection usage threshold of this memory pool in bytes.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a collection usage threshold.
*
* @see #isCollectionUsageThresholdSupported
*/
public long getCollectionUsageThreshold();
/**
* Sets the collection usage threshold of this memory pool to
* the given {@code threshold} value.
* When this threshold is set to positive, the Java virtual machine
* will check the memory usage at its best appropriate time after it has
* expended effort in recycling unused objects in this memory pool.
* <p>
* The collection usage threshold crossing checking is enabled
* in this memory pool if the threshold is set to a positive value.
* The collection usage threshold crossing checking is disabled
* if it is set to zero.
*
* @param threshold the new collection usage threshold value in bytes.
* Must be non-negative.
*
* @throws IllegalArgumentException if {@code threshold} is negative
* or greater than the maximum amount of memory for
* this memory pool if defined.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a collection usage threshold.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*
* @see #isCollectionUsageThresholdSupported
* @see <a href="#CollectionThreshold">Collection usage threshold</a>
*/
public void setCollectionUsageThreshold(long threshold);
/**
* Tests if the memory usage of this memory pool after
* the most recent collection on which the Java virtual
* machine has expended effort has reached or
* exceeded its collection usage threshold.
* This method does not request the Java virtual
* machine to perform any garbage collection other than its normal
* automatic memory management.
*
* @return {@code true} if the memory usage of this memory pool
* reaches or exceeds the collection usage threshold value
* in the most recent collection;
* {@code false} otherwise.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a usage threshold.
*/
public boolean isCollectionUsageThresholdExceeded();
/**
* Returns the number of times that the Java virtual machine
* has detected that the memory usage has reached or
* exceeded the collection usage threshold.
*
* @return the number of times that the memory
* usage has reached or exceeded the collection usage threshold.
*
* @throws UnsupportedOperationException if this memory pool
* does not support a collection usage threshold.
*
* @see #isCollectionUsageThresholdSupported
*/
public long getCollectionUsageThresholdCount();
/**
* Returns the memory usage after the Java virtual machine
* most recently expended effort in recycling unused objects
* in this memory pool.
* This method does not request the Java virtual
* machine to perform any garbage collection other than its normal
* automatic memory management.
* This method returns {@code null} if the Java virtual
* machine does not support this method.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code MemoryUsage} is
* {@code CompositeData} with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} representing the memory usage of
* this memory pool after the Java virtual machine most recently
* expended effort in recycling unused objects;
* {@code null} if this method is not supported.
*/
public MemoryUsage getCollectionUsage();
/**
* Tests if this memory pool supports a collection usage threshold.
*
* @return {@code true} if this memory pool supports the
* collection usage threshold; {@code false} otherwise.
*/
public boolean isCollectionUsageThresholdSupported();
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
/**
* Types of {@link MemoryPoolMXBean memory pools}.
*
* @author Mandy Chung
* @since 1.5
*/
public enum MemoryType {
/**
* Heap memory type.
* <p>
* The Java virtual machine has a <i>heap</i>
* that is the runtime data area from which
* memory for all class instances and arrays are allocated.
*/
HEAP("Heap memory"),
/**
* Non-heap memory type.
* <p>
* The Java virtual machine manages memory other than the heap
* (referred as <i>non-heap memory</i>). The non-heap memory includes
* the <i>method area</i> and memory required for the internal
* processing or optimization for the Java virtual machine.
* It stores per-class structures such as a runtime
* constant pool, field and method data, and the code for
* methods and constructors.
*/
NON_HEAP("Non-heap memory");
private final String description;
private MemoryType(String s) {
this.description = s;
}
/**
* Returns the string representation of this {@code MemoryType}.
* @return the string representation of this {@code MemoryType}.
*/
public String toString() {
return description;
}
private static final long serialVersionUID = 6992337162326171013L;
}

View file

@ -0,0 +1,310 @@
/*
* Copyright (c) 2003, 2017, 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 java.lang.management;
import javax.management.openmbean.CompositeData;
import sun.management.MemoryUsageCompositeData;
/**
* A {@code MemoryUsage} object represents a snapshot of memory usage.
* Instances of the {@code MemoryUsage} class are usually constructed
* by methods that are used to obtain memory usage
* information about individual memory pool of the Java virtual machine or
* the heap or non-heap memory of the Java virtual machine as a whole.
*
* <p> A {@code MemoryUsage} object contains four values:
* <table class="striped">
* <caption style="display:none">Describes the MemoryUsage object content</caption>
* <thead>
* <tr><th scope="col">Value</th><th scope="col">Description</th></tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row" style="vertical-align:top"> {@code init} </th>
* <td style="vertical-align:top"> represents the initial amount of memory (in bytes) that
* the Java virtual machine requests from the operating system
* for memory management during startup. The Java virtual machine
* may request additional memory from the operating system and
* may also release memory to the system over time.
* The value of {@code init} may be undefined.
* </td>
* </tr>
* <tr>
* <th scope="row" style="vertical-align:top"> {@code used} </th>
* <td style="vertical-align:top"> represents the amount of memory currently used (in bytes).
* </td>
* </tr>
* <tr>
* <th scope="row" style="vertical-align:top"> {@code committed} </th>
* <td style="vertical-align:top"> represents the amount of memory (in bytes) that is
* guaranteed to be available for use by the Java virtual machine.
* The amount of committed memory may change over time (increase
* or decrease). The Java virtual machine may release memory to
* the system and {@code committed} could be less than {@code init}.
* {@code committed} will always be greater than
* or equal to {@code used}.
* </td>
* </tr>
* <tr>
* <th scope="row" style="vertical-align:top"> {@code max} </th>
* <td style="vertical-align:top"> represents the maximum amount of memory (in bytes)
* that can be used for memory management. Its value may be undefined.
* The maximum amount of memory may change over time if defined.
* The amount of used and committed memory will always be less than
* or equal to {@code max} if {@code max} is defined.
* A memory allocation may fail if it attempts to increase the
* used memory such that {@code used > committed} even
* if {@code used <= max} would still be true (for example,
* when the system is low on virtual memory).
* </td>
* </tr>
* </tbody>
* </table>
*
* Below is a picture showing an example of a memory pool:
*
* <pre>
* +----------------------------------------------+
* +//////////////// | +
* +//////////////// | +
* +----------------------------------------------+
*
* |--------|
* init
* |---------------|
* used
* |---------------------------|
* committed
* |----------------------------------------------|
* max
* </pre>
*
* <h3>MXBean Mapping</h3>
* {@code MemoryUsage} is mapped to a {@link CompositeData CompositeData}
* with attributes as specified in the {@link #from from} method.
*
* @author Mandy Chung
* @since 1.5
*/
public class MemoryUsage {
private final long init;
private final long used;
private final long committed;
private final long max;
/**
* Constructs a {@code MemoryUsage} object.
*
* @param init the initial amount of memory in bytes that
* the Java virtual machine allocates;
* or {@code -1} if undefined.
* @param used the amount of used memory in bytes.
* @param committed the amount of committed memory in bytes.
* @param max the maximum amount of memory in bytes that
* can be used; or {@code -1} if undefined.
*
* @throws IllegalArgumentException if
* <ul>
* <li> the value of {@code init} or {@code max} is negative
* but not {@code -1}; or</li>
* <li> the value of {@code used} or {@code committed} is negative;
* or</li>
* <li> {@code used} is greater than the value of {@code committed};
* or</li>
* <li> {@code committed} is greater than the value of {@code max}
* {@code max} if defined.</li>
* </ul>
*/
public MemoryUsage(long init,
long used,
long committed,
long max) {
if (init < -1) {
throw new IllegalArgumentException( "init parameter = " +
init + " is negative but not -1.");
}
if (max < -1) {
throw new IllegalArgumentException( "max parameter = " +
max + " is negative but not -1.");
}
if (used < 0) {
throw new IllegalArgumentException( "used parameter = " +
used + " is negative.");
}
if (committed < 0) {
throw new IllegalArgumentException( "committed parameter = " +
committed + " is negative.");
}
if (used > committed) {
throw new IllegalArgumentException( "used = " + used +
" should be <= committed = " + committed);
}
if (max >= 0 && committed > max) {
throw new IllegalArgumentException( "committed = " + committed +
" should be < max = " + max);
}
this.init = init;
this.used = used;
this.committed = committed;
this.max = max;
}
/**
* Constructs a {@code MemoryUsage} object from a
* {@link CompositeData CompositeData}.
*/
private MemoryUsage(CompositeData cd) {
// validate the input composite data
MemoryUsageCompositeData.validateCompositeData(cd);
this.init = MemoryUsageCompositeData.getInit(cd);
this.used = MemoryUsageCompositeData.getUsed(cd);
this.committed = MemoryUsageCompositeData.getCommitted(cd);
this.max = MemoryUsageCompositeData.getMax(cd);
}
/**
* Returns the amount of memory in bytes that the Java virtual machine
* initially requests from the operating system for memory management.
* This method returns {@code -1} if the initial memory size is undefined.
*
* @return the initial size of memory in bytes;
* {@code -1} if undefined.
*/
public long getInit() {
return init;
}
/**
* Returns the amount of used memory in bytes.
*
* @return the amount of used memory in bytes.
*
*/
public long getUsed() {
return used;
};
/**
* Returns the amount of memory in bytes that is committed for
* the Java virtual machine to use. This amount of memory is
* guaranteed for the Java virtual machine to use.
*
* @return the amount of committed memory in bytes.
*
*/
public long getCommitted() {
return committed;
};
/**
* Returns the maximum amount of memory in bytes that can be
* used for memory management. This method returns {@code -1}
* if the maximum memory size is undefined.
*
* <p> This amount of memory is not guaranteed to be available
* for memory management if it is greater than the amount of
* committed memory. The Java virtual machine may fail to allocate
* memory even if the amount of used memory does not exceed this
* maximum size.
*
* @return the maximum amount of memory in bytes;
* {@code -1} if undefined.
*/
public long getMax() {
return max;
};
/**
* Returns a descriptive representation of this memory usage.
*/
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("init = " + init + "(" + (init >> 10) + "K) ");
buf.append("used = " + used + "(" + (used >> 10) + "K) ");
buf.append("committed = " + committed + "(" +
(committed >> 10) + "K) " );
buf.append("max = " + max + "(" + (max >> 10) + "K)");
return buf.toString();
}
/**
* Returns a {@code MemoryUsage} object represented by the
* given {@code CompositeData}. The given {@code CompositeData}
* must contain the following attributes:
*
* <table class="striped" style="margin-left:2em;">
* <caption style="display:none">The attributes and the types the given CompositeData contains</caption>
* <thead>
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">init</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">used</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">committed</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">max</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* </tbody>
* </table>
*
* @param cd {@code CompositeData} representing a {@code MemoryUsage}
*
* @throws IllegalArgumentException if {@code cd} does not
* represent a {@code MemoryUsage} with the attributes described
* above.
*
* @return a {@code MemoryUsage} object represented by {@code cd}
* if {@code cd} is not {@code null};
* {@code null} otherwise.
*/
public static MemoryUsage from(CompositeData cd) {
if (cd == null) {
return null;
}
if (cd instanceof MemoryUsageCompositeData) {
return ((MemoryUsageCompositeData) cd).getMemoryUsage();
} else {
return new MemoryUsage(cd);
}
}
}

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2005, 2017, 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 java.lang.management;
import javax.management.openmbean.CompositeData;
import sun.management.MonitorInfoCompositeData;
/**
* Information about an object monitor lock. An object monitor is locked
* when entering a synchronization block or method on that object.
*
* <h3>MXBean Mapping</h3>
* {@code MonitorInfo} is mapped to a {@link CompositeData CompositeData}
* with attributes as specified in
* the {@link #from from} method.
*
* @author Mandy Chung
* @since 1.6
*/
public class MonitorInfo extends LockInfo {
private int stackDepth;
private StackTraceElement stackFrame;
/**
* Construct a {@code MonitorInfo} object.
*
* @param className the fully qualified name of the class of the lock object.
* @param identityHashCode the {@link System#identityHashCode
* identity hash code} of the lock object.
* @param stackDepth the depth in the stack trace where the object monitor
* was locked.
* @param stackFrame the stack frame that locked the object monitor.
* @throws IllegalArgumentException if
* {@code stackDepth} &ge; 0 but {@code stackFrame} is {@code null},
* or {@code stackDepth} &lt; 0 but {@code stackFrame} is not
* {@code null}.
*/
public MonitorInfo(String className,
int identityHashCode,
int stackDepth,
StackTraceElement stackFrame) {
super(className, identityHashCode);
if (stackDepth >= 0 && stackFrame == null) {
throw new IllegalArgumentException("Parameter stackDepth is " +
stackDepth + " but stackFrame is null");
}
if (stackDepth < 0 && stackFrame != null) {
throw new IllegalArgumentException("Parameter stackDepth is " +
stackDepth + " but stackFrame is not null");
}
this.stackDepth = stackDepth;
this.stackFrame = stackFrame;
}
/**
* Returns the depth in the stack trace where the object monitor
* was locked. The depth is the index to the {@code StackTraceElement}
* array returned in the {@link ThreadInfo#getStackTrace} method.
*
* @return the depth in the stack trace where the object monitor
* was locked, or a negative number if not available.
*/
public int getLockedStackDepth() {
return stackDepth;
}
/**
* Returns the stack frame that locked the object monitor.
*
* @return {@code StackTraceElement} that locked the object monitor,
* or {@code null} if not available.
*/
public StackTraceElement getLockedStackFrame() {
return stackFrame;
}
/**
* Returns a {@code MonitorInfo} object represented by the
* given {@code CompositeData}.
* The given {@code CompositeData} must contain the following attributes
* as well as the attributes specified in the
* <a href="LockInfo.html#MappedType">
* mapped type</a> for the {@link LockInfo} class:
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
* <thead>
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">lockedStackFrame</th>
* <td><code>CompositeData as specified in the
* <a href="ThreadInfo.html#StackTrace">stackTrace</a>
* attribute defined in the {@link ThreadInfo#from
* ThreadInfo.from} method.
* </code></td>
* </tr>
* <tr>
* <th scope="row">lockedStackDepth</th>
* <td>{@code java.lang.Integer}</td>
* </tr>
* </tbody>
* </table>
*
* @param cd {@code CompositeData} representing a {@code MonitorInfo}
*
* @throws IllegalArgumentException if {@code cd} does not
* represent a {@code MonitorInfo} with the attributes described
* above.
* @return a {@code MonitorInfo} object represented
* by {@code cd} if {@code cd} is not {@code null};
* {@code null} otherwise.
*/
public static MonitorInfo from(CompositeData cd) {
if (cd == null) {
return null;
}
if (cd instanceof MonitorInfoCompositeData) {
return ((MonitorInfoCompositeData) cd).getMonitorInfo();
} else {
MonitorInfoCompositeData.validateCompositeData(cd);
String className = MonitorInfoCompositeData.getClassName(cd);
int identityHashCode = MonitorInfoCompositeData.getIdentityHashCode(cd);
int stackDepth = MonitorInfoCompositeData.getLockedStackDepth(cd);
StackTraceElement stackFrame = MonitorInfoCompositeData.getLockedStackFrame(cd);
return new MonitorInfo(className,
identityHashCode,
stackDepth,
stackFrame);
}
}
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
/**
* The management interface for the operating system on which
* the Java virtual machine is running.
*
* <p> A Java virtual machine has a single instance of the implementation
* class of this interface. This instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getOperatingSystemMXBean} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* the operating system within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#OPERATING_SYSTEM_MXBEAN_NAME
* java.lang:type=OperatingSystem}
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* <p> This interface defines several convenient methods for accessing
* system properties about the operating system on which the Java
* virtual machine is running.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface OperatingSystemMXBean extends PlatformManagedObject {
/**
* Returns the operating system name.
* This method is equivalent to {@code System.getProperty("os.name")}.
*
* @return the operating system name.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getName();
/**
* Returns the operating system architecture.
* This method is equivalent to {@code System.getProperty("os.arch")}.
*
* @return the operating system architecture.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getArch();
/**
* Returns the operating system version.
* This method is equivalent to {@code System.getProperty("os.version")}.
*
* @return the operating system version.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getVersion();
/**
* Returns the number of processors available to the Java virtual machine.
* This method is equivalent to the {@link Runtime#availableProcessors()}
* method.
* <p> This value may change during a particular invocation of
* the virtual machine.
*
* @return the number of processors available to the virtual
* machine; never smaller than one.
*/
public int getAvailableProcessors();
/**
* Returns the system load average for the last minute.
* The system load average is the sum of the number of runnable entities
* queued to the {@linkplain #getAvailableProcessors available processors}
* and the number of runnable entities running on the available processors
* averaged over a period of time.
* The way in which the load average is calculated is operating system
* specific but is typically a damped time-dependent average.
* <p>
* If the load average is not available, a negative value is returned.
* <p>
* This method is designed to provide a hint about the system load
* and may be queried frequently.
* The load average may be unavailable on some platform where it is
* expensive to implement this method.
*
* @return the system load average; or a negative value if not available.
*
* @since 1.6
*/
public double getSystemLoadAverage();
}

View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2009, 2011, 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 java.lang.management;
/**
* The management interface for the {@linkplain java.util.logging logging} facility.
*
* <p>There is a single global instance of the {@code PlatformLoggingMXBean}.
* The {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
* ManagementFactory.getPlatformMXBean} method can be used to obtain
* the {@code PlatformLoggingMXBean} object as follows:
* <pre>
* PlatformLoggingMXBean logging = ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class);
* </pre>
* The {@code PlatformLoggingMXBean} object is also registered with the
* platform {@linkplain java.lang.management.ManagementFactory#getPlatformMBeanServer
* MBeanServer}.
* The {@link javax.management.ObjectName ObjectName} for uniquely
* identifying the {@code PlatformLoggingMXBean} within an MBeanServer is:
* <pre>
* {@link java.util.logging.LogManager#LOGGING_MXBEAN_NAME java.util.logging:type=Logging}
* </pre>
*
* @since 1.7
*/
public interface PlatformLoggingMXBean extends PlatformManagedObject {
/**
* Returns the list of the currently registered
* {@linkplain java.util.logging.Logger logger} names. This method
* calls {@link java.util.logging.LogManager#getLoggerNames} and
* returns a list of the logger names.
*
* @return A list of {@code String} each of which is a
* currently registered {@code Logger} name.
*/
java.util.List<String> getLoggerNames();
/**
* Gets the name of the log {@linkplain java.util.logging.Logger#getLevel
* level} associated with the specified logger.
* If the specified logger does not exist, {@code null}
* is returned.
* This method first finds the logger of the given name and
* then returns the name of the log level by calling:
* <blockquote>
* {@link java.util.logging.Logger#getLevel
* Logger.getLevel()}.{@link java.util.logging.Level#getName getName()};
* </blockquote>
*
* <p>
* If the {@code Level} of the specified logger is {@code null},
* which means that this logger's effective level is inherited
* from its parent, an empty string will be returned.
*
* @param loggerName The name of the {@code Logger} to be retrieved.
*
* @return The name of the log level of the specified logger; or
* an empty string if the log level of the specified logger
* is {@code null}. If the specified logger does not
* exist, {@code null} is returned.
*
* @see java.util.logging.Logger#getLevel
*/
String getLoggerLevel(String loggerName);
/**
* Sets the specified logger to the specified new
* {@linkplain java.util.logging.Logger#setLevel level}.
* If the {@code levelName} is not {@code null}, the level
* of the specified logger is set to the parsed
* {@link java.util.logging.Level Level}
* matching the {@code levelName}.
* If the {@code levelName} is {@code null}, the level
* of the specified logger is set to {@code null} and
* the effective level of the logger is inherited from
* its nearest ancestor with a specific (non-null) level value.
*
* @param loggerName The name of the {@code Logger} to be set.
* Must be non-null.
* @param levelName The name of the level to set on the specified logger,
* or {@code null} if setting the level to inherit
* from its nearest ancestor.
*
* @throws IllegalArgumentException if the specified logger
* does not exist, or {@code levelName} is not a valid level name.
*
* @throws SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control").
*
* @see java.util.logging.Logger#setLevel
*/
void setLoggerLevel(String loggerName, String levelName);
/**
* Returns the name of the
* {@linkplain java.util.logging.Logger#getParent parent}
* for the specified logger.
* If the specified logger does not exist, {@code null} is returned.
* If the specified logger is the root {@code Logger} in the namespace,
* the result will be an empty string.
*
* @param loggerName The name of a {@code Logger}.
*
* @return the name of the nearest existing parent logger;
* an empty string if the specified logger is the root logger.
* If the specified logger does not exist, {@code null}
* is returned.
*/
String getParentLoggerName(String loggerName);
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2008, 2011, 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 java.lang.management;
import javax.management.ObjectName;
/**
* A platform managed object is a {@linkplain javax.management.MXBean JMX MXBean}
* for monitoring and managing a component in the Java platform.
* Each platform managed object has a unique
* <a href="ManagementFactory.html#MXBean">object name</a>
* for the {@linkplain ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} access.
* All platform MXBeans will implement this interface.
*
* <p>
* Note:
* The platform MXBean interfaces (i.e. all subinterfaces
* of {@code PlatformManagedObject}) are implemented
* by the Java platform only. New methods may be added in these interfaces
* in future Java SE releases.
* In addition, this {@code PlatformManagedObject} interface is only
* intended for the management interfaces for the platform to extend but
* not for applications.
*
* @see ManagementFactory
* @since 1.7
*/
public interface PlatformManagedObject {
/**
* Returns an {@link ObjectName ObjectName} instance representing
* the object name of this platform managed object.
*
* @return an {@link ObjectName ObjectName} instance representing
* the object name of this platform managed object.
*/
public ObjectName getObjectName();
}

View file

@ -0,0 +1,342 @@
/*
* Copyright (c) 2003, 2017, 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 java.lang.management;
/**
* The management interface for the runtime system of
* the Java virtual machine.
*
* <p> A Java virtual machine has a single instance of the implementation
* class of this interface. This instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getRuntimeMXBean} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* the runtime system within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#RUNTIME_MXBEAN_NAME
* java.lang:type=Runtime}
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* <p> This interface defines several convenient methods for accessing
* system properties about the Java virtual machine.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface RuntimeMXBean extends PlatformManagedObject {
/**
* Returns the name representing the running Java virtual machine.
* The returned name string can be any arbitrary string and
* a Java virtual machine implementation can choose
* to embed platform-specific useful information in the
* returned name string. Each running virtual machine could have
* a different name.
*
* @return the name representing the running Java virtual machine.
*/
public String getName();
/**
* Returns the Java virtual machine implementation name.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.vm.name")}.
*
* @return the Java virtual machine implementation name.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getVmName();
/**
* Returns the Java virtual machine implementation vendor.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.vm.vendor")}.
*
* @return the Java virtual machine implementation vendor.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getVmVendor();
/**
* Returns the Java virtual machine implementation version.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.vm.version")}.
*
* @return the Java virtual machine implementation version.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getVmVersion();
/**
* Returns the Java virtual machine specification name.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.vm.specification.name")}.
*
* @return the Java virtual machine specification name.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getSpecName();
/**
* Returns the Java virtual machine specification vendor.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.vm.specification.vendor")}.
*
* @return the Java virtual machine specification vendor.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getSpecVendor();
/**
* Returns the Java virtual machine specification version.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.vm.specification.version")}.
*
* @return the Java virtual machine specification version.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getSpecVersion();
/**
* Returns the version of the specification for the management interface
* implemented by the running Java virtual machine.
*
* @return the version of the specification for the management interface
* implemented by the running Java virtual machine.
*/
public String getManagementSpecVersion();
/**
* Returns the Java class path that is used by the system class loader
* to search for class files.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.class.path")}.
*
* <p> Multiple paths in the Java class path are separated by the
* path separator character of the platform of the Java virtual machine
* being monitored.
*
* @return the Java class path.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getClassPath();
/**
* Returns the Java library path.
* This method is equivalent to {@link System#getProperty
* System.getProperty("java.library.path")}.
*
* <p> Multiple paths in the Java library path are separated by the
* path separator character of the platform of the Java virtual machine
* being monitored.
*
* @return the Java library path.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to this system property.
* @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperty
*/
public String getLibraryPath();
/**
* Tests if the Java virtual machine supports the boot class path
* mechanism used by the bootstrap class loader to search for class
* files.
*
* @return {@code true} if the Java virtual machine supports the
* class path mechanism; {@code false} otherwise.
*/
public boolean isBootClassPathSupported();
/**
* Returns the boot class path that is used by the bootstrap class loader
* to search for class files.
*
* <p> Multiple paths in the boot class path are separated by the
* path separator character of the platform on which the Java
* virtual machine is running.
*
* <p>A Java virtual machine implementation may not support
* the boot class path mechanism for the bootstrap class loader
* to search for class files.
* The {@link #isBootClassPathSupported} method can be used
* to determine if the Java virtual machine supports this method.
*
* @return the boot class path.
*
* @throws java.lang.UnsupportedOperationException
* if the Java virtual machine does not support this operation.
*
* @throws java.lang.SecurityException
* if a security manager exists and the caller does not have
* ManagementPermission("monitor").
*/
public String getBootClassPath();
/**
* Returns the input arguments passed to the Java virtual machine
* which does not include the arguments to the {@code main} method.
* This method returns an empty list if there is no input argument
* to the Java virtual machine.
* <p>
* Some Java virtual machine implementations may take input arguments
* from multiple different sources: for examples, arguments passed from
* the application that launches the Java virtual machine such as
* the 'java' command, environment variables, configuration files, etc.
* <p>
* Typically, not all command-line options to the 'java' command
* are passed to the Java virtual machine.
* Thus, the returned input arguments may not
* include all command-line options.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code List<String>} is {@code String[]}.
*
* @return a list of {@code String} objects; each element
* is an argument passed to the Java virtual machine.
*
* @throws java.lang.SecurityException
* if a security manager exists and the caller does not have
* ManagementPermission("monitor").
*/
public java.util.List<String> getInputArguments();
/**
* Returns the uptime of the Java virtual machine in milliseconds.
*
* @return uptime of the Java virtual machine in milliseconds.
*/
public long getUptime();
/**
* Returns the start time of the Java virtual machine in milliseconds.
* This method returns the approximate time when the Java virtual
* machine started.
*
* @return start time of the Java virtual machine in milliseconds.
*
*/
public long getStartTime();
/**
* Returns a map of names and values of all system properties.
* This method calls {@link System#getProperties} to get all
* system properties. Properties whose name or value is not
* a {@code String} are omitted.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code Map<String,String>} is
* {@link javax.management.openmbean.TabularData TabularData}
* with two items in each row as follows:
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">Name and Type for each item</caption>
* <thead>
* <tr>
* <th scope="col">Item Name</th>
* <th scope="col">Item Type</th>
* </tr>
* </thead>
* <tbody>
* <tr style="text-align:left">
* <th scope="row">{@code key}</th>
* <td>{@code String}</td>
* </tr>
* <tr>
* <th scope="row">{@code value}</th>
* <td>{@code String}</td>
* </tr>
* </tbody>
* </table>
*
* @return a map of names and values of all system properties.
*
* @throws java.lang.SecurityException
* if a security manager exists and its
* {@code checkPropertiesAccess} method doesn't allow access
* to the system properties.
*/
public java.util.Map<String, String> getSystemProperties();
}

View file

@ -0,0 +1,902 @@
/*
* Copyright (c) 2003, 2017, 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 java.lang.management;
import javax.management.openmbean.CompositeData;
import sun.management.ManagementFactoryHelper;
import sun.management.ThreadInfoCompositeData;
import static java.lang.Thread.State.*;
/**
* Thread information. {@code ThreadInfo} contains the information
* about a thread including:
* <h3>General thread information</h3>
* <ul>
* <li>Thread ID.</li>
* <li>Name of the thread.</li>
* <li>Whether a thread is a daemon thread</li>
* </ul>
*
* <h3>Execution information</h3>
* <ul>
* <li>Thread state.</li>
* <li>The object upon which the thread is blocked due to:
* <ul>
* <li>waiting to enter a synchronization block/method, or</li>
* <li>waiting to be notified in a {@link Object#wait Object.wait} method,
* or</li>
* <li>parking due to a {@link java.util.concurrent.locks.LockSupport#park
* LockSupport.park} call.</li>
* </ul>
* </li>
* <li>The ID of the thread that owns the object
* that the thread is blocked.</li>
* <li>Stack trace of the thread.</li>
* <li>List of object monitors locked by the thread.</li>
* <li>List of <a href="LockInfo.html#OwnableSynchronizer">
* ownable synchronizers</a> locked by the thread.</li>
* <li>Thread priority</li>
* </ul>
*
* <h4><a id="SyncStats">Synchronization Statistics</a></h4>
* <ul>
* <li>The number of times that the thread has blocked for
* synchronization or waited for notification.</li>
* <li>The accumulated elapsed time that the thread has blocked
* for synchronization or waited for notification
* since {@link ThreadMXBean#setThreadContentionMonitoringEnabled
* thread contention monitoring}
* was enabled. Some Java virtual machine implementation
* may not support this. The
* {@link ThreadMXBean#isThreadContentionMonitoringSupported()}
* method can be used to determine if a Java virtual machine
* supports this.</li>
* </ul>
*
* <p>This thread information class is designed for use in monitoring of
* the system, not for synchronization control.
*
* <h4>MXBean Mapping</h4>
* {@code ThreadInfo} is mapped to a {@link CompositeData CompositeData}
* with attributes as specified in
* the {@link #from from} method.
*
* @see ThreadMXBean#getThreadInfo
* @see ThreadMXBean#dumpAllThreads
*
* @author Mandy Chung
* @since 1.5
*/
public class ThreadInfo {
private String threadName;
private long threadId;
private long blockedTime;
private long blockedCount;
private long waitedTime;
private long waitedCount;
private LockInfo lock;
private String lockName;
private long lockOwnerId;
private String lockOwnerName;
private boolean daemon;
private boolean inNative;
private boolean suspended;
private Thread.State threadState;
private int priority;
private StackTraceElement[] stackTrace;
private MonitorInfo[] lockedMonitors;
private LockInfo[] lockedSynchronizers;
private static MonitorInfo[] EMPTY_MONITORS = new MonitorInfo[0];
private static LockInfo[] EMPTY_SYNCS = new LockInfo[0];
/**
* Constructor of ThreadInfo created by the JVM
*
* @param t Thread
* @param state Thread state
* @param lockObj Object on which the thread is blocked
* @param lockOwner the thread holding the lock
* @param blockedCount Number of times blocked to enter a lock
* @param blockedTime Approx time blocked to enter a lock
* @param waitedCount Number of times waited on a lock
* @param waitedTime Approx time waited on a lock
* @param stackTrace Thread stack trace
*/
private ThreadInfo(Thread t, int state, Object lockObj, Thread lockOwner,
long blockedCount, long blockedTime,
long waitedCount, long waitedTime,
StackTraceElement[] stackTrace) {
initialize(t, state, lockObj, lockOwner,
blockedCount, blockedTime,
waitedCount, waitedTime, stackTrace,
EMPTY_MONITORS, EMPTY_SYNCS);
}
/**
* Constructor of ThreadInfo created by the JVM
* for {@link ThreadMXBean#getThreadInfo(long[],boolean,boolean)}
* and {@link ThreadMXBean#dumpAllThreads}
*
* @param t Thread
* @param state Thread state
* @param lockObj Object on which the thread is blocked
* @param lockOwner the thread holding the lock
* @param blockedCount Number of times blocked to enter a lock
* @param blockedTime Approx time blocked to enter a lock
* @param waitedCount Number of times waited on a lock
* @param waitedTime Approx time waited on a lock
* @param stackTrace Thread stack trace
* @param monitors List of locked monitors
* @param stackDepths List of stack depths
* @param synchronizers List of locked synchronizers
*/
private ThreadInfo(Thread t, int state, Object lockObj, Thread lockOwner,
long blockedCount, long blockedTime,
long waitedCount, long waitedTime,
StackTraceElement[] stackTrace,
Object[] monitors,
int[] stackDepths,
Object[] synchronizers) {
int numMonitors = (monitors == null ? 0 : monitors.length);
MonitorInfo[] lockedMonitors;
if (numMonitors == 0) {
lockedMonitors = EMPTY_MONITORS;
} else {
lockedMonitors = new MonitorInfo[numMonitors];
for (int i = 0; i < numMonitors; i++) {
Object lock = monitors[i];
String className = lock.getClass().getName();
int identityHashCode = System.identityHashCode(lock);
int depth = stackDepths[i];
StackTraceElement ste = (depth >= 0 ? stackTrace[depth]
: null);
lockedMonitors[i] = new MonitorInfo(className,
identityHashCode,
depth,
ste);
}
}
int numSyncs = (synchronizers == null ? 0 : synchronizers.length);
LockInfo[] lockedSynchronizers;
if (numSyncs == 0) {
lockedSynchronizers = EMPTY_SYNCS;
} else {
lockedSynchronizers = new LockInfo[numSyncs];
for (int i = 0; i < numSyncs; i++) {
Object lock = synchronizers[i];
String className = lock.getClass().getName();
int identityHashCode = System.identityHashCode(lock);
lockedSynchronizers[i] = new LockInfo(className,
identityHashCode);
}
}
initialize(t, state, lockObj, lockOwner,
blockedCount, blockedTime,
waitedCount, waitedTime, stackTrace,
lockedMonitors, lockedSynchronizers);
}
/**
* Initialize ThreadInfo object
*
* @param t Thread
* @param state Thread state
* @param lockObj Object on which the thread is blocked
* @param lockOwner the thread holding the lock
* @param blockedCount Number of times blocked to enter a lock
* @param blockedTime Approx time blocked to enter a lock
* @param waitedCount Number of times waited on a lock
* @param waitedTime Approx time waited on a lock
* @param stackTrace Thread stack trace
* @param lockedMonitors List of locked monitors
* @param lockedSynchronizers List of locked synchronizers
*/
private void initialize(Thread t, int state, Object lockObj, Thread lockOwner,
long blockedCount, long blockedTime,
long waitedCount, long waitedTime,
StackTraceElement[] stackTrace,
MonitorInfo[] lockedMonitors,
LockInfo[] lockedSynchronizers) {
this.threadId = t.getId();
this.threadName = t.getName();
this.threadState = ManagementFactoryHelper.toThreadState(state);
this.suspended = ManagementFactoryHelper.isThreadSuspended(state);
this.inNative = ManagementFactoryHelper.isThreadRunningNative(state);
this.blockedCount = blockedCount;
this.blockedTime = blockedTime;
this.waitedCount = waitedCount;
this.waitedTime = waitedTime;
this.daemon = t.isDaemon();
this.priority = t.getPriority();
if (lockObj == null) {
this.lock = null;
this.lockName = null;
} else {
this.lock = new LockInfo(lockObj);
this.lockName =
lock.getClassName() + '@' +
Integer.toHexString(lock.getIdentityHashCode());
}
if (lockOwner == null) {
this.lockOwnerId = -1;
this.lockOwnerName = null;
} else {
this.lockOwnerId = lockOwner.getId();
this.lockOwnerName = lockOwner.getName();
}
if (stackTrace == null) {
this.stackTrace = NO_STACK_TRACE;
} else {
this.stackTrace = stackTrace;
}
this.lockedMonitors = lockedMonitors;
this.lockedSynchronizers = lockedSynchronizers;
}
/*
* Constructs a {@code ThreadInfo} object from a
* {@link CompositeData CompositeData}.
*/
private ThreadInfo(CompositeData cd) {
ThreadInfoCompositeData ticd = ThreadInfoCompositeData.getInstance(cd);
threadId = ticd.threadId();
threadName = ticd.threadName();
blockedTime = ticd.blockedTime();
blockedCount = ticd.blockedCount();
waitedTime = ticd.waitedTime();
waitedCount = ticd.waitedCount();
lockName = ticd.lockName();
lockOwnerId = ticd.lockOwnerId();
lockOwnerName = ticd.lockOwnerName();
threadState = ticd.threadState();
suspended = ticd.suspended();
inNative = ticd.inNative();
stackTrace = ticd.stackTrace();
// 6.0 attributes
if (ticd.hasV6()) {
lock = ticd.lockInfo();
lockedMonitors = ticd.lockedMonitors();
lockedSynchronizers = ticd.lockedSynchronizers();
} else {
// lockInfo is a new attribute added in 1.6 ThreadInfo
// If cd is a 5.0 version, construct the LockInfo object
// from the lockName value.
if (lockName != null) {
String result[] = lockName.split("@");
if (result.length == 2) {
int identityHashCode = Integer.parseInt(result[1], 16);
lock = new LockInfo(result[0], identityHashCode);
} else {
assert result.length == 2;
lock = null;
}
} else {
lock = null;
}
lockedMonitors = EMPTY_MONITORS;
lockedSynchronizers = EMPTY_SYNCS;
}
// 9.0 attributes
if (ticd.isCurrentVersion()) {
daemon = ticd.isDaemon();
priority = ticd.getPriority();
} else {
// Not ideal, but unclear what else we can do.
daemon = false;
priority = Thread.NORM_PRIORITY;
}
}
/**
* Returns the ID of the thread associated with this {@code ThreadInfo}.
*
* @return the ID of the associated thread.
*/
public long getThreadId() {
return threadId;
}
/**
* Returns the name of the thread associated with this {@code ThreadInfo}.
*
* @return the name of the associated thread.
*/
public String getThreadName() {
return threadName;
}
/**
* Returns the state of the thread associated with this {@code ThreadInfo}.
*
* @return {@code Thread.State} of the associated thread.
*/
public Thread.State getThreadState() {
return threadState;
}
/**
* Returns the approximate accumulated elapsed time (in milliseconds)
* that the thread associated with this {@code ThreadInfo}
* has blocked to enter or reenter a monitor
* since thread contention monitoring is enabled.
* I.e. the total accumulated time the thread has been in the
* {@link java.lang.Thread.State#BLOCKED BLOCKED} state since thread
* contention monitoring was last enabled.
* This method returns {@code -1} if thread contention monitoring
* is disabled.
*
* <p>The Java virtual machine may measure the time with a high
* resolution timer. This statistic is reset when
* the thread contention monitoring is reenabled.
*
* @return the approximate accumulated elapsed time in milliseconds
* that a thread entered the {@code BLOCKED} state;
* {@code -1} if thread contention monitoring is disabled.
*
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support this operation.
*
* @see ThreadMXBean#isThreadContentionMonitoringSupported
* @see ThreadMXBean#setThreadContentionMonitoringEnabled
*/
public long getBlockedTime() {
return blockedTime;
}
/**
* Returns the total number of times that
* the thread associated with this {@code ThreadInfo}
* blocked to enter or reenter a monitor.
* I.e. the number of times a thread has been in the
* {@link java.lang.Thread.State#BLOCKED BLOCKED} state.
*
* @return the total number of times that the thread
* entered the {@code BLOCKED} state.
*/
public long getBlockedCount() {
return blockedCount;
}
/**
* Returns the approximate accumulated elapsed time (in milliseconds)
* that the thread associated with this {@code ThreadInfo}
* has waited for notification
* since thread contention monitoring is enabled.
* I.e. the total accumulated time the thread has been in the
* {@link java.lang.Thread.State#WAITING WAITING}
* or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
* since thread contention monitoring is enabled.
* This method returns {@code -1} if thread contention monitoring
* is disabled.
*
* <p>The Java virtual machine may measure the time with a high
* resolution timer. This statistic is reset when
* the thread contention monitoring is reenabled.
*
* @return the approximate accumulated elapsed time in milliseconds
* that a thread has been in the {@code WAITING} or
* {@code TIMED_WAITING} state;
* {@code -1} if thread contention monitoring is disabled.
*
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support this operation.
*
* @see ThreadMXBean#isThreadContentionMonitoringSupported
* @see ThreadMXBean#setThreadContentionMonitoringEnabled
*/
public long getWaitedTime() {
return waitedTime;
}
/**
* Returns the total number of times that
* the thread associated with this {@code ThreadInfo}
* waited for notification.
* I.e. the number of times that a thread has been
* in the {@link java.lang.Thread.State#WAITING WAITING}
* or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state.
*
* @return the total number of times that the thread
* was in the {@code WAITING} or {@code TIMED_WAITING} state.
*/
public long getWaitedCount() {
return waitedCount;
}
/**
* Returns the {@code LockInfo} of an object for which
* the thread associated with this {@code ThreadInfo}
* is blocked waiting.
* A thread can be blocked waiting for one of the following:
* <ul>
* <li>an object monitor to be acquired for entering or reentering
* a synchronization block/method.
* <br>The thread is in the {@link java.lang.Thread.State#BLOCKED BLOCKED}
* state waiting to enter the {@code synchronized} statement
* or method.
* </li>
* <li>an object monitor to be notified by another thread.
* <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING}
* or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
* due to a call to the {@link Object#wait Object.wait} method.
* </li>
* <li>a synchronization object responsible for the thread parking.
* <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING}
* or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
* due to a call to the
* {@link java.util.concurrent.locks.LockSupport#park(Object)
* LockSupport.park} method. The synchronization object
* is the object returned from
* {@link java.util.concurrent.locks.LockSupport#getBlocker
* LockSupport.getBlocker} method. Typically it is an
* <a href="LockInfo.html#OwnableSynchronizer"> ownable synchronizer</a>
* or a {@link java.util.concurrent.locks.Condition Condition}.</li>
* </ul>
*
* <p>This method returns {@code null} if the thread is not in any of
* the above conditions.
*
* @return {@code LockInfo} of an object for which the thread
* is blocked waiting if any; {@code null} otherwise.
* @since 1.6
*/
public LockInfo getLockInfo() {
return lock;
}
/**
* Returns the {@link LockInfo#toString string representation}
* of an object for which the thread associated with this
* {@code ThreadInfo} is blocked waiting.
* This method is equivalent to calling:
* <blockquote>
* <pre>
* getLockInfo().toString()
* </pre></blockquote>
*
* <p>This method will return {@code null} if this thread is not blocked
* waiting for any object or if the object is not owned by any thread.
*
* @return the string representation of the object on which
* the thread is blocked if any;
* {@code null} otherwise.
*
* @see #getLockInfo
*/
public String getLockName() {
return lockName;
}
/**
* Returns the ID of the thread which owns the object
* for which the thread associated with this {@code ThreadInfo}
* is blocked waiting.
* This method will return {@code -1} if this thread is not blocked
* waiting for any object or if the object is not owned by any thread.
*
* @return the thread ID of the owner thread of the object
* this thread is blocked on;
* {@code -1} if this thread is not blocked
* or if the object is not owned by any thread.
*
* @see #getLockInfo
*/
public long getLockOwnerId() {
return lockOwnerId;
}
/**
* Returns the name of the thread which owns the object
* for which the thread associated with this {@code ThreadInfo}
* is blocked waiting.
* This method will return {@code null} if this thread is not blocked
* waiting for any object or if the object is not owned by any thread.
*
* @return the name of the thread that owns the object
* this thread is blocked on;
* {@code null} if this thread is not blocked
* or if the object is not owned by any thread.
*
* @see #getLockInfo
*/
public String getLockOwnerName() {
return lockOwnerName;
}
/**
* Returns the stack trace of the thread
* associated with this {@code ThreadInfo}.
* If no stack trace was requested for this thread info, this method
* will return a zero-length array.
* If the returned array is of non-zero length then the first element of
* the array represents the top of the stack, which is the most recent
* method invocation in the sequence. The last element of the array
* represents the bottom of the stack, which is the least recent method
* invocation in the sequence.
*
* <p>Some Java virtual machines may, under some circumstances, omit one
* or more stack frames from the stack trace. In the extreme case,
* a virtual machine that has no stack trace information concerning
* the thread associated with this {@code ThreadInfo}
* is permitted to return a zero-length array from this method.
*
* @return an array of {@code StackTraceElement} objects of the thread.
*/
public StackTraceElement[] getStackTrace() {
return stackTrace.clone();
}
/**
* Tests if the thread associated with this {@code ThreadInfo}
* is suspended. This method returns {@code true} if
* {@link Thread#suspend} has been called.
*
* @return {@code true} if the thread is suspended;
* {@code false} otherwise.
*/
public boolean isSuspended() {
return suspended;
}
/**
* Tests if the thread associated with this {@code ThreadInfo}
* is executing native code via the Java Native Interface (JNI).
* The JNI native code does not include
* the virtual machine support code or the compiled native
* code generated by the virtual machine.
*
* @return {@code true} if the thread is executing native code;
* {@code false} otherwise.
*/
public boolean isInNative() {
return inNative;
}
/**
* Tests if the thread associated with this {@code ThreadInfo} is
* a {@linkplain Thread#isDaemon daemon thread}.
*
* @return {@code true} if the thread is a daemon thread,
* {@code false} otherwise.
* @see Thread#isDaemon
* @since 9
*/
public boolean isDaemon() {
return daemon;
}
/**
* Returns the {@linkplain Thread#getPriority() thread priority} of the
* thread associated with this {@code ThreadInfo}.
*
* @return The priority of the thread associated with this
* {@code ThreadInfo}.
* @since 9
*/
public int getPriority() {
return priority;
}
/**
* Returns a string representation of this thread info.
* The format of this string depends on the implementation.
* The returned string will typically include
* the {@linkplain #getThreadName thread name},
* the {@linkplain #getThreadId thread ID},
* its {@linkplain #getThreadState state},
* and a {@linkplain #getStackTrace stack trace} if any.
*
* @return a string representation of this thread info.
*/
public String toString() {
StringBuilder sb = new StringBuilder("\"" + getThreadName() + "\"" +
(daemon ? " daemon" : "") +
" prio=" + priority +
" Id=" + getThreadId() + " " +
getThreadState());
if (getLockName() != null) {
sb.append(" on " + getLockName());
}
if (getLockOwnerName() != null) {
sb.append(" owned by \"" + getLockOwnerName() +
"\" Id=" + getLockOwnerId());
}
if (isSuspended()) {
sb.append(" (suspended)");
}
if (isInNative()) {
sb.append(" (in native)");
}
sb.append('\n');
int i = 0;
for (; i < stackTrace.length && i < MAX_FRAMES; i++) {
StackTraceElement ste = stackTrace[i];
sb.append("\tat " + ste.toString());
sb.append('\n');
if (i == 0 && getLockInfo() != null) {
Thread.State ts = getThreadState();
switch (ts) {
case BLOCKED:
sb.append("\t- blocked on " + getLockInfo());
sb.append('\n');
break;
case WAITING:
sb.append("\t- waiting on " + getLockInfo());
sb.append('\n');
break;
case TIMED_WAITING:
sb.append("\t- waiting on " + getLockInfo());
sb.append('\n');
break;
default:
}
}
for (MonitorInfo mi : lockedMonitors) {
if (mi.getLockedStackDepth() == i) {
sb.append("\t- locked " + mi);
sb.append('\n');
}
}
}
if (i < stackTrace.length) {
sb.append("\t...");
sb.append('\n');
}
LockInfo[] locks = getLockedSynchronizers();
if (locks.length > 0) {
sb.append("\n\tNumber of locked synchronizers = " + locks.length);
sb.append('\n');
for (LockInfo li : locks) {
sb.append("\t- " + li);
sb.append('\n');
}
}
sb.append('\n');
return sb.toString();
}
private static final int MAX_FRAMES = 8;
/**
* Returns a {@code ThreadInfo} object represented by the
* given {@code CompositeData}.
* The given {@code CompositeData} must contain the following attributes
* unless otherwise specified below:
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
* <thead>
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">threadId</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">threadName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">threadState</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">suspended</th>
* <td>{@code java.lang.Boolean}</td>
* </tr>
* <tr>
* <th scope="row">inNative</th>
* <td>{@code java.lang.Boolean}</td>
* </tr>
* <tr>
* <th scope="row">blockedCount</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">blockedTime</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">waitedCount</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">waitedTime</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">lockInfo</th>
* <td>{@code javax.management.openmbean.CompositeData}
* - the mapped type for {@link LockInfo} as specified in the
* {@link LockInfo#from} method.
* <p>
* If {@code cd} does not contain this attribute,
* the {@code LockInfo} object will be constructed from
* the value of the {@code lockName} attribute. </td>
* </tr>
* <tr>
* <th scope="row">lockName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerId</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row"><a id="StackTrace">stackTrace</a></th>
* <td>{@code javax.management.openmbean.CompositeData[]}
* <p>
* Each element is a {@code CompositeData} representing
* StackTraceElement containing the following attributes:
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
* <thead style="text-align:center">
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">moduleName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">moduleVersion</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">className</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">methodName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">fileName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">lineNumber</th>
* <td>{@code java.lang.Integer}</td>
* </tr>
* <tr>
* <th scope="row">nativeMethod</th>
* <td>{@code java.lang.Boolean}</td>
* </tr>
* </tbody>
* </table>
* </td>
* </tr>
* <tr>
* <th scope="row">lockedMonitors</th>
* <td>{@code javax.management.openmbean.CompositeData[]}
* whose element type is the mapped type for
* {@link MonitorInfo} as specified in the
* {@link MonitorInfo#from Monitor.from} method.
* <p>
* If {@code cd} does not contain this attribute,
* this attribute will be set to an empty array. </td>
* </tr>
* <tr>
* <th scope="row">lockedSynchronizers</th>
* <td>{@code javax.management.openmbean.CompositeData[]}
* whose element type is the mapped type for
* {@link LockInfo} as specified in the {@link LockInfo#from} method.
* <p>
* If {@code cd} does not contain this attribute,
* this attribute will be set to an empty array. </td>
* </tr>
* <tr>
* <th scope="row">daemon</th>
* <td>{@code java.lang.Boolean}</td>
* </tr>
* <tr>
* <th scope="row">priority</th>
* <td>{@code java.lang.Integer}</td>
* </tr>
* </tbody>
* </table>
*
* @param cd {@code CompositeData} representing a {@code ThreadInfo}
*
* @throws IllegalArgumentException if {@code cd} does not
* represent a {@code ThreadInfo} with the attributes described
* above.
*
* @return a {@code ThreadInfo} object represented
* by {@code cd} if {@code cd} is not {@code null};
* {@code null} otherwise.
*
* @revised 9
* @spec JPMS
*/
public static ThreadInfo from(CompositeData cd) {
if (cd == null) {
return null;
}
if (cd instanceof ThreadInfoCompositeData) {
return ((ThreadInfoCompositeData) cd).getThreadInfo();
} else {
return new ThreadInfo(cd);
}
}
/**
* Returns an array of {@link MonitorInfo} objects, each of which
* represents an object monitor currently locked by the thread
* associated with this {@code ThreadInfo}.
* If no locked monitor was requested for this thread info or
* no monitor is locked by the thread, this method
* will return a zero-length array.
*
* @return an array of {@code MonitorInfo} objects representing
* the object monitors locked by the thread.
*
* @since 1.6
*/
public MonitorInfo[] getLockedMonitors() {
return lockedMonitors.clone();
}
/**
* Returns an array of {@link LockInfo} objects, each of which
* represents an <a href="LockInfo.html#OwnableSynchronizer">ownable
* synchronizer</a> currently locked by the thread associated with
* this {@code ThreadInfo}. If no locked synchronizer was
* requested for this thread info or no synchronizer is locked by
* the thread, this method will return a zero-length array.
*
* @return an array of {@code LockInfo} objects representing
* the ownable synchronizers locked by the thread.
*
* @since 1.6
*/
public LockInfo[] getLockedSynchronizers() {
return lockedSynchronizers.clone();
}
private static final StackTraceElement[] NO_STACK_TRACE =
new StackTraceElement[0];
}

View file

@ -0,0 +1,806 @@
/*
* Copyright (c) 2003, 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 java.lang.management;
import java.util.Map;
/**
* The management interface for the thread system of
* the Java virtual machine.
*
* <p> A Java virtual machine has a single instance of the implementation
* class of this interface. This instance implementing this interface is
* an <a href="ManagementFactory.html#MXBean">MXBean</a>
* that can be obtained by calling
* the {@link ManagementFactory#getThreadMXBean} method or
* from the {@link ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} method.
*
* <p>The {@code ObjectName} for uniquely identifying the MXBean for
* the thread system within an MBeanServer is:
* <blockquote>
* {@link ManagementFactory#THREAD_MXBEAN_NAME
* java.lang:type=Threading}
* </blockquote>
*
* It can be obtained by calling the
* {@link PlatformManagedObject#getObjectName} method.
*
* <h3>Thread ID</h3>
* Thread ID is a positive long value returned by calling the
* {@link java.lang.Thread#getId} method for a thread.
* The thread ID is unique during its lifetime. When a thread
* is terminated, this thread ID may be reused.
*
* <p> Some methods in this interface take a thread ID or an array
* of thread IDs as the input parameter and return per-thread information.
*
* <h3>Thread CPU time</h3>
* A Java virtual machine implementation may support measuring
* the CPU time for the current thread, for any thread, or for no threads.
*
* <p>
* The {@link #isThreadCpuTimeSupported} method can be used to determine
* if a Java virtual machine supports measuring of the CPU time for any
* thread. The {@link #isCurrentThreadCpuTimeSupported} method can
* be used to determine if a Java virtual machine supports measuring of
* the CPU time for the current thread.
* A Java virtual machine implementation that supports CPU time measurement
* for any thread will also support that for the current thread.
*
* <p> The CPU time provided by this interface has nanosecond precision
* but not necessarily nanosecond accuracy.
*
* <p>
* A Java virtual machine may disable CPU time measurement
* by default.
* The {@link #isThreadCpuTimeEnabled} and {@link #setThreadCpuTimeEnabled}
* methods can be used to test if CPU time measurement is enabled
* and to enable/disable this support respectively.
* Enabling thread CPU measurement could be expensive in some
* Java virtual machine implementations.
*
* <h3>Thread Contention Monitoring</h3>
* Some Java virtual machines may support thread contention monitoring.
* When thread contention monitoring is enabled, the accumulated elapsed
* time that the thread has blocked for synchronization or waited for
* notification will be collected and returned in the
* <a href="ThreadInfo.html#SyncStats">{@code ThreadInfo}</a> object.
* <p>
* The {@link #isThreadContentionMonitoringSupported} method can be used to
* determine if a Java virtual machine supports thread contention monitoring.
* The thread contention monitoring is disabled by default. The
* {@link #setThreadContentionMonitoringEnabled} method can be used to enable
* thread contention monitoring.
*
* <h3>Synchronization Information and Deadlock Detection</h3>
* Some Java virtual machines may support monitoring of
* {@linkplain #isObjectMonitorUsageSupported object monitor usage} and
* {@linkplain #isSynchronizerUsageSupported ownable synchronizer usage}.
* The {@link #getThreadInfo(long[], boolean, boolean)} and
* {@link #dumpAllThreads} methods can be used to obtain the thread stack trace
* and synchronization information including which
* {@linkplain LockInfo <i>lock</i>} a thread is blocked to
* acquire or waiting on and which locks the thread currently owns.
* <p>
* The {@code ThreadMXBean} interface provides the
* {@link #findMonitorDeadlockedThreads} and
* {@link #findDeadlockedThreads} methods to find deadlocks in
* the running application.
*
* @see ManagementFactory#getPlatformMXBeans(Class)
* @see <a href="../../../javax/management/package-summary.html">
* JMX Specification.</a>
* @see <a href="package-summary.html#examples">
* Ways to Access MXBeans</a>
*
* @author Mandy Chung
* @since 1.5
*/
public interface ThreadMXBean extends PlatformManagedObject {
/**
* Returns the current number of live threads including both
* daemon and non-daemon threads.
*
* @return the current number of live threads.
*/
public int getThreadCount();
/**
* Returns the peak live thread count since the Java virtual machine
* started or peak was reset.
*
* @return the peak live thread count.
*/
public int getPeakThreadCount();
/**
* Returns the total number of threads created and also started
* since the Java virtual machine started.
*
* @return the total number of threads started.
*/
public long getTotalStartedThreadCount();
/**
* Returns the current number of live daemon threads.
*
* @return the current number of live daemon threads.
*/
public int getDaemonThreadCount();
/**
* Returns all live thread IDs.
* Some threads included in the returned array
* may have been terminated when this method returns.
*
* @return an array of {@code long}, each is a thread ID.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
*/
public long[] getAllThreadIds();
/**
* Returns the thread info for a thread of the specified
* {@code id} with no stack trace.
* This method is equivalent to calling:
* <blockquote>
* {@link #getThreadInfo(long, int) getThreadInfo(id, 0);}
* </blockquote>
*
* <p>
* This method returns a {@code ThreadInfo} object representing
* the thread information for the thread of the specified ID.
* The stack trace, locked monitors, and locked synchronizers
* in the returned {@code ThreadInfo} object will
* be empty.
*
* If a thread of the given ID is not alive or does not exist,
* this method will return {@code null}. A thread is alive if
* it has been started and has not yet died.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code ThreadInfo} is
* {@code CompositeData} with attributes as specified in the
* {@link ThreadInfo#from ThreadInfo.from} method.
*
* @param id the thread ID of the thread. Must be positive.
*
* @return a {@link ThreadInfo} object for the thread of the given ID
* with no stack trace, no locked monitor and no synchronizer info;
* {@code null} if the thread of the given ID is not alive or
* it does not exist.
*
* @throws IllegalArgumentException if {@code id <= 0}.
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
*/
public ThreadInfo getThreadInfo(long id);
/**
* Returns the thread info for each thread
* whose ID is in the input array {@code ids} with no stack trace.
* This method is equivalent to calling:
* <blockquote><pre>
* {@link #getThreadInfo(long[], int) getThreadInfo}(ids, 0);
* </pre></blockquote>
*
* <p>
* This method returns an array of the {@code ThreadInfo} objects.
* The stack trace, locked monitors, and locked synchronizers
* in each {@code ThreadInfo} object will be empty.
*
* If a thread of a given ID is not alive or does not exist,
* the corresponding element in the returned array will
* contain {@code null}. A thread is alive if
* it has been started and has not yet died.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code ThreadInfo} is
* {@code CompositeData} with attributes as specified in the
* {@link ThreadInfo#from ThreadInfo.from} method.
*
* @param ids an array of thread IDs.
* @return an array of the {@link ThreadInfo} objects, each containing
* information about a thread whose ID is in the corresponding
* element of the input array of IDs
* with no stack trace, no locked monitor and no synchronizer info.
*
* @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <= 0}.
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
*/
public ThreadInfo[] getThreadInfo(long[] ids);
/**
* Returns a thread info for a thread of the specified {@code id},
* with stack trace of a specified number of stack trace elements.
* The {@code maxDepth} parameter indicates the maximum number of
* {@link StackTraceElement} to be retrieved from the stack trace.
* If {@code maxDepth == Integer.MAX_VALUE}, the entire stack trace of
* the thread will be dumped.
* If {@code maxDepth == 0}, no stack trace of the thread
* will be dumped.
* This method does not obtain the locked monitors and locked
* synchronizers of the thread.
* <p>
* When the Java virtual machine has no stack trace information
* about a thread or {@code maxDepth == 0},
* the stack trace in the
* {@code ThreadInfo} object will be an empty array of
* {@code StackTraceElement}.
*
* <p>
* If a thread of the given ID is not alive or does not exist,
* this method will return {@code null}. A thread is alive if
* it has been started and has not yet died.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code ThreadInfo} is
* {@code CompositeData} with attributes as specified in the
* {@link ThreadInfo#from ThreadInfo.from} method.
*
* @param id the thread ID of the thread. Must be positive.
* @param maxDepth the maximum number of entries in the stack trace
* to be dumped. {@code Integer.MAX_VALUE} could be used to request
* the entire stack to be dumped.
*
* @return a {@link ThreadInfo} of the thread of the given ID
* with no locked monitor and synchronizer info.
* {@code null} if the thread of the given ID is not alive or
* it does not exist.
*
* @throws IllegalArgumentException if {@code id <= 0}.
* @throws IllegalArgumentException if {@code maxDepth is negative}.
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
*
*/
public ThreadInfo getThreadInfo(long id, int maxDepth);
/**
* Returns the thread info for each thread
* whose ID is in the input array {@code ids},
* with stack trace of a specified number of stack trace elements.
* The {@code maxDepth} parameter indicates the maximum number of
* {@link StackTraceElement} to be retrieved from the stack trace.
* If {@code maxDepth == Integer.MAX_VALUE}, the entire stack trace of
* the thread will be dumped.
* If {@code maxDepth == 0}, no stack trace of the thread
* will be dumped.
* This method does not obtain the locked monitors and locked
* synchronizers of the threads.
* <p>
* When the Java virtual machine has no stack trace information
* about a thread or {@code maxDepth == 0},
* the stack trace in the
* {@code ThreadInfo} object will be an empty array of
* {@code StackTraceElement}.
* <p>
* This method returns an array of the {@code ThreadInfo} objects,
* each is the thread information about the thread with the same index
* as in the {@code ids} array.
* If a thread of the given ID is not alive or does not exist,
* {@code null} will be set in the corresponding element
* in the returned array. A thread is alive if
* it has been started and has not yet died.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code ThreadInfo} is
* {@code CompositeData} with attributes as specified in the
* {@link ThreadInfo#from ThreadInfo.from} method.
*
* @param ids an array of thread IDs
* @param maxDepth the maximum number of entries in the stack trace
* to be dumped. {@code Integer.MAX_VALUE} could be used to request
* the entire stack to be dumped.
*
* @return an array of the {@link ThreadInfo} objects, each containing
* information about a thread whose ID is in the corresponding
* element of the input array of IDs with no locked monitor and
* synchronizer info.
*
* @throws IllegalArgumentException if {@code maxDepth is negative}.
* @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <= 0}.
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
*
*/
public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth);
/**
* Tests if the Java virtual machine supports thread contention monitoring.
*
* @return
* {@code true}
* if the Java virtual machine supports thread contention monitoring;
* {@code false} otherwise.
*/
public boolean isThreadContentionMonitoringSupported();
/**
* Tests if thread contention monitoring is enabled.
*
* @return {@code true} if thread contention monitoring is enabled;
* {@code false} otherwise.
*
* @throws java.lang.UnsupportedOperationException if the Java virtual
* machine does not support thread contention monitoring.
*
* @see #isThreadContentionMonitoringSupported
*/
public boolean isThreadContentionMonitoringEnabled();
/**
* Enables or disables thread contention monitoring.
* Thread contention monitoring is disabled by default.
*
* @param enable {@code true} to enable;
* {@code false} to disable.
*
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support thread contention monitoring.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*
* @see #isThreadContentionMonitoringSupported
*/
public void setThreadContentionMonitoringEnabled(boolean enable);
/**
* Returns the total CPU time for the current thread in nanoseconds.
* The returned value is of nanoseconds precision but
* not necessarily nanoseconds accuracy.
* If the implementation distinguishes between user mode time and system
* mode time, the returned CPU time is the amount of time that
* the current thread has executed in user mode or system mode.
*
* <p>
* This is a convenient method for local management use and is
* equivalent to calling:
* <blockquote><pre>
* {@link #getThreadCpuTime getThreadCpuTime}(Thread.currentThread().getId());
* </pre></blockquote>
*
* @return the total CPU time for the current thread if CPU time
* measurement is enabled; {@code -1} otherwise.
*
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
* the current thread.
*
* @see #getCurrentThreadUserTime
* @see #isCurrentThreadCpuTimeSupported
* @see #isThreadCpuTimeEnabled
* @see #setThreadCpuTimeEnabled
*/
public long getCurrentThreadCpuTime();
/**
* Returns the CPU time that the current thread has executed
* in user mode in nanoseconds.
* The returned value is of nanoseconds precision but
* not necessarily nanoseconds accuracy.
*
* <p>
* This is a convenient method for local management use and is
* equivalent to calling:
* <blockquote><pre>
* {@link #getThreadUserTime getThreadUserTime}(Thread.currentThread().getId());
* </pre></blockquote>
*
* @return the user-level CPU time for the current thread if CPU time
* measurement is enabled; {@code -1} otherwise.
*
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
* the current thread.
*
* @see #getCurrentThreadCpuTime
* @see #isCurrentThreadCpuTimeSupported
* @see #isThreadCpuTimeEnabled
* @see #setThreadCpuTimeEnabled
*/
public long getCurrentThreadUserTime();
/**
* Returns the total CPU time for a thread of the specified ID in nanoseconds.
* The returned value is of nanoseconds precision but
* not necessarily nanoseconds accuracy.
* If the implementation distinguishes between user mode time and system
* mode time, the returned CPU time is the amount of time that
* the thread has executed in user mode or system mode.
*
* <p>
* If the thread of the specified ID is not alive or does not exist,
* this method returns {@code -1}. If CPU time measurement
* is disabled, this method returns {@code -1}.
* A thread is alive if it has been started and has not yet died.
* <p>
* If CPU time measurement is enabled after the thread has started,
* the Java virtual machine implementation may choose any time up to
* and including the time that the capability is enabled as the point
* where CPU time measurement starts.
*
* @param id the thread ID of a thread
* @return the total CPU time for a thread of the specified ID
* if the thread of the specified ID exists, the thread is alive,
* and CPU time measurement is enabled;
* {@code -1} otherwise.
*
* @throws IllegalArgumentException if {@code id <= 0}.
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
* other threads.
*
* @see #getThreadUserTime
* @see #isThreadCpuTimeSupported
* @see #isThreadCpuTimeEnabled
* @see #setThreadCpuTimeEnabled
*/
public long getThreadCpuTime(long id);
/**
* Returns the CPU time that a thread of the specified ID
* has executed in user mode in nanoseconds.
* The returned value is of nanoseconds precision but
* not necessarily nanoseconds accuracy.
*
* <p>
* If the thread of the specified ID is not alive or does not exist,
* this method returns {@code -1}. If CPU time measurement
* is disabled, this method returns {@code -1}.
* A thread is alive if it has been started and has not yet died.
* <p>
* If CPU time measurement is enabled after the thread has started,
* the Java virtual machine implementation may choose any time up to
* and including the time that the capability is enabled as the point
* where CPU time measurement starts.
*
* @param id the thread ID of a thread
* @return the user-level CPU time for a thread of the specified ID
* if the thread of the specified ID exists, the thread is alive,
* and CPU time measurement is enabled;
* {@code -1} otherwise.
*
* @throws IllegalArgumentException if {@code id <= 0}.
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
* other threads.
*
* @see #getThreadCpuTime
* @see #isThreadCpuTimeSupported
* @see #isThreadCpuTimeEnabled
* @see #setThreadCpuTimeEnabled
*/
public long getThreadUserTime(long id);
/**
* Tests if the Java virtual machine implementation supports CPU time
* measurement for any thread.
* A Java virtual machine implementation that supports CPU time
* measurement for any thread will also support CPU time
* measurement for the current thread.
*
* @return
* {@code true}
* if the Java virtual machine supports CPU time
* measurement for any thread;
* {@code false} otherwise.
*/
public boolean isThreadCpuTimeSupported();
/**
* Tests if the Java virtual machine supports CPU time
* measurement for the current thread.
* This method returns {@code true} if {@link #isThreadCpuTimeSupported}
* returns {@code true}.
*
* @return
* {@code true}
* if the Java virtual machine supports CPU time
* measurement for current thread;
* {@code false} otherwise.
*/
public boolean isCurrentThreadCpuTimeSupported();
/**
* Tests if thread CPU time measurement is enabled.
*
* @return {@code true} if thread CPU time measurement is enabled;
* {@code false} otherwise.
*
* @throws java.lang.UnsupportedOperationException if the Java virtual
* machine does not support CPU time measurement for other threads
* nor for the current thread.
*
* @see #isThreadCpuTimeSupported
* @see #isCurrentThreadCpuTimeSupported
*/
public boolean isThreadCpuTimeEnabled();
/**
* Enables or disables thread CPU time measurement. The default
* is platform dependent.
*
* @param enable {@code true} to enable;
* {@code false} to disable.
*
* @throws java.lang.UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
* any threads nor for the current thread.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*
* @see #isThreadCpuTimeSupported
* @see #isCurrentThreadCpuTimeSupported
*/
public void setThreadCpuTimeEnabled(boolean enable);
/**
* Finds cycles of threads that are in deadlock waiting to acquire
* object monitors. That is, threads that are blocked waiting to enter a
* synchronization block or waiting to reenter a synchronization block
* after an {@link Object#wait Object.wait} call,
* where each thread owns one monitor while
* trying to obtain another monitor already held by another thread
* in a cycle.
* <p>
* More formally, a thread is <em>monitor deadlocked</em> if it is
* part of a cycle in the relation "is waiting for an object monitor
* owned by". In the simplest case, thread A is blocked waiting
* for a monitor owned by thread B, and thread B is blocked waiting
* for a monitor owned by thread A.
* <p>
* This method is designed for troubleshooting use, but not for
* synchronization control. It might be an expensive operation.
* <p>
* This method finds deadlocks involving only object monitors.
* To find deadlocks involving both object monitors and
* <a href="LockInfo.html#OwnableSynchronizer">ownable synchronizers</a>,
* the {@link #findDeadlockedThreads findDeadlockedThreads} method
* should be used.
*
* @return an array of IDs of the threads that are monitor
* deadlocked, if any; {@code null} otherwise.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
*
* @see #findDeadlockedThreads
*/
public long[] findMonitorDeadlockedThreads();
/**
* Resets the peak thread count to the current number of
* live threads.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("control").
*
* @see #getPeakThreadCount
* @see #getThreadCount
*/
public void resetPeakThreadCount();
/**
* Finds cycles of threads that are in deadlock waiting to acquire
* object monitors or
* <a href="LockInfo.html#OwnableSynchronizer">ownable synchronizers</a>.
*
* Threads are <em>deadlocked</em> in a cycle waiting for a lock of
* these two types if each thread owns one lock while
* trying to acquire another lock already held
* by another thread in the cycle.
* <p>
* This method is designed for troubleshooting use, but not for
* synchronization control. It might be an expensive operation.
*
* @return an array of IDs of the threads that are
* deadlocked waiting for object monitors or ownable synchronizers, if any;
* {@code null} otherwise.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException if the Java virtual
* machine does not support monitoring of ownable synchronizer usage.
*
* @see #isSynchronizerUsageSupported
* @see #findMonitorDeadlockedThreads
* @since 1.6
*/
public long[] findDeadlockedThreads();
/**
* Tests if the Java virtual machine supports monitoring of
* object monitor usage.
*
* @return
* {@code true}
* if the Java virtual machine supports monitoring of
* object monitor usage;
* {@code false} otherwise.
*
* @see #dumpAllThreads
* @since 1.6
*/
public boolean isObjectMonitorUsageSupported();
/**
* Tests if the Java virtual machine supports monitoring of
* <a href="LockInfo.html#OwnableSynchronizer">
* ownable synchronizer</a> usage.
*
* @return
* {@code true}
* if the Java virtual machine supports monitoring of ownable
* synchronizer usage;
* {@code false} otherwise.
*
* @see #dumpAllThreads
* @since 1.6
*/
public boolean isSynchronizerUsageSupported();
/**
* Returns the thread info for each thread
* whose ID is in the input array {@code ids}, with stack trace
* and synchronization information.
*
* <p>
* This method obtains a snapshot of the thread information
* for each thread including:
* <ul>
* <li>the entire stack trace,</li>
* <li>the object monitors currently locked by the thread
* if {@code lockedMonitors} is {@code true}, and</li>
* <li>the <a href="LockInfo.html#OwnableSynchronizer">
* ownable synchronizers</a> currently locked by the thread
* if {@code lockedSynchronizers} is {@code true}.</li>
* </ul>
* <p>
* This method returns an array of the {@code ThreadInfo} objects,
* each is the thread information about the thread with the same index
* as in the {@code ids} array.
* If a thread of the given ID is not alive or does not exist,
* {@code null} will be set in the corresponding element
* in the returned array. A thread is alive if
* it has been started and has not yet died.
* <p>
* If a thread does not lock any object monitor or {@code lockedMonitors}
* is {@code false}, the returned {@code ThreadInfo} object will have an
* empty {@code MonitorInfo} array. Similarly, if a thread does not
* lock any synchronizer or {@code lockedSynchronizers} is {@code false},
* the returned {@code ThreadInfo} object
* will have an empty {@code LockInfo} array.
*
* <p>
* When both {@code lockedMonitors} and {@code lockedSynchronizers}
* parameters are {@code false}, it is equivalent to calling:
* <blockquote><pre>
* {@link #getThreadInfo(long[], int) getThreadInfo(ids, Integer.MAX_VALUE)}
* </pre></blockquote>
*
* <p>
* This method is designed for troubleshooting use, but not for
* synchronization control. It might be an expensive operation.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of {@code ThreadInfo} is
* {@code CompositeData} with attributes as specified in the
* {@link ThreadInfo#from ThreadInfo.from} method.
*
* @param ids an array of thread IDs.
* @param lockedMonitors if {@code true}, retrieves all locked monitors.
* @param lockedSynchronizers if {@code true}, retrieves all locked
* ownable synchronizers.
*
* @return an array of the {@link ThreadInfo} objects, each containing
* information about a thread whose ID is in the corresponding
* element of the input array of IDs.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException
* <ul>
* <li>if {@code lockedMonitors} is {@code true} but
* the Java virtual machine does not support monitoring
* of {@linkplain #isObjectMonitorUsageSupported
* object monitor usage}; or</li>
* <li>if {@code lockedSynchronizers} is {@code true} but
* the Java virtual machine does not support monitoring
* of {@linkplain #isSynchronizerUsageSupported
* ownable synchronizer usage}.</li>
* </ul>
*
* @see #isObjectMonitorUsageSupported
* @see #isSynchronizerUsageSupported
*
* @since 1.6
*/
public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers);
/**
* Returns the thread info for all live threads with stack trace
* and synchronization information.
* Some threads included in the returned array
* may have been terminated when this method returns.
*
* <p>
* This method returns an array of {@link ThreadInfo} objects
* as specified in the {@link #getThreadInfo(long[], boolean, boolean)}
* method.
*
* @param lockedMonitors if {@code true}, dump all locked monitors.
* @param lockedSynchronizers if {@code true}, dump all locked
* ownable synchronizers.
*
* @return an array of {@link ThreadInfo} for all live threads.
*
* @throws java.lang.SecurityException if a security manager
* exists and the caller does not have
* ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException
* <ul>
* <li>if {@code lockedMonitors} is {@code true} but
* the Java virtual machine does not support monitoring
* of {@linkplain #isObjectMonitorUsageSupported
* object monitor usage}; or</li>
* <li>if {@code lockedSynchronizers} is {@code true} but
* the Java virtual machine does not support monitoring
* of {@linkplain #isSynchronizerUsageSupported
* ownable synchronizer usage}.</li>
* </ul>
*
* @see #isObjectMonitorUsageSupported
* @see #isSynchronizerUsageSupported
*
* @since 1.6
*/
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers);
}

View file

@ -0,0 +1,243 @@
<!--
Copyright (c) 2003, 2017, 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.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<body bgcolor="white">
Provides the management interfaces for monitoring and management of the
Java virtual machine and other components in the Java runtime.
It allows both local and remote
monitoring and management of the running Java virtual machine.
<h3><a id="MXBean">Platform MXBean</a></h3>
<p>
A platform MXBean is a <i>managed bean</i> that
conforms to the {@linkplain javax.management JMX}
Instrumentation Specification and only uses a set of basic data types.
Each platform MXBean is a {@link java.lang.management.PlatformManagedObject}
with a unique
{@linkplain java.lang.management.PlatformManagedObject#getObjectName name}.
<h3>ManagementFactory</h3>
<p>The {@link java.lang.management.ManagementFactory} class is the management
factory class for the Java platform. This class provides a set of
static factory methods to obtain the MXBeans for the Java platform
to allow an application to access the MXBeans directly.
<p>A <em>platform MBeanServer</em> can be accessed with the
{@link java.lang.management.ManagementFactory#getPlatformMBeanServer
getPlatformMBeanServer} method. On the first call to this method,
it creates the platform MBeanServer and registers all platform MXBeans
including {@linkplain java.lang.management.PlatformManagedObject
platform MXBeans}.
Each platform MXBean is registered with a unique name defined in
the specification of the management interface.
This is a single MBeanServer that can be shared by different managed
components running within the same Java virtual machine.
<h3>Interoperability</h3>
<p>A management application and a platform MBeanServer of a running
virtual machine can interoperate
without requiring classes used by the platform MXBean interfaces.
The data types being transmitted between the JMX connector
server and the connector client are JMX
{@linkplain javax.management.openmbean.OpenType open types} and
this allows interoperation across versions.
A data type used by the MXBean interfaces are mapped to an
open type when being accessed via MBeanServer interface.
See the <a href="{@docRoot}/javax/management/MXBean.html#MXBean-spec">
MXBean</a> specification for details.
<h3><a id="examples">Ways to Access MXBeans</a></h3>
<p>An application can monitor the instrumentation of the
Java virtual machine and the runtime in the following ways:
<p>
<b>1. Direct access to an MXBean interface</b>
<ul>
<li>Get an MXBean instance locally in the running Java virtual machine:
<pre>
RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// Get the standard attribute "VmVendor"
String vendor = mxbean.getVmVendor();
</pre>
<p>Or by calling the
{@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
getPlatformMXBean} or
{@link java.lang.management.ManagementFactory#getPlatformMXBeans(Class)
getPlatformMXBeans} method:
<pre>
RuntimeMXBean mxbean = ManagementFactory.getPlatformMXBean(RuntimeMXBean.class);
// Get the standard attribute "VmVendor"
String vendor = mxbean.getVmVendor();
</pre>
</li>
<li>Construct an MXBean proxy instance that forwards the
method calls to a given MBeanServer:
<pre>
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection
// that has the JVM MBeans registered in it
...
// Get a MBean proxy for RuntimeMXBean interface
RuntimeMXBean proxy =
{@link java.lang.management.ManagementFactory#getPlatformMXBean(MBeanServerConnection, Class)
ManagementFactory.getPlatformMXBean}(mbs,
RuntimeMXBean.class);
// Get standard attribute "VmVendor"
String vendor = proxy.getVmVendor();
</pre>
<p>A proxy is typically used to access an MXBean
in a remote Java virtual machine.
An alternative way to create an MXBean proxy is:
<pre>
RuntimeMXBean proxy =
{@link java.lang.management.ManagementFactory#newPlatformMXBeanProxy
ManagementFactory.newPlatformMXBeanProxy}(mbs,
ManagementFactory.RUNTIME_MXBEAN_NAME,
RuntimeMXBean.class);
</pre>
</li>
</ul>
<p>
<b>2. Indirect access to an MXBean interface via MBeanServer</b>
<ul>
<li>Go through the
{@link java.lang.management.ManagementFactory#getPlatformMBeanServer
platform MBeanServer} to access MXBeans locally or
a specific {@code MBeanServerConnection} to access
MXBeans remotely.
The attributes and operations of an MXBean use only
<em>JMX open types</em> which include basic data types,
{@link javax.management.openmbean.CompositeData CompositeData},
and {@link javax.management.openmbean.TabularData TabularData}
defined in {@link javax.management.openmbean.OpenType OpenType}.
<pre>
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection
// that has the JVM MXBeans registered in it
...
try {
// Assuming the RuntimeMXBean has been registered in mbs
ObjectName oname = new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);
// Get standard attribute "VmVendor"
String vendor = (String) mbs.getAttribute(oname, "VmVendor");
} catch (....) {
// Catch the exceptions thrown by ObjectName constructor
// and MBeanServer.getAttribute method
...
}
</pre>
</li>
</ul>
<h3><a id="extension">Platform Extension</a></h3>
<p>A Java virtual machine implementation may add its platform extension to
the management interface by defining platform-dependent
interfaces that extend the standard management interfaces to include
platform-specific metrics and management operations.
The static factory methods in the <code>ManagementFactory</code> class will
return the MXBeans with the platform extension.
<p>
It is recommended to name the platform-specific attributes with
a vendor-specific prefix such as the vendor's name to
avoid collisions of the attribute name between the future extension
to the standard management interface and the platform extension.
If the future extension to the standard management interface defines
a new attribute for a management interface and the attribute name
is happened to be same as some vendor-specific attribute's name,
the applications accessing that vendor-specific attribute would have
to be modified to cope with versioning and compatibility issues.
<p>Below is an example showing how to access an attribute
from the platform extension:
<p>
1) Direct access to the Oracle-specific MXBean interface
<blockquote>
<pre>
List&lt;com.sun.management.GarbageCollectorMXBean&gt; mxbeans =
ManagementFactory.getPlatformMXBeans(com.sun.management.GarbageCollectorMXBean.class);
for (com.sun.management.GarbageCollectorMXBean gc : mxbeans) {
// Get the standard attribute "CollectionCount"
String count = mxbean.getCollectionCount();
// Get the platform-specific attribute "LastGcInfo"
GcInfo gcinfo = gc.getLastGcInfo();
...
}
</pre>
</blockquote>
<p>
2) Access the Oracle-specific MXBean interface via <code>MBeanServer</code>
through proxy
<blockquote><pre>
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection
// that has the JVM MXBeans registered in it
...
List&lt;com.sun.management.GarbageCollectorMXBean&gt; mxbeans =
ManagementFactory.getPlatformMXBeans(mbs, com.sun.management.GarbageCollectorMXBean.class);
for (com.sun.management.GarbageCollectorMXBean gc : mxbeans) {
// Get the standard attribute "CollectionCount"
String count = mxbean.getCollectionCount();
// Get the platform-specific attribute "LastGcInfo"
GcInfo gcinfo = gc.getLastGcInfo();
...
}
</pre></blockquote>
<p> Unless otherwise noted, passing a <code>null</code> argument to a constructor
or method in any class or interface in this package will cause a {@link
java.lang.NullPointerException NullPointerException} to be thrown.
<p> The java.lang.management API is thread-safe.
@see {@linkplain javax.management JMX Specification}
@author Mandy Chung
@since 1.5
</body>
</html>

View file

@ -0,0 +1,107 @@
/*
* 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 javax.management;
/**
* This class is used by the query building mechanism to represent conjunctions
* of relational expressions.
* @serial include
*
* @since 1.5
*/
class AndQueryExp extends QueryEval implements QueryExp {
/* Serial version */
private static final long serialVersionUID = -1081892073854801359L;
/**
* @serial The first QueryExp of the conjunction
*/
private QueryExp exp1;
/**
* @serial The second QueryExp of the conjunction
*/
private QueryExp exp2;
/**
* Default constructor.
*/
public AndQueryExp() {
}
/**
* Creates a new AndQueryExp with q1 and q2 QueryExp.
*/
public AndQueryExp(QueryExp q1, QueryExp q2) {
exp1 = q1;
exp2 = q2;
}
/**
* Returns the left query expression.
*/
public QueryExp getLeftExp() {
return exp1;
}
/**
* Returns the right query expression.
*/
public QueryExp getRightExp() {
return exp2;
}
/**
* Applies the AndQueryExp on a MBean.
*
* @param name The name of the MBean on which the AndQueryExp will be applied.
*
* @return True if the query was successfully applied to the MBean, false otherwise.
*
*
* @exception BadStringOperationException The string passed to the method is invalid.
* @exception BadBinaryOpValueExpException The expression passed to the method is invalid.
* @exception BadAttributeValueExpException The attribute value passed to the method is invalid.
* @exception InvalidApplicationException An attempt has been made to apply a subquery expression to a
* managed object or a qualified attribute expression to a managed object of the wrong class.
*/
public boolean apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
return exp1.apply(name) && exp2.apply(name);
}
/**
* Returns a string representation of this AndQueryExp
*/
@Override
public String toString() {
return "(" + exp1 + ") and (" + exp2 + ")";
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 1999, 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 javax.management;
// java import
import java.io.Serializable;
/**
* Represents an MBean attribute by associating its name with its value.
* The MBean server and other objects use this class to get and set attributes values.
*
* @since 1.5
*/
public class Attribute implements Serializable {
/* Serial version */
private static final long serialVersionUID = 2484220110589082382L;
/**
* @serial Attribute name.
*/
private String name;
/**
* @serial Attribute value
*/
private Object value= null;
/**
* Constructs an Attribute object which associates the given attribute name with the given value.
*
* @param name A String containing the name of the attribute to be created. Cannot be null.
* @param value The Object which is assigned to the attribute. This object must be of the same type as the attribute.
*
*/
public Attribute(String name, Object value) {
if (name == null) {
throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name cannot be null "));
}
this.name = name;
this.value = value;
}
/**
* Returns a String containing the name of the attribute.
*
* @return the name of the attribute.
*/
public String getName() {
return name;
}
/**
* Returns an Object that is the value of this attribute.
*
* @return the value of the attribute.
*/
public Object getValue() {
return value;
}
/**
* Compares the current Attribute Object with another Attribute Object.
*
* @param object The Attribute that the current Attribute is to be compared with.
*
* @return True if the two Attribute objects are equal, otherwise false.
*/
public boolean equals(Object object) {
if (!(object instanceof Attribute)) {
return false;
}
Attribute val = (Attribute) object;
if (value == null) {
if (val.getValue() == null) {
return name.equals(val.getName());
} else {
return false;
}
}
return ((name.equals(val.getName())) &&
(value.equals(val.getValue())));
}
/**
* Returns a hash code value for this attribute.
*
* @return a hash code value for this attribute.
*/
public int hashCode() {
return name.hashCode() ^ (value == null ? 0 : value.hashCode());
}
/**
* Returns a String object representing this Attribute's value. The format of this
* string is not specified, but users can expect that two Attributes return the
* same string if and only if they are equal.
*/
public String toString() {
return getName() + " = " + getValue();
}
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 1999, 2003, 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 javax.management;
/**
* Provides definitions of the attribute change notifications sent by MBeans.
* <P>
* It's up to the MBean owning the attribute of interest to create and send
* attribute change notifications when the attribute change occurs.
* So the <CODE>NotificationBroadcaster</CODE> interface has to be implemented
* by any MBean for which an attribute change is of interest.
* <P>
* Example:
* If an MBean called <CODE>myMbean</CODE> needs to notify registered listeners
* when its attribute:
* <BLOCKQUOTE><CODE>
* String myString
* </CODE></BLOCKQUOTE>
* is modified, <CODE>myMbean</CODE> creates and emits the following notification:
* <BLOCKQUOTE><CODE>
* new AttributeChangeNotification(myMbean, sequenceNumber, timeStamp, msg,
* "myString", "String", oldValue, newValue);
* </CODE></BLOCKQUOTE>
*
* @since 1.5
*/
public class AttributeChangeNotification extends javax.management.Notification {
/* Serial version */
private static final long serialVersionUID = 535176054565814134L;
/**
* Notification type which indicates that the observed MBean attribute value has changed.
* <BR>The value of this type string is <CODE>jmx.attribute.change</CODE>.
*/
public static final String ATTRIBUTE_CHANGE = "jmx.attribute.change";
/**
* @serial The MBean attribute name.
*/
private String attributeName = null;
/**
* @serial The MBean attribute type.
*/
private String attributeType = null;
/**
* @serial The MBean attribute old value.
*/
private Object oldValue = null;
/**
* @serial The MBean attribute new value.
*/
private Object newValue = null;
/**
* Constructs an attribute change notification object.
* In addition to the information common to all notification, the caller must supply the name and type
* of the attribute, as well as its old and new values.
*
* @param source The notification producer, that is, the MBean the attribute belongs to.
* @param sequenceNumber The notification sequence number within the source object.
* @param timeStamp The date at which the notification is being sent.
* @param msg A String containing the message of the notification.
* @param attributeName A String giving the name of the attribute.
* @param attributeType A String containing the type of the attribute.
* @param oldValue An object representing value of the attribute before the change.
* @param newValue An object representing value of the attribute after the change.
*/
public AttributeChangeNotification(Object source, long sequenceNumber, long timeStamp, String msg,
String attributeName, String attributeType, Object oldValue, Object newValue) {
super(AttributeChangeNotification.ATTRIBUTE_CHANGE, source, sequenceNumber, timeStamp, msg);
this.attributeName = attributeName;
this.attributeType = attributeType;
this.oldValue = oldValue;
this.newValue = newValue;
}
/**
* Gets the name of the attribute which has changed.
*
* @return A String containing the name of the attribute.
*/
public String getAttributeName() {
return attributeName;
}
/**
* Gets the type of the attribute which has changed.
*
* @return A String containing the type of the attribute.
*/
public String getAttributeType() {
return attributeType;
}
/**
* Gets the old value of the attribute which has changed.
*
* @return An Object containing the old value of the attribute.
*/
public Object getOldValue() {
return oldValue;
}
/**
* Gets the new value of the attribute which has changed.
*
* @return An Object containing the new value of the attribute.
*/
public Object getNewValue() {
return newValue;
}
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 1999, 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 javax.management;
import java.util.Vector;
/**
* This class implements of the {@link javax.management.NotificationFilter NotificationFilter}
* interface for the {@link javax.management.AttributeChangeNotification attribute change notification}.
* The filtering is performed on the name of the observed attribute.
* <P>
* It manages a list of enabled attribute names.
* A method allows users to enable/disable as many attribute names as required.
*
* @since 1.5
*/
public class AttributeChangeNotificationFilter implements NotificationFilter {
/* Serial version */
private static final long serialVersionUID = -6347317584796410029L;
/**
* @serial {@link Vector} that contains the enabled attribute names.
* The default value is an empty vector.
*/
private Vector<String> enabledAttributes = new Vector<String>();
/**
* Invoked before sending the specified notification to the listener.
* <BR>This filter compares the attribute name of the specified attribute change notification
* with each enabled attribute name.
* If the attribute name equals one of the enabled attribute names,
* the notification must be sent to the listener and this method returns <CODE>true</CODE>.
*
* @param notification The attribute change notification to be sent.
* @return <CODE>true</CODE> if the notification has to be sent to the listener, <CODE>false</CODE> otherwise.
*/
public synchronized boolean isNotificationEnabled(Notification notification) {
String type = notification.getType();
if ((type == null) ||
(type.equals(AttributeChangeNotification.ATTRIBUTE_CHANGE) == false) ||
(!(notification instanceof AttributeChangeNotification))) {
return false;
}
String attributeName =
((AttributeChangeNotification)notification).getAttributeName();
return enabledAttributes.contains(attributeName);
}
/**
* Enables all the attribute change notifications the attribute name of which equals
* the specified name to be sent to the listener.
* <BR>If the specified name is already in the list of enabled attribute names,
* this method has no effect.
*
* @param name The attribute name.
* @exception java.lang.IllegalArgumentException The attribute name parameter is null.
*/
public synchronized void enableAttribute(String name) throws java.lang.IllegalArgumentException {
if (name == null) {
throw new java.lang.IllegalArgumentException("The name cannot be null.");
}
if (!enabledAttributes.contains(name)) {
enabledAttributes.addElement(name);
}
}
/**
* Disables all the attribute change notifications the attribute name of which equals
* the specified attribute name to be sent to the listener.
* <BR>If the specified name is not in the list of enabled attribute names,
* this method has no effect.
*
* @param name The attribute name.
*/
public synchronized void disableAttribute(String name) {
enabledAttributes.removeElement(name);
}
/**
* Disables all the attribute names.
*/
public synchronized void disableAllAttributes() {
enabledAttributes.removeAllElements();
}
/**
* Gets all the enabled attribute names for this filter.
*
* @return The list containing all the enabled attribute names.
*/
public synchronized Vector<String> getEnabledAttributes() {
return enabledAttributes;
}
}

View file

@ -0,0 +1,337 @@
/*
* 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 javax.management;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* <p>Represents a list of values for attributes of an MBean. See the
* {@link MBeanServerConnection#getAttributes getAttributes} and
* {@link MBeanServerConnection#setAttributes setAttributes} methods of
* {@link MBeanServer} and {@link MBeanServerConnection}.</p>
*
* <p id="type-safe">For compatibility reasons, it is possible, though
* highly discouraged, to add objects to an {@code AttributeList} that are
* not instances of {@code Attribute}. However, an {@code AttributeList}
* can be made <em>type-safe</em>, which means that an attempt to add
* an object that is not an {@code Attribute} will produce an {@code
* IllegalArgumentException}. An {@code AttributeList} becomes type-safe
* when the method {@link #asList()} is called on it.</p>
*
* @since 1.5
*/
/* We cannot extend ArrayList<Attribute> because our legacy
add(Attribute) method would then override add(E) in ArrayList<E>,
and our return value is void whereas ArrayList.add(E)'s is boolean.
Likewise for set(int,Attribute). Grrr. We cannot use covariance
to override the most important methods and have them return
Attribute, either, because that would break subclasses that
override those methods in turn (using the original return type
of Object). Finally, we cannot implement Iterable<Attribute>
so you could write
for (Attribute a : attributeList)
because ArrayList<> implements Iterable<> and the same class cannot
implement two versions of a generic interface. Instead we provide
the asList() method so you can write
for (Attribute a : attributeList.asList())
*/
public class AttributeList extends ArrayList<Object> {
private transient volatile boolean typeSafe;
private transient volatile boolean tainted;
/* Serial version */
private static final long serialVersionUID = -4077085769279709076L;
/**
* Constructs an empty <CODE>AttributeList</CODE>.
*/
public AttributeList() {
super();
}
/**
* Constructs an empty <CODE>AttributeList</CODE> with
* the initial capacity specified.
*
* @param initialCapacity the initial capacity of the
* <code>AttributeList</code>, as specified by {@link
* ArrayList#ArrayList(int)}.
*/
public AttributeList(int initialCapacity) {
super(initialCapacity);
}
/**
* Constructs an <CODE>AttributeList</CODE> containing the
* elements of the <CODE>AttributeList</CODE> specified, in the
* order in which they are returned by the
* <CODE>AttributeList</CODE>'s iterator. The
* <CODE>AttributeList</CODE> instance has an initial capacity of
* 110% of the size of the <CODE>AttributeList</CODE> specified.
*
* @param list the <code>AttributeList</code> that defines the initial
* contents of the new <code>AttributeList</code>.
*
* @see ArrayList#ArrayList(java.util.Collection)
*/
public AttributeList(AttributeList list) {
super(list);
}
/**
* Constructs an {@code AttributeList} containing the elements of the
* {@code List} specified, in the order in which they are returned by
* the {@code List}'s iterator.
*
* @param list the {@code List} that defines the initial contents of
* the new {@code AttributeList}.
*
* @exception IllegalArgumentException if the {@code list} parameter
* is {@code null} or if the {@code list} parameter contains any
* non-Attribute objects.
*
* @see ArrayList#ArrayList(java.util.Collection)
*
* @since 1.6
*/
public AttributeList(List<Attribute> list) {
// Check for null parameter
//
if (list == null)
throw new IllegalArgumentException("Null parameter");
// Check for non-Attribute objects
//
adding(list);
// Build the List<Attribute>
//
super.addAll(list);
}
/**
* Return a view of this list as a {@code List<Attribute>}.
* Changes to the returned value are reflected by changes
* to the original {@code AttributeList} and vice versa.
*
* @return a {@code List<Attribute>} whose contents
* reflect the contents of this {@code AttributeList}.
*
* <p>If this method has ever been called on a given
* {@code AttributeList} instance, a subsequent attempt to add
* an object to that instance which is not an {@code Attribute}
* will fail with an {@code IllegalArgumentException}. For compatibility
* reasons, an {@code AttributeList} on which this method has never
* been called does allow objects other than {@code Attribute}s to
* be added.</p>
*
* @throws IllegalArgumentException if this {@code AttributeList} contains
* an element that is not an {@code Attribute}.
*
* @since 1.6
*/
@SuppressWarnings("unchecked")
public List<Attribute> asList() {
typeSafe = true;
if (tainted)
adding((Collection<?>) this); // will throw IllegalArgumentException
return (List<Attribute>) (List<?>) this;
}
/**
* Adds the {@code Attribute} specified as the last element of the list.
*
* @param object The attribute to be added.
*/
public void add(Attribute object) {
super.add(object);
}
/**
* Inserts the attribute specified as an element at the position specified.
* Elements with an index greater than or equal to the current position are
* shifted up. If the index is out of range {@literal (index < 0 || index >
* size())} a RuntimeOperationsException should be raised, wrapping the
* java.lang.IndexOutOfBoundsException thrown.
*
* @param object The <CODE>Attribute</CODE> object to be inserted.
* @param index The position in the list where the new {@code Attribute}
* object is to be inserted.
*/
public void add(int index, Attribute object) {
try {
super.add(index, object);
}
catch (IndexOutOfBoundsException e) {
throw new RuntimeOperationsException(e,
"The specified index is out of range");
}
}
/**
* Sets the element at the position specified to be the attribute specified.
* The previous element at that position is discarded. If the index is
* out of range {@literal (index < 0 || index > size())} a RuntimeOperationsException
* should be raised, wrapping the java.lang.IndexOutOfBoundsException thrown.
*
* @param object The value to which the attribute element should be set.
* @param index The position specified.
*/
public void set(int index, Attribute object) {
try {
super.set(index, object);
}
catch (IndexOutOfBoundsException e) {
throw new RuntimeOperationsException(e,
"The specified index is out of range");
}
}
/**
* Appends all the elements in the <CODE>AttributeList</CODE> specified to
* the end of the list, in the order in which they are returned by the
* Iterator of the <CODE>AttributeList</CODE> specified.
*
* @param list Elements to be inserted into the list.
*
* @return true if this list changed as a result of the call.
*
* @see ArrayList#addAll(java.util.Collection)
*/
public boolean addAll(AttributeList list) {
return (super.addAll(list));
}
/**
* Inserts all of the elements in the <CODE>AttributeList</CODE> specified
* into this list, starting at the specified position, in the order in which
* they are returned by the Iterator of the {@code AttributeList} specified.
* If the index is out of range {@literal (index < 0 || index > size())} a
* RuntimeOperationsException should be raised, wrapping the
* java.lang.IndexOutOfBoundsException thrown.
*
* @param list Elements to be inserted into the list.
* @param index Position at which to insert the first element from the
* <CODE>AttributeList</CODE> specified.
*
* @return true if this list changed as a result of the call.
*
* @see ArrayList#addAll(int, java.util.Collection)
*/
public boolean addAll(int index, AttributeList list) {
try {
return super.addAll(index, list);
} catch (IndexOutOfBoundsException e) {
throw new RuntimeOperationsException(e,
"The specified index is out of range");
}
}
/*
* Override all of the methods from ArrayList<Object> that might add
* a non-Attribute to the List, and disallow that if asList has ever
* been called on this instance.
*/
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code element} is not an
* {@code Attribute}.
*/
@Override
public boolean add(Object element) {
adding(element);
return super.add(element);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code element} is not an
* {@code Attribute}.
*/
@Override
public void add(int index, Object element) {
adding(element);
super.add(index, element);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code c} contains an
* element that is not an {@code Attribute}.
*/
@Override
public boolean addAll(Collection<?> c) {
adding(c);
return super.addAll(c);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code c} contains an
* element that is not an {@code Attribute}.
*/
@Override
public boolean addAll(int index, Collection<?> c) {
adding(c);
return super.addAll(index, c);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code element} is not an
* {@code Attribute}.
*/
@Override
public Object set(int index, Object element) {
adding(element);
return super.set(index, element);
}
private void adding(Object x) {
if (x == null || x instanceof Attribute)
return;
if (typeSafe)
throw new IllegalArgumentException("Not an Attribute: " + x);
else
tainted = true;
}
private void adding(Collection<?> c) {
for (Object x : c)
adding(x);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 1999, 2003, 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 javax.management;
/**
* The specified attribute does not exist or cannot be retrieved.
*
* @since 1.5
*/
public class AttributeNotFoundException extends OperationsException {
/* Serial version */
private static final long serialVersionUID = 6511584241791106926L;
/**
* Default constructor.
*/
public AttributeNotFoundException() {
super();
}
/**
* Constructor that allows a specific error message to be specified.
*
* @param message detail message.
*/
public AttributeNotFoundException(String message) {
super(message);
}
}

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 1999, 2015, 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 javax.management;
import com.sun.jmx.mbeanserver.Introspector;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* <p>Represents attributes used as arguments to relational constraints.
* Instances of this class are usually obtained using {@link Query#attr(String)
* Query.attr}.</p>
*
* <p>An <CODE>AttributeValueExp</CODE> may be used anywhere a
* <CODE>ValueExp</CODE> is required.
*
* @since 1.5
*/
public class AttributeValueExp implements ValueExp {
/* Serial version */
private static final long serialVersionUID = -7768025046539163385L;
/**
* @serial The name of the attribute
*/
private String attr;
/**
* An <code>AttributeValueExp</code> with a null attribute.
* @deprecated An instance created with this constructor cannot be
* used in a query.
*/
@Deprecated
public AttributeValueExp() {
}
/**
* Creates a new <CODE>AttributeValueExp</CODE> representing the
* specified object attribute, named attr.
*
* @param attr the name of the attribute whose value is the value
* of this {@link ValueExp}.
*/
public AttributeValueExp(String attr) {
this.attr = attr;
}
/**
* Returns a string representation of the name of the attribute.
*
* @return the attribute name.
*/
public String getAttributeName() {
return attr;
}
/**
* <p>Applies the <CODE>AttributeValueExp</CODE> on an MBean.
* This method calls {@link #getAttribute getAttribute(name)} and wraps
* the result as a {@code ValueExp}. The value returned by
* {@code getAttribute} must be a {@code Number}, {@code String},
* or {@code Boolean}; otherwise this method throws a
* {@code BadAttributeValueExpException}, which will cause
* the containing query to be false for this {@code name}.</p>
*
* @param name The name of the MBean on which the <CODE>AttributeValueExp</CODE> will be applied.
*
* @return The <CODE>ValueExp</CODE>.
*
* @throws BadStringOperationException {@inheritDoc}
* @throws BadBinaryOpValueExpException {@inheritDoc}
* @throws BadAttributeValueExpException {@inheritDoc}
* @throws InvalidApplicationException {@inheritDoc}
*/
@Override
public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
Object result = getAttribute(name);
if (result instanceof Number) {
return new NumericValueExp((Number)result);
} else if (result instanceof String) {
return new StringValueExp((String)result);
} else if (result instanceof Boolean) {
return new BooleanValueExp((Boolean)result);
} else {
throw new BadAttributeValueExpException(result);
}
}
/**
* Returns the string representing its value.
*/
@Override
public String toString() {
return attr;
}
/**
* Sets the MBean server on which the query is to be performed.
*
* @param s The MBean server on which the query is to be performed.
*
* @deprecated This method has no effect. The MBean Server used to
* obtain an attribute value is {@link QueryEval#getMBeanServer()}.
*/
/* There is no need for this method, because if a query is being
evaluted an AttributeValueExp can only appear inside a QueryExp,
and that QueryExp will itself have done setMBeanServer. */
@Deprecated
@Override
public void setMBeanServer(MBeanServer s) {
}
/**
* <p>Return the value of the given attribute in the named MBean.
* If the attempt to access the attribute generates an exception,
* return null.</p>
*
* <p>The MBean Server used is the one returned by {@link
* QueryEval#getMBeanServer()}.</p>
*
* @param name the name of the MBean whose attribute is to be returned.
*
* @return the value of the attribute, or null if it could not be
* obtained.
*/
protected Object getAttribute(ObjectName name) {
try {
// Get the value from the MBeanServer
MBeanServer server = QueryEval.getMBeanServer();
return server.getAttribute(name, attr);
} catch (Exception re) {
return null;
}
}
}

View file

@ -0,0 +1,91 @@
/*
* 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 javax.management;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* Thrown when an invalid MBean attribute is passed to a query
* constructing method. This exception is used internally by JMX
* during the evaluation of a query. User code does not usually
* see it.
*
* @since 1.5
*/
public class BadAttributeValueExpException extends Exception {
/* Serial version */
private static final long serialVersionUID = -3105272988410493376L;
/**
* @serial A string representation of the attribute that originated this exception.
* for example, the string value can be the return of {@code attribute.toString()}
*/
private Object val;
/**
* Constructs a BadAttributeValueExpException using the specified Object to
* create the toString() value.
*
* @param val the inappropriate value.
*/
public BadAttributeValueExpException (Object val) {
this.val = val == null ? null : val.toString();
}
/**
* Returns the string representing the object.
*/
public String toString() {
return "BadAttributeValueException: " + val;
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);
if (valObj == null) {
val = null;
} else if (valObj instanceof String) {
val= valObj;
} else if (System.getSecurityManager() == null
|| valObj instanceof Long
|| valObj instanceof Integer
|| valObj instanceof Float
|| valObj instanceof Double
|| valObj instanceof Byte
|| valObj instanceof Short
|| valObj instanceof Boolean) {
val = valObj.toString();
} else { // the serialized object is from a version without JDK-8019292 fix
val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
}
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 1999, 2003, 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 javax.management;
/**
* Thrown when an invalid expression is passed to a method for
* constructing a query. This exception is used internally by JMX
* during the evaluation of a query. User code does not usually see
* it.
*
* @since 1.5
*/
public class BadBinaryOpValueExpException extends Exception {
/* Serial version */
private static final long serialVersionUID = 5068475589449021227L;
/**
* @serial the {@link ValueExp} that originated this exception
*/
private ValueExp exp;
/**
* Constructs a <CODE>BadBinaryOpValueExpException</CODE> with the specified <CODE>ValueExp</CODE>.
*
* @param exp the expression whose value was inappropriate.
*/
public BadBinaryOpValueExpException(ValueExp exp) {
this.exp = exp;
}
/**
* Returns the <CODE>ValueExp</CODE> that originated the exception.
*
* @return the problematic {@link ValueExp}.
*/
public ValueExp getExp() {
return exp;
}
/**
* Returns the string representing the object.
*/
public String toString() {
return "BadBinaryOpValueExpException: " + exp;
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 1999, 2003, 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 javax.management;
/**
* Thrown when an invalid string operation is passed
* to a method for constructing a query.
*
* @since 1.5
*/
public class BadStringOperationException extends Exception {
/* Serial version */
private static final long serialVersionUID = 7802201238441662100L;
/**
* @serial The description of the operation that originated this exception
*/
private String op;
/**
* Constructs a <CODE>BadStringOperationException</CODE> with the specified detail
* message.
*
* @param message the detail message.
*/
public BadStringOperationException(String message) {
this.op = message;
}
/**
* Returns the string representing the object.
*/
public String toString() {
return "BadStringOperationException: " + op;
}
}

View file

@ -0,0 +1,142 @@
/*
* 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 javax.management;
/**
* This class is used by the query-building mechanism to represent binary
* relations.
* @serial include
*
* @since 1.5
*/
class BetweenQueryExp extends QueryEval implements QueryExp {
/* Serial version */
private static final long serialVersionUID = -2933597532866307444L;
/**
* @serial The checked value
*/
private ValueExp exp1;
/**
* @serial The lower bound value
*/
private ValueExp exp2;
/**
* @serial The upper bound value
*/
private ValueExp exp3;
/**
* Basic Constructor.
*/
public BetweenQueryExp() {
}
/**
* Creates a new BetweenQueryExp with v1 checked value, v2 lower bound
* and v3 upper bound values.
*/
public BetweenQueryExp(ValueExp v1, ValueExp v2, ValueExp v3) {
exp1 = v1;
exp2 = v2;
exp3 = v3;
}
/**
* Returns the checked value of the query.
*/
public ValueExp getCheckedValue() {
return exp1;
}
/**
* Returns the lower bound value of the query.
*/
public ValueExp getLowerBound() {
return exp2;
}
/**
* Returns the upper bound value of the query.
*/
public ValueExp getUpperBound() {
return exp3;
}
/**
* Applies the BetweenQueryExp on an MBean.
*
* @param name The name of the MBean on which the BetweenQueryExp will be applied.
*
* @return True if the query was successfully applied to the MBean, false otherwise.
*
* @exception BadStringOperationException
* @exception BadBinaryOpValueExpException
* @exception BadAttributeValueExpException
* @exception InvalidApplicationException
*/
public boolean apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
ValueExp val1 = exp1.apply(name);
ValueExp val2 = exp2.apply(name);
ValueExp val3 = exp3.apply(name);
boolean numeric = val1 instanceof NumericValueExp;
if (numeric) {
if (((NumericValueExp)val1).isLong()) {
long lval1 = ((NumericValueExp)val1).longValue();
long lval2 = ((NumericValueExp)val2).longValue();
long lval3 = ((NumericValueExp)val3).longValue();
return lval2 <= lval1 && lval1 <= lval3;
} else {
double dval1 = ((NumericValueExp)val1).doubleValue();
double dval2 = ((NumericValueExp)val2).doubleValue();
double dval3 = ((NumericValueExp)val3).doubleValue();
return dval2 <= dval1 && dval1 <= dval3;
}
} else {
String sval1 = ((StringValueExp)val1).getValue();
String sval2 = ((StringValueExp)val2).getValue();
String sval3 = ((StringValueExp)val3).getValue();
return sval2.compareTo(sval1) <= 0 && sval1.compareTo(sval3) <= 0;
}
}
/**
* Returns the string representing the object.
*/
@Override
public String toString() {
return "(" + exp1 + ") between (" + exp2 + ") and (" + exp3 + ")";
}
}

View file

@ -0,0 +1,257 @@
/*
* 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 javax.management;
/**
* This class is used by the query-building mechanism to represent binary
* operations.
* @serial include
*
* @since 1.5
*/
class BinaryOpValueExp extends QueryEval implements ValueExp {
/* Serial version */
private static final long serialVersionUID = 1216286847881456786L;
/**
* @serial The operator
*/
private int op;
/**
* @serial The first value
*/
private ValueExp exp1;
/**
* @serial The second value
*/
private ValueExp exp2;
/**
* Basic Constructor.
*/
public BinaryOpValueExp() {
}
/**
* Creates a new BinaryOpValueExp using operator o applied on v1 and
* v2 values.
*/
public BinaryOpValueExp(int o, ValueExp v1, ValueExp v2) {
op = o;
exp1 = v1;
exp2 = v2;
}
/**
* Returns the operator of the value expression.
*/
public int getOperator() {
return op;
}
/**
* Returns the left value of the value expression.
*/
public ValueExp getLeftValue() {
return exp1;
}
/**
* Returns the right value of the value expression.
*/
public ValueExp getRightValue() {
return exp2;
}
/**
* Applies the BinaryOpValueExp on a MBean.
*
* @param name The name of the MBean on which the BinaryOpValueExp will be applied.
*
* @return The ValueExp.
*
* @exception BadStringOperationException
* @exception BadBinaryOpValueExpException
* @exception BadAttributeValueExpException
* @exception InvalidApplicationException
*/
public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
ValueExp val1 = exp1.apply(name);
ValueExp val2 = exp2.apply(name);
String sval1;
String sval2;
double dval1;
double dval2;
long lval1;
long lval2;
boolean numeric = val1 instanceof NumericValueExp;
if (numeric) {
if (((NumericValueExp)val1).isLong()) {
lval1 = ((NumericValueExp)val1).longValue();
lval2 = ((NumericValueExp)val2).longValue();
switch (op) {
case Query.PLUS:
return Query.value(lval1 + lval2);
case Query.TIMES:
return Query.value(lval1 * lval2);
case Query.MINUS:
return Query.value(lval1 - lval2);
case Query.DIV:
return Query.value(lval1 / lval2);
}
} else {
dval1 = ((NumericValueExp)val1).doubleValue();
dval2 = ((NumericValueExp)val2).doubleValue();
switch (op) {
case Query.PLUS:
return Query.value(dval1 + dval2);
case Query.TIMES:
return Query.value(dval1 * dval2);
case Query.MINUS:
return Query.value(dval1 - dval2);
case Query.DIV:
return Query.value(dval1 / dval2);
}
}
} else {
sval1 = ((StringValueExp)val1).getValue();
sval2 = ((StringValueExp)val2).getValue();
switch (op) {
case Query.PLUS:
return new StringValueExp(sval1 + sval2);
default:
throw new BadStringOperationException(opString());
}
}
throw new BadBinaryOpValueExpException(this);
}
/**
* Returns the string representing the object
*/
public String toString() {
try {
return parens(exp1, true) + " " + opString() + " " + parens(exp2, false);
} catch (BadBinaryOpValueExpException ex) {
return "invalid expression";
}
}
/*
* Add parentheses to the given subexpression if necessary to
* preserve meaning. Suppose this BinaryOpValueExp is
* Query.times(Query.plus(Query.attr("A"), Query.attr("B")), Query.attr("C")).
* Then the original toString() logic would return A + B * C.
* We check precedences in order to return (A + B) * C, which is the
* meaning of the ValueExp.
*
* We need to add parentheses if the unparenthesized expression would
* be parsed as a different ValueExp from the original.
* We cannot omit parentheses even when mathematically
* the result would be equivalent, because we do not know whether the
* numeric values will be integer or floating-point. Addition and
* multiplication are associative for integers but not always for
* floating-point.
*
* So the rule is that we omit parentheses if the ValueExp
* is (A op1 B) op2 C and the precedence of op1 is greater than or
* equal to that of op2; or if the ValueExp is A op1 (B op2 C) and
* the precedence of op2 is greater than that of op1. (There are two
* precedences: that of * and / is greater than that of + and -.)
* The case of (A op1 B) op2 (C op3 D) applies each rule in turn.
*
* The following examples show the rules in action. On the left,
* the original ValueExp. On the right, the string representation.
*
* (A + B) + C A + B + C
* (A * B) + C A * B + C
* (A + B) * C (A + B) * C
* (A * B) * C A * B * C
* A + (B + C) A + (B + C)
* A + (B * C) A + B * C
* A * (B + C) A * (B + C)
* A * (B * C) A * (B * C)
*/
private String parens(ValueExp subexp, boolean left)
throws BadBinaryOpValueExpException {
boolean omit;
if (subexp instanceof BinaryOpValueExp) {
int subop = ((BinaryOpValueExp) subexp).op;
if (left)
omit = (precedence(subop) >= precedence(op));
else
omit = (precedence(subop) > precedence(op));
} else
omit = true;
if (omit)
return subexp.toString();
else
return "(" + subexp + ")";
}
private int precedence(int xop) throws BadBinaryOpValueExpException {
switch (xop) {
case Query.PLUS: case Query.MINUS: return 0;
case Query.TIMES: case Query.DIV: return 1;
default:
throw new BadBinaryOpValueExpException(this);
}
}
private String opString() throws BadBinaryOpValueExpException {
switch (op) {
case Query.PLUS:
return "+";
case Query.TIMES:
return "*";
case Query.MINUS:
return "-";
case Query.DIV:
return "/";
}
throw new BadBinaryOpValueExpException(this);
}
@Deprecated
public void setMBeanServer(MBeanServer s) {
super.setMBeanServer(s);
}
}

View file

@ -0,0 +1,212 @@
/*
* 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 javax.management;
/**
* This class is used by the query-building mechanism to represent binary
* operations.
* @serial include
*
* @since 1.5
*/
class BinaryRelQueryExp extends QueryEval implements QueryExp {
/* Serial version */
private static final long serialVersionUID = -5690656271650491000L;
/**
* @serial The operator
*/
private int relOp;
/**
* @serial The first value
*/
private ValueExp exp1;
/**
* @serial The second value
*/
private ValueExp exp2;
/**
* Basic Constructor.
*/
public BinaryRelQueryExp() {
}
/**
* Creates a new BinaryRelQueryExp with operator op applied on v1 and
* v2 values.
*/
public BinaryRelQueryExp(int op, ValueExp v1, ValueExp v2) {
relOp = op;
exp1 = v1;
exp2 = v2;
}
/**
* Returns the operator of the query.
*/
public int getOperator() {
return relOp;
}
/**
* Returns the left value of the query.
*/
public ValueExp getLeftValue() {
return exp1;
}
/**
* Returns the right value of the query.
*/
public ValueExp getRightValue() {
return exp2;
}
/**
* Applies the BinaryRelQueryExp on an MBean.
*
* @param name The name of the MBean on which the BinaryRelQueryExp will be applied.
*
* @return True if the query was successfully applied to the MBean, false otherwise.
*
* @exception BadStringOperationException
* @exception BadBinaryOpValueExpException
* @exception BadAttributeValueExpException
* @exception InvalidApplicationException
*/
public boolean apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
Object val1 = exp1.apply(name);
Object val2 = exp2.apply(name);
boolean numeric = val1 instanceof NumericValueExp;
boolean bool = val1 instanceof BooleanValueExp;
if (numeric) {
if (((NumericValueExp)val1).isLong()) {
long lval1 = ((NumericValueExp)val1).longValue();
long lval2 = ((NumericValueExp)val2).longValue();
switch (relOp) {
case Query.GT:
return lval1 > lval2;
case Query.LT:
return lval1 < lval2;
case Query.GE:
return lval1 >= lval2;
case Query.LE:
return lval1 <= lval2;
case Query.EQ:
return lval1 == lval2;
}
} else {
double dval1 = ((NumericValueExp)val1).doubleValue();
double dval2 = ((NumericValueExp)val2).doubleValue();
switch (relOp) {
case Query.GT:
return dval1 > dval2;
case Query.LT:
return dval1 < dval2;
case Query.GE:
return dval1 >= dval2;
case Query.LE:
return dval1 <= dval2;
case Query.EQ:
return dval1 == dval2;
}
}
} else if (bool) {
boolean bval1 = ((BooleanValueExp)val1).getValue().booleanValue();
boolean bval2 = ((BooleanValueExp)val2).getValue().booleanValue();
switch (relOp) {
case Query.GT:
return bval1 && !bval2;
case Query.LT:
return !bval1 && bval2;
case Query.GE:
return bval1 || !bval2;
case Query.LE:
return !bval1 || bval2;
case Query.EQ:
return bval1 == bval2;
}
} else {
String sval1 = ((StringValueExp)val1).getValue();
String sval2 = ((StringValueExp)val2).getValue();
switch (relOp) {
case Query.GT:
return sval1.compareTo(sval2) > 0;
case Query.LT:
return sval1.compareTo(sval2) < 0;
case Query.GE:
return sval1.compareTo(sval2) >= 0;
case Query.LE:
return sval1.compareTo(sval2) <= 0;
case Query.EQ:
return sval1.compareTo(sval2) == 0;
}
}
return false;
}
/**
* Returns the string representing the object.
*/
@Override
public String toString() {
return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")";
}
private String relOpString() {
switch (relOp) {
case Query.GT:
return ">";
case Query.LT:
return "<";
case Query.GE:
return ">=";
case Query.LE:
return "<=";
case Query.EQ:
return "=";
}
return "=";
}
}

View file

@ -0,0 +1,93 @@
/*
* 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 javax.management;
/**
* This class represents a boolean value. A BooleanValueExp may be
* used anywhere a ValueExp is required.
* @serial include
*
* @since 1.5
*/
class BooleanValueExp extends QueryEval implements ValueExp {
/* Serial version */
private static final long serialVersionUID = 7754922052666594581L;
/**
* @serial The boolean value
*/
private boolean val = false;
/** Creates a new BooleanValueExp representing the boolean literal {@code val}.*/
BooleanValueExp(boolean val) {
this.val = val;
}
/**Creates a new BooleanValueExp representing the Boolean object {@code val}.*/
BooleanValueExp(Boolean val) {
this.val = val.booleanValue();
}
/** Returns the Boolean object representing the value of the BooleanValueExp object.*/
public Boolean getValue() {
return Boolean.valueOf(val);
}
/**
* Returns the string representing the object.
*/
public String toString() {
return String.valueOf(val);
}
/**
* Applies the ValueExp on a MBean.
*
* @param name The name of the MBean on which the ValueExp will be applied.
*
* @return The <CODE>ValueExp</CODE>.
*
* @exception BadStringOperationException
* @exception BadBinaryOpValueExpException
* @exception BadAttributeValueExpException
* @exception InvalidApplicationException
*/
public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
return this;
}
@Deprecated
public void setMBeanServer(MBeanServer s) {
super.setMBeanServer(s);
}
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 1999, 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 javax.management;
import java.security.AccessController;
import com.sun.jmx.mbeanserver.GetPropertyAction;
/**
* This class represents the name of the Java implementation class of
* the MBean. It is used for performing queries based on the class of
* the MBean.
* @serial include
*
* <p>The <b>serialVersionUID</b> of this class is <code>-1081892073854801359L</code>.
*
* @since 1.5
*/
@SuppressWarnings("serial") // serialVersionUID is not constant
class ClassAttributeValueExp extends AttributeValueExp {
// Serialization compatibility stuff:
// Two serial forms are supported in this class. The selected form depends
// on system property "jmx.serial.form":
// - "1.0" for JMX 1.0
// - any other value for JMX 1.1 and higher
//
// Serial version for old serial form
private static final long oldSerialVersionUID = -2212731951078526753L;
//
// Serial version for new serial form
private static final long newSerialVersionUID = -1081892073854801359L;
private static final long serialVersionUID;
static {
boolean compat = false;
try {
GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
String form = AccessController.doPrivileged(act);
compat = (form != null && form.equals("1.0"));
} catch (Exception e) {
// OK: exception means no compat with 1.0, too bad
}
if (compat)
serialVersionUID = oldSerialVersionUID;
else
serialVersionUID = newSerialVersionUID;
}
/**
* @serial The name of the attribute
*
* <p>The <b>serialVersionUID</b> of this class is <code>-1081892073854801359L</code>.
*/
private String attr;
/**
* Basic Constructor.
*/
public ClassAttributeValueExp() {
/* Compatibility: we have an attr field that we must hold on to
for serial compatibility, even though our parent has one too. */
super("Class");
attr = "Class";
}
/**
* Applies the ClassAttributeValueExp on an MBean. Returns the name of
* the Java implementation class of the MBean.
*
* @param name The name of the MBean on which the ClassAttributeValueExp will be applied.
*
* @return The ValueExp.
*
* @exception BadAttributeValueExpException
* @exception InvalidApplicationException
*/
public ValueExp apply(ObjectName name)
throws BadStringOperationException, BadBinaryOpValueExpException,
BadAttributeValueExpException, InvalidApplicationException {
// getAttribute(name);
Object result = getValue(name);
if (result instanceof String) {
return new StringValueExp((String)result);
} else {
throw new BadAttributeValueExpException(result);
}
}
/**
* Returns the string "Class" representing its value
*/
public String toString() {
return attr;
}
protected Object getValue(ObjectName name) {
try {
// Get the class of the object
MBeanServer server = QueryEval.getMBeanServer();
return server.getObjectInstance(name).getClassName();
} catch (Exception re) {
return null;
/* In principle the MBean does exist because otherwise we
wouldn't be evaluating the query on it. But it could
potentially have disappeared in between the time we
discovered it and the time the query is evaluated.
Also, the exception could be a SecurityException.
Returning null from here will cause
BadAttributeValueExpException, which will in turn cause
this MBean to be omitted from the query result. */
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2006, 2015, 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 javax.management;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* <p>
* An annotation on a constructor that shows how the parameters of
* that constructor correspond to the constructed object's getter
* methods. For example:
* </p>
* <blockquote>
* <pre>
* public class MemoryUsage {
* // standard JavaBean conventions with getters
* <b>@ConstructorParameters({"init", "used", "committed", "max"})</b>
* public MemoryUsage(long init, long used,
* long committed, long max) {...}
* public long getInit() {...}
* public long getUsed() {...}
* public long getCommitted() {...}
* public long getMax() {...}
* }
* </pre>
* </blockquote>
* <p>
* The annotation shows that the first parameter of the constructor
* can be retrieved with the {@code getInit()} method, the second one with
* the {@code getUsed()} method, and so on. Since parameter names are not in
* general available at runtime, without the annotation there would be
* no way of knowing which parameter corresponds to which property.
* </p>
* <p>
* If a constructor is annotated by the both {@code @java.beans.ConstructorProperties}
* and {@code @javax.management.ConstructorParameters} annotations
* the JMX introspection will give an absolute precedence to the latter one.
* </p>
*
* @since 9
*/
@Documented @Target(CONSTRUCTOR) @Retention(RUNTIME)
public @interface ConstructorParameters {
/**
* <p>The getter names.</p>
*
* @return the getter names corresponding to the parameters in the
* annotated constructor.
*/
String[] value();
}

View file

@ -0,0 +1,90 @@
/*
* 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 javax.management;
import javax.management.loading.ClassLoaderRepository;
/**
* <p>Keeps the list of Class Loaders registered in the MBean Server.
* It provides the necessary methods to load classes using the registered
* Class Loaders.</p>
*
* <p>This deprecated class is maintained for compatibility. In
* previous versions of the JMX API, there was one
* <code>DefaultLoaderRepository</code> shared by all MBean servers.
* As of version 1.2 of the JMX API, that functionality is
* approximated by using {@link MBeanServerFactory#findMBeanServer} to
* find all known MBean servers, and consulting the {@link
* ClassLoaderRepository} of each one. It is strongly recommended
* that code referencing <code>DefaultLoaderRepository</code> be
* rewritten.</p>
*
* @deprecated Use
* {@link javax.management.MBeanServer#getClassLoaderRepository()}
* instead.
*
* @since 1.5
*/
@Deprecated
public class DefaultLoaderRepository {
/**
* Go through the list of class loaders and try to load the requested class.
* The method will stop as soon as the class is found. If the class
* is not found the method will throw a <CODE>ClassNotFoundException</CODE>
* exception.
*
* @param className The name of the class to be loaded.
*
* @return the loaded class.
*
* @exception ClassNotFoundException The specified class could not be found.
*/
public static Class<?> loadClass(String className)
throws ClassNotFoundException {
return javax.management.loading.DefaultLoaderRepository.loadClass(className);
}
/**
* Go through the list of class loaders but exclude the given class loader, then try to load
* the requested class.
* The method will stop as soon as the class is found. If the class
* is not found the method will throw a <CODE>ClassNotFoundException</CODE>
* exception.
*
* @param className The name of the class to be loaded.
* @param loader The class loader to be excluded.
*
* @return the loaded class.
*
* @exception ClassNotFoundException The specified class could not be found.
*/
public static Class<?> loadClassWithout(ClassLoader loader,String className)
throws ClassNotFoundException {
return javax.management.loading.DefaultLoaderRepository.loadClassWithout(loader, className);
}
}

View file

@ -0,0 +1,649 @@
/*
* Copyright (c) 2000, 2017, 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.
*/
/*
* @author IBM Corp.
*
* Copyright IBM Corp. 1999-2000. All rights reserved.
*/
package javax.management;
import java.io.Serializable;
// Javadoc imports:
import java.lang.management.MemoryUsage;
import java.util.Arrays;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
import javax.management.openmbean.OpenType;
/**
* <p>Additional metadata for a JMX element. A {@code Descriptor}
* is associated with a {@link MBeanInfo}, {@link MBeanAttributeInfo}, etc.
* It consists of a collection of fields. A field is a name and an
* associated value.</p>
*
* <p>Field names are not case-sensitive. The names {@code descriptorType},
* {@code descriptortype}, and {@code DESCRIPTORTYPE} are all equivalent.
* However, the case that was used when the field was first set is preserved
* in the result of the {@link #getFields} and {@link #getFieldNames}
* methods.</p>
*
* <p>Not all field names and values are predefined.
* New fields can be defined and added by any program.</p>
*
* <p>A descriptor can be mutable or immutable.
* An immutable descriptor, once created, never changes.
* The <code>Descriptor</code> methods that could modify the contents
* of the descriptor will throw an exception
* for an immutable descriptor. Immutable descriptors are usually
* instances of {@link ImmutableDescriptor} or a subclass. Mutable
* descriptors are usually instances of
* {@link javax.management.modelmbean.DescriptorSupport} or a subclass.
*
* <p>Certain fields are used by the JMX implementation. This means
* either that the presence of the field may change the behavior of
* the JMX API or that the field may be set in descriptors returned by
* the JMX API. These fields appear in <i>italics</i> in the table
* below, and each one has a corresponding constant in the {@link JMX}
* class. For example, the field {@code defaultValue} is represented
* by the constant {@link JMX#DEFAULT_VALUE_FIELD}.</p>
*
* <p>Certain other fields have conventional meanings described in the
* table below but they are not required to be understood or set by
* the JMX implementation.</p>
*
* <p>Field names defined by the JMX specification in this and all
* future versions will never contain a period (.). Users can safely
* create their own fields by including a period in the name and be
* sure that these names will not collide with any future version of
* the JMX API. It is recommended to follow the Java package naming
* convention to avoid collisions between field names from different
* origins. For example, a field created by {@code example.com} might
* have the name {@code com.example.interestLevel}.</p>
*
* <p>Note that the values in the {@code defaultValue}, {@code
* legalValues}, {@code maxValue}, and {@code minValue} fields should
* be consistent with the type returned by the {@code getType()}
* method for the associated {@code MBeanAttributeInfo} or {@code
* MBeanParameterInfo}. For MXBeans, this means that they should be
* of the mapped Java type, called <em>opendata</em>(J) in the <a
* href="MXBean.html#mapping-rules">MXBean type mapping rules</a>.</p>
*
* <table class="striped">
* <caption style="display:none">Descriptor Fields</caption>
* <thead>
* <tr><th scope="col">Name</th>
* <th scope="col">Type</th>
* <th scope="col">Used in</th>
* <th scope="col">Meaning</th></tr>
* </thead>
*
* <tbody style="text-align:left">
* <tr id="defaultValue"><th scope="row"><i>defaultValue</i><td>Object</td>
* <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
*
* <td>Default value for an attribute or parameter. See
* {@link javax.management.openmbean}.</td>
*
* <tr><th scope="row">deprecated</th><td>String</td><td>Any</td>
*
* <td>An indication that this element of the information model is no
* longer recommended for use. A set of MBeans defined by an
* application is collectively called an <em>information model</em>.
* The convention is for the value of this field to contain a string
* that is the version of the model in which the element was first
* deprecated, followed by a space, followed by an explanation of the
* deprecation, for example {@code "1.3 Replaced by the Capacity
* attribute"}.</td>
*
* <tr><th scope="row" id="descriptionResourceBundleBaseName">descriptionResource<br>
* BundleBaseName</th><td>String</td><td>Any</td>
*
* <td>The base name for the {@link ResourceBundle} in which the key given in
* the {@code descriptionResourceKey} field can be found, for example
* {@code "com.example.myapp.MBeanResources"}. The meaning of this
* field is defined by this specification but the field is not set or
* used by the JMX API itself.</td>
*
* <tr><th scope="row" id="descriptionResourceKey">descriptionResourceKey</th>
* <td>String</td><td>Any</td>
*
* <td>A resource key for the description of this element. In
* conjunction with the {@code descriptionResourceBundleBaseName},
* this can be used to find a localized version of the description.
* The meaning of this field is defined by this specification but the
* field is not set or used by the JMX API itself.</td>
*
* <tr><th scope="row">enabled</th><td>String</td>
* <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td>
*
* <td>The string {@code "true"} or {@code "false"} according as this
* item is enabled. When an attribute or operation is not enabled, it
* exists but cannot currently be accessed. A user interface might
* present it as a greyed-out item. For example, an attribute might
* only be meaningful after the {@code start()} method of an MBean has
* been called, and is otherwise disabled. Likewise, a notification
* might be disabled if it cannot currently be emitted but could be in
* other circumstances.</td>
*
* <tr id="exceptions"><th scope="row">exceptions<td>String[]</td>
* <td>MBeanAttributeInfo, MBeanConstructorInfo, MBeanOperationInfo</td>
*
* <td>The class names of the exceptions that can be thrown when invoking a
* constructor or operation, or getting an attribute. The meaning of this field
* is defined by this specification but the field is not set or used by the
* JMX API itself. Exceptions thrown when
* setting an attribute are specified by the field
* <a href="#setExceptions">{@code setExceptions}</a>.
*
* <tr id="immutableInfo"><th scope="row"><i>immutableInfo</i><td>String</td>
* <td>MBeanInfo</td>
*
* <td>The string {@code "true"} or {@code "false"} according as this
* MBean's MBeanInfo is <em>immutable</em>. When this field is true,
* the MBeanInfo for the given MBean is guaranteed not to change over
* the lifetime of the MBean. Hence, a client can read it once and
* cache the read value. When this field is false or absent, there is
* no such guarantee, although that does not mean that the MBeanInfo
* will necessarily change. See also the <a
* href="MBeanInfo.html#info-changed">{@code "jmx.mbean.info.changed"}</a>
* notification.</td>
*
* <tr id="infoTimeout"><th scope="row">infoTimeout</th><td>String<br>Long</td><td>MBeanInfo</td>
*
* <td>The time in milli-seconds that the MBeanInfo can reasonably be
* expected to be unchanged. The value can be a {@code Long} or a
* decimal string. This provides a hint from a DynamicMBean or any
* MBean that does not define {@code immutableInfo} as {@code true}
* that the MBeanInfo is not likely to change within this period and
* therefore can be cached. When this field is missing or has the
* value zero, it is not recommended to cache the MBeanInfo unless it
* has the {@code immutableInfo} set to {@code true} or it has <a
* href="MBeanInfo.html#info-changed">{@code "jmx.mbean.info.changed"}</a> in
* its {@link MBeanNotificationInfo} array.</td></tr>
*
* <tr id="interfaceClassName"><th scope="row"><i>interfaceClassName</i></th>
* <td>String</td><td>MBeanInfo</td>
*
* <td>The Java interface name for a Standard MBean or MXBean, as
* returned by {@link Class#getName()}. A Standard MBean or MXBean
* registered directly in the MBean Server or created using the {@link
* StandardMBean} class will have this field in its MBeanInfo
* Descriptor.</td>
*
* <tr id="legalValues"><th scope="row"><i>legalValues</i></th>
* <td>{@literal Set<?>}</td><td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
*
* <td>Legal values for an attribute or parameter. See
* {@link javax.management.openmbean}.</td>
*
* <tr id="locale"><th scope="row">locale</th>
* <td>String</td><td>Any</td>
*
* <td>The {@linkplain Locale locale} of the description in this
* {@code MBeanInfo}, {@code MBeanAttributeInfo}, etc, as returned
* by {@link Locale#toString()}.</td>
*
* <tr id="maxValue"><th scope="row"><i>maxValue</i><td>Object</td>
* <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
*
* <td>Maximum legal value for an attribute or parameter. See
* {@link javax.management.openmbean}.</td>
*
* <tr id="metricType"><th scope="row">metricType</th><td>String</td>
* <td>MBeanAttributeInfo<br>MBeanOperationInfo</td>
*
* <td>The type of a metric, one of the strings "counter" or "gauge".
* A metric is a measurement exported by an MBean, usually an
* attribute but sometimes the result of an operation. A metric that
* is a <em>counter</em> has a value that never decreases except by
* being reset to a starting value. Counter metrics are almost always
* non-negative integers. An example might be the number of requests
* received. A metric that is a <em>gauge</em> has a numeric value
* that can increase or decrease. Examples might be the number of
* open connections or a cache hit rate or a temperature reading.
*
* <tr id="minValue"><th scope="row"><i>minValue</i><td>Object</td>
* <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
*
* <td>Minimum legal value for an attribute or parameter. See
* {@link javax.management.openmbean}.</td>
*
* <tr id="mxbean"><th scope="row"><i>mxbean</i><td>String</td>
* <td>MBeanInfo</td>
*
* <td>The string {@code "true"} or {@code "false"} according as this
* MBean is an {@link MXBean}. A Standard MBean or MXBean registered
* directly with the MBean Server or created using the {@link
* StandardMBean} class will have this field in its MBeanInfo
* Descriptor.</td>
*
* <tr id="openType"><th scope="row"><i>openType</i><td>{@link OpenType}</td>
* <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
*
* <td><p>The Open Type of this element. In the case of {@code
* MBeanAttributeInfo} and {@code MBeanParameterInfo}, this is the
* Open Type of the attribute or parameter. In the case of {@code
* MBeanOperationInfo}, it is the Open Type of the return value. This
* field is set in the Descriptor for all instances of {@link
* OpenMBeanAttributeInfoSupport}, {@link
* OpenMBeanOperationInfoSupport}, and {@link
* OpenMBeanParameterInfoSupport}. It is also set for attributes,
* operations, and parameters of MXBeans.</p>
*
* <p>This field can be set for an {@code MBeanNotificationInfo}, in
* which case it indicates the Open Type that the {@link
* Notification#getUserData() user data} will have.</td>
*
* <tr id="originalType"><th scope="row"><i>originalType</i><td>String</td>
* <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
*
* <td><p>The original Java type of this element as it appeared in the
* {@link MXBean} interface method that produced this {@code
* MBeanAttributeInfo} (etc). For example, a method<br> <code>public
* </code> {@link MemoryUsage}<code> getHeapMemoryUsage();</code><br>
* in an MXBean interface defines an attribute called {@code
* HeapMemoryUsage} of type {@link CompositeData}. The {@code
* originalType} field in the Descriptor for this attribute will have
* the value {@code "java.lang.management.MemoryUsage"}.
*
* <p>The format of this string is described in the section <a
* href="MXBean.html#type-names">Type Names</a> of the MXBean
* specification.</p>
*
* <tr id="setExceptions"><th scope="row"><i>setExceptions</i><td>String[]</td>
* <td>MBeanAttributeInfo</td>
*
* <td>The class names of the exceptions that can be thrown when setting
* an attribute. The meaning of this field
* is defined by this specification but the field is not set or used by the
* JMX API itself. Exceptions thrown when getting an attribute are specified
* by the field <a href="#exceptions">{@code exceptions}</a>.
*
* <tr><th scope="row">severity</th><td>String<br>Integer</td>
* <td>MBeanNotificationInfo</td>
*
* <td>The severity of this notification. It can be 0 to mean
* unknown severity or a value from 1 to 6 representing decreasing
* levels of severity. It can be represented as a decimal string or
* an {@code Integer}.</td>
*
* <tr><th scope="row">since</th><td>String</td><td>Any</td>
*
* <td>The version of the information model in which this element
* was introduced. A set of MBeans defined by an application is
* collectively called an <em>information model</em>. The
* application may also define versions of this model, and use the
* {@code "since"} field to record the version in which an element
* first appeared.</td>
*
* <tr><th scope="row">units</th><td>String</td>
* <td>MBeanAttributeInfo<br>MBeanParameterInfo<br>MBeanOperationInfo</td>
*
* <td>The units in which an attribute, parameter, or operation return
* value is measured, for example {@code "bytes"} or {@code
* "seconds"}.</td>
*
* </tbody>
* </table>
*
* <p>Some additional fields are defined by Model MBeans. See the
* information for <a href="modelmbean/ModelMBeanInfo.html#descriptor"><!--
* -->{@code ModelMBeanInfo}</a>,
* <a href="modelmbean/ModelMBeanAttributeInfo.html#descriptor"><!--
* -->{@code ModelMBeanAttributeInfo}</a>,
* <a href="modelmbean/ModelMBeanConstructorInfo.html#descriptor"><!--
* -->{@code ModelMBeanConstructorInfo}</a>,
* <a href="modelmbean/ModelMBeanNotificationInfo.html#descriptor"><!--
* -->{@code ModelMBeanNotificationInfo}</a>, and
* <a href="modelmbean/ModelMBeanOperationInfo.html#descriptor"><!--
* -->{@code ModelMBeanOperationInfo}</a>, as
* well as the chapter "Model MBeans" of the <a
* href="http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html">JMX
* Specification</a>. The following table summarizes these fields. Note
* that when the Type in this table is Number, a String that is the decimal
* representation of a Long can also be used.</p>
*
* <p>Nothing prevents the use of these fields in MBeans that are not Model
* MBeans. The <a href="#displayName">displayName</a>, <a href="#severity"><!--
* -->severity</a>, and <a href="#visibility">visibility</a> fields are of
* interest outside Model MBeans, for example. But only Model MBeans have
* a predefined behavior for these fields.</p>
*
* <table class="striped">
* <caption style="display:none">ModelMBean Fields</caption>
*
* <thead>
* <tr><th scope="col">Name</th>
* <th scope="col">Type</th>
* <th scope="col">Used in</th>
* <th scope="col">Meaning</th></tr>
* </thead>
*
* <tbody style="text-align:left">
* <tr><th scope="row">class</th><td>String</td><td>ModelMBeanOperationInfo</td>
* <td>Class where method is defined (fully qualified).</td></tr>
*
* <tr><th scope="row">currencyTimeLimit</th><td>Number</td>
* <td>ModelMBeanInfo<br>ModelMBeanAttributeInfo<br>ModelMBeanOperationInfo</td>
* <td>How long cached value is valid: &lt;0 never, =0 always,
* &gt;0 seconds.</td></tr>
*
* <tr><th scope="row">default</th><td>Object</td><td>ModelMBeanAttributeInfo</td>
* <td>Default value for attribute.</td></tr>
*
* <tr><th scope="row">descriptorType</th><td>String</td><td>Any</td>
* <td>Type of descriptor, "mbean", "attribute", "constructor", "operation",
* or "notification".</td></tr>
*
* <tr id="displayName"><th scope="row">displayName</th><td>String</td><td>Any</td>
* <td>Human readable name of this item.</td></tr>
*
* <tr><th scope="row">export</th><td>String</td><td>ModelMBeanInfo</td>
* <td>Name to be used to export/expose this MBean so that it is
* findable by other JMX Agents.</td></tr>
*
* <tr><th scope="row">getMethod</th><td>String</td><td>ModelMBeanAttributeInfo</td>
* <td>Name of operation descriptor for get method.</td></tr>
*
* <tr><th scope="row">lastUpdatedTimeStamp</th><td>Number</td>
* <td>ModelMBeanAttributeInfo<br>ModelMBeanOperationInfo</td>
* <td>When <a href="#value-field">value</a> was set.</td></tr>
*
* <tr><th scope="row">log</th><td>String</td><td>ModelMBeanInfo<br>ModelMBeanNotificationInfo</td>
* <td>t or T: log all notifications, f or F: log no notifications.</td></tr>
*
* <tr><th scope="row">logFile</th><td>String</td><td>ModelMBeanInfo<br>ModelMBeanNotificationInfo</td>
* <td>Fully qualified filename to log events to.</td></tr>
*
* <tr><th scope="row">messageID</th><td>String</td><td>ModelMBeanNotificationInfo</td>
* <td>Unique key for message text (to allow translation, analysis).</td></tr>
*
* <tr><th scope="row">messageText</th><td>String</td><td>ModelMBeanNotificationInfo</td>
* <td>Text of notification.</td></tr>
*
* <tr><th scope="row">name</th><td>String</td><td>Any</td>
* <td>Name of this item.</td></tr>
*
* <tr><th scope="row">persistFile</th><td>String</td><td>ModelMBeanInfo</td>
* <td>File name into which the MBean should be persisted.</td></tr>
*
* <tr><th scope="row">persistLocation</th><td>String</td><td>ModelMBeanInfo</td>
* <td>The fully qualified directory name where the MBean should be
* persisted (if appropriate).</td></tr>
*
* <tr><th scope="row">persistPeriod</th><td>Number</td>
* <td>ModelMBeanInfo<br>ModelMBeanAttributeInfo</td>
* <td>Frequency of persist cycle in seconds. Used when persistPolicy is
* "OnTimer" or "NoMoreOftenThan".</td></tr>
*
* <tr><th scope="row">persistPolicy</th><td>String</td>
* <td>ModelMBeanInfo<br>ModelMBeanAttributeInfo</td>
* <td>One of: OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never.
* See the section "MBean Descriptor Fields" in the JMX specification
* document.</td></tr>
*
* <tr><th scope="row">presentationString</th><td>String</td><td>Any</td>
* <td>XML formatted string to allow presentation of data.</td></tr>
*
* <tr><th scope="row">protocolMap</th><td>Descriptor</td><td>ModelMBeanAttributeInfo</td>
* <td>See the section "Protocol Map Support" in the JMX specification
* document. Mappings must be appropriate for the attribute and entries
* can be updated or augmented at runtime.</td></tr>
*
* <tr><th scope="row">role</th><td>String</td>
* <td>ModelMBeanConstructorInfo<br>ModelMBeanOperationInfo</td>
* <td>One of "constructor", "operation", "getter", or "setter".</td></tr>
*
* <tr><th scope="row">setMethod</th><td>String</td><td>ModelMBeanAttributeInfo</td>
* <td>Name of operation descriptor for set method.</td></tr>
*
* <tr id="severity"><th scope="row">severity</th><td>Number</td>
* <td>ModelMBeanNotificationInfo</td>
* <td>0-6 where 0: unknown; 1: non-recoverable;
* 2: critical, failure; 3: major, severe;
* 4: minor, marginal, error; 5: warning;
* 6: normal, cleared, informative</td></tr>
*
* <tr><th scope="row">targetObject</th><td>Object</td><td>ModelMBeanOperationInfo</td>
* <td>Object on which to execute this method.</td></tr>
*
* <tr><th scope="row">targetType</th><td>String</td><td>ModelMBeanOperationInfo</td>
* <td>type of object reference for targetObject. Can be:
* ObjectReference | Handle | EJBHandle | IOR | RMIReference.</td></tr>
*
* <tr id="value-field"><th scope="row">value</th><td>Object</td>
* <td>ModelMBeanAttributeInfo<br>ModelMBeanOperationInfo</td>
* <td>Current (cached) value for attribute or operation.</td></tr>
*
* <tr id="visibility"><th scope="row">visibility</th><td>Number</td><td>Any</td>
* <td>1-4 where 1: always visible, 4: rarely visible.</td></tr>
*
* </tbody>
* </table>
*
* @since 1.5
*/
public interface Descriptor extends Serializable, Cloneable
{
/**
* Returns the value for a specific field name, or null if no value
* is present for that name.
*
* @param fieldName the field name.
*
* @return the corresponding value, or null if the field is not present.
*
* @exception RuntimeOperationsException if the field name is illegal.
*/
public Object getFieldValue(String fieldName)
throws RuntimeOperationsException;
/**
* <p>Sets the value for a specific field name. This will
* modify an existing field or add a new field.</p>
*
* <p>The field value will be validated before it is set.
* If it is not valid, then an exception will be thrown.
* The meaning of validity is dependent on the descriptor
* implementation.</p>
*
* @param fieldName The field name to be set. Cannot be null or empty.
* @param fieldValue The field value to be set for the field
* name. Can be null if that is a valid value for the field.
*
* @exception RuntimeOperationsException if the field name or field value
* is illegal (wrapped exception is {@link IllegalArgumentException}); or
* if the descriptor is immutable (wrapped exception is
* {@link UnsupportedOperationException}).
*/
public void setField(String fieldName, Object fieldValue)
throws RuntimeOperationsException;
/**
* Returns all of the fields contained in this descriptor as a string array.
*
* @return String array of fields in the format <i>fieldName=fieldValue</i>
* <br>If the value of a field is not a String, then the toString() method
* will be called on it and the returned value, enclosed in parentheses,
* used as the value for the field in the returned array. If the value
* of a field is null, then the value of the field in the returned array
* will be empty. If the descriptor is empty, you will get
* an empty array.
*
* @see #setFields
*/
public String[] getFields();
/**
* Returns all the field names in the descriptor.
*
* @return String array of field names. If the descriptor is empty,
* you will get an empty array.
*/
public String[] getFieldNames();
/**
* Returns all the field values in the descriptor as an array of Objects. The
* returned values are in the same order as the {@code fieldNames} String array parameter.
*
* @param fieldNames String array of the names of the fields that
* the values should be returned for. If the array is empty then
* an empty array will be returned. If the array is null then all
* values will be returned, as if the parameter were the array
* returned by {@link #getFieldNames()}. If a field name in the
* array does not exist, including the case where it is null or
* the empty string, then null is returned for the matching array
* element being returned.
*
* @return Object array of field values. If the list of {@code fieldNames}
* is empty, you will get an empty array.
*/
public Object[] getFieldValues(String... fieldNames);
/**
* Removes a field from the descriptor.
*
* @param fieldName String name of the field to be removed.
* If the field name is illegal or the field is not found,
* no exception is thrown.
*
* @exception RuntimeOperationsException if a field of the given name
* exists and the descriptor is immutable. The wrapped exception will
* be an {@link UnsupportedOperationException}.
*/
public void removeField(String fieldName);
/**
* <p>Sets all fields in the field names array to the new value with
* the same index in the field values array. Array sizes must match.</p>
*
* <p>The field value will be validated before it is set.
* If it is not valid, then an exception will be thrown.
* If the arrays are empty, then no change will take effect.</p>
*
* @param fieldNames String array of field names. The array and array
* elements cannot be null.
* @param fieldValues Object array of the corresponding field values.
* The array cannot be null. Elements of the array can be null.
*
* @throws RuntimeOperationsException if the change fails for any reason.
* Wrapped exception is {@link IllegalArgumentException} if
* {@code fieldNames} or {@code fieldValues} is null, or if
* the arrays are of different lengths, or if there is an
* illegal value in one of them.
* Wrapped exception is {@link UnsupportedOperationException}
* if the descriptor is immutable, and the call would change
* its contents.
*
* @see #getFields
*/
public void setFields(String[] fieldNames, Object[] fieldValues)
throws RuntimeOperationsException;
/**
* <p>Returns a descriptor which is equal to this descriptor.
* Changes to the returned descriptor will have no effect on this
* descriptor, and vice versa. If this descriptor is immutable,
* it may fulfill this condition by returning itself.</p>
* @exception RuntimeOperationsException for illegal value for field names
* or field values.
* If the descriptor construction fails for any reason, this exception will
* be thrown.
* @return A descriptor which is equal to this descriptor.
*/
public Object clone() throws RuntimeOperationsException;
/**
* Returns true if all of the fields have legal values given their
* names.
*
* @return true if the values are legal.
*
* @exception RuntimeOperationsException If the validity checking fails for
* any reason, this exception will be thrown.
* The method returns false if the descriptor is not valid, but throws
* this exception if the attempt to determine validity fails.
*/
public boolean isValid() throws RuntimeOperationsException;
/**
* <p>Compares this descriptor to the given object. The objects are equal if
* the given object is also a Descriptor, and if the two Descriptors have
* the same field names (possibly differing in case) and the same
* associated values. The respective values for a field in the two
* Descriptors are equal if the following conditions hold:</p>
*
* <ul>
* <li>If one value is null then the other must be too.</li>
* <li>If one value is a primitive array then the other must be a primitive
* array of the same type with the same elements.</li>
* <li>If one value is an object array then the other must be too and
* {@link Arrays#deepEquals(Object[],Object[])} must return true.</li>
* <li>Otherwise {@link Object#equals(Object)} must return true.</li>
* </ul>
*
* @param obj the object to compare with.
*
* @return {@code true} if the objects are the same; {@code false}
* otherwise.
*
* @since 1.6
*/
public boolean equals(Object obj);
/**
* <p>Returns the hash code value for this descriptor. The hash
* code is computed as the sum of the hash codes for each field in
* the descriptor. The hash code of a field with name {@code n}
* and value {@code v} is {@code n.toLowerCase().hashCode() ^ h}.
* Here {@code h} is the hash code of {@code v}, computed as
* follows:</p>
*
* <ul>
* <li>If {@code v} is null then {@code h} is 0.</li>
* <li>If {@code v} is a primitive array then {@code h} is computed using
* the appropriate overloading of {@code java.util.Arrays.hashCode}.</li>
* <li>If {@code v} is an object array then {@code h} is computed using
* {@link Arrays#deepHashCode(Object[])}.</li>
* <li>Otherwise {@code h} is {@code v.hashCode()}.</li>
* </ul>
*
* @return A hash code value for this object.
*
* @since 1.6
*/
public int hashCode();
}

Some files were not shown because too many files have changed in this diff Show more