Frames | No Frames |
1: /* MBeanServerFactory.java -- Manages server instances. 2: Copyright (C) 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.management; 39: 40: import gnu.classpath.SystemProperties; 41: 42: import java.util.ArrayList; 43: import java.util.HashMap; 44: import java.util.Iterator; 45: import java.util.Map; 46: 47: import javax.management.loading.ClassLoaderRepository; 48: 49: /** 50: * <p> 51: * Creates and maintains a set of {@link MBeanServer} instances. 52: * Server instances, as of JMX 1.2, are created using a subclass 53: * of {@link MBeanServerBuilder}. The exact class used is controlled 54: * by the property <code>javax.management.builder.initial</code>, 55: * and allows the instances created by {@link MBeanServerBuilder} 56: * to be wrapped, thus providing additional functionality. 57: * </p> 58: * <p> 59: * The property is used as follows: 60: * </p> 61: * <ol> 62: * <li>If the property has no value, then an instance of 63: * {@link MBeanServerBuilder} is used.</li> 64: * <li>If a value is given, then: 65: * <ol> 66: * <li>The class is loaded using 67: * <code>Thread.currentThread().getContextClassLoader()</code>, or, 68: * if this is <code>null</code>, by <code>Class.forName()</code>.</li> 69: * <li><code>Class.newInstance()</code> is used to create an instance 70: * of the class. The class must be public and have a public empty 71: * constructor. If an exception is thrown, it is propogated as 72: * a {@link JMRuntimeException} and no new server instances may be 73: * created until the property is set to a valid value.</li> 74: * </ol></li> 75: * <li>The value is checked on each successive request for a server. 76: * If it differs from the class of the existing instance of 77: * {@link MBeanServerBuilder}, then the value is used to create 78: * a new instance.</li> 79: * </ol> 80: */ 81: public class MBeanServerFactory 82: { 83: 84: /** 85: * The last builder instance. 86: */ 87: private static MBeanServerBuilder builder; 88: 89: /** 90: * The map of registered servers (identifiers to servers). 91: */ 92: private static final Map<Object,MBeanServer> servers = 93: new HashMap<Object,MBeanServer>(); 94: 95: /** 96: * Private constructor to prevent instance creation. 97: */ 98: private MBeanServerFactory() {} 99: 100: /** 101: * Returns a server implementation using the default domain name 102: * of <code>"DefaultDomain"</code>. The default domain name is 103: * used when the domain name specified by the user is <code>null</code. 104: * A reference to the created server is retained, so that it can 105: * be retrieved at a later date using {@link #findMBeanServer}. 106: * Calling this method is equivalent to calling 107: * {@link createMBeanServer(String)} with a <code>null</code> value. 108: * 109: * @return a new {@link MBeanServer} instance. 110: * @throws SecurityException if a security manager exists and the 111: * caller's permissions don't imply {@link 112: * MBeanServerPermission(String)}("createMBeanServer") 113: * @throws JMRuntimeException if the property 114: * <code>javax.management.builder.initial</code> 115: * exists but names a class which either can not be 116: * instantiated or provides an implementation that returns 117: * <code>null</code> from either 118: * {@link MBeanServerBuilder#newMBeanServerDelegate()} 119: * or {@link MBeanServerBuilder#newMBeanServer()} 120: * @throws ClassCastException if the property 121: * <code>javax.management.builder.initial</code> 122: * exists but names a class which is not a subclass 123: * of {@link MBeanServerBuilder}. 124: * @see #createMBeanServer(String) 125: */ 126: public static MBeanServer createMBeanServer() 127: { 128: return createMBeanServer(null); 129: } 130: 131: /** 132: * Returns a server implementation using the default domain name 133: * given, or <code>"DefaultDomain"</code> if this is <code>null</code>. 134: * The default domain name is used when the domain name specified by 135: * the user is <code>null</code. A reference to the created server is 136: * retained, so that it can be retrieved at a later date using 137: * {@link #findMBeanServer}. 138: * 139: * @param domain the default domain name of the server. 140: * @return a new {@link MBeanServer} instance. 141: * @throws SecurityException if a security manager exists and the 142: * caller's permissions don't imply {@link 143: * MBeanServerPermission(String)}("createMBeanServer") 144: * @throws JMRuntimeException if the property 145: * <code>javax.management.builder.initial</code> 146: * exists but names a class which either can not be 147: * instantiated or provides an implementation that returns 148: * <code>null</code> from either 149: * {@link MBeanServerBuilder#newMBeanServerDelegate()} 150: * or {@link MBeanServerBuilder#newMBeanServer()} 151: * @throws ClassCastException if the property 152: * <code>javax.management.builder.initial</code> 153: * exists but names a class which is not a subclass 154: * of {@link MBeanServerBuilder}. 155: */ 156: public static MBeanServer createMBeanServer(String domain) 157: { 158: SecurityManager sm = System.getSecurityManager(); 159: if (sm != null) 160: sm.checkPermission(new MBeanServerPermission("createMBeanServer")); 161: MBeanServer server = createServer(domain); 162: try 163: { 164: ObjectName dn = new 165: ObjectName("JMImplementation:type=MBeanServerDelegate"); 166: servers.put(server.getAttribute(dn, "MBeanServerId"), server); 167: } 168: catch (MalformedObjectNameException e) 169: { 170: throw (Error) 171: (new InternalError("Malformed delegate bean name.").initCause(e)); 172: } 173: catch (MBeanException e) 174: { 175: throw (Error) 176: (new InternalError("Exception in getMBeanServerId().").initCause(e)); 177: } 178: catch (AttributeNotFoundException e) 179: { 180: throw (Error) 181: (new InternalError("Could not find MBeanServerId attribute.").initCause(e)); 182: } 183: catch (InstanceNotFoundException e) 184: { 185: throw (Error) 186: (new InternalError("Could not find the delegate bean.").initCause(e)); 187: } 188: catch (ReflectionException e) 189: { 190: throw (Error) 191: (new InternalError("Could not call getMBeanServerId().").initCause(e)); 192: } 193: return server; 194: } 195: 196: /** 197: * Returns the specified server, or, if <code>id</code> is <code>null</code>, 198: * a list of all registered servers. A registered server is one that 199: * was created using {@link #createMBeanServer()} or 200: * {@link #createMBeanServer(String)} and has not yet been released 201: * using {@link releaseMBeanServer(MBeanServer)}. 202: * 203: * @param id the id of the server to retrieve, or <code>null</code> 204: * to return all servers. 205: * @return a list of {@link MBeanServer}s. 206: * @throws SecurityException if a security manager exists and the 207: * caller's permissions don't imply {@link 208: * MBeanServerPermission(String)}("findMBeanServer") 209: */ 210: public static ArrayList<MBeanServer> findMBeanServer(String id) 211: { 212: SecurityManager sm = System.getSecurityManager(); 213: if (sm != null) 214: sm.checkPermission(new MBeanServerPermission("findMBeanServer")); 215: if (id == null) 216: return new ArrayList<MBeanServer>(servers.values()); 217: ArrayList<MBeanServer> list = new ArrayList<MBeanServer>(); 218: MBeanServer server = servers.get(id); 219: if (server != null) 220: list.add(servers.get(id)); 221: return list; 222: } 223: 224: /** 225: * Returns the class loader repository used by the specified server. 226: * This is equivalent to calling {@link MBeanServer#getClassLoaderRepository()} 227: * on the given server. 228: * 229: * @param server the server whose class loader repository should be 230: * retrieved. 231: * @throws NullPointerException if <code>server</code> is <code>null</code>. 232: * @throws SecurityException if a security manager exists and the 233: * caller's permissions don't imply {@link 234: * MBeanPermission(String,String,ObjectName,String) 235: * <code>MBeanPermission(null, null, null, 236: * "getClassLoaderRepository")</code> 237: */ 238: public static ClassLoaderRepository getClassLoaderRepository(MBeanServer server) 239: { 240: return server.getClassLoaderRepository(); 241: } 242: 243: /** 244: * Returns a server implementation using the default domain name 245: * of <code>"DefaultDomain"</code>. The default domain name is 246: * used when the domain name specified by the user is <code>null</code. 247: * No reference to the created server is retained, so the server is 248: * garbage collected when it is no longer used, but it can not be 249: * retrieved at a later date using {@link #findMBeanServer}. 250: * Calling this method is equivalent to calling 251: * {@link newMBeanServer(String)} with a <code>null</code> value. 252: * 253: * @return a new {@link MBeanServer} instance. 254: * @throws SecurityException if a security manager exists and the 255: * caller's permissions don't imply {@link 256: * MBeanServerPermission(String)}("newMBeanServer") 257: * @throws JMRuntimeException if the property 258: * <code>javax.management.builder.initial</code> 259: * exists but names a class which either can not be 260: * instantiated or provides an implementation that returns 261: * <code>null</code> from either 262: * {@link MBeanServerBuilder#newMBeanServerDelegate()} 263: * or {@link MBeanServerBuilder#newMBeanServer()} 264: * @throws ClassCastException if the property 265: * <code>javax.management.builder.initial</code> 266: * exists but names a class which is not a subclass 267: * of {@link MBeanServerBuilder}. 268: * @see #newMBeanServer(String) 269: */ 270: public static MBeanServer newMBeanServer() 271: { 272: return newMBeanServer(null); 273: } 274: 275: /** 276: * Returns a server implementation using the default domain name 277: * given, or <code>"DefaultDomain"</code> if this is <code>null</code>. 278: * The default domain name is used when the domain name specified by 279: * the user is <code>null</code. No reference to the created server is 280: * retained, so the server is garbage collected when it is no longer 281: * used, but it can not be retrieved at a later date using 282: * {@link #findMBeanServer}. 283: * 284: * @param domain the default domain name of the server. 285: * @return a new {@link MBeanServer} instance. 286: * @throws SecurityException if a security manager exists and the 287: * caller's permissions don't imply {@link 288: * MBeanServerPermission(String)}("newMBeanServer") 289: * @throws JMRuntimeException if the property 290: * <code>javax.management.builder.initial</code> 291: * exists but names a class which either can not be 292: * instantiated or provides an implementation that returns 293: * <code>null</code> from either 294: * {@link MBeanServerBuilder#newMBeanServerDelegate()} 295: * or {@link MBeanServerBuilder#newMBeanServer()} 296: * @throws ClassCastException if the property 297: * <code>javax.management.builder.initial</code> 298: * exists but names a class which is not a subclass 299: * of {@link MBeanServerBuilder}. 300: */ 301: public static MBeanServer newMBeanServer(String domain) 302: { 303: SecurityManager sm = System.getSecurityManager(); 304: if (sm != null) 305: sm.checkPermission(new MBeanServerPermission("newMBeanServer")); 306: return createServer(domain); 307: } 308: 309: /** 310: * Common method to create a server for the {@link #createMBeanServer(String)} 311: * and {@link #newMBeanServer(String)} methods above. 312: * 313: * @param domain the default domain name of the server. 314: * @throws JMRuntimeException if the property 315: * <code>javax.management.builder.initial</code> 316: * exists but names a class which either can not be 317: * instantiated or provides an implementation that returns 318: * <code>null</code> from either 319: * {@link MBeanServerBuilder#newMBeanServerDelegate()} 320: * or {@link MBeanServerBuilder#newMBeanServer()} 321: * @throws ClassCastException if the property 322: * <code>javax.management.builder.initial</code> 323: * exists but names a class which is not a subclass 324: * of {@link MBeanServerBuilder}. 325: */ 326: private static MBeanServer createServer(String domain) 327: { 328: if (domain == null) 329: domain = "DefaultDomain"; 330: String builderClass = 331: SystemProperties.getProperty("javax.management.builder.initial"); 332: if (builderClass == null) 333: { 334: if (builder == null || 335: builder.getClass() != MBeanServerBuilder.class) 336: builder = new MBeanServerBuilder(); 337: } 338: else if (!(builder != null && 339: builderClass.equals(builder.getClass().getName()))) 340: { 341: ClassLoader cl = Thread.currentThread().getContextClassLoader(); 342: if (cl == null) 343: cl = MBeanServerFactory.class.getClassLoader(); 344: try 345: { 346: Class<?> bClass = Class.forName(builderClass, true, cl); 347: builder = (MBeanServerBuilder) bClass.newInstance(); 348: } 349: catch (ClassNotFoundException e) 350: { 351: throw (JMRuntimeException) (new JMRuntimeException("The builder class, " 352: + builderClass + 353: ", could not be found.")) 354: .initCause(e); 355: } 356: catch (InstantiationException e) 357: { 358: throw (JMRuntimeException) (new JMRuntimeException("The builder class, " 359: + builderClass + 360: ", could not be instantiated.")) 361: .initCause(e); 362: } 363: catch (IllegalAccessException e) 364: { 365: throw (JMRuntimeException) (new JMRuntimeException("The builder class, " 366: + builderClass + 367: ", could not be accessed.")) 368: .initCause(e); 369: } 370: } 371: MBeanServerDelegate delegate = builder.newMBeanServerDelegate(); 372: if (delegate == null) 373: throw new JMRuntimeException("A delegate could not be created."); 374: MBeanServer server = builder.newMBeanServer(domain, null, delegate); 375: if (server == null) 376: throw new JMRuntimeException("A server could not be created."); 377: return server; 378: } 379: 380: /** 381: * Removes the reference to the specified server, thus allowing it to 382: * be garbage collected. 383: * 384: * @param server the server to remove. 385: * @throws IllegalArgumentException if a reference to the server is not 386: * held (i.e. it wasn't created by 387: * {@link #createMBeanServer(String)} 388: * or this method has already been called 389: * on it. 390: * @throws SecurityException if a security manager exists and the 391: * caller's permissions don't imply {@link 392: * MBeanServerPermission(String)}("releaseMBeanServer") 393: */ 394: public static void releaseMBeanServer(MBeanServer server) 395: { 396: SecurityManager sm = System.getSecurityManager(); 397: if (sm != null) 398: sm.checkPermission(new MBeanServerPermission("releaseMBeanServer")); 399: Iterator<MBeanServer> i = servers.values().iterator(); 400: while (i.hasNext()) 401: { 402: MBeanServer s = i.next(); 403: if (server == s) 404: { 405: i.remove(); 406: return; 407: } 408: } 409: throw new IllegalArgumentException("The server given is not referenced."); 410: } 411: 412: 413: }