001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.management;
023:
024: import org.jboss.logging.Logger;
025: import org.jboss.mx.metadata.StandardMetaData;
026: import org.jboss.mx.server.ExceptionHandler;
027: import org.jboss.mx.loading.LoaderRepository;
028:
029: import java.lang.reflect.Method;
030: import java.util.Iterator;
031:
032: /**
033: * A helper class to allow standard mbeans greater control over their
034: * management interface.<p>
035: *
036: * Extending this class actually makes the mbean a dynamic mbean, but
037: * with the convenience of a standard mbean.
038: *
039: * @todo make this more dynamic, somehow delegate to an XMBean?
040: *
041: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
042: * @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
043: * @version $Revision: 57200 $
044: */
045: public class StandardMBean implements DynamicMBean {
046: // Constants ---------------------------------------------------
047:
048: private static final Logger log = Logger
049: .getLogger(StandardMBean.class);
050:
051: // Attributes --------------------------------------------------
052:
053: /**
054: * The implementation object
055: */
056: private Object implementation;
057:
058: /**
059: * The management interface
060: */
061: private Class mbeanInterface;
062:
063: /**
064: * The cached mbeaninfo
065: */
066: private MBeanInfo cachedMBeanInfo;
067:
068: // Static -----------------------------------------------------
069:
070: // Constructors ------------------------------------------------
071:
072: /**
073: * Construct a DynamicMBean from the given implementation object
074: * and the passed management interface class.
075: *
076: * @param implementation the object implementing the mbean
077: * @param mbeanInterface the management interface of the mbean
078: * @exception IllegalArgumentException for a null implementation
079: * @exception NotCompliantMBeanException if the management interface
080: * does not follow the JMX design patterns or the implementation
081: * does not implement the interface
082: */
083: public StandardMBean(Object implementation, Class mbeanInterface)
084: throws NotCompliantMBeanException {
085: this .implementation = implementation;
086: this .mbeanInterface = mbeanInterface;
087: MBeanInfo info = buildMBeanInfo(implementation, mbeanInterface);
088: cacheMBeanInfo(info);
089: }
090:
091: /**
092: * Construct a DynamicMBean from this object
093: * and the passed management interface class.<p>
094: *
095: * Used in subclassing
096: *
097: * @param mbeanInterface the management interface of the mbean
098: * @exception NotCompliantMBeanException if the management interface
099: * does not follow the JMX design patterns or this
100: * does not implement the interface
101: */
102: protected StandardMBean(Class mbeanInterface)
103: throws NotCompliantMBeanException {
104: this .implementation = this ;
105: this .mbeanInterface = mbeanInterface;
106: MBeanInfo info = buildMBeanInfo(implementation, mbeanInterface);
107: cacheMBeanInfo(info);
108: }
109:
110: // Public ------------------------------------------------------
111:
112: /**
113: * Retrieve the implementation object
114: *
115: * @return the implementation
116: */
117: public Object getImplementation() {
118: return implementation;
119: }
120:
121: /**
122: * Replace the implementation object
123: *
124: * @todo make this work after the mbean is registered
125: * @param implementation the new implementation
126: * @exception IllegalArgumentException for a null parameter
127: * @exception NotCompliantMBeanException if the new implementation
128: * does not implement the interface supplied at
129: * construction
130: */
131: public void setImplementation(Object implementation)
132: throws NotCompliantMBeanException {
133: if (implementation == null)
134: throw new IllegalArgumentException("Null implementation");
135: this .implementation = implementation;
136: }
137:
138: /**
139: * Retrieve the implementation class
140: *
141: * @return the class of the implementation
142: */
143: public Class getImplementationClass() {
144: return implementation.getClass();
145: }
146:
147: /**
148: * Retrieve the management interface
149: *
150: * @return the management interface
151: */
152: public final Class getMBeanInterface() {
153: return mbeanInterface;
154: }
155:
156: // DynamicMBean Implementation ---------------------------------
157:
158: public Object getAttribute(String attribute)
159: throws AttributeNotFoundException, MBeanException,
160: ReflectionException {
161: try {
162: Method method = implementation.getClass().getMethod(
163: "get" + attribute, null);
164: return method.invoke(implementation, new Object[0]);
165: } catch (Exception e) {
166: JMException result = ExceptionHandler.handleException(e);
167: if (result instanceof AttributeNotFoundException)
168: throw (AttributeNotFoundException) result;
169: if (result instanceof MBeanException)
170: throw (MBeanException) result;
171: if (result instanceof ReflectionException)
172: throw (ReflectionException) result;
173: throw new MBeanException(e, "Cannot get attribute: "
174: + attribute);
175: }
176: }
177:
178: public void setAttribute(Attribute attribute)
179: throws AttributeNotFoundException,
180: InvalidAttributeValueException, MBeanException,
181: ReflectionException {
182: try {
183: Class[] clArr = null;
184: if (attribute.getValue() != null) {
185: clArr = new Class[] { attribute.getValue().getClass() };
186: }
187: Method method = implementation.getClass().getMethod(
188: "set" + attribute.getName(), clArr);
189: method.invoke(implementation, new Object[] { attribute
190: .getValue() });
191: } catch (Exception e) {
192: JMException result = ExceptionHandler.handleException(e);
193: if (result instanceof AttributeNotFoundException)
194: throw (AttributeNotFoundException) result;
195: if (result instanceof InvalidAttributeValueException)
196: throw (InvalidAttributeValueException) result;
197: if (result instanceof MBeanException)
198: throw (MBeanException) result;
199: if (result instanceof ReflectionException)
200: throw (ReflectionException) result;
201: throw new MBeanException(e, "Cannot set attribute: "
202: + attribute);
203: }
204: }
205:
206: public AttributeList getAttributes(String[] attributes) {
207: try {
208: AttributeList attrList = new AttributeList(
209: attributes.length);
210: for (int i = 0; i < attributes.length; i++) {
211: String name = attributes[i];
212: Object value = getAttribute(name);
213: attrList.add(new Attribute(name, value));
214: }
215: return attrList;
216: } catch (Exception e) {
217: JMException result = ExceptionHandler.handleException(e);
218: // Why is this not throwing the same exceptions as getAttribute(String)
219: throw new RuntimeException("Cannot get attributes", result);
220: }
221: }
222:
223: public AttributeList setAttributes(AttributeList attributes) {
224: try {
225: AttributeList attrList = new AttributeList(attributes
226: .size());
227: Iterator it = attributes.iterator();
228: while (it.hasNext()) {
229: Attribute attr = (Attribute) it.next();
230: setAttribute(attr);
231: String name = attr.getName();
232: Object value = getAttribute(name);
233: attrList.add(new Attribute(name, value));
234: }
235: return attrList;
236: } catch (Exception e) {
237: JMException result = ExceptionHandler.handleException(e);
238: // Why is this not throwing the same exceptions as setAttribute(Attribute)
239: throw new RuntimeException("Cannot set attributes", result);
240: }
241: }
242:
243: public Object invoke(String actionName, Object[] params,
244: String[] signature) throws MBeanException,
245: ReflectionException {
246: try {
247: Class[] sigcl = new Class[signature.length];
248: for (int i = 0; i < signature.length; i++) {
249: sigcl[i] = loadClass(signature[i]);
250: }
251: Method method = implementation.getClass().getMethod(
252: actionName, sigcl);
253: return method.invoke(implementation, params);
254: } catch (Exception e) {
255: JMException result = ExceptionHandler.handleException(e);
256: if (result instanceof MBeanException)
257: throw (MBeanException) result;
258: if (result instanceof ReflectionException)
259: throw (ReflectionException) result;
260: throw new MBeanException(e, "Cannot invoke: " + actionName);
261: }
262: }
263:
264: /**
265: * Load a class from the classloader that loaded this MBean
266: */
267: private Class loadClass(String className)
268: throws ClassNotFoundException {
269: Class clazz = LoaderRepository.getNativeClassForName(className);
270: if (clazz == null) {
271: ClassLoader cl = getClass().getClassLoader();
272: clazz = cl.loadClass(className);
273: }
274: return clazz;
275: }
276:
277: public MBeanInfo getMBeanInfo() {
278: MBeanInfo info = getCachedMBeanInfo();
279: if (info == null) {
280: try {
281: info = buildMBeanInfo(implementation, mbeanInterface);
282: cacheMBeanInfo(info);
283: } catch (NotCompliantMBeanException e) {
284: log.error("Unexcepted exception", e);
285: throw new IllegalStateException("Unexcepted exception "
286: + e.toString());
287: }
288:
289: }
290: return info;
291: }
292:
293: // Y overrides -------------------------------------------------
294:
295: // Protected ---------------------------------------------------
296:
297: /**
298: * Retrieve the class name of the mbean
299: *
300: * @param info the default mbeaninfo derived by reflection
301: * @return the class name
302: */
303: protected String getClassName(MBeanInfo info) {
304: return info.getClassName();
305: }
306:
307: /**
308: * Retrieve the description of the mbean
309: *
310: * @param info the default mbeaninfo derived by reflection
311: * @return the description
312: */
313: protected String getDescription(MBeanInfo info) {
314: return info.getDescription();
315: }
316:
317: /**
318: * Retrieve the description of the mbean feature
319: *
320: * @param info the default mbeanfeatureinfo derived by reflection
321: * @return the description
322: */
323: protected String getDescription(MBeanFeatureInfo info) {
324: return info.getDescription();
325: }
326:
327: /**
328: * Retrieve the description of the mbean attribute
329: *
330: * @param info the default mbeanattributeinfo derived by reflection
331: * @return the description
332: */
333: protected String getDescription(MBeanAttributeInfo info) {
334: return getDescription((MBeanFeatureInfo) info);
335: }
336:
337: /**
338: * Retrieve the description of the mbean constructor
339: *
340: * @param info the default mbeanconstructorinfo derived by reflection
341: * @return the description
342: */
343: protected String getDescription(MBeanConstructorInfo info) {
344: return getDescription((MBeanFeatureInfo) info);
345: }
346:
347: /**
348: * Retrieve the description of the mbean operation
349: *
350: * @param info the default mbeanoperationinfo derived by reflection
351: * @return the description
352: */
353: protected String getDescription(MBeanOperationInfo info) {
354: return getDescription((MBeanFeatureInfo) info);
355: }
356:
357: /**
358: * Retrieve the description of the mbean constructor parameter
359: *
360: * @param info the default mbeanconstructorinfo derived by reflection
361: * @param param the parameter information
362: * @param sequence the parameter index, starting with zero
363: * @return the description
364: */
365: protected String getDescription(MBeanConstructorInfo info,
366: MBeanParameterInfo param, int sequence) {
367: return param.getDescription();
368: }
369:
370: /**
371: * Retrieve the description of the mbean operation parameter
372: *
373: * @param info the default mbeanoperationinfo derived by reflection
374: * @param param the parameter information
375: * @param sequence the parameter index, starting with zero
376: * @return the description
377: */
378: protected String getDescription(MBeanOperationInfo info,
379: MBeanParameterInfo param, int sequence) {
380: return param.getDescription();
381: }
382:
383: /**
384: * Retrieve the parameter name for a constructor
385: *
386: * @param info the default mbeanconstructorinfo derived by reflection
387: * @param param the parameter information
388: * @param sequence the parameter index, starting with zero
389: * @return the parameter name
390: */
391: protected String getParameterName(MBeanConstructorInfo info,
392: MBeanParameterInfo param, int sequence) {
393: return param.getName();
394: }
395:
396: /**
397: * Retrieve the parameter name for an operation
398: *
399: * @param info the default mbeanoperationinfo derived by reflection
400: * @param param the parameter information
401: * @param sequence the parameter index, starting with zero
402: * @return the parameter name
403: */
404: protected String getParameterName(MBeanOperationInfo info,
405: MBeanParameterInfo param, int sequence) {
406: return param.getName();
407: }
408:
409: /**
410: * Retrieve the impact of the mbean operation
411: *
412: * @param info the default mbeanoperationinfo derived by reflection
413: * @return the impact
414: */
415: protected int getImpact(MBeanOperationInfo info) {
416: return info.getImpact();
417: }
418:
419: /**
420: * Retrieve the constructors
421: *
422: * @param constructors the default constructors derived by reflection
423: * @param implementation the implementation
424: * @return the constructors if the implementation is this, otherwise null
425: */
426: protected MBeanConstructorInfo[] getConstructors(
427: MBeanConstructorInfo[] constructors, Object implementation) {
428: if (implementation == this )
429: return constructors;
430: else
431: return null;
432: }
433:
434: /**
435: * Retrieve the cached mbean info
436: *
437: * @return the cached mbean info
438: */
439: protected MBeanInfo getCachedMBeanInfo() {
440: return cachedMBeanInfo;
441: }
442:
443: /**
444: * Sets the cached mbean info
445: *
446: * @todo make this work after the mbean is registered
447: * @param info the mbeaninfo to cache, can be null to erase the cache
448: */
449: protected void cacheMBeanInfo(MBeanInfo info) {
450: cachedMBeanInfo = info;
451: }
452:
453: // Package Private ---------------------------------------------
454:
455: // Private -----------------------------------------------------
456:
457: /**
458: * Builds a default MBeanInfo for this MBean, using the Management Interface specified for this MBean.
459: *
460: * While building the MBeanInfo, this method calls the customization hooks that make it possible for subclasses to
461: * supply their custom descriptions, parameter names, etc...
462: */
463: private final MBeanInfo buildMBeanInfo(Object implementation,
464: Class mbeanInterface) throws NotCompliantMBeanException {
465: if (implementation == null)
466: throw new IllegalArgumentException("Null implementation");
467:
468: StandardMetaData metaData = new StandardMetaData(
469: implementation, mbeanInterface);
470: this .mbeanInterface = metaData.getMBeanInterface();
471: MBeanInfo info = metaData.build();
472:
473: String className = getClassName(info);
474: String mainDescription = getDescription(info);
475: MBeanAttributeInfo[] attributes = info.getAttributes();
476: MBeanConstructorInfo[] constructors = info.getConstructors();
477: MBeanOperationInfo[] operations = info.getOperations();
478: MBeanNotificationInfo[] notifications = info.getNotifications();
479:
480: for (int i = 0; i < attributes.length; i++) {
481: MBeanAttributeInfo attribute = attributes[i];
482: String description = getDescription(attribute);
483: attributes[i] = new MBeanAttributeInfo(attribute.getName(),
484: attribute.getType(), description, attribute
485: .isReadable(), attribute.isWritable(),
486: attribute.isIs());
487: }
488:
489: // If this StandardMBean is a wrapper of another resource we don't expose constructors
490: if (implementation == this ) {
491: constructors = getConstructors(constructors, this );
492: for (int i = 0; i < constructors.length; i++) {
493: MBeanConstructorInfo constructor = constructors[i];
494: MBeanParameterInfo[] parameters = constructor
495: .getSignature();
496: for (int j = 0; j < parameters.length; j++) {
497: MBeanParameterInfo param = parameters[j];
498: String description = getDescription(constructor,
499: param, j);
500: String name = getParameterName(constructor, param,
501: j);
502: parameters[j] = new MBeanParameterInfo(name, param
503: .getType(), description);
504: }
505: String description = getDescription(constructor);
506: constructors[i] = new MBeanConstructorInfo(constructor
507: .getName(), description, parameters);
508: }
509: } else {
510: constructors = new MBeanConstructorInfo[0];
511: }
512:
513: for (int i = 0; i < operations.length; i++) {
514: MBeanOperationInfo operation = operations[i];
515: MBeanParameterInfo[] parameters = operation.getSignature();
516: for (int j = 0; j < parameters.length; j++) {
517: MBeanParameterInfo param = parameters[j];
518: String description = getDescription(operation, param, j);
519: String name = getParameterName(operation, param, j);
520: parameters[j] = new MBeanParameterInfo(name, param
521: .getType(), description);
522: }
523: String description = getDescription(operation);
524: int impact = getImpact(operation);
525: operations[i] = new MBeanOperationInfo(operation.getName(),
526: description, parameters, operation.getReturnType(),
527: impact);
528: }
529:
530: info = new MBeanInfo(className, mainDescription, attributes,
531: constructors, operations, notifications);
532: return info;
533: }
534:
535: // Inner Classes -----------------------------------------------
536: }
|