1 /* 2 * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.management; 27 28 import com.sun.jmx.defaults.JmxProperties; 29 import static com.sun.jmx.defaults.JmxProperties.JMX_INITIAL_BUILDER; 30 import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; 31 import com.sun.jmx.mbeanserver.GetPropertyAction; 32 import java.security.AccessController; 33 import java.security.Permission; 34 import java.util.ArrayList; 35 import java.util.logging.Level; 36 import javax.management.loading.ClassLoaderRepository; 37 38 39 /** 40 * <p>Provides MBean server references. There are no instances of 41 * this class.</p> 42 * 43 * <p>Since JMX 1.2 this class makes it possible to replace the default 44 * MBeanServer implementation. This is done using the 45 * {@link javax.management.MBeanServerBuilder} class. 46 * The class of the initial MBeanServerBuilder to be 47 * instantiated can be specified through the 48 * <b>javax.management.builder.initial</b> system property. 49 * The specified class must be a public subclass of 50 * {@link javax.management.MBeanServerBuilder}, and must have a public 51 * empty constructor. 52 * <p>By default, if no value for that property is specified, an instance of 53 * {@link 54 * javax.management.MBeanServerBuilder javax.management.MBeanServerBuilder} 55 * is created. Otherwise, the MBeanServerFactory attempts to load the 56 * specified class using 57 * {@link java.lang.Thread#getContextClassLoader() 58 * Thread.currentThread().getContextClassLoader()}, or if that is null, 59 * {@link java.lang.Class#forName(java.lang.String) Class.forName()}. Then 60 * it creates an initial instance of that Class using 61 * {@link java.lang.Class#newInstance()}. If any checked exception 62 * is raised during this process (e.g. 63 * {@link java.lang.ClassNotFoundException}, 64 * {@link java.lang.InstantiationException}) the MBeanServerFactory 65 * will propagate this exception from within a RuntimeException.</p> 66 * 67 * <p>The <b>javax.management.builder.initial</b> system property is 68 * consulted every time a new MBeanServer needs to be created, and the 69 * class pointed to by that property is loaded. If that class is different 70 * from that of the current MBeanServerBuilder, then a new MBeanServerBuilder 71 * is created. Otherwise, the MBeanServerFactory may create a new 72 * MBeanServerBuilder or reuse the current one.</p> 73 * 74 * <p>If the class pointed to by the property cannot be 75 * loaded, or does not correspond to a valid subclass of MBeanServerBuilder 76 * then an exception is propagated, and no MBeanServer can be created until 77 * the <b>javax.management.builder.initial</b> system property is reset to 78 * valid value.</p> 79 * 80 * <p>The MBeanServerBuilder makes it possible to wrap the MBeanServers 81 * returned by the default MBeanServerBuilder implementation, for the purpose 82 * of e.g. adding an additional security layer.</p> 83 * 84 * @since 1.5 85 */ 86 public class MBeanServerFactory { 87 88 /* 89 * There are no instances of this class so don't generate the 90 * default public constructor. 91 */ 92 private MBeanServerFactory() { 93 94 } 95 96 /** 97 * The builder that will be used to construct MBeanServers. 98 * 99 **/ 100 private static MBeanServerBuilder builder = null; 101 102 /** 103 * Provide a new {@link javax.management.MBeanServerBuilder}. 104 * @param builder The new MBeanServerBuilder that will be used to 105 * create {@link javax.management.MBeanServer}s. 106 * @exception IllegalArgumentException if the given builder is null. 107 * 108 * @exception SecurityException if there is a SecurityManager and 109 * the caller's permissions do not include or imply <code>{@link 110 * MBeanServerPermission}("setMBeanServerBuilder")</code>. 111 * 112 **/ 113 // public static synchronized void 114 // setMBeanServerBuilder(MBeanServerBuilder builder) { 115 // checkPermission("setMBeanServerBuilder"); 116 // MBeanServerFactory.builder = builder; 117 // } 118 119 /** 120 * Get the current {@link javax.management.MBeanServerBuilder}. 121 * 122 * @return the current {@link javax.management.MBeanServerBuilder}. 123 * 124 * @exception SecurityException if there is a SecurityManager and 125 * the caller's permissions do not include or imply <code>{@link 126 * MBeanServerPermission}("getMBeanServerBuilder")</code>. 127 * 128 **/ 129 // public static synchronized MBeanServerBuilder getMBeanServerBuilder() { 130 // checkPermission("getMBeanServerBuilder"); 131 // return builder; 132 // } 133 134 /** 135 * Remove internal MBeanServerFactory references to a created 136 * MBeanServer. This allows the garbage collector to remove the 137 * MBeanServer object. 138 * 139 * @param mbeanServer the MBeanServer object to remove. 140 * 141 * @exception java.lang.IllegalArgumentException if 142 * <code>mbeanServer</code> was not generated by one of the 143 * <code>createMBeanServer</code> methods, or if 144 * <code>releaseMBeanServer</code> was already called on it. 145 * 146 * @exception SecurityException if there is a SecurityManager and 147 * the caller's permissions do not include or imply <code>{@link 148 * MBeanServerPermission}("releaseMBeanServer")</code>. 149 */ 150 public static void releaseMBeanServer(MBeanServer mbeanServer) { 151 checkPermission("releaseMBeanServer"); 152 153 removeMBeanServer(mbeanServer); 154 } 155 156 /** 157 * <p>Return a new object implementing the MBeanServer interface 158 * with a standard default domain name. The default domain name 159 * is used as the domain part in the ObjectName of MBeans when the 160 * domain is specified by the user is null.</p> 161 * 162 * <p>The standard default domain name is 163 * <code>DefaultDomain</code>.</p> 164 * 165 * <p>The MBeanServer reference is internally kept. This will 166 * allow <CODE>findMBeanServer</CODE> to return a reference to 167 * this MBeanServer object.</p> 168 * 169 * <p>This method is equivalent to <code>createMBeanServer(null)</code>. 170 * 171 * @return the newly created MBeanServer. 172 * 173 * @exception SecurityException if there is a SecurityManager and the 174 * caller's permissions do not include or imply <code>{@link 175 * MBeanServerPermission}("createMBeanServer")</code>. 176 * 177 * @exception JMRuntimeException if the property 178 * <code>javax.management.builder.initial</code> exists but the 179 * class it names cannot be instantiated through a public 180 * no-argument constructor; or if the instantiated builder returns 181 * null from its {@link MBeanServerBuilder#newMBeanServerDelegate 182 * newMBeanServerDelegate} or {@link 183 * MBeanServerBuilder#newMBeanServer newMBeanServer} methods. 184 * 185 * @exception ClassCastException if the property 186 * <code>javax.management.builder.initial</code> exists and can be 187 * instantiated but is not assignment compatible with {@link 188 * MBeanServerBuilder}. 189 */ 190 public static MBeanServer createMBeanServer() { 191 return createMBeanServer(null); 192 } 193 194 /** 195 * <p>Return a new object implementing the {@link MBeanServer} 196 * interface with the specified default domain name. The given 197 * domain name is used as the domain part in the ObjectName of 198 * MBeans when the domain is specified by the user is null.</p> 199 * 200 * <p>The MBeanServer reference is internally kept. This will 201 * allow <CODE>findMBeanServer</CODE> to return a reference to 202 * this MBeanServer object.</p> 203 * 204 * @param domain the default domain name for the created 205 * MBeanServer. This is the value that will be returned by {@link 206 * MBeanServer#getDefaultDomain}. 207 * 208 * @return the newly created MBeanServer. 209 * 210 * @exception SecurityException if there is a SecurityManager and 211 * the caller's permissions do not include or imply <code>{@link 212 * MBeanServerPermission}("createMBeanServer")</code>. 213 * 214 * @exception JMRuntimeException if the property 215 * <code>javax.management.builder.initial</code> exists but the 216 * class it names cannot be instantiated through a public 217 * no-argument constructor; or if the instantiated builder returns 218 * null from its {@link MBeanServerBuilder#newMBeanServerDelegate 219 * newMBeanServerDelegate} or {@link 220 * MBeanServerBuilder#newMBeanServer newMBeanServer} methods. 221 * 222 * @exception ClassCastException if the property 223 * <code>javax.management.builder.initial</code> exists and can be 224 * instantiated but is not assignment compatible with {@link 225 * MBeanServerBuilder}. 226 */ 227 public static MBeanServer createMBeanServer(String domain) { 228 checkPermission("createMBeanServer"); 229 230 final MBeanServer mBeanServer = newMBeanServer(domain); 231 addMBeanServer(mBeanServer); 232 return mBeanServer; 233 } 234 235 /** 236 * <p>Return a new object implementing the MBeanServer interface 237 * with a standard default domain name, without keeping an 238 * internal reference to this new object. The default domain name 239 * is used as the domain part in the ObjectName of MBeans when the 240 * domain is specified by the user is null.</p> 241 * 242 * <p>The standard default domain name is 243 * <code>DefaultDomain</code>.</p> 244 * 245 * <p>No reference is kept. <CODE>findMBeanServer</CODE> will not 246 * be able to return a reference to this MBeanServer object, but 247 * the garbage collector will be able to remove the MBeanServer 248 * object when it is no longer referenced.</p> 249 * 250 * <p>This method is equivalent to <code>newMBeanServer(null)</code>.</p> 251 * 252 * @return the newly created MBeanServer. 253 * 254 * @exception SecurityException if there is a SecurityManager and the 255 * caller's permissions do not include or imply <code>{@link 256 * MBeanServerPermission}("newMBeanServer")</code>. 257 * 258 * @exception JMRuntimeException if the property 259 * <code>javax.management.builder.initial</code> exists but the 260 * class it names cannot be instantiated through a public 261 * no-argument constructor; or if the instantiated builder returns 262 * null from its {@link MBeanServerBuilder#newMBeanServerDelegate 263 * newMBeanServerDelegate} or {@link 264 * MBeanServerBuilder#newMBeanServer newMBeanServer} methods. 265 * 266 * @exception ClassCastException if the property 267 * <code>javax.management.builder.initial</code> exists and can be 268 * instantiated but is not assignment compatible with {@link 269 * MBeanServerBuilder}. 270 */ 271 public static MBeanServer newMBeanServer() { 272 return newMBeanServer(null); 273 } 274 275 /** 276 * <p>Return a new object implementing the MBeanServer interface 277 * with the specified default domain name, without keeping an 278 * internal reference to this new object. The given domain name 279 * is used as the domain part in the ObjectName of MBeans when the 280 * domain is specified by the user is null.</p> 281 * 282 * <p>No reference is kept. <CODE>findMBeanServer</CODE> will not 283 * be able to return a reference to this MBeanServer object, but 284 * the garbage collector will be able to remove the MBeanServer 285 * object when it is no longer referenced.</p> 286 * 287 * @param domain the default domain name for the created 288 * MBeanServer. This is the value that will be returned by {@link 289 * MBeanServer#getDefaultDomain}. 290 * 291 * @return the newly created MBeanServer. 292 * 293 * @exception SecurityException if there is a SecurityManager and the 294 * caller's permissions do not include or imply <code>{@link 295 * MBeanServerPermission}("newMBeanServer")</code>. 296 * 297 * @exception JMRuntimeException if the property 298 * <code>javax.management.builder.initial</code> exists but the 299 * class it names cannot be instantiated through a public 300 * no-argument constructor; or if the instantiated builder returns 301 * null from its {@link MBeanServerBuilder#newMBeanServerDelegate 302 * newMBeanServerDelegate} or {@link 303 * MBeanServerBuilder#newMBeanServer newMBeanServer} methods. 304 * 305 * @exception ClassCastException if the property 306 * <code>javax.management.builder.initial</code> exists and can be 307 * instantiated but is not assignment compatible with {@link 308 * MBeanServerBuilder}. 309 */ 310 public static MBeanServer newMBeanServer(String domain) { 311 checkPermission("newMBeanServer"); 312 313 // Get the builder. Creates a new one if necessary. 314 // 315 final MBeanServerBuilder mbsBuilder = getNewMBeanServerBuilder(); 316 // Returned value cannot be null. NullPointerException if violated. 317 318 synchronized(mbsBuilder) { 319 final MBeanServerDelegate delegate = 320 mbsBuilder.newMBeanServerDelegate(); 321 if (delegate == null) { 322 final String msg = 323 "MBeanServerBuilder.newMBeanServerDelegate() " + 324 "returned null"; 325 throw new JMRuntimeException(msg); 326 } 327 final MBeanServer mbeanServer = 328 mbsBuilder.newMBeanServer(domain,null,delegate); 329 if (mbeanServer == null) { 330 final String msg = 331 "MBeanServerBuilder.newMBeanServer() returned null"; 332 throw new JMRuntimeException(msg); 333 } 334 return mbeanServer; 335 } 336 } 337 338 /** 339 * <p>Return a list of registered MBeanServer objects. A 340 * registered MBeanServer object is one that was created by one of 341 * the <code>createMBeanServer</code> methods and not subsequently 342 * released with <code>releaseMBeanServer</code>.</p> 343 * 344 * @param agentId The agent identifier of the MBeanServer to 345 * retrieve. If this parameter is null, all registered 346 * MBeanServers in this JVM are returned. Otherwise, only 347 * MBeanServers whose id is equal to <code>agentId</code> are 348 * returned. The id of an MBeanServer is the 349 * <code>MBeanServerId</code> attribute of its delegate MBean. 350 * 351 * @return A list of MBeanServer objects. 352 * 353 * @exception SecurityException if there is a SecurityManager and the 354 * caller's permissions do not include or imply <code>{@link 355 * MBeanServerPermission}("findMBeanServer")</code>. 356 */ 357 public synchronized static 358 ArrayList<MBeanServer> findMBeanServer(String agentId) { 359 360 checkPermission("findMBeanServer"); 361 362 if (agentId == null) 363 return new ArrayList<MBeanServer>(mBeanServerList); 364 365 ArrayList<MBeanServer> result = new ArrayList<MBeanServer>(); 366 for (MBeanServer mbs : mBeanServerList) { 367 String name = mBeanServerId(mbs); 368 if (agentId.equals(name)) 369 result.add(mbs); 370 } 371 return result; 372 } 373 374 /** 375 * Return the ClassLoaderRepository used by the given MBeanServer. 376 * This method is equivalent to {@link 377 * MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}. 378 * @param server The MBeanServer under examination. Since JMX 1.2, 379 * if <code>server</code> is <code>null</code>, the result is a 380 * {@link NullPointerException}. This behavior differs from what 381 * was implemented in JMX 1.1 - where the possibility to use 382 * <code>null</code> was deprecated. 383 * @return The Class Loader Repository used by the given MBeanServer. 384 * @exception SecurityException if there is a SecurityManager and 385 * the caller's permissions do not include or imply <code>{@link 386 * MBeanPermission}("getClassLoaderRepository")</code>. 387 * 388 * @exception NullPointerException if <code>server</code> is null. 389 * 390 **/ 391 public static ClassLoaderRepository getClassLoaderRepository( 392 MBeanServer server) { 393 return server.getClassLoaderRepository(); 394 } 395 396 private static String mBeanServerId(MBeanServer mbs) { 397 try { 398 return (String) mbs.getAttribute(MBeanServerDelegate.DELEGATE_NAME, 399 "MBeanServerId"); 400 } catch (JMException e) { 401 JmxProperties.MISC_LOGGER.finest( 402 "Ignoring exception while getting MBeanServerId: "+e); 403 return null; 404 } 405 } 406 407 private static void checkPermission(String action) 408 throws SecurityException { 409 SecurityManager sm = System.getSecurityManager(); 410 if (sm != null) { 411 Permission perm = new MBeanServerPermission(action); 412 sm.checkPermission(perm); 413 } 414 } 415 416 private static synchronized void addMBeanServer(MBeanServer mbs) { 417 mBeanServerList.add(mbs); 418 } 419 420 private static synchronized void removeMBeanServer(MBeanServer mbs) { 421 boolean removed = mBeanServerList.remove(mbs); 422 if (!removed) { 423 MBEANSERVER_LOGGER.logp(Level.FINER, 424 MBeanServerFactory.class.getName(), 425 "removeMBeanServer(MBeanServer)", 426 "MBeanServer was not in list!"); 427 throw new IllegalArgumentException("MBeanServer was not in list!"); 428 } 429 } 430 431 private static final ArrayList<MBeanServer> mBeanServerList = 432 new ArrayList<MBeanServer>(); 433 434 /** 435 * Load the builder class through the context class loader. 436 * @param builderClassName The name of the builder class. 437 **/ 438 private static Class<?> loadBuilderClass(String builderClassName) 439 throws ClassNotFoundException { 440 final ClassLoader loader = 441 Thread.currentThread().getContextClassLoader(); 442 443 if (loader != null) { 444 // Try with context class loader 445 return loader.loadClass(builderClassName); 446 } 447 448 // No context class loader? Try with Class.forName() 449 return Class.forName(builderClassName); 450 } 451 452 /** 453 * Creates the initial builder according to the 454 * javax.management.builder.initial System property - if specified. 455 * If any checked exception needs to be thrown, it is embedded in 456 * a JMRuntimeException. 457 **/ 458 private static MBeanServerBuilder newBuilder(Class<?> builderClass) { 459 try { 460 final Object abuilder = builderClass.newInstance(); 461 return (MBeanServerBuilder)abuilder; 462 } catch (RuntimeException x) { 463 throw x; 464 } catch (Exception x) { 465 final String msg = 466 "Failed to instantiate a MBeanServerBuilder from " + 467 builderClass + ": " + x; 468 throw new JMRuntimeException(msg, x); 469 } 470 } 471 472 /** 473 * Instantiate a new builder according to the 474 * javax.management.builder.initial System property - if needed. 475 **/ 476 private static synchronized void checkMBeanServerBuilder() { 477 try { 478 GetPropertyAction act = 479 new GetPropertyAction(JMX_INITIAL_BUILDER); 480 String builderClassName = AccessController.doPrivileged(act); 481 482 try { 483 final Class<?> newBuilderClass; 484 if (builderClassName == null || builderClassName.length() == 0) 485 newBuilderClass = MBeanServerBuilder.class; 486 else 487 newBuilderClass = loadBuilderClass(builderClassName); 488 489 // Check whether a new builder needs to be created 490 if (builder != null) { 491 final Class<?> builderClass = builder.getClass(); 492 if (newBuilderClass == builderClass) 493 return; // no need to create a new builder... 494 } 495 496 // Create a new builder 497 builder = newBuilder(newBuilderClass); 498 } catch (ClassNotFoundException x) { 499 final String msg = 500 "Failed to load MBeanServerBuilder class " + 501 builderClassName + ": " + x; 502 throw new JMRuntimeException(msg, x); 503 } 504 } catch (RuntimeException x) { 505 if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { 506 StringBuilder strb = new StringBuilder() 507 .append("Failed to instantiate MBeanServerBuilder: ").append(x) 508 .append("\n\t\tCheck the value of the ") 509 .append(JMX_INITIAL_BUILDER).append(" property."); 510 MBEANSERVER_LOGGER.logp(Level.FINEST, 511 MBeanServerFactory.class.getName(), 512 "checkMBeanServerBuilder", 513 strb.toString()); 514 } 515 throw x; 516 } 517 } 518 519 /** 520 * Get the current {@link javax.management.MBeanServerBuilder}, 521 * as specified by the current value of the 522 * javax.management.builder.initial property. 523 * 524 * This method consults the property and instantiates a new builder 525 * if needed. 526 * 527 * @return the new current {@link javax.management.MBeanServerBuilder}. 528 * 529 * @exception SecurityException if there is a SecurityManager and 530 * the caller's permissions do not make it possible to instantiate 531 * a new builder. 532 * @exception JMRuntimeException if the builder instantiation 533 * fails with a checked exception - 534 * {@link java.lang.ClassNotFoundException} etc... 535 * 536 **/ 537 private static synchronized MBeanServerBuilder getNewMBeanServerBuilder() { 538 checkMBeanServerBuilder(); 539 return builder; 540 } 541 542 }