001 /* MBeanServerFactory.java -- Manages server instances. 002 Copyright (C) 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package javax.management; 039 040 import gnu.classpath.SystemProperties; 041 042 import java.util.ArrayList; 043 import java.util.HashMap; 044 import java.util.Iterator; 045 import java.util.Map; 046 047 import javax.management.loading.ClassLoaderRepository; 048 049 /** 050 * <p> 051 * Creates and maintains a set of {@link MBeanServer} instances. 052 * Server instances, as of JMX 1.2, are created using a subclass 053 * of {@link MBeanServerBuilder}. The exact class used is controlled 054 * by the property <code>javax.management.builder.initial</code>, 055 * and allows the instances created by {@link MBeanServerBuilder} 056 * to be wrapped, thus providing additional functionality. 057 * </p> 058 * <p> 059 * The property is used as follows: 060 * </p> 061 * <ol> 062 * <li>If the property has no value, then an instance of 063 * {@link MBeanServerBuilder} is used.</li> 064 * <li>If a value is given, then: 065 * <ol> 066 * <li>The class is loaded using 067 * <code>Thread.currentThread().getContextClassLoader()</code>, or, 068 * if this is <code>null</code>, by <code>Class.forName()</code>.</li> 069 * <li><code>Class.newInstance()</code> is used to create an instance 070 * of the class. The class must be public and have a public empty 071 * constructor. If an exception is thrown, it is propogated as 072 * a {@link JMRuntimeException} and no new server instances may be 073 * created until the property is set to a valid value.</li> 074 * </ol></li> 075 * <li>The value is checked on each successive request for a server. 076 * If it differs from the class of the existing instance of 077 * {@link MBeanServerBuilder}, then the value is used to create 078 * a new instance.</li> 079 * </ol> 080 */ 081 public class MBeanServerFactory 082 { 083 084 /** 085 * The last builder instance. 086 */ 087 private static MBeanServerBuilder builder; 088 089 /** 090 * The map of registered servers (identifiers to servers). 091 */ 092 private static final Map<Object,MBeanServer> servers = new HashMap(); 093 094 /** 095 * Private constructor to prevent instance creation. 096 */ 097 private MBeanServerFactory() {} 098 099 /** 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 }