| /* 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 final Map<Object,MBeanServer> servers = new HashMap(); |
| |
| /** |
| * 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) |
| { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) |
| sm.checkPermission(new MBeanServerPermission("createMBeanServer")); |
| MBeanServer server = createServer(domain); |
| 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<MBeanServer> findMBeanServer(String id) |
| { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) |
| sm.checkPermission(new MBeanServerPermission("findMBeanServer")); |
| if (id == null) |
| return new ArrayList(servers.values()); |
| ArrayList<MBeanServer> list = new ArrayList<MBeanServer>(); |
| MBeanServer server = 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) |
| { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) |
| sm.checkPermission(new MBeanServerPermission("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 (!(builder != null && |
| 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(domain, 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) |
| { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) |
| sm.checkPermission(new MBeanServerPermission("releaseMBeanServer")); |
| Iterator<MBeanServer> i = servers.values().iterator(); |
| while (i.hasNext()) |
| { |
| MBeanServer s = i.next(); |
| if (server == s) |
| { |
| i.remove(); |
| return; |
| } |
| } |
| throw new IllegalArgumentException("The server given is not referenced."); |
| } |
| |
| |
| } |