001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.com
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 org.huihoo.jfox.jmx.MBeanMetaData;
011: import org.huihoo.jfox.jmx.MBeanMetaDataSupport;
012: import org.huihoo.jfox.jmx.MBeanIntrospector;
013: import org.huihoo.jfox.jmx.MBeanIntrospectorSupport;
014: import org.huihoo.jfox.jmx.MBeanInterfaceMetaDataSupport;
015:
016: /**
017: * <p>An MBean whose management interface is determined by reflection
018: * on a Java interface.</p>
019: *
020: * <p>This class brings more flexibility to the notion of Management
021: * Interface in the use of Standard MBeans. Straightforward use of
022: * the patterns for Standard MBeans described in the JMX Specification
023: * means that there is a fixed relationship between the implementation
024: * class of an MBean and its management interface (i.e., if the
025: * implementation class is Thing, the management interface must be
026: * ThingMBean). This class makes it possible to keep the convenience
027: * of specifying the management interface with a Java interface,
028: * without requiring that there be any naming relationship between the
029: * implementation and interface classes.</p>
030: *
031: * <p>By making a DynamicMBean out of an MBean, this class makes
032: * it possible to select any interface implemented by the MBean as its
033: * management interface, provided that it complies with JMX patterns
034: * (i.e., attributes defined by getter/setter etc...).</p>
035: *
036: * <p> This class also provides hooks that make it possible to supply
037: * custom descriptions and names for the {@link MBeanInfo} returned by
038: * the DynamicMBean interface.</p>
039: *
040: * <p>Using this class, an MBean can be created with any
041: * implementation class name <i>Impl</i> and with a management
042: * interface defined (as for current Standard MBeans) by any interface
043: * <i>Intf</i>, in one of two general ways:</p>
044: *
045: * <ul>
046: *
047: * <li>Using the public constructor
048: * {@link #StandardMBean(java.lang.Object, java.lang.Class)
049: * StandardMBean(impl,interface)}:
050: * <pre>
051: * MBeanServer mbs;
052: * ...
053: * Impl impl = new Impl(...);
054: * StandardMBean mbean = new StandardMBean(impl, Intf.class);
055: * mbs.registerMBean(mbean, objectName);
056: * </pre></li>
057: *
058: * <li>Subclassing StandardMBean:
059: * <pre>
060: * public class Impl extends StandardMBean implements Intf {
061: * public Impl() {
062: * super(Intf.class);
063: * }
064: * // implement methods of Intf
065: * }
066: *
067: * [...]
068: *
069: * MBeanServer mbs;
070: * ....
071: * Impl impl = new Impl();
072: * mbs.registerMBean(impl, objectName);
073: * </pre></li>
074: *
075: * </ul>
076: *
077: * <p>In either case, the class <i>Impl</i> must implement the
078: * interface <i>Intf</i>.</p>
079: *
080: * <p>Standard MBeans based on the naming relationship between
081: * implementation and interface classes are of course still
082: * available.</p>
083: *
084: * @since JMX 1.2
085: *
086: * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
087: */
088:
089: public class StandardMBean implements DynamicMBean, MBeanRegistration {
090:
091: /**
092: * The management interface.
093: **/
094: private Class mbeanInterface = null;
095:
096: /**
097: * The implementation.
098: **/
099: private Object implementation = null;
100:
101: private MBeanMetaData meta = null;
102:
103: /**
104: * The cached MBeanInfo.
105: **/
106: private MBeanInfo cachedMBeanInfo = null;
107:
108: private MBeanIntrospector introspector = MBeanIntrospectorSupport
109: .getInstance();
110:
111: /**
112: * <p>Make a DynamicMBean out of the object
113: * <var>implementation</var>, using the specified
114: * <var>mbeanInterface</var> class.</p>
115: *
116: * @param implementation The implementation of this MBean.
117: * @param mbeanInterface The Management Interface exported by this
118: * MBean's implementation. If <code>null</code>, then this
119: * object will use standard JMX design pattern to determine
120: * the management interface associated with the given
121: * implementation.
122: *
123: * @exception IllegalArgumentException if the given
124: * <var>implementation</var> is null.
125: * @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
126: * does not follow JMX design patterns for Management Interfaces, or
127: * if the given <var>implementation</var> does not implement the
128: * specified interface.
129: **/
130: public StandardMBean(Object implementation, Class mbeanInterface)
131: throws NotCompliantMBeanException {
132: if (implementation == null) {
133: throw new IllegalArgumentException("implementation is null");
134: }
135: setImplementation(implementation, mbeanInterface);
136: }
137:
138: /**
139: * <p>Make a DynamicMBean out of <var>this</var>, using the specified
140: * <var>mbeanInterface</var> class.</p>
141: *
142: * <p>Call {@link #StandardMBean(java.lang.Object, java.lang.Class)
143: * this(this,mbeanInterface)}.
144: * This constructor is reserved to subclasses.</p>
145: *
146: * @param mbeanInterface The Management Interface exported by this
147: * MBean.
148: *
149: * @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
150: * does not follow JMX design patterns for Management Interfaces, or
151: * if <var>this</var> does not implement the specified interface.
152: **/
153: protected StandardMBean(Class mbeanInterface)
154: throws NotCompliantMBeanException {
155: setImplementation(this , mbeanInterface);
156: }
157:
158: /**
159: * <p>Replace the implementation object wrapped in this
160: * object.</p>
161: *
162: * @param implementation The new implementation of this MBean.
163: * The <code>implementation</code> object must implement the MBean
164: * interface that was supplied when this
165: * <code>StandardMBean</code> was constructed.
166: *
167: * @exception IllegalArgumentException if the given
168: * <var>implementation</var> is null.
169: *
170: * @exception NotCompliantMBeanException if the given
171: * <var>implementation</var> does not implement the MBean
172: * interface that was supplied at construction.
173: *
174: * @see #getImplementation
175: **/
176: public synchronized void setImplementation(Object implementation)
177: throws NotCompliantMBeanException {
178: setImplementation(implementation, getMBeanInterface());
179: }
180:
181: /**
182: * Replace the implementation and management interface wrapped in
183: * this object.
184: * @param implementation The new implementation of this MBean.
185: * @param mbeanInterface The Management Interface exported by this
186: * MBean's implementation. If <code>null</code>, then this
187: * object will use standard JMX design patterns to determine
188: * the management interface associated with the given
189: * implementation.
190: * @exception IllegalArgumentException if the given
191: * <var>implementation</var> is null.
192: * @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
193: * does not follow JMX design patterns for Management Interfaces, or
194: * if the given <var>implementation</var> does not implement the
195: * specified interface.
196: **/
197: private synchronized void setImplementation(Object implementation,
198: Class mbeanInterface) throws NotCompliantMBeanException {
199: if (implementation == null) {
200: throw new IllegalArgumentException("implementation is null");
201: }
202:
203: if (mbeanInterface == null) {
204: if (introspector.isDynamic(implementation.getClass())) {
205: throw new NotCompliantMBeanException(
206: "the implementation: " + implementation
207: + " is DynamicMBean.");
208: }
209:
210: mbeanInterface = introspector
211: .checkCompliance(implementation.getClass());
212: }
213:
214: this .mbeanInterface = mbeanInterface;
215: this .implementation = implementation;
216:
217: ObjectName name = null;
218: if (meta != null) {
219: name = meta.getObjectName();
220: }
221:
222: MBeanMetaData _meta = new MBeanMetaDataSupport(name,
223: implementation, MBeanInterfaceMetaDataSupport
224: .getInstance(mbeanInterface));
225: setMBeanMetaData(_meta);
226: }
227:
228: /**
229: * Get the Management Interface of this MBean.
230: * @return The management interface of this MBean.
231: **/
232: public final synchronized Class getMBeanInterface() {
233: return mbeanInterface;
234: }
235:
236: /**
237: * Get the class of the implementation of this MBean.
238: * @return The class of the implementation of this MBean.
239: **/
240: public synchronized Class getImplementationClass() {
241: if (implementation == null)
242: return null;
243: return implementation.getClass();
244: }
245:
246: /**
247: * Get the implementation of this MBean.
248: * @return The implementation of this MBean.
249: *
250: * @see #setImplementation
251: **/
252: public synchronized Object getImplementation() {
253: return implementation;
254: }
255:
256: public Object getAttribute(String attribute)
257: throws AttributeNotFoundException, MBeanException,
258: ReflectionException {
259: return meta.getAttribute(attribute);
260: }
261:
262: public void setAttribute(Attribute attribute)
263: throws AttributeNotFoundException,
264: InvalidAttributeValueException, MBeanException,
265: ReflectionException {
266: meta.setAttribute(attribute);
267: }
268:
269: public AttributeList getAttributes(String[] attributes) {
270: try {
271: return meta.getAttributes(attributes);
272: } catch (AttributeNotFoundException e) {
273: throw new JMRuntimeException(e.getMessage(), e);
274: } catch (MBeanException e) {
275: Exception ex = e.getTargetException();
276: throw new JMRuntimeException(ex.getMessage(), ex);
277: } catch (ReflectionException e) {
278: throw new JMRuntimeException(e.getMessage(), e);
279: }
280: }
281:
282: public AttributeList setAttributes(AttributeList attributes) {
283: try {
284: return meta.setAttributes(attributes);
285: } catch (MBeanException e) {
286: Exception ex = e.getTargetException();
287: throw new JMRuntimeException(ex.getMessage(), ex);
288: } catch (AttributeNotFoundException e) {
289: throw new JMRuntimeException(e.getMessage(), e);
290: } catch (InvalidAttributeValueException e) {
291: throw new JMRuntimeException(e.getMessage(), e);
292: } catch (ReflectionException e) {
293: throw new JMRuntimeException(e.getMessage(), e);
294: }
295: }
296:
297: public Object invoke(String actionName, Object params[],
298: String signature[]) throws MBeanException,
299: ReflectionException {
300: return meta.invoke(actionName, params, signature);
301: }
302:
303: public MBeanInfo getMBeanInfo() {
304: return meta.getMBeanInfo();
305: }
306:
307: /**
308: * Customization hook:
309: * Return the MBeanInfo cached for this object.
310: *
311: * <p>Subclasses may redefine this method in order to implement their
312: * own caching policy. The default implementation stores one
313: * {@link MBeanInfo} object per instance.
314: *
315: * @return The cached MBeanInfo, or null if no MBeanInfo is cached.
316: *
317: * @see #cacheMBeanInfo(MBeanInfo)
318: **/
319: protected MBeanInfo getCachedMBeanInfo() {
320: if (cachedMBeanInfo == null && meta != null) {
321: cacheMBeanInfo(meta.getMBeanInfo());
322: }
323: return cachedMBeanInfo;
324: }
325:
326: /**
327: * Customization hook:
328: * cache the MBeanInfo built for this object.
329: *
330: * <p>Subclasses may redefine this method in order to implement
331: * their own caching policy. The default implementation stores
332: * <code>info</code> in this instance. A subclass can define
333: * other policies, such as not saving <code>info</code> (so it is
334: * reconstructed every time {@link #getMBeanInfo()} is called) or
335: * sharing a unique {@link MBeanInfo} object when several
336: * <code>StandardMBean</code> instances have equal {@link
337: * MBeanInfo} values.
338: *
339: * @param info the new <code>MBeanInfo</code> to cache. Any
340: * previously cached value is discarded. This parameter may be
341: * null, in which case there is no new cached value.
342: **/
343: protected synchronized void cacheMBeanInfo(MBeanInfo info) {
344: cachedMBeanInfo = info;
345: }
346:
347: /**
348: * Customization hook:
349: * Get the className that will be used in the MBeanInfo returned by
350: * this MBean.
351: * <br>
352: * Subclasses may redefine this method in order to supply their
353: * custom class name. The default implementation returns
354: * {@link MBeanInfo#getClassName() info.getClassName()}.
355: * @param info The default MBeanInfo derived by reflection.
356: * @return the class name for the new MBeanInfo.
357: **/
358: protected String getClassName(MBeanInfo info) {
359: if (info == null)
360: return getImplementationClass().getName();
361: return info.getClassName();
362: }
363:
364: /**
365: * Customization hook:
366: * Get the description that will be used in the MBeanInfo returned by
367: * this MBean.
368: * <br>
369: * Subclasses may redefine this method in order to supply their
370: * custom MBean description. The default implementation returns
371: * {@link MBeanInfo#getDescription() info.getDescription()}.
372: * @param info The default MBeanInfo derived by reflection.
373: * @return the description for the new MBeanInfo.
374: **/
375: protected String getDescription(MBeanInfo info) {
376: if (info == null)
377: return null;
378: return info.getDescription();
379: }
380:
381: /**
382: * <p>Customization hook:
383: * Get the description that will be used in the MBeanFeatureInfo
384: * returned by this MBean.</p>
385: *
386: * <p>Subclasses may redefine this method in order to supply
387: * their custom description. The default implementation returns
388: * {@link MBeanFeatureInfo#getDescription()
389: * info.getDescription()}.</p>
390: *
391: * <p>This method is called by
392: * {@link #getDescription(MBeanAttributeInfo)},
393: * {@link #getDescription(MBeanOperationInfo)},
394: * {@link #getDescription(MBeanConstructorInfo)}.</p>
395: *
396: * @param info The default MBeanFeatureInfo derived by reflection.
397: * @return the description for the given MBeanFeatureInfo.
398: **/
399: protected String getDescription(MBeanFeatureInfo info) {
400: if (info == null)
401: return null;
402: return info.getDescription();
403: }
404:
405: /**
406: * Customization hook:
407: * Get the description that will be used in the MBeanAttributeInfo
408: * returned by this MBean.
409: *
410: * <p>Subclasses may redefine this method in order to supply their
411: * custom description. The default implementation returns {@link
412: * #getDescription(MBeanFeatureInfo)
413: * getDescription((MBeanFeatureInfo) info)}.
414: * @param info The default MBeanAttributeInfo derived by reflection.
415: * @return the description for the given MBeanAttributeInfo.
416: **/
417: protected String getDescription(MBeanAttributeInfo info) {
418: return getDescription((MBeanFeatureInfo) info);
419: }
420:
421: /**
422: * Customization hook:
423: * Get the description that will be used in the MBeanConstructorInfo
424: * returned by this MBean.
425: * <br>
426: * Subclasses may redefine this method in order to supply their
427: * custom description.
428: * The default implementation returns {@link
429: * #getDescription(MBeanFeatureInfo)
430: * getDescription((MBeanFeatureInfo) info)}.
431: * @param info The default MBeanConstructorInfo derived by reflection.
432: * @return the description for the given MBeanConstructorInfo.
433: **/
434: protected String getDescription(MBeanConstructorInfo info) {
435: return getDescription((MBeanFeatureInfo) info);
436: }
437:
438: /**
439: * Customization hook:
440: * Get the description that will be used for the <var>sequence</var>
441: * MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
442: * <br>
443: * Subclasses may redefine this method in order to supply their
444: * custom description. The default implementation returns
445: * {@link MBeanParameterInfo#getDescription() param.getDescription()}.
446: *
447: * @param ctor The default MBeanConstructorInfo derived by reflection.
448: * @param param The default MBeanParameterInfo derived by reflection.
449: * @param sequence The sequence number of the parameter considered
450: * ("0" for the first parameter, "1" for the second parameter,
451: * etc...).
452: * @return the description for the given MBeanParameterInfo.
453: **/
454: protected String getDescription(MBeanConstructorInfo ctor,
455: MBeanParameterInfo param, int sequence) {
456: if (param == null)
457: return null;
458: return param.getDescription();
459: }
460:
461: /**
462: * Customization hook:
463: * Get the name that will be used for the <var>sequence</var>
464: * MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
465: * <br>
466: * Subclasses may redefine this method in order to supply their
467: * custom parameter name. The default implementation returns
468: * {@link MBeanParameterInfo#getName() param.getNameSpace()}.
469: *
470: * @param ctor The default MBeanConstructorInfo derived by reflection.
471: * @param param The default MBeanParameterInfo derived by reflection.
472: * @param sequence The sequence number of the parameter considered
473: * ("0" for the first parameter, "1" for the second parameter,
474: * etc...).
475: * @return the name for the given MBeanParameterInfo.
476: **/
477: protected String getParameterName(MBeanConstructorInfo ctor,
478: MBeanParameterInfo param, int sequence) {
479: if (param == null)
480: return null;
481: return param.getName();
482: }
483:
484: /**
485: * Customization hook:
486: * Get the description that will be used in the MBeanOperationInfo
487: * returned by this MBean.
488: * <br>
489: * Subclasses may redefine this method in order to supply their
490: * custom description. The default implementation returns
491: * {@link #getDescription(MBeanFeatureInfo)
492: * getDescription((MBeanFeatureInfo) info)}.
493: * @param info The default MBeanOperationInfo derived by reflection.
494: * @return the description for the given MBeanOperationInfo.
495: **/
496: protected String getDescription(MBeanOperationInfo info) {
497: return getDescription((MBeanFeatureInfo) info);
498: }
499:
500: /**
501: * Customization hook:
502: * Get the <var>impact</var> flag of the operation that will be used in
503: * the MBeanOperationInfo returned by this MBean.
504: * <br>
505: * Subclasses may redefine this method in order to supply their
506: * custom impact flag. The default implementation returns
507: * {@link MBeanOperationInfo#getImpact() info.getImpact()}.
508: * @param info The default MBeanOperationInfo derived by reflection.
509: * @return the impact flag for the given MBeanOperationInfo.
510: **/
511: protected int getImpact(MBeanOperationInfo info) {
512: if (info == null)
513: return MBeanOperationInfo.UNKNOWN;
514: return info.getImpact();
515: }
516:
517: /**
518: * Customization hook:
519: * Get the name that will be used for the <var>sequence</var>
520: * MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
521: * <br>
522: * Subclasses may redefine this method in order to supply their
523: * custom parameter name. The default implementation returns
524: * {@link MBeanParameterInfo#getName() param.getNameSpace()}.
525: *
526: * @param op The default MBeanOperationInfo derived by reflection.
527: * @param param The default MBeanParameterInfo derived by reflection.
528: * @param sequence The sequence number of the parameter considered
529: * ("0" for the first parameter, "1" for the second parameter,
530: * etc...).
531: * @return the name to use for the given MBeanParameterInfo.
532: **/
533: protected String getParameterName(MBeanOperationInfo op,
534: MBeanParameterInfo param, int sequence) {
535: if (param == null)
536: return null;
537: return param.getName();
538: }
539:
540: /**
541: * Customization hook:
542: * Get the description that will be used for the <var>sequence</var>
543: * MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
544: * <br>
545: * Subclasses may redefine this method in order to supply their
546: * custom description. The default implementation returns
547: * {@link MBeanParameterInfo#getDescription() param.getDescription()}.
548: *
549: * @param op The default MBeanOperationInfo derived by reflection.
550: * @param param The default MBeanParameterInfo derived by reflection.
551: * @param sequence The sequence number of the parameter considered
552: * ("0" for the first parameter, "1" for the second parameter,
553: * etc...).
554: * @return the description for the given MBeanParameterInfo.
555: **/
556: protected String getDescription(MBeanOperationInfo op,
557: MBeanParameterInfo param, int sequence) {
558: if (param == null)
559: return null;
560: return param.getDescription();
561: }
562:
563: /**
564: * Customization hook:
565: * Get the MBeanConstructorInfo[] that will be used in the MBeanInfo
566: * returned by this MBean.
567: * <br>
568: * By default, this method returns <code>null</code> if the wrapped
569: * implementation is not <var>this</var>. Indeed, if the wrapped
570: * implementation is not this object itself, it will not be possible
571: * to recreate a wrapped implementation by calling the implementation
572: * constructors through <code>MBeanServer.createMBean(...)</code>.<br>
573: * Otherwise, if the wrapped implementation is <var>this</var>,
574: * <var>ctors</var> is returned.
575: * <br>
576: * Subclasses may redefine this method in order to modify this
577: * behaviour, if needed.
578: * @param ctors The default MBeanConstructorInfo[] derived by reflection.
579: * @param impl The wrapped implementation. If <code>null</code> is
580: * passed, the wrapped implementation is ignored and
581: * <var>ctors</var> is returned.
582: * @return the MBeanConstructorInfo[] for the new MBeanInfo.
583: **/
584: protected MBeanConstructorInfo[] getConstructors(
585: MBeanConstructorInfo[] ctors, Object impl) {
586: if (ctors == null)
587: return null;
588: if (impl != null && impl != this )
589: return null;
590: return ctors;
591: }
592:
593: /**
594: * Customization hook:
595: * Get the MBeanNotificationInfo[] that will be used in the MBeanInfo
596: * returned by this MBean.
597: * <br>
598: * Subclasses may redefine this method in order to supply their
599: * custom notifications.
600: * @param info The default MBeanInfo derived by reflection.
601: * @return the MBeanNotificationInfo[] for the new MBeanInfo.
602: **/
603: protected MBeanNotificationInfo[] getNotifications(MBeanInfo info) {
604: if (info == null)
605: return null;
606: return info.getNotifications();
607: }
608:
609: private void setMBeanMetaData(MBeanMetaData meta) {
610: this .meta = meta;
611: }
612:
613: public MBeanMetaData getMetaData() {
614: return meta;
615: }
616:
617: public ObjectName preRegister(MBeanServer server, ObjectName name)
618: throws Exception {
619: if (name == null) {
620: throw new JMRuntimeException("ObjectName is null.");
621: }
622: meta.setObjectName(name);
623: return name;
624: }
625:
626: public void postRegister(Boolean registrationDone) {
627: }
628:
629: public void preDeregister() throws Exception {
630: }
631:
632: public void postDeregister() {
633: }
634:
635: }
|