KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > soto > jmx > MBeanDescriptor


1 package org.sapia.soto.jmx;
2
3 import org.sapia.soto.util.matcher.PathPattern;
4 import org.sapia.soto.util.matcher.Pattern;
5
6 import java.lang.reflect.InvocationTargetException JavaDoc;
7 import java.lang.reflect.Method JavaDoc;
8 import java.lang.reflect.Modifier JavaDoc;
9
10 import java.util.ArrayList JavaDoc;
11 import java.util.HashMap JavaDoc;
12 import java.util.Iterator JavaDoc;
13 import java.util.List JavaDoc;
14 import java.util.Map JavaDoc;
15
16 import javax.management.Attribute JavaDoc;
17 import javax.management.AttributeNotFoundException JavaDoc;
18 import javax.management.IntrospectionException JavaDoc;
19 import javax.management.MBeanAttributeInfo JavaDoc;
20 import javax.management.MBeanConstructorInfo JavaDoc;
21 import javax.management.MBeanException JavaDoc;
22 import javax.management.MBeanInfo JavaDoc;
23 import javax.management.MBeanNotificationInfo JavaDoc;
24 import javax.management.MBeanOperationInfo JavaDoc;
25 import javax.management.ReflectionException JavaDoc;
26
27
28 /**
29  * An instance of this class generates the <code>MBeanInfo</code> corresponding
30  * to a given arbitrary Java object that must respect the JavaBean pattern pertaining
31  * to the naming of setter/getter methods. Specifically, a setter and/or getter will
32  * be mapped to a given MBean attribute.
33  * <p>
34  * In addition, all methods that are not setter/getter will be considered as JMX operations.
35  * <p>
36  * Whether the methods correspond to setter and/or getter, they must be public an non-static
37  * to be considered as attributes or operations.
38  * <p>
39  * An instance of this class is used as follows:
40  * <pre>
41  * Object someJavaBean = new SomeObject();
42  * MBeanDescriptor desc = MBeanDescriptor.newInstanceFor(someJavaBean);
43  * </pre>
44  *
45  * @author Yanick Duchesne
46  * <dl>
47  * <dt><b>Copyright:</b><dd>Copyright &#169; 2002-2003 <a HREF="http://www.sapia-oss.org">Sapia Open Source Software</a>. All Rights Reserved.</dd></dt>
48  * <dt><b>License:</b><dd>Read the license.txt file of the jar or visit the
49  * <a HREF="http://www.sapia-oss.org/license.html">license page</a> at the Sapia OSS web site</dd></dt>
50  * </dl>
51  */

