KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mx4j > AbstractDynamicMBean


1 /*
2  * Copyright (C) The MX4J Contributors.
3  * All rights reserved.
4  *
5  * This software is distributed under the terms of the MX4J License version 1.0.
6  * See the terms of the MX4J License in the documentation provided with this software.
7  */

8
9 package mx4j;
10
11 import java.lang.reflect.InvocationTargetException JavaDoc;
12 import java.lang.reflect.Method JavaDoc;
13 import java.util.Arrays JavaDoc;
14 import javax.management.Attribute JavaDoc;
15 import javax.management.AttributeList JavaDoc;
16 import javax.management.AttributeNotFoundException JavaDoc;
17 import javax.management.DynamicMBean JavaDoc;
18 import javax.management.InvalidAttributeValueException 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.MBeanParameterInfo JavaDoc;
26 import javax.management.ReflectionException JavaDoc;
27 import javax.management.RuntimeErrorException JavaDoc;
28 import javax.management.RuntimeMBeanException JavaDoc;
29
30 import mx4j.util.Utils;
31
32 /**
33  * Utility class that allow the user to easily write DynamicMBeans. <br>
34  * By extending this class, the developer does not have to implement the methods of the DynamicMBean interface, but
35  * has instead to provide only the metadata (by overriding few methods) and the implementation (by implementing
36  * the methods) of the MBean itself. <br>
37  * The methods to override that provides metadata information are usually the following:
38  * <ul>
39  * <li> <code>createMBeanAttributeInfo</code>, if the MBeans has manageable attributes </li>
40  * <li> <code>createMBeanOperationInfo</code>, if the MBeans has manageable operations </li>
41  * <li> <code>createMBeanNotificationInfo</code>, if the MBeans has manageable notifications </li>
42  * <li> <code>createMBeanConstructorInfo</code>, if the MBeans has manageable constructors </li>
43  * <li> <code>getMBeanDescription</code> </li>
44  * </ul>
45  * For example, the following MBean only has one manageable attribute:
46  * <pre>
47  * public class SimpleDynamic extends AbstractDynamicMBean
48  * {
49  * protected MBeanAttributeInfo[] createMBeanAttributeInfo()
50  * {
51  * return new MBeanAttributeInfo[]
52  * {
53  * new MBeanAttributeInfo("Name", String.class.getName(), "The name", true, true, false)
54  * };
55  * }
56  * <p/>
57  * protected String getMBeanDescription()
58  * {
59  * return "A simple DynamicMBean";
60  * }
61  * <p/>
62  * public String getName() { ... }
63  * <p/>
64  * public void setName(String name) { ... }
65  * }
66  * </pre>
67  * It is responsibility of the developer to specify the metadata <b>and</b> implement the methods specified by the
68  * metadata, that will be invoked via reflection by the AbstractDynamicMBean class. For this reason, the methods
69  * belonging to the MBean implementation (in the case above <code>getName()</code> and <code>setName(...)</code>)
70  * must be public.
71  *
72  * @version $Revision: 1.7 $
73  */

