- /*
- * @(#)MBeanServerFactory.java 1.55 04/02/23
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.management;
-
- // java import
- import java.security.AccessController;
- import java.security.Permission;
- import java.security.PrivilegedAction;
- import java.util.ArrayList;
- import java.util.Iterator;
-
- // RI import
- import javax.management.loading.ClassLoaderRepository;
-
- import com.sun.jmx.defaults.ServiceName;
- import com.sun.jmx.defaults.JmxProperties;
- import com.sun.jmx.mbeanserver.GetPropertyAction;
- import com.sun.jmx.trace.Trace;
-
- /**
- * <p>Provides MBean server references. There are no instances of
- * this class.</p>
- *
- * <p>Since JMX 1.2 this class makes it possible to replace the default
- * MBeanServer implementation. This is done using the
- * {@link javax.management.MBeanServerBuilder} class.
- * The class of the initial MBeanServerBuilder to be
- * instantiated can be specified through the
- * <b>javax.management.builder.initial</b> system property.
- * The specified class must be a public subclass of
- * {@link javax.management.MBeanServerBuilder}, and must have a public
- * empty constructor.
- * <p>By default, if no value for that property is specified, an instance of
- * {@link
- * javax.management.MBeanServerBuilder javax.management.MBeanServerBuilder}
- * is created. Otherwise, the MBeanServerFactory attempts to load the
- * specified class using
- * {@link java.lang.Thread#getContextClassLoader()
- * Thread.currentThread().getContextClassLoader()}, or if that is null,
- * {@link java.lang.Class#forName(java.lang.String) Class.forName()}. Then
- * it creates an initial instance of that Class using
- * {@link java.lang.Class#newInstance()}. If any checked exception
- * is raised during this process (e.g.
- * {@link java.lang.ClassNotFoundException},
- * {@link java.lang.InstantiationException}) the MBeanServerFactory
- * will propagate this exception from within a RuntimeException.</p>
- *
- * <p>The <b>javax.management.builder.initial</b> system property is
- * consulted every time a new MBeanServer needs to be created, and the
- * class pointed to by that property is loaded. If that class is different
- * from that of the current MBeanServerBuilder, then a new MBeanServerBuilder
- * is created. Otherwise, the MBeanServerFactory may create a new
- * MBeanServerBuilder or reuse the current one.</p>
- *
- * <p>If the class pointed to by the property cannot be
- * loaded, or does not correspond to a valid subclass of MBeanServerBuilder
- * then an exception is propagated, and no MBeanServer can be created until
- * the <b>javax.management.builder.initial</b> system property is reset to
- * valid value.</p>
- *
- * <p>The MBeanServerBuilder makes it possible to wrap the MBeanServers
- * returned by the default MBeanServerBuilder implementation, for the purpose
- * of e.g. adding an additional security layer.</p>
- *
- * @since 1.5
- */
- public class MBeanServerFactory {
-
- /*
- * There are no instances of this class so don't generate the
- * default public constructor.
- */
- private MBeanServerFactory() {
-
- }
-
- /**
- * The builder that will be used to construct MBeanServers.
- *
- * @since.unbundled JMX 1.2
- **/
- private static MBeanServerBuilder builder = null;
-
- /**
- * Provide a new {@link javax.management.MBeanServerBuilder}.
- * @param builder The new MBeanServerBuilder that will be used to
- * create {@link javax.management.MBeanServer}s.
- * @exception IllegalArgumentException if the given builder is null.
- *
- * @exception SecurityException if there is a SecurityManager and
- * the caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("setMBeanServerBuilder")</code>.
- *
- * @since.unbundled JMX 1.2
- **/
- // public static synchronized void
- // setMBeanServerBuilder(MBeanServerBuilder builder) {
- // checkPermission("setMBeanServerBuilder");
- // MBeanServerFactory.builder = builder;
- // }
-
- /**
- * Get the current {@link javax.management.MBeanServerBuilder}.
- *
- * @return the current {@link javax.management.MBeanServerBuilder}.
- *
- * @exception SecurityException if there is a SecurityManager and
- * the caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("getMBeanServerBuilder")</code>.
- *
- * @since.unbundled JMX 1.2
- **/
- // public static synchronized MBeanServerBuilder getMBeanServerBuilder() {
- // checkPermission("getMBeanServerBuilder");
- // return builder;
- // }
-
- /**
- * Remove internal MBeanServerFactory references to a created
- * MBeanServer. This allows the garbage collector to remove the
- * MBeanServer object.
- *
- * @param mbeanServer the MBeanServer object to remove.
- *
- * @exception java.lang.IllegalArgumentException if
- * <code>mbeanServer</code> was not generated by one of the
- * <code>createMBeanServer</code> methods, or if
- * <code>releaseMBeanServer</code> was already called on it.
- *
- * @exception SecurityException if there is a SecurityManager and
- * the caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("releaseMBeanServer")</code>.
- */
- public static void releaseMBeanServer(MBeanServer mbeanServer) {
- checkPermission("releaseMBeanServer");
-
- removeMBeanServer(mbeanServer);
- }
-
- /**
- * <p>Return a new object implementing the MBeanServer interface
- * with a standard default domain name. The default domain name
- * is used as the domain part in the ObjectName of MBeans when the
- * domain is specified by the user is null.</p>
- *
- * <p>The standard default domain name is
- * <code>DefaultDomain</code>.</p>
- *
- * <p>The MBeanServer reference is internally kept. This will
- * allow <CODE>findMBeanServer</CODE> to return a reference to
- * this MBeanServer object.</p>
- *
- * <p>This method is equivalent to <code>createMBeanServer(null)</code>.
- *
- * @return the newly created MBeanServer.
- *
- * @exception SecurityException if there is a SecurityManager and the
- * caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("createMBeanServer")</code>.
- *
- * @exception JMRuntimeException if the property
- * <code>javax.management.builder.initial</code> exists but the
- * class it names cannot be instantiated through a public
- * no-argument constructor; or if the instantiated builder returns
- * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
- * newMBeanServerDelegate} or {@link
- * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
- *
- * @exception ClassCastException if the property
- * <code>javax.management.builder.initial</code> exists and can be
- * instantiated but is not assignment compatible with {@link
- * MBeanServerBuilder}.
- */
- public static MBeanServer createMBeanServer() {
- return createMBeanServer(null);
- }
-
- /**
- * <p>Return a new object implementing the {@link MBeanServer}
- * interface with the specified default domain name. The given
- * domain name is used as the domain part in the ObjectName of
- * MBeans when the domain is specified by the user is null.</p>
- *
- * <p>The MBeanServer reference is internally kept. This will
- * allow <CODE>findMBeanServer</CODE> to return a reference to
- * this MBeanServer object.</p>
- *
- * @param domain the default domain name for the created
- * MBeanServer. This is the value that will be returned by {@link
- * MBeanServer#getDefaultDomain}.
- *
- * @return the newly created MBeanServer.
- *
- * @exception SecurityException if there is a SecurityManager and
- * the caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("createMBeanServer")</code>.
- *
- * @exception JMRuntimeException if the property
- * <code>javax.management.builder.initial</code> exists but the
- * class it names cannot be instantiated through a public
- * no-argument constructor; or if the instantiated builder returns
- * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
- * newMBeanServerDelegate} or {@link
- * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
- *
- * @exception ClassCastException if the property
- * <code>javax.management.builder.initial</code> exists and can be
- * instantiated but is not assignment compatible with {@link
- * MBeanServerBuilder}.
- */
- public static MBeanServer createMBeanServer(String domain) {
- checkPermission("createMBeanServer");
-
- final MBeanServer mBeanServer = newMBeanServer(domain);
- addMBeanServer(mBeanServer);
- return mBeanServer;
- }
-
- /**
- * <p>Return a new object implementing the MBeanServer interface
- * with a standard default domain name, without keeping an
- * internal reference to this new object. The default domain name
- * is used as the domain part in the ObjectName of MBeans when the
- * domain is specified by the user is null.</p>
- *
- * <p>The standard default domain name is
- * <code>DefaultDomain</code>.</p>
- *
- * <p>No reference is kept. <CODE>findMBeanServer</CODE> will not
- * be able to return a reference to this MBeanServer object, but
- * the garbage collector will be able to remove the MBeanServer
- * object when it is no longer referenced.</p>
- *
- * <p>This method is equivalent to <code>newMBeanServer(null)</code>.</p>
- *
- * @return the newly created MBeanServer.
- *
- * @exception SecurityException if there is a SecurityManager and the
- * caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("newMBeanServer")</code>.
- *
- * @exception JMRuntimeException if the property
- * <code>javax.management.builder.initial</code> exists but the
- * class it names cannot be instantiated through a public
- * no-argument constructor; or if the instantiated builder returns
- * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
- * newMBeanServerDelegate} or {@link
- * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
- *
- * @exception ClassCastException if the property
- * <code>javax.management.builder.initial</code> exists and can be
- * instantiated but is not assignment compatible with {@link
- * MBeanServerBuilder}.
- */
- public static MBeanServer newMBeanServer() {
- return newMBeanServer(null);
- }
-
- /**
- * <p>Return a new object implementing the MBeanServer interface
- * with the specified default domain name, without keeping an
- * internal reference to this new object. The given domain name
- * is used as the domain part in the ObjectName of MBeans when the
- * domain is specified by the user is null.</p>
- *
- * <p>No reference is kept. <CODE>findMBeanServer</CODE> will not
- * be able to return a reference to this MBeanServer object, but
- * the garbage collector will be able to remove the MBeanServer
- * object when it is no longer referenced.</p>
- *
- * @param domain the default domain name for the created
- * MBeanServer. This is the value that will be returned by {@link
- * MBeanServer#getDefaultDomain}.
- *
- * @return the newly created MBeanServer.
- *
- * @exception SecurityException if there is a SecurityManager and the
- * caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("newMBeanServer")</code>.
- *
- * @exception JMRuntimeException if the property
- * <code>javax.management.builder.initial</code> exists but the
- * class it names cannot be instantiated through a public
- * no-argument constructor; or if the instantiated builder returns
- * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
- * newMBeanServerDelegate} or {@link
- * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
- *
- * @exception ClassCastException if the property
- * <code>javax.management.builder.initial</code> exists and can be
- * instantiated but is not assignment compatible with {@link
- * MBeanServerBuilder}.
- */
- public static MBeanServer newMBeanServer(String domain) {
- checkPermission("newMBeanServer");
-
- // Get the builder. Creates a new one if necessary.
- //
- final MBeanServerBuilder mbsBuilder = getNewMBeanServerBuilder();
- // Returned value cannot be null. NullPointerException if violated.
-
- synchronized(mbsBuilder) {
- final MBeanServerDelegate delegate =
- mbsBuilder.newMBeanServerDelegate();
- if (delegate == null) {
- final String msg =
- "MBeanServerBuilder.newMBeanServerDelegate() " +
- "returned null";
- throw new JMRuntimeException(msg);
- }
- final MBeanServer mbeanServer =
- mbsBuilder.newMBeanServer(domain,null,delegate);
- if (mbeanServer == null) {
- final String msg =
- "MBeanServerBuilder.newMBeanServer() returned null";
- throw new JMRuntimeException(msg);
- }
- return mbeanServer;
- }
- }
-
- /**
- * <p>Return a list of registered MBeanServer objects. A
- * registered MBeanServer object is one that was created by one of
- * the <code>createMBeanServer</code> methods and not subsequently
- * released with <code>releaseMBeanServer</code>.</p>
- *
- * @param agentId The agent identifier of the MBeanServer to
- * retrieve. If this parameter is null, all registered
- * MBeanServers in this JVM are returned. Otherwise, only
- * MBeanServers whose id is equal to <code>agentId</code> are
- * returned. The id of an MBeanServer is the
- * <code>MBeanServerId</code> attribute of its delegate MBean.
- *
- * @return A list of MBeanServer objects.
- *
- * @exception SecurityException if there is a SecurityManager and the
- * caller's permissions do not include or imply <code>{@link
- * MBeanServerPermission}("findMBeanServer")</code>.
- */
- public synchronized static ArrayList findMBeanServer(String agentId) {
- checkPermission("findMBeanServer");
-
- if (agentId == null)
- return (ArrayList) mBeanServerList.clone();
-
- ArrayList result = new ArrayList();
- for (Iterator i = mBeanServerList.iterator(); i.hasNext(); ) {
- MBeanServer mbs = (MBeanServer) i.next();
- String name = mBeanServerName(mbs);
- if (agentId.equals(name))
- result.add(mbs);
- }
- return result;
- }
-
- /**
- * Return the ClassLoaderRepository used by the given MBeanServer.
- * This method is equivalent to {@link MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}.
- * @param server The MBeanServer under examination. Since JMX 1.2,
- * if <code>server</code> is <code>null</code>, the result is a
- * {@link NullPointerException}. This behavior differs from what
- * was implemented in JMX 1.1 - where the possibility to use
- * <code>null</code> was deprecated.
- * @return The Class Loader Repository used by the given MBeanServer.
- * @exception SecurityException if there is a SecurityManager and
- * the caller's permissions do not include or imply <code>{@link
- * MBeanPermission}("getClassLoaderRepository")</code>.
- *
- * @exception NullPointerException if <code>server</code> is null.
- *
- * @since.unbundled JMX 1.1
- **/
- public static ClassLoaderRepository getClassLoaderRepository(
- MBeanServer server) {
- return server.getClassLoaderRepository();
- }
-
- private static final ObjectName delegateName;
- static {
- ObjectName name;
- try {
- name = new ObjectName(ServiceName.DELEGATE);
- } catch (JMException e) {
- /* This can only happen if ServiceName.DELEGATE is an invalid
- ObjectName, which means serious brokenness! */
- name = null;
- trace("<clinit>",
- "internal error creating delegate ObjectName: " + e);
- }
- delegateName = name;
- }
-
- private static String mBeanServerName(MBeanServer mbs) {
- try {
- return (String) mbs.getAttribute(delegateName, "MBeanServerId");
- } catch (JMException e) {
- return null;
- }
- }
-
- private static void checkPermission(String action)
- throws SecurityException {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- Permission perm = new MBeanServerPermission(action);
- sm.checkPermission(perm);
- }
- }
-
- private static synchronized void addMBeanServer(MBeanServer mbs) {
- mBeanServerList.add(mbs);
- }
-
- private static synchronized void removeMBeanServer(MBeanServer mbs) {
- boolean removed = mBeanServerList.remove(mbs);
- if (!removed) {
- trace("removeMBeanServer", "MBeanServer was not in list!");
- throw new IllegalArgumentException("MBeanServer was not in list!");
- }
- }
-
- private static final ArrayList mBeanServerList = new ArrayList();
-
- /**
- * Load the builder class through the context class loader.
- * @param builderClassName The name of the builder class.
- **/
- private static Class loadBuilderClass(String builderClassName)
- throws ClassNotFoundException {
- final ClassLoader loader =
- Thread.currentThread().getContextClassLoader();
-
- if (loader != null) {
- // Try with context class loader
- return loader.loadClass(builderClassName);
- }
-
- // No context class loader? Try with Class.forName()
- return Class.forName(builderClassName);
- }
-
- /**
- * Creates the initial builder according to the
- * javax.management.builder.initial System property - if specified.
- * If any checked exception needs to be thrown, it is embedded in
- * a JMRuntimeException.
- **/
- private static MBeanServerBuilder newBuilder(Class builderClass) {
- try {
- final Object builder = builderClass.newInstance();
- return (MBeanServerBuilder)builder;
- } catch (RuntimeException x) {
- throw x;
- } catch (Exception x) {
- final String msg =
- "Failed to instantiate a MBeanServerBuilder from " +
- builderClass + ": " + x;
- throw new JMRuntimeException(msg, x);
- }
- }
-
- /**
- * Instantiate a new builder according to the
- * javax.management.builder.initial System property - if needed.
- **/
- private static synchronized void checkMBeanServerBuilder() {
- try {
- PrivilegedAction act =
- new GetPropertyAction(JmxProperties.JMX_INITIAL_BUILDER);
- String builderClassName = (String)
- AccessController.doPrivileged(act);
-
- try {
- final Class newBuilderClass;
- if (builderClassName == null || builderClassName.length() == 0)
- newBuilderClass = MBeanServerBuilder.class;
- else
- newBuilderClass = loadBuilderClass(builderClassName);
-
- // Check whether a new builder needs to be created
- if (builder != null) {
- final Class builderClass = builder.getClass();
- if (newBuilderClass == builderClass)
- return; // no need to create a new builder...
- }
-
- // Create a new builder
- builder = newBuilder(newBuilderClass);
- } catch (ClassNotFoundException x) {
- final String msg =
- "Failed to load MBeanServerBuilder class " +
- builderClassName + ": " + x;
- throw new JMRuntimeException(msg, x);
- }
- } catch (RuntimeException x) {
- debug("checkMBeanServerBuilder",
- "Failed to instantiate MBeanServerBuilder: " + x +
- "\n\t\tCheck the value of the " +
- JmxProperties.JMX_INITIAL_BUILDER + " property." );
- throw x;
- }
- }
-
- /**
- * Get the current {@link javax.management.MBeanServerBuilder},
- * as specified by the current value of the
- * javax.management.builder.initial property.
- *
- * This method consults the property and instantiates a new builder
- * if needed.
- *
- * @return the new current {@link javax.management.MBeanServerBuilder}.
- *
- * @exception SecurityException if there is a SecurityManager and
- * the caller's permissions do not make it possible to instantiate
- * a new builder.
- * @exception JMRuntimeException if the builder instantiation
- * fails with a checked exception -
- * {@link java.lang.ClassNotFoundException} etc...
- *
- * @since.unbundled JMX 1.2
- **/
- private static synchronized MBeanServerBuilder getNewMBeanServerBuilder() {
- checkMBeanServerBuilder();
- return builder;
- }
-
- /** Private Stuff **/
- private static void trace(String method, String message) {
- if (Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER)) {
- Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER,
- MBeanServerFactory.class.getName(), method, message);
- }
- }
- /** Private Stuff **/
- private static void debug(String method, String message) {
- if (Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER)) {
- Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER,
- MBeanServerFactory.class.getName(), method, message);
- }
- }
- /** Private Stuff **/
- private static void error(String method, String message) {
- if (Trace.isSelected(Trace.LEVEL_ERROR, Trace.INFO_MBEANSERVER)) {
- Trace.send(Trace.LEVEL_ERROR, Trace.INFO_MBEANSERVER,
- MBeanServerFactory.class.getName(), method, message);
- }
- }
- }