Source for javax.management.MBeanServerFactory

   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 = new HashMap();
  93: 
  94:   /**
  95:    * Private constructor to prevent instance creation.
  96:    */
  97:   private MBeanServerFactory() {}
  98: 
  99:   /**
 100:    * Returns a server implementation using the default domain name
 101:    * of <code>"DefaultDomain"</code>.  The default domain name is
 102:    * used when the domain name specified by the user is <code>null</code.
 103:    * A reference to the created server is retained, so that it can
 104:    * be retrieved at a later date using {@link #findMBeanServer}.
 105:    * Calling this method is equivalent to calling
 106:    * {@link createMBeanServer(String)} with a <code>null</code> value.
 107:    *
 108:    * @return a new {@link MBeanServer} instance.
 109:    * @throws SecurityException if a security manager exists and the
 110:    *                           caller's permissions don't imply {@link
 111:    *                           MBeanServerPermission(String)}("createMBeanServer")
 112:    * @throws JMRuntimeException if the property
 113:    *                     <code>javax.management.builder.initial</code>
 114:    *                     exists but names a class which either can not be
 115:    *                     instantiated or provides an implementation that returns
 116:    *                     <code>null</code> from either
 117:    *                     {@link MBeanServerBuilder#newMBeanServerDelegate()}
 118:    *                     or {@link MBeanServerBuilder#newMBeanServer()}
 119:    * @throws ClassCastException if the property
 120:    *                     <code>javax.management.builder.initial</code>
 121:    *                     exists but names a class which is not a subclass
 122:    *                     of {@link MBeanServerBuilder}.
 123:    * @see #createMBeanServer(String)
 124:    */
 125:   public static MBeanServer createMBeanServer()
 126:   {
 127:     return createMBeanServer(null);
 128:   }
 129: 
 130:   /**
 131:    * Returns a server implementation using the default domain name
 132:    * given, or <code>"DefaultDomain"</code> if this is <code>null</code>.
 133:    * The default domain name is used when the domain name specified by
 134:    * the user is <code>null</code.  A reference to the created server is
 135:    * retained, so that it can be retrieved at a later date using
 136:    * {@link #findMBeanServer}.  
 137:    *
 138:    * @param domain the default domain name of the server.
 139:    * @return a new {@link MBeanServer} instance.
 140:    * @throws SecurityException if a security manager exists and the
 141:    *                           caller's permissions don't imply {@link
 142:    *                           MBeanServerPermission(String)}("createMBeanServer")
 143:    * @throws JMRuntimeException if the property
 144:    *                     <code>javax.management.builder.initial</code>
 145:    *                     exists but names a class which either can not be
 146:    *                     instantiated or provides an implementation that returns
 147:    *                     <code>null</code> from either
 148:    *                     {@link MBeanServerBuilder#newMBeanServerDelegate()}
 149:    *                     or {@link MBeanServerBuilder#newMBeanServer()}
 150:    * @throws ClassCastException if the property
 151:    *                     <code>javax.management.builder.initial</code>
 152:    *                     exists but names a class which is not a subclass
 153:    *                     of {@link MBeanServerBuilder}.
 154:    */
 155:   public static MBeanServer createMBeanServer(String domain)
 156:   {
 157:     SecurityManager sm = System.getSecurityManager();
 158:     if (sm != null)
 159:       sm.checkPermission(new MBeanServerPermission("createMBeanServer"));
 160:     MBeanServer server = createServer(domain);
 161:     try
 162:       {
 163:     ObjectName dn = new
 164:       ObjectName("JMImplementation:type=MBeanServerDelegate");
 165:     servers.put(server.getAttribute(dn, "MBeanServerId"), server);
 166:       }
 167:     catch (MalformedObjectNameException e)
 168:       {
 169:     throw (Error) 
 170:       (new InternalError("Malformed delegate bean name.").initCause(e));
 171:       }
 172:     catch (MBeanException e)
 173:       {
 174:     throw (Error) 
 175:       (new InternalError("Exception in getMBeanServerId().").initCause(e));
 176:       }
 177:     catch (AttributeNotFoundException e)
 178:       {
 179:     throw (Error) 
 180:       (new InternalError("Could not find MBeanServerId attribute.").initCause(e));
 181:       }
 182:     catch (InstanceNotFoundException e)
 183:       {
 184:     throw (Error) 
 185:       (new InternalError("Could not find the delegate bean.").initCause(e));
 186:       }
 187:     catch (ReflectionException e)
 188:       {
 189:     throw (Error) 
 190:       (new InternalError("Could not call getMBeanServerId().").initCause(e));
 191:       }
 192:     return server;
 193:   }
 194: 
 195:   /**
 196:    * Returns the specified server, or, if <code>id</code> is <code>null</code>,
 197:    * a list of all registered servers.  A registered server is one that
 198:    * was created using {@link #createMBeanServer()} or
 199:    * {@link #createMBeanServer(String)} and has not yet been released
 200:    * using {@link releaseMBeanServer(MBeanServer)}.
 201:    *
 202:    * @param id the id of the server to retrieve, or <code>null</code>
 203:    *           to return all servers.
 204:    * @return a list of {@link MBeanServer}s.
 205:    * @throws SecurityException if a security manager exists and the
 206:    *                           caller's permissions don't imply {@link
 207:    *                           MBeanServerPermission(String)}("findMBeanServer")
 208:    */
 209:   public static ArrayList<MBeanServer> findMBeanServer(String id)
 210:   {
 211:     SecurityManager sm = System.getSecurityManager();
 212:     if (sm != null)
 213:       sm.checkPermission(new MBeanServerPermission("findMBeanServer"));
 214:     if (id == null)
 215:       return new ArrayList(servers.values());
 216:     ArrayList<MBeanServer> list = new ArrayList<MBeanServer>();
 217:     MBeanServer server = servers.get(id);
 218:     if (server != null)
 219:       list.add(servers.get(id));
 220:     return list;
 221:   }
 222: 
 223:   /**
 224:    * Returns the class loader repository used by the specified server.
 225:    * This is equivalent to calling {@link MBeanServer#getClassLoaderRepository()}
 226:    * on the given server.
 227:    * 
 228:    * @param server the server whose class loader repository should be
 229:    *               retrieved.
 230:    * @throws NullPointerException if <code>server</code> is <code>null</code>.
 231:    * @throws SecurityException if a security manager exists and the
 232:    *                           caller's permissions don't imply {@link
 233:    *                           MBeanPermission(String,String,ObjectName,String)
 234:    *                           <code>MBeanPermission(null, null, null,
 235:    *                           "getClassLoaderRepository")</code>
 236:    */
 237:   public static ClassLoaderRepository getClassLoaderRepository(MBeanServer server)
 238:   {
 239:     return server.getClassLoaderRepository();
 240:   }
 241: 
 242:   /**
 243:    * Returns a server implementation using the default domain name
 244:    * of <code>"DefaultDomain"</code>.  The default domain name is
 245:    * used when the domain name specified by the user is <code>null</code.
 246:    * No reference to the created server is retained, so the server is
 247:    * garbage collected when it is no longer used, but it can not be
 248:    * retrieved at a later date using {@link #findMBeanServer}.   
 249:    * Calling this method is equivalent to calling
 250:    * {@link newMBeanServer(String)} with a <code>null</code> value.
 251:    *
 252:    * @return a new {@link MBeanServer} instance.
 253:    * @throws SecurityException if a security manager exists and the
 254:    *                           caller's permissions don't imply {@link
 255:    *                           MBeanServerPermission(String)}("newMBeanServer")
 256:    * @throws JMRuntimeException if the property
 257:    *                     <code>javax.management.builder.initial</code>
 258:    *                     exists but names a class which either can not be
 259:    *                     instantiated or provides an implementation that returns
 260:    *                     <code>null</code> from either
 261:    *                     {@link MBeanServerBuilder#newMBeanServerDelegate()}
 262:    *                     or {@link MBeanServerBuilder#newMBeanServer()}
 263:    * @throws ClassCastException if the property
 264:    *                     <code>javax.management.builder.initial</code>
 265:    *                     exists but names a class which is not a subclass
 266:    *                     of {@link MBeanServerBuilder}.
 267:    * @see #newMBeanServer(String)
 268:    */
 269:   public static MBeanServer newMBeanServer()
 270:   {
 271:     return newMBeanServer(null);
 272:   }
 273: 
 274:   /**
 275:    * Returns a server implementation using the default domain name
 276:    * given, or <code>"DefaultDomain"</code> if this is <code>null</code>.
 277:    * The default domain name is used when the domain name specified by
 278:    * the user is <code>null</code.  No reference to the created server is
 279:    * retained, so the server is garbage collected when it is no longer
 280:    * used, but it can not be retrieved at a later date using
 281:    * {@link #findMBeanServer}.
 282:    *
 283:    * @param domain the default domain name of the server.
 284:    * @return a new {@link MBeanServer} instance.
 285:    * @throws SecurityException if a security manager exists and the
 286:    *                           caller's permissions don't imply {@link
 287:    *                           MBeanServerPermission(String)}("newMBeanServer")
 288:    * @throws JMRuntimeException if the property
 289:    *                     <code>javax.management.builder.initial</code>
 290:    *                     exists but names a class which either can not be
 291:    *                     instantiated or provides an implementation that returns
 292:    *                     <code>null</code> from either
 293:    *                     {@link MBeanServerBuilder#newMBeanServerDelegate()}
 294:    *                     or {@link MBeanServerBuilder#newMBeanServer()}
 295:    * @throws ClassCastException if the property
 296:    *                     <code>javax.management.builder.initial</code>
 297:    *                     exists but names a class which is not a subclass
 298:    *                     of {@link MBeanServerBuilder}.
 299:    */
 300:   public static MBeanServer newMBeanServer(String domain)
 301:   {
 302:     SecurityManager sm = System.getSecurityManager();
 303:     if (sm != null)
 304:       sm.checkPermission(new MBeanServerPermission("newMBeanServer"));
 305:     return createServer(domain);
 306:   }
 307: 
 308:   /**
 309:    * Common method to create a server for the {@link #createMBeanServer(String)}
 310:    * and {@link #newMBeanServer(String)} methods above.
 311:    *
 312:    * @param domain the default domain name of the server.
 313:    * @throws JMRuntimeException if the property
 314:    *                     <code>javax.management.builder.initial</code>
 315:    *                     exists but names a class which either can not be
 316:    *                     instantiated or provides an implementation that returns
 317:    *                     <code>null</code> from either
 318:    *                     {@link MBeanServerBuilder#newMBeanServerDelegate()}
 319:    *                     or {@link MBeanServerBuilder#newMBeanServer()}
 320:    * @throws ClassCastException if the property
 321:    *                     <code>javax.management.builder.initial</code>
 322:    *                     exists but names a class which is not a subclass
 323:    *                     of {@link MBeanServerBuilder}.
 324:    */
 325:   private static MBeanServer createServer(String domain)
 326:     {
 327:     if (domain == null)
 328:       domain = "DefaultDomain";
 329:     String builderClass =
 330:       SystemProperties.getProperty("javax.management.builder.initial");
 331:     if (builderClass == null)
 332:       {
 333:     if (builder == null ||
 334:         builder.getClass() != MBeanServerBuilder.class)
 335:       builder = new MBeanServerBuilder();
 336:       }
 337:     else if (!(builder != null &&
 338:            builderClass.equals(builder.getClass().getName())))
 339:       {
 340:     ClassLoader cl = Thread.currentThread().getContextClassLoader();
 341:     if (cl == null)
 342:       cl = MBeanServerFactory.class.getClassLoader();
 343:     try
 344:       {
 345:         Class bClass = Class.forName(builderClass, true, cl);
 346:         builder = (MBeanServerBuilder) bClass.newInstance();
 347:       }
 348:     catch (ClassNotFoundException e)
 349:       {
 350:         throw (JMRuntimeException) (new JMRuntimeException("The builder class, " 
 351:                                    + builderClass +
 352:                                    ", could not be found."))
 353:           .initCause(e);
 354:       }
 355:     catch (InstantiationException e)
 356:       {
 357:         throw (JMRuntimeException) (new JMRuntimeException("The builder class, " 
 358:                                    + builderClass +
 359:                                    ", could not be instantiated."))
 360:           .initCause(e);
 361:       }
 362:     catch (IllegalAccessException e)
 363:       {
 364:         throw (JMRuntimeException) (new JMRuntimeException("The builder class, " 
 365:                                    + builderClass +
 366:                                    ", could not be accessed."))
 367:           .initCause(e);
 368:       }
 369:       }
 370:     MBeanServerDelegate delegate = builder.newMBeanServerDelegate();
 371:     if (delegate == null)
 372:       throw new JMRuntimeException("A delegate could not be created.");
 373:     MBeanServer server = builder.newMBeanServer(domain, null, delegate);
 374:     if (server == null)
 375:       throw new JMRuntimeException("A server could not be created.");
 376:     return server;
 377:   }
 378: 
 379:   /**
 380:    * Removes the reference to the specified server, thus allowing it to
 381:    * be garbage collected.
 382:    *
 383:    * @param server the server to remove.
 384:    * @throws IllegalArgumentException if a reference to the server is not
 385:    *                                  held (i.e. it wasn't created by
 386:    *                                  {@link #createMBeanServer(String)}
 387:    *                                  or this method has already been called
 388:    *                                  on it.
 389:    * @throws SecurityException if a security manager exists and the
 390:    *                           caller's permissions don't imply {@link
 391:    *                           MBeanServerPermission(String)}("releaseMBeanServer")
 392:    */
 393:   public static void releaseMBeanServer(MBeanServer server)
 394:   {
 395:     SecurityManager sm = System.getSecurityManager();
 396:     if (sm != null)
 397:       sm.checkPermission(new MBeanServerPermission("releaseMBeanServer"));
 398:     Iterator<MBeanServer> i = servers.values().iterator();
 399:     while (i.hasNext())
 400:       {
 401:     MBeanServer s = i.next();
 402:     if (server == s)
 403:       {
 404:         i.remove();
 405:         return;
 406:       }
 407:       }
 408:     throw new IllegalArgumentException("The server given is not referenced.");
 409:   }
 410: 
 411: 
 412: }