74 public abstract class AbstractDynamicMBean implements DynamicMBean JavaDoc
75 {
76    private MBeanInfo JavaDoc info;
77    private Object JavaDoc resource;
78
79    /**
80     * Only subclasses can create a new instance of an AbstractDynamicMBean.
81     *
82     * @see #createMBeanConstructorInfo
83     */

84    protected AbstractDynamicMBean()
85    {
86    }
87
88    /**
89     * Returns the value of the manageable attribute, as specified by the DynamicMBean interface.
90     *
91     * @see #createMBeanAttributeInfo
92     */

93    public Object JavaDoc getAttribute(String JavaDoc attribute) throws AttributeNotFoundException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc
94    {
95       if (attribute == null) throw new AttributeNotFoundException JavaDoc("Attribute " + attribute + " not found");
96
97       Object JavaDoc resource = null;
98       MBeanInfo JavaDoc info = null;
99       synchronized (this)
100       {
101          resource = getResourceOrThis();
102          info = getMBeanInfo();
103       }
104
105       MBeanAttributeInfo JavaDoc[] attrs = info.getAttributes();
106       if (attrs == null || attrs.length == 0) throw new AttributeNotFoundException JavaDoc("No attributes defined for this MBean");
107
108       for (int i = 0; i < attrs.length; ++i)
109       {
110          MBeanAttributeInfo JavaDoc attr = attrs[i];
111          if (attr == null) continue;
112
113          if (attribute.equals(attr.getName()))
114          {
115             if (!attr.isReadable()) throw new ReflectionException JavaDoc(new NoSuchMethodException JavaDoc("No getter defined for attribute: " + attribute));
116
117             // Found, invoke via reflection
118
String JavaDoc prefix = null;
119             if (attr.isIs())
120                prefix = "is";
121             else
122                prefix = "get";
123
124             try
125             {
126                return invoke(resource, prefix + attr.getName(), new Class JavaDoc[0], new Object JavaDoc[0]);
127             }
128             catch (InvalidAttributeValueException JavaDoc x)
129             {
130                throw new ReflectionException JavaDoc(x);
131             }
132          }
133       }
134
135       throw new AttributeNotFoundException JavaDoc("Attribute " + attribute + " not found");
136    }
137
138    /**
139     * Returns the manageable attributes, as specified by the DynamicMBean interface.
140     */

141    public AttributeList JavaDoc getAttributes(String JavaDoc[] attributes)
142    {
143       AttributeList JavaDoc list = new AttributeList JavaDoc();
144
145       if (attributes != null)
146       {
147          for (int i = 0; i < attributes.length; ++i)
148          {
149             String JavaDoc attribute = attributes[i];
150             try
151             {
152                Object JavaDoc result = getAttribute(attribute);
153                list.add(new Attribute JavaDoc(attribute, result));
154             }
155             catch (AttributeNotFoundException JavaDoc ignored)
156             {
157             }
158             catch (MBeanException JavaDoc ignored)
159             {
160             }
161             catch (ReflectionException JavaDoc ignored)
162             {
163             }
164          }
165       }
166
167       return list;
168    }
169
170    /**
171     * Returns the MBeaInfo, as specified by the DynamicMBean interface; the default implementation caches the value
172     * returned by {@link #createMBeanInfo} (that is thus called only once).
173     *
174     * @see #createMBeanInfo
175     * @see #setMBeanInfo
176     */

177    public synchronized MBeanInfo JavaDoc getMBeanInfo()
178    {
179       if (info == null) setMBeanInfo(createMBeanInfo());
180       return info;
181    }
182
183    /**
184     * Returns the value of the manageable operation as specified by the DynamicMBean interface
185     *
186     * @see #createMBeanOperationInfo
187     */

188    public Object JavaDoc invoke(String JavaDoc method, Object JavaDoc[] arguments, String JavaDoc[] params) throws MBeanException JavaDoc, ReflectionException JavaDoc
189    {
190       if (method == null) throw new IllegalArgumentException JavaDoc("Method name cannot be null");
191       if (arguments == null) arguments = new Object JavaDoc[0];
192       if (params == null) params = new String JavaDoc[0];
193
194       Object JavaDoc resource = null;
195       MBeanInfo JavaDoc info = null;
196       synchronized (this)
197       {
198          resource = getResourceOrThis();
199          info = getMBeanInfo();
200       }
201
202       MBeanOperationInfo JavaDoc[] opers = info.getOperations();
203       if (opers == null || opers.length == 0) throw new ReflectionException JavaDoc(new NoSuchMethodException JavaDoc("No operations defined for this MBean"));
204
205       for (int i = 0; i < opers.length; ++i)
206       {
207          MBeanOperationInfo JavaDoc oper = opers[i];
208          if (oper == null) continue;
209
210          if (method.equals(oper.getName()))
211          {
212             MBeanParameterInfo JavaDoc[] parameters = oper.getSignature();
213             if (params.length != parameters.length) continue;
214
215             String JavaDoc[] signature = new String JavaDoc[parameters.length];
216             for (int j = 0; j < signature.length; ++j)
217             {
218                MBeanParameterInfo JavaDoc param = parameters[j];
219                if (param == null)
220                   signature[j] = null;
221                else
222                   signature[j] = param.getType();
223             }
224
225             if (Utils.arrayEquals(params, signature))
226             {
227                // Found the right operation
228
try
229                {
230                   Class JavaDoc[] classes = Utils.loadClasses(resource.getClass().getClassLoader(), signature);
231                   return invoke(resource, method, classes, arguments);
232                }
233                catch (ClassNotFoundException JavaDoc x)
234                {
235                   throw new ReflectionException JavaDoc(x);
236                }
237                catch (InvalidAttributeValueException JavaDoc x)
238                {
239                   throw new ReflectionException JavaDoc(x);
240                }
241             }
242          }
243       }
244
245       throw new ReflectionException JavaDoc(new NoSuchMethodException JavaDoc("Operation " + method + " with signature " + Arrays.asList(params) + " is not defined for this MBean"));
246    }
247
248    /**
249     * Sets the value of the manageable attribute, as specified by the DynamicMBean interface.
250     *
251     * @see #createMBeanAttributeInfo
252     */

253    public void setAttribute(Attribute JavaDoc attribute) throws AttributeNotFoundException JavaDoc, InvalidAttributeValueException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc
254    {
255       if (attribute == null) throw new AttributeNotFoundException JavaDoc("Attribute " + attribute + " not found");
256
257       Object JavaDoc resource = null;
258       MBeanInfo JavaDoc info = null;
259       synchronized (this)
260       {
261          resource = getResourceOrThis();
262          info = getMBeanInfo();
263       }
264
265       MBeanAttributeInfo JavaDoc[] attrs = info.getAttributes();
266       if (attrs == null || attrs.length == 0) throw new AttributeNotFoundException JavaDoc("No attributes defined for this MBean");
267
268       for (int i = 0; i < attrs.length; ++i)
269       {
270          MBeanAttributeInfo JavaDoc attr = attrs[i];
271          if (attr == null) continue;
272
273          if (attribute.getName().equals(attr.getName()))
274          {
275             if (!attr.isWritable()) throw new ReflectionException JavaDoc(new NoSuchMethodException JavaDoc("No setter defined for attribute: " + attribute));
276
277             try
278             {
279                String JavaDoc signature = attr.getType();
280                Class JavaDoc cls = Utils.loadClass(resource.getClass().getClassLoader(), signature);
281                invoke(resource, "set" + attr.getName(), new Class JavaDoc[]{cls}, new Object JavaDoc[]{attribute.getValue()});
282                return;
283             }
284             catch (ClassNotFoundException JavaDoc x)
285             {
286                throw new ReflectionException JavaDoc(x);
287             }
288          }
289       }
290
291       throw new AttributeNotFoundException JavaDoc("Attribute " + attribute + " not found");
292    }
293
294    /**
295     * Sets the manageable attributes, as specified by the DynamicMBean interface.
296     */

297    public AttributeList JavaDoc setAttributes(AttributeList JavaDoc attributes)
298    {
299       AttributeList JavaDoc list = new AttributeList JavaDoc();
300
301       if (attributes != null)
302       {
303          for (int i = 0; i < attributes.size(); ++i)
304          {
305             Attribute JavaDoc attribute = (Attribute JavaDoc)attributes.get(i);
306             try
307             {
308                setAttribute(attribute);
309                list.add(attribute);
310             }
311             catch (AttributeNotFoundException JavaDoc ignored)
312             {
313             }
314             catch (InvalidAttributeValueException JavaDoc ignored)
315             {
316             }
317             catch (MBeanException JavaDoc ignored)
318             {
319             }
320             catch (ReflectionException JavaDoc ignored)
321             {
322             }
323          }
324       }
325
326       return list;
327    }
328
329    /**
330     * @deprecated Replaced by {@link #invoke(Object,String,Class[],Object[])}. <br>
331     * The resource passed is the resource as set by {@link #setResource} or - if it is null - 'this' instance. <br>
332     * This method is deprecated because it is not thread safe.
333     */

334    protected Object JavaDoc invoke(String JavaDoc name, Class JavaDoc[] params, Object JavaDoc[] args) throws InvalidAttributeValueException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc
335    {
336       Object JavaDoc resource = getResourceOrThis();
337       return invoke(resource, name, params, args);
338    }
339
340    /**
341     * Looks up the method to call on given resource and invokes it.
342     * The default implementation requires that the methods that implement attribute and operation behavior
343     * on the resource object are public, but it is possible to override this behavior, and call
344     * also private methods.
345     *
346     * @see #findMethod
347     * @see #invokeMethod
348     */

349    protected Object JavaDoc invoke(Object JavaDoc resource, String JavaDoc name, Class JavaDoc[] params, Object JavaDoc[] args) throws InvalidAttributeValueException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc
350    {
351       try
352       {
353          Class JavaDoc cls = resource.getClass();
354          Method JavaDoc method = findMethod(cls, name, params);
355          return invokeMethod(method, resource, args);
356       }
357       catch (NoSuchMethodException JavaDoc x)
358       {
359          throw new ReflectionException JavaDoc(x);
360       }
361       catch (IllegalAccessException JavaDoc x)
362       {
363          throw new ReflectionException JavaDoc(x);
364       }
365       catch (IllegalArgumentException JavaDoc x)
366       {
367          throw new InvalidAttributeValueException JavaDoc(x.toString());
368       }
369       catch (InvocationTargetException JavaDoc x)
370       {
371          Throwable JavaDoc t = x.getTargetException();
372          if (t instanceof RuntimeException JavaDoc)
373             throw new RuntimeMBeanException JavaDoc((RuntimeException JavaDoc)t);
374          else if (t instanceof Exception JavaDoc) throw new MBeanException JavaDoc((Exception JavaDoc)t);
375          throw new RuntimeErrorException JavaDoc((Error JavaDoc)t);
376       }
377    }
378
379    /**
380     * Returns the (public) method with the given name and signature on the given class. <br>
381     * Override to return non-public methods, or to map methods to other classes, or to map methods with
382     * different signatures
383     *
384     * @see #invoke(String, Class[], Object[])
385     * @see #invokeMethod
386     */

387    protected Method JavaDoc findMethod(Class JavaDoc cls, String JavaDoc name, Class JavaDoc[] params) throws NoSuchMethodException JavaDoc
388    {
389       return cls.getMethod(name, params);
390    }
391
392    /**
393     * Invokes the given method on the given resource object with the given arguments. <br>
394     * Override to map methods to other objects, or to map methods with different arguments
395     *
396     * @see #invoke(String, Class[], Object[])
397     * @see #findMethod
398     */

399    protected Object JavaDoc invokeMethod(Method JavaDoc method, Object JavaDoc resource, Object JavaDoc[] args) throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc
400    {
401       return method.invoke(resource, args);
402    }
403
404    private Object JavaDoc getResourceOrThis()
405    {
406       Object JavaDoc resource = getResource();
407       if (resource == null) resource = this;
408       return resource;
409    }
410
411    /**
412     * Returns the resource object on which invoke attribute's getters, attribute's setters and operation's methods
413     *
414     * @see #setResource
415     */

416    protected synchronized Object JavaDoc getResource()
417    {
418       return resource;
419    }
420
421    /**
422     * Specifies the resource object on which invoke attribute's getters, attribute's setters and operation's methods.
423     *
424     * @see #getResource
425     */

426    public synchronized void setResource(Object JavaDoc resource)
427    {
428       this.resource = resource;
429    }
430
431    /**
432     * Sets the MBeanInfo object cached by this instance. <br>
433     * The given MBeanInfo is not cloned.
434     *
435     * @see #getMBeanInfo
436     */

437    protected synchronized void setMBeanInfo(MBeanInfo JavaDoc info)
438    {
439       this.info = info;
440    }
441
442    /**
443     * Creates the MBeanInfo for this instance, calling in succession factory methods that the user can override.
444     * Information to create MBeanInfo are taken calling the following methods:
445     * <ul>
446     * <li><code>{@link #createMBeanAttributeInfo}</code></li>
447     * <li><code>{@link #createMBeanConstructorInfo}</code></li>
448     * <li><code>{@link #createMBeanOperationInfo}</code></li>
449     * <li><code>{@link #createMBeanNotificationInfo}</code></li>
450     * <li><code>{@link #getMBeanClassName}</code></li>
451     * <li><code>{@link #getMBeanDescription}</code></li>
452     * </ul>
453     */

454    protected MBeanInfo JavaDoc createMBeanInfo()
455    {
456       MBeanAttributeInfo JavaDoc[] attrs = createMBeanAttributeInfo();
457       MBeanConstructorInfo JavaDoc[] ctors = createMBeanConstructorInfo();
458       MBeanOperationInfo JavaDoc[] opers = createMBeanOperationInfo();
459       MBeanNotificationInfo JavaDoc[] notifs = createMBeanNotificationInfo();
460       String JavaDoc className = getMBeanClassName();
461       String JavaDoc description = getMBeanDescription();
462       return new MBeanInfo JavaDoc(className, description, attrs, ctors, opers, notifs);
463    }
464
465    /**
466     * To be overridden to return metadata information about manageable attributes.
467     */

468    protected MBeanAttributeInfo JavaDoc[] createMBeanAttributeInfo()
469    {
470       return null;
471    }
472
473    /**
474     * To be overridden to return metadata information about manageable constructors.
475     */

476    protected MBeanConstructorInfo JavaDoc[] createMBeanConstructorInfo()
477    {
478       return null;
479    }
480
481    /**
482     * To be overridden to return metadata information about manageable operations.
483     */

484    protected MBeanOperationInfo JavaDoc[] createMBeanOperationInfo()
485    {
486       return null;
487    }
488
489    /**
490     * To be overridden to return metadata information about manageable notifications.
491     */

492    protected MBeanNotificationInfo JavaDoc[] createMBeanNotificationInfo()
493    {
494       return null;
495    }
496
497    /**
498     * To be overridden to return metadata information about the class name of this MBean;
499     * by default returns this class' name.
500     */

501    protected String JavaDoc getMBeanClassName()
502    {
503       return getClass().getName();
504    }
505
506    /**
507     * To be overridden to return metadata information about the description of this MBean.
508     */

509    protected String JavaDoc getMBeanDescription()
510    {
511       return null;
512    }
513 }
514
Popular Tags