001: /*
002: * Copyright (C) The MX4J Contributors.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the MX4J License version 1.0.
006: * See the terms of the MX4J License in the documentation provided with this software.
007: */
008:
009: package javax.management;
010:
011: import mx4j.AbstractDynamicMBean;
012: import mx4j.server.MBeanIntrospector;
013: import mx4j.server.MBeanMetaData;
014:
015: /**
016: * StandardMBean eases the development of MBeans that have a management interface described
017: * by a java interface, like plain standard MBeans have; differently from a plain standard
018: * MBean, StandardMBean is not tied to the JMX lexical patterns and allows more control on the
019: * customization of the MBeanInfo that describes the MBean (for example it allows to describe
020: * metadata descriptions). <br>
021: * Usage of StandardMBean with a management interface that does not follow the JMX lexical patterns:
022: * <pre>
023: * public interface Management
024: * {
025: * ...
026: * }
027: * <p/>
028: * public class Service implements Management
029: * {
030: * ...
031: * }
032: * <p/>
033: * Service service = new Service();
034: * StandardMBean mbean = new StandardMBean(service, Management.class);
035: * MBeanServer server = ...;
036: * ObjectName name = ...;
037: * server.registerMBean(mbean, name);
038: * </pre>
039: * Usage of a subclass of StandardMBean:
040: * <pre>
041: * public interface Management
042: * {
043: * ...
044: * }
045: * <p/>
046: * public class Service extends StandardMBean implements Management
047: * {
048: * public Service()
049: * {
050: * super(Manegement.class);
051: * }
052: * ...
053: * }
054: * <p/>
055: * Service mbean = new Service();
056: * MBeanServer server = ...;
057: * ObjectName name = ...;
058: * server.registerMBean(mbean, name);
059: * </pre>
060: * Usage of StandardMBean with a management interface that follows the JMX lexical patterns
061: * (this is similar to plain standard MBeans):
062: * <pre>
063: * public interface ServiceMBean
064: * {
065: * ...
066: * }
067: * <p/>
068: * public class Service implements ServiceMBean
069: * {
070: * ...
071: * }
072: * <p/>
073: * Service service = new Service();
074: * StandardMBean mbean = new StandardMBean(service, null);
075: * MBeanServer server = ...;
076: * ObjectName name = ...;
077: * server.registerMBean(mbean, name);
078: * </pre>
079: *
080: * @version $Revision: 1.5 $
081: * @since JMX 1.2
082: */
083: public class StandardMBean implements DynamicMBean {
084: private MBeanMetaData metadata;
085: private MBeanInfo info;
086: private DynamicMBean support;
087:
088: /**
089: * Creates a new StandardMBean.
090: *
091: * @param implementation The MBean implementation for this StandardMBean
092: * @param management The management interface; if null, the JMX lexical patterns will be used
093: * @throws IllegalArgumentException If <code>implementation</code> is null
094: * @throws NotCompliantMBeanException If <code>implementation</code> does not implement <code>managementInterface</code>,
095: * or if the management interface is not a valid JMX Management Interface
096: * @see #setImplementation
097: */
098: public StandardMBean(Object implementation, Class management)
099: throws NotCompliantMBeanException {
100: this (implementation, management, false);
101: }
102:
103: /**
104: * Creates a new StandardMBean using 'this' as implementation.
105: *
106: * @see #StandardMBean(Object,Class)
107: */
108: protected StandardMBean(Class managementInterface)
109: throws NotCompliantMBeanException {
110: this (null, managementInterface, true);
111: }
112:
113: private StandardMBean(Object implementation, Class management,
114: boolean useThis) throws NotCompliantMBeanException {
115: if (useThis)
116: implementation = this ;
117: if (implementation == null)
118: throw new IllegalArgumentException(
119: "Implementation cannot be null");
120: if (management != null && !management.isInterface())
121: throw new NotCompliantMBeanException("Class " + management
122: + " is not an interface");
123:
124: metadata = introspectMBean(implementation, management);
125: if (metadata == null)
126: throw new NotCompliantMBeanException(
127: "StandardMBean is not compliant");
128:
129: support = new StandardMBeanSupport();
130: }
131:
132: /**
133: * Sets the MBean implementation for this StandardMBean.
134: *
135: * @param implementation The MBean implementation for this StandardMBean
136: * @throws IllegalArgumentException If <code>implementation</code> is null
137: * @throws NotCompliantMBeanException If <code>implementation</code> does not implement the management interface
138: * returned by {@link #getMBeanInterface}
139: * @see #StandardMBean(Object,Class)
140: */
141: public void setImplementation(Object implementation)
142: throws NotCompliantMBeanException {
143: if (implementation == null)
144: throw new IllegalArgumentException(
145: "Implementation cannot be null");
146: Class management = getMBeanInterface();
147: if (!management.isInstance(implementation))
148: throw new NotCompliantMBeanException("Implementation "
149: + implementation + " does not implement interface "
150: + management);
151: metadata.setMBean(implementation);
152: }
153:
154: /**
155: * Returns the implementation supplied to this StandardMBean, or this object if no implementation was supplied
156: *
157: * @see #StandardMBean(Object,Class)
158: * @see #setImplementation
159: */
160: public Object getImplementation() {
161: return metadata.getMBean();
162: }
163:
164: /**
165: * Returns the management interface for this MBean. This interface is set at creation time and cannot be changed
166: * even if the implementation object can be changed (but it must implement the same interface).
167: *
168: * @see #StandardMBean(Object,Class)}
169: * @see #setImplementation
170: */
171: public final Class getMBeanInterface() {
172: return metadata.getMBeanInterface();
173: }
174:
175: /**
176: * Returns the class of the MBean implementation for this StandardMBean, or 'this' (sub)class if no
177: * implementation was supplied.
178: *
179: * @see #StandardMBean(Object,Class)}
180: */
181: public Class getImplementationClass() {
182: return metadata.getMBean().getClass();
183: }
184:
185: public Object getAttribute(String attribute)
186: throws AttributeNotFoundException, MBeanException,
187: ReflectionException {
188: return support.getAttribute(attribute);
189: }
190:
191: public void setAttribute(Attribute attribute)
192: throws AttributeNotFoundException,
193: InvalidAttributeValueException, MBeanException,
194: ReflectionException {
195: support.setAttribute(attribute);
196: }
197:
198: public AttributeList getAttributes(String[] attributes) {
199: return support.getAttributes(attributes);
200: }
201:
202: public AttributeList setAttributes(AttributeList attributes) {
203: return support.setAttributes(attributes);
204: }
205:
206: public Object invoke(String method, Object[] arguments,
207: String[] params) throws MBeanException, ReflectionException {
208: return support.invoke(method, arguments, params);
209: }
210:
211: /**
212: * See {@link DynamicMBean#getMBeanInfo}. <br>
213: * By default, the metadata is cached the first time is created; if the caching has been disabled,
214: * the metadata is created from scratch each time.
215: *
216: * @see #getCachedMBeanInfo
217: * @see #cacheMBeanInfo
218: */
219: public MBeanInfo getMBeanInfo() {
220: MBeanInfo info = getCachedMBeanInfo();
221: if (info == null) {
222: info = setupMBeanInfo(metadata.getMBeanInfo());
223: cacheMBeanInfo(info);
224: }
225: return info;
226: }
227:
228: /**
229: * Returns the class name of this MBean. <br>
230: * By default returns {@link MBeanInfo#getClassName info.getClassName()}
231: */
232: protected String getClassName(MBeanInfo info) {
233: return info == null ? null : info.getClassName();
234: }
235:
236: /**
237: * Returns the description for this MBean. <br>
238: * By default returns {@link MBeanInfo#getDescription info.getDescription()}
239: */
240: protected String getDescription(MBeanInfo info) {
241: return info == null ? null : info.getDescription();
242: }
243:
244: /**
245: * Returns the description for the given feature. <br>
246: * By default returns {@link MBeanFeatureInfo#getDescription info.getDescription()}
247: *
248: * @see #getDescription(MBeanAttributeInfo)
249: * @see #getDescription(MBeanConstructorInfo)
250: * @see #getDescription(MBeanOperationInfo)
251: */
252: protected String getDescription(MBeanFeatureInfo info) {
253: return info == null ? null : info.getDescription();
254: }
255:
256: /**
257: * Returns the description for the given attribute. <br>
258: * By default calls {@link #getDescription(MBeanFeatureInfo)}
259: */
260: protected String getDescription(MBeanAttributeInfo info) {
261: return getDescription((MBeanFeatureInfo) info);
262: }
263:
264: /**
265: * Returns the description for the given constructor. <br>
266: * By default calls {@link #getDescription(MBeanFeatureInfo)}
267: */
268: protected String getDescription(MBeanConstructorInfo info) {
269: return getDescription((MBeanFeatureInfo) info);
270: }
271:
272: /**
273: * Returns the description for the given operation. <br>
274: * By default calls {@link #getDescription(MBeanFeatureInfo)}
275: */
276: protected String getDescription(MBeanOperationInfo info) {
277: return getDescription((MBeanFeatureInfo) info);
278: }
279:
280: /**
281: * Returns the description of the (sequence + 1)th parameter (that is: if sequence is 0 returns the description of the first
282: * parameter, if sequence is 1 returns the description of the second parameter, and so on) for the given constructor. <br>
283: * By default returns {@link MBeanParameterInfo#getDescription param.getDescription()}.
284: */
285: protected String getDescription(MBeanConstructorInfo constructor,
286: MBeanParameterInfo param, int sequence) {
287: return param == null ? null : param.getDescription();
288: }
289:
290: /**
291: * Returns the description of the (sequence + 1)th parameter (that is: if sequence is 0 returns the description of the first
292: * parameter, if sequence is 1 returns the description of the second parameter, and so on) for the given operation. <br>
293: * By default returns {@link MBeanParameterInfo#getDescription param.getDescription()}.
294: */
295: protected String getDescription(MBeanOperationInfo operation,
296: MBeanParameterInfo param, int sequence) {
297: return param == null ? null : param.getDescription();
298: }
299:
300: /**
301: * Returns the name of the (sequence + 1)th parameter (that is: if sequence is 0 returns the name of the first
302: * parameter, if sequence is 1 returns the name of the second parameter, and so on) for the given constructor. <br>
303: * By default returns {@link MBeanParameterInfo#getName param.getName()}.
304: */
305: protected String getParameterName(MBeanConstructorInfo constructor,
306: MBeanParameterInfo param, int sequence) {
307: return param == null ? null : param.getName();
308: }
309:
310: /**
311: * Returns the name of the (sequence + 1)th parameter (that is: if sequence is 0 returns the name of the first
312: * parameter, if sequence is 1 returns the name of the second parameter, and so on) for the given operation. <br>
313: * By default returns {@link MBeanParameterInfo#getName param.getName()}.
314: */
315: protected String getParameterName(MBeanOperationInfo operation,
316: MBeanParameterInfo param, int sequence) {
317: return param == null ? null : param.getName();
318: }
319:
320: /**
321: * Returns the impact flag for the given MBeanOperationInfo. <br>
322: * By default returns {@link MBeanOperationInfo#getImpact info.getImpact()}
323: */
324: protected int getImpact(MBeanOperationInfo info) {
325: return info == null ? MBeanOperationInfo.UNKNOWN : info
326: .getImpact();
327: }
328:
329: /**
330: * Returns, by default, the given <code>constructors</code> if <code>implementation</code>
331: * is 'this' object or null, otherwise returns null. <br>
332: * Since the MBean that is registered in an MBeanServer is always an instance of StandardMBean,
333: * there is no meaning in providing MBeanConstructorInfo if the implementation passed to
334: * {@link #StandardMBean(Object,Class)} is not 'this' object.
335: */
336: protected MBeanConstructorInfo[] getConstructors(
337: MBeanConstructorInfo[] constructors, Object implementation) {
338: if (implementation == this || implementation == null)
339: return constructors;
340: return null;
341: }
342:
343: /**
344: * Returns the cached MBeanInfo, or null if the MBeanInfo is not cached.
345: *
346: * @see #cacheMBeanInfo
347: * @see #getMBeanInfo
348: */
349: protected MBeanInfo getCachedMBeanInfo() {
350: return info;
351: }
352:
353: /**
354: * Caches the given MBeanInfo after it has been created, by introspection, with the information
355: * provided to constructors. <br>
356: * Override to disable caching, or to install different caching policies.
357: *
358: * @param info The MBeanInfo to cache; if it is null, the cache is cleared.
359: * @see #getCachedMBeanInfo
360: * @see #getMBeanInfo
361: */
362: protected void cacheMBeanInfo(MBeanInfo info) {
363: this .info = info;
364: }
365:
366: /**
367: * This method calls the callbacks provided by this class that allow the user to customize the MBeanInfo
368: *
369: * @param info The MBeanInfo as it was introspected
370: */
371: private MBeanInfo setupMBeanInfo(MBeanInfo info) {
372: String clsName = getClassName(info);
373: String description = getDescription(info);
374: MBeanConstructorInfo[] ctors = setupConstructors(info
375: .getConstructors());
376: MBeanAttributeInfo[] attrs = setupAttributes(info
377: .getAttributes());
378: MBeanOperationInfo[] opers = setupOperations(info
379: .getOperations());
380: MBeanNotificationInfo[] notifs = setupNotifications(info
381: .getNotifications());
382: return new MBeanInfo(clsName, description, attrs, ctors, opers,
383: notifs);
384: }
385:
386: private MBeanConstructorInfo[] setupConstructors(
387: MBeanConstructorInfo[] originalCtors) {
388: MBeanConstructorInfo[] ctors = getConstructors(originalCtors,
389: getImplementation());
390: if (ctors == null)
391: return null;
392:
393: MBeanConstructorInfo[] newCtors = new MBeanConstructorInfo[ctors.length];
394: for (int i = 0; i < ctors.length; ++i) {
395: MBeanConstructorInfo ctor = ctors[i];
396: if (ctor == null)
397: continue;
398:
399: MBeanParameterInfo[] newParams = null;
400: MBeanParameterInfo[] params = ctor.getSignature();
401: if (params != null) {
402: newParams = new MBeanParameterInfo[params.length];
403: for (int j = 0; j < params.length; ++j) {
404: MBeanParameterInfo param = params[j];
405: if (param == null)
406: continue;
407:
408: String paramName = getParameterName(ctor, param, j);
409: String paramDescr = getDescription(ctor, param, j);
410: newParams[j] = new MBeanParameterInfo(paramName,
411: param.getType(), paramDescr);
412: }
413: }
414:
415: String ctorDescr = getDescription(ctor);
416: newCtors[i] = new MBeanConstructorInfo(ctor.getName(),
417: ctorDescr, newParams);
418: }
419:
420: return newCtors;
421: }
422:
423: private MBeanAttributeInfo[] setupAttributes(
424: MBeanAttributeInfo[] attrs) {
425: if (attrs == null)
426: return null;
427:
428: MBeanAttributeInfo[] newAttrs = new MBeanAttributeInfo[attrs.length];
429: for (int i = 0; i < attrs.length; ++i) {
430: MBeanAttributeInfo attr = attrs[i];
431: if (attr == null)
432: continue;
433:
434: String attrDescr = getDescription(attr);
435: newAttrs[i] = new MBeanAttributeInfo(attr.getName(), attr
436: .getType(), attrDescr, attr.isReadable(), attr
437: .isWritable(), attr.isIs());
438: }
439:
440: return newAttrs;
441: }
442:
443: private MBeanOperationInfo[] setupOperations(
444: MBeanOperationInfo[] opers) {
445: if (opers == null)
446: return null;
447:
448: MBeanOperationInfo[] newOpers = new MBeanOperationInfo[opers.length];
449: for (int i = 0; i < opers.length; ++i) {
450: MBeanOperationInfo oper = opers[i];
451: if (oper == null)
452: continue;
453:
454: MBeanParameterInfo[] newParams = null;
455: MBeanParameterInfo[] params = oper.getSignature();
456: if (params != null) {
457: newParams = new MBeanParameterInfo[params.length];
458: for (int j = 0; j < params.length; ++j) {
459: MBeanParameterInfo param = params[j];
460: if (param == null)
461: continue;
462:
463: String paramName = getParameterName(oper, param, j);
464: String paramDescr = getDescription(oper, param, j);
465: newParams[j] = new MBeanParameterInfo(paramName,
466: param.getType(), paramDescr);
467: }
468: }
469:
470: String operDescr = getDescription(oper);
471: int operImpact = getImpact(oper);
472: newOpers[i] = new MBeanOperationInfo(oper.getName(),
473: operDescr, newParams, oper.getReturnType(),
474: operImpact);
475: }
476:
477: return newOpers;
478: }
479:
480: private MBeanNotificationInfo[] setupNotifications(
481: MBeanNotificationInfo[] notifs) {
482: return notifs == null ? null : notifs;
483: }
484:
485: private MBeanMetaData introspectMBean(Object implementation,
486: Class management) {
487: MBeanMetaData metadata = MBeanMetaData.Factory.create();
488: metadata.setMBean(implementation);
489: metadata.setClassLoader(implementation.getClass()
490: .getClassLoader());
491: metadata.setMBeanStandard(true);
492: metadata.setMBeanInterface(management);
493:
494: MBeanIntrospector introspector = new MBeanIntrospector();
495: introspector.introspect(metadata);
496: if (!introspector.isMBeanCompliant(metadata))
497: return null;
498:
499: return metadata;
500: }
501:
502: private class StandardMBeanSupport extends AbstractDynamicMBean {
503: public synchronized MBeanInfo getMBeanInfo() {
504: return StandardMBean.this .getMBeanInfo();
505: }
506:
507: protected Object getResource() {
508: return StandardMBean.this.getImplementation();
509: }
510: }
511: }
|