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