From 995879ef3b083996ec31c59c5f88958b65a1ce63 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Mon, 4 Dec 2006 00:10:18 +0000 Subject: 2006-12-04 Andrew John Hughes * 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. --- ChangeLog | 11 + gnu/javax/management/Server.java | 63 ++++- java/lang/management/ManagementFactory.java | 171 ++++++++++++ javax/management/MBeanServerFactory.java | 405 ++++++++++++++++++++++++++++ 4 files changed, 637 insertions(+), 13 deletions(-) create mode 100644 javax/management/MBeanServerFactory.java diff --git a/ChangeLog b/ChangeLog index d80c84181..f54176c7e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-12-04 Andrew John Hughes + + * 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 * 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 @@ -103,12 +103,17 @@ public class Server implements MBeanServer { + /** + * 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. @@ -120,11 +125,6 @@ public class Server */ private MBeanServer outer; - /** - * The delegate bean. - */ - private MBeanServerDelegate delegate; - /** * The class loader repository. */ @@ -136,6 +136,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; /** *

@@ -66,6 +73,11 @@ import javax.management.NotCompliantMBeanException; *

    *
  1. Calling the appropriate static method of this factory. *
  2. + *
  3. 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.
  4. *
*

Open Data Types

*

@@ -117,6 +129,60 @@ import javax.management.NotCompliantMBeanException; 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. */ @@ -147,6 +213,11 @@ public class ManagementFactory */ private static CompilationMXBean compilationBean; + /** + * The platform server. + */ + private static MBeanServer platformServer; + /** * Private constructor to prevent instance creation. */ @@ -371,4 +442,104 @@ public class ManagementFactory return gcBeans; } + /** + *

+ * 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 javax.management.builder.initial + * is set, its value will be used as the name of the class which is used + * to provide the server instance. + *

+ *

+ * 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. + *

+ * + * @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; + +/** + *

+ * 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 javax.management.builder.initial, + * and allows the instances created by {@link MBeanServerBuilder} + * to be wrapped, thus providing additional functionality. + *

+ *

+ * The property is used as follows: + *

+ *
    + *
  1. If the property has no value, then an instance of + * {@link MBeanServerBuilder} is used.
  2. + *
  3. If a value is given, then: + *
      + *
    1. The class is loaded using + * Thread.currentThread().getContextClassLoader(), or, + * if this is null, by Class.forName().
    2. + *
    3. Class.newInstance() 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.
    4. + *
  4. + *
  5. 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.
  6. + *
+ */ +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 "DefaultDomain". The default domain name is + * used when the domain name specified by the user is nullnull 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 + * javax.management.builder.initial + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * null from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * javax.management.builder.initial + * 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 "DefaultDomain" if this is null. + * The default domain name is used when the domain name specified by + * the user is nulljavax.management.builder.initial + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * null from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * javax.management.builder.initial + * 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 id is null, + * 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 null + * 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 server is null. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, null, + * "getClassLoaderRepository") + */ + public static ClassLoaderRepository getClassLoaderRepository(MBeanServer server) + { + return server.getClassLoaderRepository(); + } + + /** + * Returns a server implementation using the default domain name + * of "DefaultDomain". The default domain name is + * used when the domain name specified by the user is nullnull 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 + * javax.management.builder.initial + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * null from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * javax.management.builder.initial + * 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 "DefaultDomain" if this is null. + * The default domain name is used when the domain name specified by + * the user is nulljavax.management.builder.initial + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * null from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * javax.management.builder.initial + * 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 + * javax.management.builder.initial + * exists but names a class which either can not be + * instantiated or provides an implementation that returns + * null from either + * {@link MBeanServerBuilder#newMBeanServerDelegate()} + * or {@link MBeanServerBuilder#newMBeanServer()} + * @throws ClassCastException if the property + * javax.management.builder.initial + * 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."); + } + + +} -- cgit v1.2.1