001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.org
004: * Distributable under GNU LGPL license
005: * See the GNU Lesser General Public License for more details.
006: */
007:
008: package javax.management;
009:
010: import java.util.ArrayList;
011: import java.util.Iterator;
012: import java.security.Permission;
013: import java.security.PrivilegedAction;
014: import java.security.AccessController;
015: import javax.management.loading.ClassLoaderRepository;
016:
017: import org.huihoo.jfox.jmx.ExtendedMBeanServerDelegate;
018:
019: /**
020: * <p>Provides MBean server references. There are no instances of
021: * this class.</p>
022: *
023: * <p>Since JMX 1.2 this class makes it possible to replace the default
024: * MBeanServer implementation. This is done using the
025: * {@link javax.management.MBeanServerBuilder} class.
026: * The class of the initial MBeanServerBuilder to be
027: * instantiated can be specified through the
028: * <b>javax.management.builder.initial</b> system property.
029: * The specified class must be a public subclass of
030: * {@link javax.management.MBeanServerBuilder}, and must have a public
031: * empty constructor.
032: * <p>By default, if no value for that property is specified, an instance of
033: * {@link
034: * javax.management.MBeanServerBuilder javax.management.MBeanServerBuilder}
035: * is created. Otherwise, the MBeanServerFactory attempts to load the
036: * specified class using
037: * {@link java.lang.Thread#getContextClassLoader()
038: * Thread.currentThread().getContextClassLoader()}, or if that is null,
039: * {@link java.lang.Class#forName(java.lang.String) Class.forName()}. Then
040: * it creates an initial instance of that Class using
041: * {@link java.lang.Class#newInstance()}. If any checked exception
042: * is raised during this process (e.g.
043: * {@link java.lang.ClassNotFoundException},
044: * {@link java.lang.InstantiationException}) the MBeanServerFactory
045: * will propagate this exception from within a RuntimeException.</p>
046: *
047: * <p>The <b>javax.management.builder.initial</b> system property is
048: * consulted every time a new MBeanServer needs to be created, and the
049: * class pointed to by that property is loaded. If that class is different
050: * from that of the current MBeanServerBuilder, then a new MBeanServerBuilder
051: * is created. Otherwise, the MBeanServerFactory may doCreate a new
052: * MBeanServerBuilder or reuse the current one.</p>
053: *
054: * <p>If the class pointed to by the property cannot be
055: * loaded, or does not correspond to a valid subclass of MBeanServerBuilder
056: * then an exception is propagated, and no MBeanServer can be created until
057: * the <b>javax.management.builder.initial</b> system property is reset to
058: * valid value.</p>
059: *
060: * <p>The MBeanServerBuilder makes it possible to wrap the MBeanServers
061: * returned by the default MBeanServerBuilder implementation, for the purpose
062: * of e.g. adding an additional security layer.</p>
063: *
064: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
065: */
066:
067: public class MBeanServerFactory {
068: private final static String DEFAULT_DOMAIN = "DefaultDomain";
069: private static ArrayList servers = new ArrayList();
070: private static SecurityManager secManager = System
071: .getSecurityManager();
072: private static final String MBEAN_SERVER_BUILDER_PROPERTY = "javax.management.builder.initial";
073:
074: /**
075: * The builder that will be used to construct MBeanServers.
076: * @since JMX 1.2
077: **/
078: private static MBeanServerBuilder builder = null;
079:
080: /*
081: * There are no instances of this class so don't generate the
082: * default public constructor.
083: */
084: private MBeanServerFactory() {
085:
086: }
087:
088: /**
089: * Remove internal MBeanServerFactory references to a created
090: * MBeanServer. This allows the garbage collector to remove the
091: * MBeanServer object.
092: *
093: * @param mbeanServer the MBeanServer object to remove.
094: *
095: * @exception java.lang.IllegalArgumentException if
096: * <code>mbeanServer</code> was not generated by one of the
097: * <code>createMBeanServer</code> methods, or if
098: * <code>releaseMBeanServer</code> was already called on it.
099: *
100: * @exception SecurityException if there is a SecurityManager and
101: * the caller's permissions do not include or imply <code>{@link
102: * MBeanServerPermission}("releaseMBeanServer")</code>.
103: */
104: public static synchronized void releaseMBeanServer(
105: MBeanServer mbeanServer) {
106: checkPermission(MBeanServerPermission.RELEASE_MBEAN_SERVER);
107: servers.remove(mbeanServer);
108: }
109:
110: /**
111: * <p>Return a new object implementing the MBeanServer interface
112: * with a standard default domain name. The default domain name
113: * is used as the domain part in the ObjectName of MBeans when the
114: * domain is specified by the user is null.</p>
115: *
116: * <p>The standard default domain name is defined in {@link
117: * com.sun.jmx.defaults.ServiceName#DOMAIN ServiceName.DOMAIN}.</p>
118: *
119: * <p>The MBeanServer reference is internally kept. This will
120: * allow <CODE>findMBeanServer</CODE> to return a reference to
121: * this MBeanServer object.</p>
122: *
123: * <p>This method is equivalent to <code>createMBeanServer(null)</code>.
124: *
125: * @return the newly created MBeanServer.
126: *
127: * @exception SecurityException if there is a SecurityManager and the
128: * caller's permissions do not include or imply <code>{@link
129: * MBeanServerPermission}("createMBeanServer")</code>.
130: *
131: * @exception JMRuntimeException if the property
132: * <code>javax.management.builder.initial</code> exists but the
133: * class it names cannot be instantiated through a public
134: * no-argument constructor; or if the instantiated builder returns
135: * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
136: * newMBeanServerDelegate} or {@link
137: * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
138: *
139: * @exception ClassCastException if the property
140: * <code>javax.management.builder.initial</code> exists and can be
141: * instantiated but is not assignment compatible with {@link
142: * MBeanServerBuilder}.
143: */
144: public static MBeanServer createMBeanServer() {
145: return createMBeanServer(DEFAULT_DOMAIN);
146: }
147:
148: /**
149: * <p>Return a new object implementing the {@link MBeanServer}
150: * interface with the specified default domain name. The given
151: * domain name is used as the domain part in the ObjectName of
152: * MBeans when the domain is specified by the user is null.</p>
153: *
154: * <p>The MBeanServer reference is internally kept. This will
155: * allow <CODE>findMBeanServer</CODE> to return a reference to
156: * this MBeanServer object.</p>
157: *
158: * @param domain the default domain name for the created
159: * MBeanServer. This is the value that will be returned by {@link
160: * MBeanServer#getDefaultDomain}.
161: *
162: * @return the newly created MBeanServer.
163: *
164: * @exception SecurityException if there is a SecurityManager and
165: * the caller's permissions do not include or imply <code>{@link
166: * MBeanServerPermission}("createMBeanServer")</code>.
167: *
168: * @exception JMRuntimeException if the property
169: * <code>javax.management.builder.initial</code> exists but the
170: * class it names cannot be instantiated through a public
171: * no-argument constructor; or if the instantiated builder returns
172: * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
173: * newMBeanServerDelegate} or {@link
174: * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
175: *
176: * @exception ClassCastException if the property
177: * <code>javax.management.builder.initial</code> exists and can be
178: * instantiated but is not assignment compatible with {@link
179: * MBeanServerBuilder}.
180: */
181: public static synchronized MBeanServer createMBeanServer(
182: String domain) {
183: for (Iterator iterator = servers.iterator(); iterator.hasNext();) {
184: MBeanServer mbeanserver = (MBeanServer) iterator.next();
185: // have already exists , return it
186: if (domain.equals(mbeanserver.getDefaultDomain()))
187: return mbeanserver;
188: }
189: MBeanServer mbeanserver = newMBeanServer(domain);
190: servers.add(mbeanserver);
191: return mbeanserver;
192: }
193:
194: /**
195: * <p>Return a new object implementing the MBeanServer interface
196: * with a standard default domain name, without keeping an
197: * internal reference to this new object. The default domain name
198: * is used as the domain part in the ObjectName of MBeans when the
199: * domain is specified by the user is null.</p>
200: *
201: * <p>The standard default domain name is defined in {@link
202: * com.sun.jmx.defaults.ServiceName#DOMAIN ServiceName.DOMAIN}.</p>
203: *
204: * <p>No reference is kept. <CODE>findMBeanServer</CODE> will not
205: * be able to return a reference to this MBeanServer object, but
206: * the garbage collector will be able to remove the MBeanServer
207: * object when it is no longer referenced.</p>
208: *
209: * <p>This method is equivalent to <code>newMBeanServer(null)</code>.</p>
210: *
211: * @return the newly created MBeanServer.
212: *
213: * @exception SecurityException if there is a SecurityManager and the
214: * caller's permissions do not include or imply <code>{@link
215: * MBeanServerPermission}("newMBeanServer")</code>.
216: *
217: * @exception JMRuntimeException if the property
218: * <code>javax.management.builder.initial</code> exists but the
219: * class it names cannot be instantiated through a public
220: * no-argument constructor; or if the instantiated builder returns
221: * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
222: * newMBeanServerDelegate} or {@link
223: * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
224: *
225: * @exception ClassCastException if the property
226: * <code>javax.management.builder.initial</code> exists and can be
227: * instantiated but is not assignment compatible with {@link
228: * MBeanServerBuilder}.
229: */
230: public static MBeanServer newMBeanServer() {
231: return newMBeanServer(DEFAULT_DOMAIN);
232: }
233:
234: /**
235: * <p>Return a new object implementing the MBeanServer interface
236: * with the specified default domain name, without keeping an
237: * internal reference to this new object. The given domain name
238: * is used as the domain part in the ObjectName of MBeans when the
239: * domain is specified by the user is null.</p>
240: *
241: * <p>No reference is kept. <CODE>findMBeanServer</CODE> will not
242: * be able to return a reference to this MBeanServer object, but
243: * the garbage collector will be able to remove the MBeanServer
244: * object when it is no longer referenced.</p>
245: *
246: * @param domain the default domain name for the created
247: * MBeanServer. This is the value that will be returned by {@link
248: * MBeanServer#getDefaultDomain}.
249: *
250: * @return the newly created MBeanServer.
251: *
252: * @exception SecurityException if there is a SecurityManager and the
253: * caller's permissions do not include or imply <code>{@link
254: * MBeanServerPermission}("newMBeanServer")</code>.
255: *
256: * @exception JMRuntimeException if the property
257: * <code>javax.management.builder.initial</code> exists but the
258: * class it names cannot be instantiated through a public
259: * no-argument constructor; or if the instantiated builder returns
260: * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
261: * newMBeanServerDelegate} or {@link
262: * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
263: *
264: * @exception ClassCastException if the property
265: * <code>javax.management.builder.initial</code> exists and can be
266: * instantiated but is not assignment compatible with {@link
267: * MBeanServerBuilder}.
268: */
269: public static synchronized MBeanServer newMBeanServer(String domain) {
270: checkPermission(MBeanServerPermission.NEW_MBEAN_SERVER);
271: MBeanServerBuilder msBuilder = getMBeanServerBuilder();
272: MBeanServerDelegate delegate = msBuilder
273: .newMBeanServerDelegate();
274: if (delegate == null) {
275: throw new JMRuntimeException(
276: "MBeanServerBuilder.newMBeanServerDelegate() returned null");
277: }
278: MBeanServer mbeanServer = msBuilder.newMBeanServer(domain,
279: null, delegate);
280: if (mbeanServer == null) {
281: throw new JMRuntimeException(
282: "MBeanServerBuilder.newMBeanServer() returned null");
283: }
284: return mbeanServer;
285: }
286:
287: /**
288: * <p>Return a list of registered MBeanServer objects. A
289: * registered MBeanServer object is one that was created by one of
290: * the <code>createMBeanServer</code> methods and not subsequently
291: * released with <code>releaseMBeanServer</code>.</p>
292: *
293: * @param agentId The agent identifier of the MBeanServer to
294: * retrieve. If this parameter is null, all registered
295: * MBeanServers in this JVM are returned. Otherwise, only
296: * MBeanServers whose id is equal to <code>agentId</code> are
297: * returned. The id of an MBeanServer is the
298: * <code>MBeanServerId</code> attribute of its delegate MBean.
299: *
300: * @return A list of MBeanServer objects.
301: *
302: * @exception SecurityException if there is a SecurityManager and the
303: * caller's permissions do not include or imply <code>{@link
304: * MBeanServerPermission}("findMBeanServer")</code>.
305: */
306: public static synchronized ArrayList findMBeanServer(String agentId) {
307: checkPermission(MBeanServerPermission.FIND_MBEAN_SERVER);
308: // all mbeanservers
309: if (agentId == null)
310: return (ArrayList) servers.clone();
311:
312: ArrayList list = new ArrayList();
313: for (Iterator iter = servers.iterator(); iter.hasNext();) {
314: MBeanServer mbeanServer = (MBeanServer) iter.next();
315: String serverId = null;
316: try {
317: serverId = (String) mbeanServer.getAttribute(
318: ExtendedMBeanServerDelegate.getObjectName(),
319: "MBeanServerId");
320: } catch (Exception e) {
321: e.printStackTrace();
322: }
323: if (agentId.equals(serverId)) {
324: list.add(mbeanServer);
325: }
326: }
327: return list;
328: }
329:
330: /**
331: * Return the ClassLoaderRepository used by the given MBeanServer.
332: * This method is equivalent to {@link MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}.
333: * @param mbeanServer The MBeanServer under examination. Since JMX 1.2,
334: * if <code>server</code> is <code>null</code>, the result is a
335: * {@link NullPointerException}. This behaviour differs from what
336: * was implemented in JMX 1.1 - where the possibility to use
337: * <code>null</code> was deprecated.
338: * @return The Class Loader Repository used by the given MBeanServer.
339: * @exception SecurityException if there is a SecurityManager and
340: * the caller's permissions do not include or imply <code>{@link
341: * MBeanPermission}("getClassLoaderRepository")</code>.
342: *
343: * @exception NullPointerException if <code>server</code> is null.
344: *
345: **/
346: public static ClassLoaderRepository getClassLoaderRepository(
347: MBeanServer mbeanServer) {
348: return mbeanServer.getClassLoaderRepository();
349: }
350:
351: private static void checkPermission(String action)
352: throws SecurityException {
353: if (secManager != null) {
354: Permission perm = MBeanServerPermission.getInstance(action);
355: secManager.checkPermission(perm);
356: }
357: }
358:
359: /*
360: * get a MBeanServerBuilder , doCreate a new if needed
361: *
362: */
363: private static MBeanServerBuilder getMBeanServerBuilder() {
364: String builderClassName = (String) AccessController
365: .doPrivileged(new PrivilegedAction() {
366: public Object run() {
367: return System
368: .getProperty(MBEAN_SERVER_BUILDER_PROPERTY);
369: }
370: });
371:
372: Class newBuilderClass = null;
373: if (builderClassName == null
374: || builderClassName.trim().length() == 0) {
375: newBuilderClass = MBeanServerBuilder.class;
376: // no needed to doCreate a new
377: if (builder != null
378: && builder.getClass().getName().equals(
379: newBuilderClass.getName())) {
380: return builder;
381: }
382: } else {
383: try {
384: newBuilderClass = loadBuilderClass(builderClassName);
385: } catch (ClassNotFoundException e) {
386: throw new JMRuntimeException(
387: "Failed to load MBeanServerBuilder class "
388: + builderClassName, e);
389: }
390: }
391: // doCreate a new mbeanserver builder
392: if (builder == null
393: || !(builder.getClass().getName()
394: .equals(newBuilderClass.getName()))) {
395: Object obj = null;
396: try {
397: obj = newBuilderClass.newInstance();
398: } catch (Exception e) {
399: throw new JMRuntimeException(
400: "can not make MBeanServerBuilder instance:"
401: + newBuilderClass.getName(), e);
402: }
403: if (!(obj instanceof MBeanServerBuilder)) {
404: throw new JMRuntimeException("Class name "
405: + newBuilderClass.getName()
406: + " is not a MBeanServerBuilder sub class");
407: }
408: // set the builder
409: builder = (MBeanServerBuilder) obj;
410:
411: }
412: return builder;
413: }
414:
415: private static Class loadBuilderClass(String builderClassName)
416: throws ClassNotFoundException {
417: ClassLoader loader = Thread.currentThread()
418: .getContextClassLoader();
419:
420: if (loader != null) {
421: // Try with context class loader
422: return loader.loadClass(builderClassName);
423: }
424: // No context class loader? Try with Class.forName()
425: return Class.forName(builderClassName);
426: }
427: }
|