52 public class MBeanDescriptor {
53   public static final String JavaDoc DEFAULT_DESC = "No description available";
54   private Map JavaDoc _attributes = new HashMap JavaDoc();
55   private Map JavaDoc _operations = new HashMap JavaDoc();
56   private MBeanInfo JavaDoc _info;
57   private String JavaDoc _className;
58   private String JavaDoc _description = DEFAULT_DESC;
59   private Object JavaDoc _bean;
60
61   /**
62    * Constructor for MBeanDescriptor.
63    */

64   private MBeanDescriptor(Object JavaDoc bean) {
65     _bean = bean;
66   }
67
68   /**
69    * Sets this instance's description.
70    *
71    * @param desc a description.
72    */

73   public void setDescription(String JavaDoc desc) {
74     _description = desc;
75   }
76
77   /**
78    * Returns the bean with which this instance was created.
79    *
80    * @return an <code>Object</code>
81    */

82   public Object JavaDoc getBean() {
83     return _bean;
84   }
85
86   /**
87    * Creates a <code>MBeanDescriptor</code> with the given object (that must comply with the JavaBean style)
88    * and returns it.
89    *
90    * @param obj an <code>Object</code> for which to create an instance of this class.
91    * @return a <code>MBeanDescriptor</code>
92    */

93   public static MBeanDescriptor newInstanceFor(Object JavaDoc obj)
94     throws IntrospectionException JavaDoc {
95     MBeanDescriptor desc = new MBeanDescriptor(obj);
96     Method JavaDoc[] methods = obj.getClass().getDeclaredMethods();
97
98     for (int i = 0; i < methods.length; i++) {
99       if (((methods[i].getModifiers() & Modifier.STATIC) != 0) &&
100             ((methods[i].getModifiers() & Modifier.PUBLIC) == 0)) {
101         continue;
102       }
103
104       if (MethodUtils.isSetter(methods[i]) || MethodUtils.isGetter(methods[i]) ||
105             MethodUtils.isBoolean(methods[i])) {
106         desc.getAttributeDescriptorFor(methods[i]);
107       } else if (MethodUtils.isOperation(methods[i])) {
108         desc.getOperationDescriptor(methods[i]);
109       }
110     }
111
112     desc.init();
113
114     return desc;
115   }
116
117   /**
118    * Returns the <code>AttributeDescriptor</code> that corresponds to the given method. The method
119    * object passed in must be a setter or getter.
120    * <p>
121    * If no descriptor exists for the given method, one is internally created. Only one descriptor will
122    * be created for a given setter/getter pair.
123    *
124    * @param method a <code>Method</code> object for which to create an <code>AttributeDescriptor</code>, or
125    * for which to return an existing one.
126    * @return an <code>AttributeDescriptor</code>.
127    */

128   public AttributeDescriptor getAttributeDescriptorFor(Method JavaDoc method)
129     throws IllegalArgumentException JavaDoc {
130     String JavaDoc name = null;
131     MethodInfo info;
132
133     if (MethodUtils.isSetter(method)) {
134       name = MethodUtils.getAttributeName(method, MethodUtils.SET_PREFIX);
135       info = new MethodInfo(name, method.getParameterTypes());
136     } else if (MethodUtils.isGetter(method)) {
137       name = MethodUtils.getAttributeName(method, MethodUtils.GET_PREFIX);
138       info = new MethodInfo(name, new Class JavaDoc[] { method.getReturnType() });
139     } else if (MethodUtils.isBoolean(method)) {
140       name = MethodUtils.getAttributeName(method, "is");
141       info = new MethodInfo(name, new Class JavaDoc[] { method.getReturnType() });
142     } else {
143       throw new IllegalArgumentException JavaDoc("Method " + method +
144         " does not start with set/get/is prefix");
145     }
146
147     AttributeDescriptor desc = (AttributeDescriptor) _attributes.get(info);
148
149     if (desc == null) {
150       desc = new AttributeDescriptor();
151       desc.setAttributeName(name);
152       initAttributeDesc(desc, method);
153       _attributes.put(info, desc);
154     } else {
155       initAttributeDesc(desc, method);
156     }
157
158     return desc;
159   }
160
161   /**
162    * Returns the <code>OperationDescriptor</code> that corresponds to the given method. The method
163    * object passed in must not corrspond to a setter or getter.
164    * <p>
165    * If no descriptor exists for the given method, one is internally created.
166    *
167    * @param method a <code>Method</code> object for which to create an <code>OperationDescriptor</code>, or
168    * for which to return an existing one.
169    * @return an <code>OperationDescriptor</code>
170    */

171   public OperationDescriptor getOperationDescriptor(Method JavaDoc method) {
172     MethodInfo toCompare = new MethodInfo(method);
173     OperationDescriptor od = (OperationDescriptor) _operations.get(toCompare);
174
175     if (od == null) {
176       if (!MethodUtils.isOperation(method)) {
177         throw new IllegalArgumentException JavaDoc("Method " + method +
178           " does not correspond to a MBean operation");
179       }
180
181       od = new OperationDescriptor();
182       _operations.put(toCompare, od);
183       initOperationDesc(od, method);
184     }
185
186     return od;
187   }
188
189   /**
190    * Returns the <code>MBeanInfo</code> corresponding to this instance - or rather, to the object wrapped
191    * by this instance.
192    *
193    * @return the <code>MBeanInfo</code> corresponding to this instance.
194    */

195   public MBeanInfo JavaDoc getMBeanInfo() {
196     return _info;
197   }
198
199   /**
200    * Invokes the getter corresponding to the given attribute name an returns the result of the invocation.
201    *
202    * @param name the name of the attribute whose getter should be invoked.
203    * @return the getter's invocation result.
204    * @throws AttributeNotFoundException if no getter could be found for the given attribute name.
205    * @throws MBeanException if an exception occurred calling the given attribute's corresponding getter.
206    * @throws ReflectionException if a problem pertaining to the internal Java reflection hack occurs.
207    */

208   public Object JavaDoc getAttribute(String JavaDoc name)
209     throws AttributeNotFoundException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc {
210     List JavaDoc attrs;
211
212     try {
213       attrs = getAttributeDescriptorsFor(name, null);
214     } catch (IntrospectionException JavaDoc e) {
215       throw new MBeanException JavaDoc(e, "Get value for attribute: " + name);
216     }
217
218     if (attrs.size() == 0) {
219       throw new AttributeNotFoundException JavaDoc("No attribute for: " + name);
220     }
221
222     AttributeDescriptor ad = (AttributeDescriptor) attrs.get(0);
223
224     if (ad == null) {
225       throw new AttributeNotFoundException JavaDoc(name);
226     }
227
228     if (ad.getReadMethod() == null) {
229       throw new AttributeNotFoundException JavaDoc("Attribute '" + name +
230         "' is not readable");
231     }
232
233     try {
234       return ad.getReadMethod().invoke(_bean, new Object JavaDoc[0]);
235     } catch (IllegalAccessException JavaDoc e) {
236       throw new ReflectionException JavaDoc(e,
237         "Attribute '" + name + "' is not accessible");
238     } catch (InvocationTargetException JavaDoc e) {
239       Exception JavaDoc err;
240
241       if (e.getTargetException() instanceof Exception JavaDoc) {
242         err = (Exception JavaDoc) e.getTargetException();
243       } else {
244         err = e;
245       }
246
247       throw new MBeanException JavaDoc(err, "Error occured reading attribute: " + name);
248     }
249   }
250
251   /**
252    * Invokes the setter corresponding to the given attribute name.
253    *
254    * @param name the name of the attribute whose setter should be invoked.
255    * @throws AttributeNotFoundException if no setter could be found for the given attribute name.
256    * @throws MBeanException if an exception occurred calling the given attribute's corresponding setter.
257    * @throws ReflectionException if a problem pertaining to the internal Java reflection hack occurs.
258    */

259   public void setAttribute(Attribute JavaDoc attr)
260     throws AttributeNotFoundException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc {
261     List JavaDoc attrs;
262
263     try {
264       attrs = getAttributeDescriptorsFor(attr.getName(), null);
265     } catch (IntrospectionException JavaDoc e) {
266       throw new MBeanException JavaDoc(e, "Get value for attribute: " + attr.getName());
267     }
268
269     if (attrs.size() == 0) {
270       throw new AttributeNotFoundException JavaDoc("No attribute for: " +
271         attr.getName());
272     }
273
274     AttributeDescriptor ad = null;
275
276     for (int i = 0; i < attrs.size(); i++) {
277       ad = (AttributeDescriptor) attrs.get(i);
278
279       if ((ad.getWriteMethod() != null) &&
280             ((attr.getValue() == null) ||
281             ad.getWriteMethod().getParameterTypes()[0].isAssignableFrom(
282               attr.getValue().getClass()))) {
283         break;
284       }
285     }
286
287     if (ad == null) {
288       throw new AttributeNotFoundException JavaDoc(attr.getName());
289     }
290
291     if (ad.getWriteMethod() == null) {
292       throw new AttributeNotFoundException JavaDoc("Attribute '" + attr.getName() +
293         "' is not writable");
294     }
295
296     try {
297       ad.getWriteMethod().invoke(_bean, new Object JavaDoc[] { attr.getValue() });
298     } catch (IllegalAccessException JavaDoc e) {
299       throw new ReflectionException JavaDoc(e,
300         "Attribute '" + attr.getName() + "' is not accessible");
301     } catch (InvocationTargetException JavaDoc e) {
302       Exception JavaDoc err;
303
304       if (e.getTargetException() instanceof Exception JavaDoc) {
305         err = (Exception JavaDoc) e.getTargetException();
306       } else {
307         err = e;
308       }
309
310       throw new MBeanException JavaDoc(err,
311         "Error occured writing attribute: " + attr.getName());
312     }
313   }
314
315   /**
316    * Performs the operation corresponding to the given parameters.
317    *
318    * @param opName the name of the method to invoke.
319    * @param params the method's parameters.
320    * @param sig an array of <code>Class</code> objects corresponding to the desired method's signature.
321    */

322   public Object JavaDoc invoke(String JavaDoc opName, Object JavaDoc[] params, String JavaDoc[] sig)
323     throws MBeanException JavaDoc, ReflectionException JavaDoc {
324     MethodInfo info = new MethodInfo(opName, sig);
325     OperationDescriptor od = (OperationDescriptor) _operations.get(info);
326
327     if (od == null) {
328       throw new MBeanException JavaDoc(new NullPointerException JavaDoc(),
329         "No action found for " + opName);
330     }
331
332     try {
333       return od.getMethod().invoke(_bean, params);
334     } catch (IllegalAccessException JavaDoc e) {
335       throw new ReflectionException JavaDoc(e,
336         "Operation '" + opName + "' is not accessible");
337     } catch (InvocationTargetException JavaDoc e) {
338       throw new MBeanException JavaDoc(e, "Error occured peforming operation: " +
339         opName);
340     }
341   }
342
343   /**
344    * Returns the list of attribute descriptors corresponding to the given
345    * information.
346    * <p>
347    * This method's first argument is the pattern intended to match given
348    * attribute names. For example:
349    * <ul>
350    * <li>'Name' matches the 'Name' attribute (corresponding to the setName/getName method.
351    * <li>'*Name' matches any attribute whose name ends with 'Name'.
352    * <li>'Name*' matches any attribute whose name starts with 'Name'.
353    * <li>'*Name*' matches any attribute whose name ends and starts with 'Name'.
354    * <li>etc.
355    * </ul>
356    * <p>
357    * Pattern matching for the type works the same way; if the type is null,
358    * then any attribute descriptor whose name matches the name pattern is returned.
359    * <p>
360    *
361    *
362    * @param name an attribute name pattern.
363    * @param type an attribute type (class name) pattern.
364    */

365   public List JavaDoc getAttributeDescriptorsFor(String JavaDoc name, String JavaDoc type)
366     throws IntrospectionException JavaDoc {
367     if (name == null) {
368       throw new IntrospectionException JavaDoc("name arg cannot be null");
369     }
370
371     List JavaDoc toReturn = new ArrayList JavaDoc();
372     AttributeDescriptor desc;
373     Pattern namePattern = PathPattern.parse(name, true);
374     Pattern typePattern = null;
375
376     if (type != null) {
377       typePattern = PathPattern.parse(type, true);
378     }
379
380     for (Iterator JavaDoc iter = _attributes.values().iterator(); iter.hasNext();) {
381       desc = (AttributeDescriptor) iter.next();
382
383       if (desc.getInfo().getType() != null) {
384         if (type != null) {
385           if (namePattern.matches(desc.getAttributeName()) &&
386                 typePattern.matches(desc.getType())) {
387             toReturn.add(desc);
388           }
389         } else {
390           if (namePattern.matches(desc.getAttributeName())) {
391             toReturn.add(desc);
392           }
393         }
394       } else {
395         if (namePattern.matches(desc.getAttributeName())) {
396           toReturn.add(desc);
397         }
398       }
399     }
400
401     return toReturn;
402   }
403
404   /**
405    * Removes the list of attribute descriptors corresponding to the given
406    * information.
407    * <p>
408    * This method's first argument is the pattern intended to match given
409    * attribute names. For example:
410    * <ul>
411    * <li>'Name' matches the 'Name' attribute (corresponding to the setName/getName method.
412    * <li>'*Name' matches any attribute whose name ends with 'Name'.
413    * <li>'Name*' matches any attribute whose name starts with 'Name'.
414    * <li>'*Name*' matches any attribute whose name ends and starts with 'Name'.
415    * <li>etc.
416    * </ul>
417    * <p>
418    * Pattern matching for the type works the same way; if the type is null,
419    * then any attribute descriptor whose name matches the name pattern is removed.
420    * <p>
421    *
422    * @param name an attribute name pattern.
423    * @param type an attribute type (class name) pattern.
424    */

425   public void removeAttributeDescriptorsFor(String JavaDoc name, String JavaDoc type)
426     throws IntrospectionException JavaDoc {
427     List JavaDoc toRemove = getAttributeDescriptorsFor(name, type);
428     AttributeDescriptor desc;
429
430     for (int i = 0; i < toRemove.size(); i++) {
431       desc = (AttributeDescriptor) toRemove.get(i);
432       _attributes.remove(new MethodInfo(desc.getAttributeName(),
433           new String JavaDoc[] { desc.getType() }));
434     }
435   }
436
437   /**
438    * Adds the given attribute descriptor to this instance.
439    *
440    * @param an <code>AttributeDescriptor</code>.
441    */

442   public void addAttributeDescriptor(AttributeDescriptor desc) {
443     _attributes.put(new MethodInfo(desc.getAttributeName(),
444         new String JavaDoc[] { desc.getType() }), desc);
445   }
446
447   /**
448    * Returns the list of attribute descriptors corresponding to the given
449    * information.
450    * <p>
451    * This method's first argument is the pattern intended to match given
452    * operation names. For example:
453    * <ul>
454    * <li>'performAction' matches the 'performAction' operation (corresponding to the setName/getName method.
455    * <li>'*Action' matches any operation whose name ends with 'Action'.
456    * <li>'perform*' matches any operation whose name starts with 'perform'.
457    * <li>'*Action*' matches any operation whose name ends and starts with 'Action'.
458    * <li>etc.
459    * </ul>
460    * <p>
461    * Pattern matching for the parameters works the same way; if the params array is null
462    * null, then any operation descriptor whose name matches the name pattern is returned; if
463    * the params array is not null, then its length is compared to each operation descriptor's
464    * number of parameter. If that number is equal AND the operation's parameter types match the
465    * passed in parameter patterns, then the operation descriptor is returned.
466    * <p>
467    *
468    * @param name an operation name pattern.
469    * @param param an array of parameter type (class name) patterns.
470    */

471   public List JavaDoc getOperationDescriptorsFor(String JavaDoc name, String JavaDoc[] params)
472     throws IntrospectionException JavaDoc {
473     if (name == null) {
474       throw new IntrospectionException JavaDoc("name arg cannot be null");
475     }
476
477     List JavaDoc toReturn = new ArrayList JavaDoc();
478     OperationDescriptor desc;
479     ParameterDescriptor paramDesc;
480     Pattern namePattern = PathPattern.parse(name, true);
481     Pattern[] typePatterns = null;
482
483     if (params != null) {
484       typePatterns = new Pattern[params.length];
485
486       for (int i = 0; i < params.length; i++) {
487         typePatterns[i] = PathPattern.parse(params[i], false);
488       }
489     }
490
491     for (Iterator JavaDoc iter = _operations.values().iterator(); iter.hasNext();) {
492       desc = (OperationDescriptor) iter.next();
493
494       if (namePattern.matches(desc.getOperationName())) {
495         if (params == null) {
496           toReturn.add(desc);
497         } else {
498           List JavaDoc paramList = desc.getParameters();
499           int count = 0;
500
501           if (paramList.size() != typePatterns.length) {
502             continue;
503           }
504
505           for (int i = 0; i < paramList.size(); i++) {
506             paramDesc = (ParameterDescriptor) paramList.get(i);
507
508             if (typePatterns[i].matches(paramDesc.getInfo().getType())) {
509               count++;
510             }
511           }
512
513           if (count == params.length) {
514             toReturn.add(desc);
515           }
516         }
517       }
518     }
519
520     return toReturn;
521   }
522
523   /**
524    * Removes the list of attribute descriptors corresponding to the given
525    * information.
526    * <p>
527    * This method's first argument is the pattern intended to match given
528    * operation names. For example:
529    * <ul>
530    * <li>'performAction' matches the 'performAction' operation (corresponding to the setName/getName method.
531    * <li>'*Action' matches any operation whose name ends with 'Action'.
532    * <li>'perform*' matches any operation whose name starts with 'perform'.
533    * <li>'*Action*' matches any operation whose name ends and starts with 'Action'.
534    * <li>etc.
535    * </ul>
536    * <p>
537    * Pattern matching for the parameters works the same way; if the params array is null
538    * null, then any operation descriptor whose name matches the name pattern is removed; if
539    * the params array is not null, then its length is compared to each operation descriptor's
540    * number of parameter. If that number is equal AND the operation's parameter types match the
541    * passed in parameter patterns, then the operation descriptor is removed.
542    * <p>
543    *
544    * @param name an operation name pattern.
545    * @param param an array of parameter type (class name) patterns.
546    */

547   public void removeOperationDescriptorsFor(String JavaDoc name, String JavaDoc[] params)
548     throws IntrospectionException JavaDoc {
549     List JavaDoc toRemove = getOperationDescriptorsFor(name, params);
550     OperationDescriptor desc;
551
552     for (int i = 0; i < toRemove.size(); i++) {
553       desc = (OperationDescriptor) toRemove.get(i);
554       _operations.remove(new MethodInfo(desc.getMethod()));
555     }
556   }
557
558   /**
559    * Adds the given operation descriptor to this instance.
560    *
561    * @param an <code>OperationDescriptor</code>.
562    */

563   public void addOperationDescriptor(OperationDescriptor desc) {
564     _operations.put(new MethodInfo(desc.getMethod()), desc);
565   }
566
567   private MBeanAttributeInfo JavaDoc[] getAttributeInfos()
568     throws IntrospectionException JavaDoc {
569     MBeanAttributeInfo JavaDoc[] infos = new MBeanAttributeInfo JavaDoc[_attributes.size()];
570     AttributeDescriptor desc;
571     int i = 0;
572
573     for (Iterator JavaDoc iter = _attributes.values().iterator(); iter.hasNext();
574           i++) {
575       desc = (AttributeDescriptor) iter.next();
576       infos[i] = desc.getInfo();
577     }
578
579     return infos;
580   }
581
582   private MBeanOperationInfo JavaDoc[] getOperationInfos() {
583     MBeanOperationInfo JavaDoc[] infos = new MBeanOperationInfo JavaDoc[_operations.size()];
584     OperationDescriptor desc;
585     int i = 0;
586
587     for (Iterator JavaDoc iter = _operations.values().iterator(); iter.hasNext();
588           i++) {
589       desc = (OperationDescriptor) iter.next();
590       infos[i] = desc.getInfo();
591     }
592
593     return infos;
594   }
595
596   private static void initAttributeDesc(AttributeDescriptor ad, Method JavaDoc method) {
597     if (MethodUtils.isSetter(method)) {
598       ad.setWritable(method);
599     } else if (MethodUtils.isGetter(method)) {
600       ad.setReadable(method);
601     }
602   }
603
604   private static void initOperationDesc(OperationDescriptor od, Method JavaDoc method) {
605     od.setOperationName(method.getName());
606     od.setMethod(method);
607
608     Class JavaDoc[] params = method.getParameterTypes();
609     ParameterDescriptor pd;
610     String JavaDoc name;
611
612     for (int i = 0; i < params.length; i++) {
613       pd = new ParameterDescriptor();
614       pd.setType(params[i].getName());
615       pd.setName(MethodUtils.getShortClassName(params[i]));
616       od.addParameters(pd);
617     }
618   }
619
620   public void init() throws IntrospectionException JavaDoc {
621     _info = new MBeanInfo JavaDoc(_bean.getClass().getName(), _description,
622         getAttributeInfos(), new MBeanConstructorInfo JavaDoc[0], getOperationInfos(),
623         new MBeanNotificationInfo JavaDoc[0]);
624   }
625
626   public String JavaDoc toString() {
627     return "[ attributes=" + _attributes + ", operations=" + _operations +
628     " ]";
629   }
630 }
631
Popular Tags