diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | gnu/javax/management/Server.java | 63 | ||||
-rw-r--r-- | java/lang/management/ManagementFactory.java | 171 | ||||
-rw-r--r-- | javax/management/MBeanServerFactory.java | 405 |
4 files changed, 637 insertions, 13 deletions
@@ -1,3 +1,14 @@ +2006-12-04 Andrew John Hughes <gnu_andrew@member.fsf.org> + + * gnu/javax/management/Server.java: + Make map final and initialise it. + (unregisterMBean(ObjectName)): Match against + delegate's object name and not the instance. + * java/lang/management/ManagementFactory.java: + Added constant fields. + (getPlatformMBeanServer()): Implemented. + * javax/management/MBeanServerFactory.java: New file. + 2006-12-04 Roman Kennke <kennke@aicas.com> * javax/swing/text/BoxView.java diff --git a/gnu/javax/management/Server.java b/gnu/javax/management/Server.java index 049b0e360..5501b4af7 100644 --- a/gnu/javax/management/Server.java +++ b/gnu/javax/management/Server.java @@ -104,11 +104,16 @@ public class Server { /** + * The name of the delegate bean. + */ + private static final ObjectName DELEGATE_NAME; + + /** * The registered beans, represented as a map of * {@link javax.management.ObjectName}s to * {@link java.lang.Object}s. */ - private Map beans; + private final Map beans = new HashMap(); /** * The default domain. @@ -121,11 +126,6 @@ public class Server private MBeanServer outer; /** - * The delegate bean. - */ - private MBeanServerDelegate delegate; - - /** * The class loader repository. */ private ClassLoaderRepository repository; @@ -137,6 +137,24 @@ public class Server private Map listeners; /** + * Initialise the delegate name. + */ + static + { + try + { + DELEGATE_NAME = + new ObjectName("JMImplementation:type=MBeanServerDelegate"); + } + catch (MalformedObjectNameException e) + { + throw (Error) + (new InternalError("Failed to construct " + + "the delegate's object name.").initCause(e)); + } + } + + /** * Constructs a new management server using the specified * default domain, delegate bean and outer server. * @@ -153,7 +171,28 @@ public class Server { this.defaultDomain = defaultDomain; this.outer = outer; - this.delegate = delegate; + try + { + registerMBean(delegate, DELEGATE_NAME); + } + catch (InstanceAlreadyExistsException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "already registered.").initCause(e)); + } + catch (MBeanRegistrationException e) + { + throw (Error) + (new InternalError("The delegate bean's preRegister " + + "methods threw an exception.").initCause(e)); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "not compliant.").initCause(e)); + } } /** @@ -1646,9 +1685,7 @@ public class Server throw new MBeanRegistrationException(e, "Pre-registration failed."); } } - if (beans == null) - beans = new HashMap(); - else if (beans.containsKey(name)) + if (beans.containsKey(name)) { if (register != null) register.postRegister(Boolean.FALSE); @@ -2021,14 +2058,14 @@ public class Server new IllegalArgumentException("The name was null."); throw new RuntimeOperationsException(e); } - Object bean = getBean(name); - checkSecurity(name, null, "unregisterMBean"); - if (bean == delegate) + if (name.equals(DELEGATE_NAME)) { RuntimeException e = new IllegalArgumentException("The delegate can not be unregistered."); throw new RuntimeOperationsException(e); } + Object bean = getBean(name); + checkSecurity(name, null, "unregisterMBean"); MBeanRegistration register = null; if (bean instanceof MBeanRegistration) { diff --git a/java/lang/management/ManagementFactory.java b/java/lang/management/ManagementFactory.java index 69f1435c2..ef3feace7 100644 --- a/java/lang/management/ManagementFactory.java +++ b/java/lang/management/ManagementFactory.java @@ -50,9 +50,16 @@ import gnu.java.lang.management.RuntimeMXBeanImpl; import gnu.java.lang.management.ThreadMXBeanImpl; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; /** * <p> @@ -66,6 +73,11 @@ import javax.management.NotCompliantMBeanException; * <ol> * <li>Calling the appropriate static method of this factory. * </li> + * <li>Using the platform {@link javax.management.MBeanServer} + * to access the beans locally, or an + * {@link javax.management.MBeanServerConnection} for remote + * access. The attributes and operations use the limited + * range of data types specified below.</li> * </ol> * <h2>Open Data Types</h2> * <p> @@ -118,6 +130,60 @@ public class ManagementFactory { /** + * The object name for the class loading bean. + */ + public static final String CLASS_LOADING_MXBEAN_NAME = + "java.lang:type=ClassLoading"; + + /** + * The object name for the compilation bean. + */ + public static final String COMPILATION_MXBEAN_NAME = + "java.lang:type=Compilation"; + + /** + * The domain for the garbage collecting beans. + */ + public static final String GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE = + "java.lang:type=GarbageCollector"; + + /** + * The domain for the memory manager beans. + */ + public static final String MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE = + "java.lang:type=MemoryManager"; + + /** + * The object name for the memory bean. + */ + public static final String MEMORY_MXBEAN_NAME = + "java.lang:type=Memory"; + + /** + * The domain for the memory pool beans. + */ + public static final String MEMORY_POOL_MXBEAN_DOMAIN_TYPE = + "java.lang:type=MemoryPool"; + + /** + * The object name for the operating system bean. + */ + public static final String OPERATING_SYSTEM_MXBEAN_NAME = + "java.lang:type=OperatingSystem"; + + /** + * The object name for the runtime bean. + */ + public static final String RUNTIME_MXBEAN_NAME = + "java.lang:type=Runtime"; + + /** + * The object name for the threading bean. + */ + public static final String THREAD_MXBEAN_NAME = + "java.lang:type=Threading"; + + /** * The operating system management bean. */ private static OperatingSystemMXBean osBean; @@ -148,6 +214,11 @@ public class ManagementFactory private static CompilationMXBean compilationBean; /** + * The platform server. + */ + private static MBeanServer platformServer; + + /** * Private constructor to prevent instance creation. */ private ManagementFactory() {} @@ -371,4 +442,104 @@ public class ManagementFactory return gcBeans; } + /** + * <p> + * Returns the platform {@link javax.management.MBeanServer}. On the + * first call to this method, a server instance is retrieved from + * the {@link javax.management.MBeanServerFactory} and each of the + * beans are registered with it. Subsequent calls return the existing + * instance. If the property <code>javax.management.builder.initial</code> + * is set, its value will be used as the name of the class which is used + * to provide the server instance. + * </p> + * <p> + * It is recommended that the platform server is used for other beans as + * well, in order to simplify their discovery and publication. Name conflicts + * should be avoided. + * </p> + * + * @return the platform {@link javax.management.MBeanServer} + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("createMBeanServer") + * @see javax.management.MBeanServerFactory + * @see javax.management.MBeanServerFactory#createMBeanServer() + */ + public static MBeanServer getPlatformMBeanServer() + { + if (platformServer == null) + { + platformServer = MBeanServerFactory.createMBeanServer(); + try + { + platformServer.registerMBean(getOperatingSystemMXBean(), + new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME)); + platformServer.registerMBean(getRuntimeMXBean(), + new ObjectName(RUNTIME_MXBEAN_NAME)); + platformServer.registerMBean(getClassLoadingMXBean(), + new ObjectName(CLASS_LOADING_MXBEAN_NAME)); + platformServer.registerMBean(getThreadMXBean(), + new ObjectName(THREAD_MXBEAN_NAME)); + platformServer.registerMBean(getMemoryMXBean(), + new ObjectName(MEMORY_MXBEAN_NAME)); + CompilationMXBean compBean = getCompilationMXBean(); + if (compBean != null) + platformServer.registerMBean(compBean, + new ObjectName(COMPILATION_MXBEAN_NAME)); + Iterator beans = getMemoryPoolMXBeans().iterator(); + while (beans.hasNext()) + { + MemoryPoolMXBean bean = (MemoryPoolMXBean) beans.next(); + platformServer.registerMBean(bean, + new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE + + ",name=" + + bean.getName())); + } + beans = getMemoryManagerMXBeans().iterator(); + while (beans.hasNext()) + { + MemoryManagerMXBean bean = (MemoryManagerMXBean) beans.next(); + platformServer.registerMBean(bean, + new ObjectName(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE + + ",name=" + + bean.getName())); + } + beans = getGarbageCollectorMXBeans().iterator(); + while (beans.hasNext()) + { + GarbageCollectorMXBean bean = (GarbageCollectorMXBean) beans.next(); + platformServer.registerMBean(bean, + new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + + ",name=" + + bean.getName())); + } + } + catch (InstanceAlreadyExistsException e) + { + throw (Error) + (new InternalError("One of the management beans is " + + "already registered.").initCause(e)); + } + catch (MBeanRegistrationException e) + { + throw (Error) + (new InternalError("One of the management beans' preRegister " + + "methods threw an exception.").initCause(e)); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("One of the management beans is " + + "not compliant.").initCause(e)); + } + catch (MalformedObjectNameException e) + { + throw (Error) + (new InternalError("The object name of a management bean is " + + "not compliant.").initCause(e)); + } + } + return platformServer; + } + } diff --git a/javax/management/MBeanServerFactory.java b/javax/management/MBeanServerFactory.java new file mode 100644 index 000000000..9ff4e9c85 --- /dev/null +++ b/javax/management/MBeanServerFactory.java @@ -0,0 +1,405 @@ +/* MBeanServerFactory.java -- Manages server instances. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +import gnu.classpath.SystemProperties; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.management.loading.ClassLoaderRepository; + +/** + * <p> + * Creates and maintains a set of {@link MBeanServer} instances. + * Server instances, as of JMX 1.2, are created using a subclass + * of {@link MBeanServerBuilder}. The exact class used is controlled + * by the property <code>javax.management.builder.initial</code>, + * and allows the instances created by {@link MBeanServerBuilder} + * to be wrapped, thus providing additional functionality. + * </p> + * <p> + * The property is used as follows: + * </p> + * <ol> + * <li>If the property has no value, then an instance of + * {@link MBeanServerBuilder} is used.</li> + * <li>If a value is given, then: + * <ol> + * <li>The class is loaded using + * <code>Thread.currentThread().getContextClassLoader()</code>, or, + * if this is <code>null</code>, by <code>Class.forName()</code>.</li> + * <li><code>Class.newInstance()</code> is used to create an instance + * of the class. The class must be public and have a public empty + * constructor. If an exception is thrown, it is propogated as + * a {@link JMRuntimeException} and no new server instances may be + * created until the property is set to a valid value.</li> + * </ol></li> + * <li>The value is checked on each successive request for a server. + * If it differs from the class of the existing instance of + * {@link MBeanServerBuilder}, then the value is used to create + * a new instance.</li> + * </ol> + */ +public class MBeanServerFactory +{ + + /** + * The last builder instance. + */ + private static MBeanServerBuilder builder; + + /** + * The map of registered servers (identifiers to servers). + */ + private static Map servers; + + /** + * Private constructor to prevent instance creation. + */ + private MBeanServerFactory() {} + + /** + * Returns a server implementation using the default domain name + * of <code>"DefaultDomain"</code>. The default domain name is + * used when the domain name specified by the user is <code>null</code. + * A reference to the created server is retained, so that it can + * be retrieved at a later date using {@link #findMBeanServer}. + * Calling this method is equivalent to calling + * {@link createMBeanServer(String)} with a <code>null</code> value. + * + * @return a new {@link MBeanServer} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("createMBeanServer") + * @throws JMRuntimeException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * <code>null</code> from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which is not a subclass + * of {@link MBeanServerBuilder}. + * @see #createMBeanServer(String) + */ + public static MBeanServer createMBeanServer() + { + return createMBeanServer(null); + } + + /** + * Returns a server implementation using the default domain name + * given, or <code>"DefaultDomain"</code> if this is <code>null</code>. + * The default domain name is used when the domain name specified by + * the user is <code>null</code. A reference to the created server is + * retained, so that it can be retrieved at a later date using + * {@link #findMBeanServer}. + * + * @param domain the default domain name of the server. + * @return a new {@link MBeanServer} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("createMBeanServer") + * @throws JMRuntimeException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * <code>null</code> from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which is not a subclass + * of {@link MBeanServerBuilder}. + */ + public static MBeanServer createMBeanServer(String domain) + { + /* FIXME: Check for permission "createMBeanServer" */ + MBeanServer server = createServer(domain); + if (servers == null) + servers = new HashMap(); + try + { + ObjectName dn = new + ObjectName("JMImplementation:type=MBeanServerDelegate"); + servers.put(server.getAttribute(dn, "MBeanServerId"), server); + } + catch (MalformedObjectNameException e) + { + throw (Error) + (new InternalError("Malformed delegate bean name.").initCause(e)); + } + catch (MBeanException e) + { + throw (Error) + (new InternalError("Exception in getMBeanServerId().").initCause(e)); + } + catch (AttributeNotFoundException e) + { + throw (Error) + (new InternalError("Could not find MBeanServerId attribute.").initCause(e)); + } + catch (InstanceNotFoundException e) + { + throw (Error) + (new InternalError("Could not find the delegate bean.").initCause(e)); + } + catch (ReflectionException e) + { + throw (Error) + (new InternalError("Could not call getMBeanServerId().").initCause(e)); + } + return server; + } + + /** + * Returns the specified server, or, if <code>id</code> is <code>null</code>, + * a list of all registered servers. A registered server is one that + * was created using {@link #createMBeanServer()} or + * {@link #createMBeanServer(String)} and has not yet been released + * using {@link releaseMBeanServer(MBeanServer)}. + * + * @param id the id of the server to retrieve, or <code>null</code> + * to return all servers. + * @return a list of {@link MBeanServer}s. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("findMBeanServer") + */ + public static ArrayList findMBeanServer(String id) + { + /* FIXME: Check for permission "findMBeanServer" */ + if (id == null) + return new ArrayList(servers.values()); + ArrayList list = new ArrayList(); + MBeanServer server = (MBeanServer) servers.get(id); + if (server != null) + list.add(servers.get(id)); + return list; + } + + /** + * Returns the class loader repository used by the specified server. + * This is equivalent to calling {@link MBeanServer#getClassLoaderRepository()} + * on the given server. + * + * @param server the server whose class loader repository should be + * retrieved. + * @throws NullPointerException if <code>server</code> is <code>null</code>. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, null, + * "getClassLoaderRepository")</code> + */ + public static ClassLoaderRepository getClassLoaderRepository(MBeanServer server) + { + return server.getClassLoaderRepository(); + } + + /** + * Returns a server implementation using the default domain name + * of <code>"DefaultDomain"</code>. The default domain name is + * used when the domain name specified by the user is <code>null</code. + * No reference to the created server is retained, so the server is + * garbage collected when it is no longer used, but it can not be + * retrieved at a later date using {@link #findMBeanServer}. + * Calling this method is equivalent to calling + * {@link newMBeanServer(String)} with a <code>null</code> value. + * + * @return a new {@link MBeanServer} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("newMBeanServer") + * @throws JMRuntimeException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * <code>null</code> from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which is not a subclass + * of {@link MBeanServerBuilder}. + * @see #newMBeanServer(String) + */ + public static MBeanServer newMBeanServer() + { + return newMBeanServer(null); + } + + /** + * Returns a server implementation using the default domain name + * given, or <code>"DefaultDomain"</code> if this is <code>null</code>. + * The default domain name is used when the domain name specified by + * the user is <code>null</code. No reference to the created server is + * retained, so the server is garbage collected when it is no longer + * used, but it can not be retrieved at a later date using + * {@link #findMBeanServer}. + * + * @param domain the default domain name of the server. + * @return a new {@link MBeanServer} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("newMBeanServer") + * @throws JMRuntimeException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * <code>null</code> from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which is not a subclass + * of {@link MBeanServerBuilder}. + */ + public static MBeanServer newMBeanServer(String domain) + { + /* FIXME: Check for permission "newMBeanServer" */ + return createServer(domain); + } + + /** + * Common method to create a server for the {@link #createMBeanServer(String)} + * and {@link #newMBeanServer(String)} methods above. + * + * @param domain the default domain name of the server. + * @throws JMRuntimeException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * <code>null</code> from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * <code>javax.management.builder.initial</code> + * exists but names a class which is not a subclass + * of {@link MBeanServerBuilder}. + */ + private static MBeanServer createServer(String domain) + { + if (domain == null) + domain = "DefaultDomain"; + String builderClass = + SystemProperties.getProperty("javax.management.builder.initial"); + if (builderClass == null) + { + if (builder == null || + builder.getClass() != MBeanServerBuilder.class) + builder = new MBeanServerBuilder(); + } + else if (!(builderClass.equals(builder.getClass().getName()))) + { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) + cl = MBeanServerFactory.class.getClassLoader(); + try + { + Class bClass = Class.forName(builderClass, true, cl); + builder = (MBeanServerBuilder) bClass.newInstance(); + } + catch (ClassNotFoundException e) + { + throw (JMRuntimeException) (new JMRuntimeException("The builder class, " + + builderClass + + ", could not be found.")) + .initCause(e); + } + catch (InstantiationException e) + { + throw (JMRuntimeException) (new JMRuntimeException("The builder class, " + + builderClass + + ", could not be instantiated.")) + .initCause(e); + } + catch (IllegalAccessException e) + { + throw (JMRuntimeException) (new JMRuntimeException("The builder class, " + + builderClass + + ", could not be accessed.")) + .initCause(e); + } + } + MBeanServerDelegate delegate = builder.newMBeanServerDelegate(); + if (delegate == null) + throw new JMRuntimeException("A delegate could not be created."); + MBeanServer server = builder.newMBeanServer("DefaultDomain", null, delegate); + if (server == null) + throw new JMRuntimeException("A server could not be created."); + return server; + } + + /** + * Removes the reference to the specified server, thus allowing it to + * be garbage collected. + * + * @param server the server to remove. + * @throws IllegalArgumentException if a reference to the server is not + * held (i.e. it wasn't created by + * {@link #createMBeanServer(String)} + * or this method has already been called + * on it. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanServerPermission(String)}("releaseMBeanServer") + */ + public static void releaseMBeanServer(MBeanServer server) + { + /* FIXME: Check for permission "releaseMBeanServer" */ + Iterator i = servers.values().iterator(); + while (i.hasNext()) + { + MBeanServer s = (MBeanServer) i.next(); + if (server == s) + { + i.remove(); + return; + } + } + throw new IllegalArgumentException("The server given is not referenced."); + } + + +} |