MBeanServerFactory.java 18 KB

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