KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mx > mxbean > MXBeanInvocationHandler


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2006, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.mx.mxbean;
23
24 import java.io.Serializable JavaDoc;
25 import java.lang.reflect.InvocationHandler JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27 import java.lang.reflect.Proxy JavaDoc;
28 import java.lang.reflect.Type JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.management.Attribute JavaDoc;
33 import javax.management.MBeanAttributeInfo JavaDoc;
34 import javax.management.MBeanOperationInfo JavaDoc;
35 import javax.management.MBeanParameterInfo JavaDoc;
36 import javax.management.MBeanServerConnection JavaDoc;
37 import javax.management.NotificationBroadcaster JavaDoc;
38 import javax.management.NotificationEmitter JavaDoc;
39 import javax.management.NotificationFilter JavaDoc;
40 import javax.management.NotificationListener JavaDoc;
41 import javax.management.ObjectName JavaDoc;
42 import javax.management.openmbean.OpenMBeanAttributeInfo JavaDoc;
43 import javax.management.openmbean.OpenMBeanInfo JavaDoc;
44 import javax.management.openmbean.OpenMBeanOperationInfo JavaDoc;
45 import javax.management.openmbean.OpenMBeanParameterInfo JavaDoc;
46 import javax.management.openmbean.OpenType JavaDoc;
47
48 import org.jboss.mx.util.JMXExceptionDecoder;
49
50 /**
51  * MXBeanInvocationHandler.
52  *
53  * @author <a HREF="adrian@jboss.com">Adrian Brock</a>
54  * @version $Revision: 1.1 $
55  */

56 public class MXBeanInvocationHandler implements InvocationHandler JavaDoc, Serializable JavaDoc
57 {
58    /** The serialVersionUID */
59    private static final long serialVersionUID = -2872014223541692039L;
60    
61    private static final Class JavaDoc[] LISTENER = new Class JavaDoc[] { NotificationListener JavaDoc.class };
62    private static final Class JavaDoc[] TRIPLET = new Class JavaDoc[] { NotificationListener JavaDoc.class, NotificationFilter JavaDoc.class, Object JavaDoc.class };
63
64    private static final Method JavaDoc EQUALS;
65    private static final Method JavaDoc HASH_CODE;
66    private static final Method JavaDoc TO_STRING;
67
68    private static final Method JavaDoc ADD_NOTIFICATION_LISTENER;
69    private static final Method JavaDoc GET_NOTIFICATION_INFO;
70    private static final Method JavaDoc REMOVE_NOTIFICATION_LISTENER;
71    private static final Method JavaDoc REMOVE_NOTIFICATION_LISTENER_TRIPLET;
72
73    /** The connection */
74    private MBeanServerConnection JavaDoc mbeanServerConnection;
75    
76    /** The interface */
77    private Class JavaDoc<?> mxbeanInterface;
78    
79    /** The object name */
80    private ObjectName JavaDoc objectName;
81
82    /** The method mappings */
83    private transient Map JavaDoc<Method JavaDoc, Action> mappings;
84    
85    /** The MBean Info */
86    private transient OpenMBeanInfo JavaDoc mbeanInfo;
87
88    static
89    {
90       try
91       {
92          ADD_NOTIFICATION_LISTENER = NotificationBroadcaster JavaDoc.class.getDeclaredMethod("addNotificationListener", TRIPLET);
93          GET_NOTIFICATION_INFO = NotificationBroadcaster JavaDoc.class.getDeclaredMethod("getNotificationInfo", new Class JavaDoc[0]);
94          REMOVE_NOTIFICATION_LISTENER = NotificationBroadcaster JavaDoc.class.getDeclaredMethod("removeNotificationListener", LISTENER);
95          REMOVE_NOTIFICATION_LISTENER_TRIPLET = NotificationEmitter JavaDoc.class.getDeclaredMethod("removeNotificationListener", TRIPLET);
96          EQUALS = Object JavaDoc.class.getDeclaredMethod("equals", new Class JavaDoc[] { Object JavaDoc.class });
97          HASH_CODE = Object JavaDoc.class.getDeclaredMethod("hashCode", new Class JavaDoc[0]);
98          TO_STRING = Object JavaDoc.class.getDeclaredMethod("toString", new Class JavaDoc[0]);
99       }
100       catch (Exception JavaDoc e)
101       {
102          throw new RuntimeException JavaDoc(e);
103       }
104    }
105    
106    /**
107     * Create a new MXBeanInvocationHandler.
108     *
109     * @param mbeanServerConnection the connection
110     * @param mxbeanInterface the interface
111     * @param objectName the object name
112     */

113    public MXBeanInvocationHandler(MBeanServerConnection JavaDoc mbeanServerConnection, Class JavaDoc<?> mxbeanInterface, ObjectName JavaDoc objectName)
114    {
115       if (mbeanServerConnection == null)
116          throw new IllegalArgumentException JavaDoc("Null mbeanServerConnection");
117       if (mxbeanInterface == null)
118          throw new IllegalArgumentException JavaDoc("Null mxmbeanInterface");
119       if (objectName == null)
120          throw new IllegalArgumentException JavaDoc("Null objectName");
121
122       this.mbeanServerConnection = mbeanServerConnection;
123       this.mxbeanInterface = mxbeanInterface;
124       this.objectName = objectName;
125    }
126
127    /**
128     * Get the mbeanServerConnection.
129     *
130     * @return the mbeanServerConnection.
131     */

132    public MBeanServerConnection JavaDoc getMBeanServerConnection()
133    {
134       return mbeanServerConnection;
135    }
136
137    /**
138     * Get the mxbeanInterface.
139     *
140     * @return the mxbeanInterface.
141     */

142    public Class JavaDoc<?> getMXBeanInterface()
143    {
144       return mxbeanInterface;
145    }
146
147    /**
148     * Get the objectName.
149     *
150     * @return the objectName.
151     */

152    public ObjectName JavaDoc getObjectName()
153    {
154       return objectName;
155    }
156
157    public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc
158    {
159       try
160       {
161          return getAction(proxy, method).perform(args);
162       }
163       catch (Throwable JavaDoc t)
164       {
165          throw JMXExceptionDecoder.decode(t);
166       }
167    }
168
169    /**
170     * Get the actions for this method
171     * @param proxy the proxy
172     * @param method the method
173     * @return the action
174     * @throws Throwable for any error
175     */

176    private Action getAction(Object JavaDoc proxy, Method JavaDoc method) throws Throwable JavaDoc
177    {
178       // Doesn't really matter if the mappings are
179
// setup twice by two different threads, they are the same.
180
if (mappings == null)
181          mappings = getMappings(proxy);
182
183       // Check the action
184
Action result = mappings.get(method);
185       if (result == null)
186          throw new UnsupportedOperationException JavaDoc("Unknown method: " + method);
187
188       // Return the result
189
return result;
190    }
191
192    /**
193     * Set up the mappings
194     *
195     * @param proxy the proxy
196     * @return the mapping
197     * @throws Throwable for any error
198     */

199    private Map JavaDoc<Method JavaDoc, Action> getMappings(Object JavaDoc proxy) throws Throwable JavaDoc
200    {
201       mbeanInfo = (OpenMBeanInfo JavaDoc) mbeanServerConnection.getMBeanInfo(objectName);
202       Map JavaDoc<String JavaDoc, OpenMBeanAttributeInfo JavaDoc> attributesMap = new HashMap JavaDoc<String JavaDoc, OpenMBeanAttributeInfo JavaDoc>();
203       MBeanAttributeInfo JavaDoc[] attributes = mbeanInfo.getAttributes();
204       for (int i = 0; i < attributes.length; ++i)
205       {
206          OpenMBeanAttributeInfo JavaDoc openAttribute = (OpenMBeanAttributeInfo JavaDoc) attributes[i];
207          attributesMap.put(openAttribute.getName(), openAttribute);
208       }
209       MBeanOperationInfo JavaDoc[] operations = mbeanInfo.getOperations();
210       
211       Map JavaDoc<Method JavaDoc, Action> result = new HashMap JavaDoc<Method JavaDoc, Action>();
212
213       Class JavaDoc[] interfaces = proxy.getClass().getInterfaces();
214       for (int i = 0; i < interfaces.length; ++i)
215       {
216          if (NotificationBroadcaster JavaDoc.class.isAssignableFrom(interfaces[i]))
217          {
218             result.put(ADD_NOTIFICATION_LISTENER, new AddNotificationListenerAction());
219             result.put(GET_NOTIFICATION_INFO, new GetNotificationInfoAction());
220             result.put(REMOVE_NOTIFICATION_LISTENER, new RemoveNotificationListenerAction());
221             result.put(REMOVE_NOTIFICATION_LISTENER_TRIPLET, new RemoveNotificationListenerTripletAction());
222          }
223          else
224          {
225             Method JavaDoc[] methods = interfaces[i].getMethods();
226             for (Method JavaDoc method : methods)
227             {
228                String JavaDoc methodName = method.getName();
229                Class JavaDoc returnType = method.getReturnType();
230                Class JavaDoc[] parameterTypes = method.getParameterTypes();
231
232                // Getter
233
if (methodName.startsWith("get") &&
234                    methodName.length() > 3 &&
235                    Void.TYPE.equals(returnType) == false &&
236                    parameterTypes.length == 0)
237                {
238                   String JavaDoc name = methodName.substring(3);
239                   OpenMBeanAttributeInfo JavaDoc attribute = attributesMap.get(name);
240                   if (attribute != null)
241                   {
242                      Type JavaDoc type = method.getGenericReturnType();
243                      result.put(method, new GetAction(attribute, type));
244                      continue;
245                   }
246                }
247                // Getter (is)
248
else if(methodName.startsWith("is") &&
249                      methodName.length() > 2 &&
250                      Boolean.TYPE.equals(returnType) &&
251                      parameterTypes.length == 0)
252                {
253                   String JavaDoc name = methodName.substring(2);
254                   OpenMBeanAttributeInfo JavaDoc attribute = attributesMap.get(name);
255                   if (attribute != null)
256                   {
257                      Type JavaDoc type = method.getGenericReturnType();
258                      result.put(method, new GetAction(attribute, type));
259                      continue;
260                   }
261                }
262                // Setter
263
else if(methodName.startsWith("set") &&
264                      methodName.length() > 3 &&
265                      Void.TYPE.equals(returnType) &&
266                      parameterTypes.length == 1)
267                {
268                   String JavaDoc name = methodName.substring(3);
269                   OpenMBeanAttributeInfo JavaDoc attribute = attributesMap.get(name);
270                   if (attribute != null)
271                   {
272                      result.put(method, new SetAction(attribute));
273                      continue;
274                   }
275                }
276                // Invoker
277
OpenMBeanOperationInfo JavaDoc operation = findOperation(methodName, method.getGenericParameterTypes(), operations);
278                if (operation != null)
279                {
280                   String JavaDoc[] signature = getSignature(method);
281                   Type JavaDoc type = method.getGenericReturnType();
282                   result.put(method, new InvokeAction(operation, signature, type));
283                }
284                else
285                {
286                   result.put(method, new InvalidAction(method));
287                }
288             }
289          }
290       }
291
292       // Add the Object mappings
293
result.put(EQUALS, new EqualsAction());
294       result.put(HASH_CODE, new HashCodeAction());
295       result.put(TO_STRING, new ToStringAction());
296       
297       return result;
298    }
299
300    private static OpenMBeanOperationInfo JavaDoc findOperation(String JavaDoc name, Type JavaDoc[] parameterTypes, MBeanOperationInfo JavaDoc[] operations)
301    {
302       OpenType JavaDoc[] signature = getSignature(parameterTypes);
303       for (int i = 0; i < operations.length; ++i)
304       {
305          if (operations[i].getName().equals(name) == false)
306             continue;
307          MBeanParameterInfo JavaDoc[] parameters = operations[i].getSignature();
308          boolean match = true;
309          for (int p = 0; p < parameters.length && match; ++p)
310          {
311             OpenMBeanParameterInfo JavaDoc openMBeanParameterInfo = (OpenMBeanParameterInfo JavaDoc) parameters[p];
312             if (signature[p].equals(openMBeanParameterInfo.getOpenType()) == false)
313                match = false;
314          }
315          if (match)
316             return (OpenMBeanOperationInfo JavaDoc) operations[i];
317       }
318       return null;
319    }
320    
321    private static String JavaDoc[] getSignature(final Method JavaDoc method)
322    {
323       Class JavaDoc[] parameterTypes = method.getParameterTypes();
324       String JavaDoc[] signature = new String JavaDoc[parameterTypes.length];
325       for (int p = 0; p < parameterTypes.length; ++p)
326           signature[p] = parameterTypes[p].getName();
327       return signature;
328    }
329    
330    private static OpenType JavaDoc[] getSignature(final Type JavaDoc[] parameterTypes)
331    {
332       OpenType JavaDoc[] signature = new OpenType JavaDoc[parameterTypes.length];
333       for (int p = 0; p < parameterTypes.length; ++p)
334           signature[p] = MXBeanUtils.getOpenType(parameterTypes[p]);
335       return signature;
336    }
337
338    private interface Action
339    {
340       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc;
341    }
342
343    private class GetAction implements Action
344    {
345       private OpenMBeanAttributeInfo JavaDoc attribute;
346       private Type JavaDoc type;
347
348       public GetAction(OpenMBeanAttributeInfo JavaDoc attribute, Type JavaDoc type)
349       {
350          this.attribute = attribute;
351          this.type = type;
352       }
353
354       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
355       {
356          Object JavaDoc result = mbeanServerConnection.getAttribute(objectName, attribute.getName());
357          
358          return MXBeanUtils.reconstruct(attribute.getOpenType(), type, result, "Get attribute: " + attribute.getName());
359       }
360    }
361
362    private class SetAction implements Action
363    {
364       private OpenMBeanAttributeInfo JavaDoc attribute;
365
366       public SetAction(OpenMBeanAttributeInfo JavaDoc attribute)
367       {
368          this.attribute = attribute;
369       }
370
371       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
372       {
373          Object JavaDoc value = MXBeanUtils.construct(attribute.getOpenType(), args[0], "Set attribute: " + attribute.getName());
374          
375          Attribute JavaDoc attr = new Attribute JavaDoc(attribute.getName(), value);
376          mbeanServerConnection.setAttribute(objectName, attr);
377          return null;
378       }
379    }
380
381    private class InvokeAction implements Action
382    {
383       private OpenMBeanOperationInfo JavaDoc operation;
384       private String JavaDoc[] signature;
385       private Type JavaDoc type;
386
387       public InvokeAction(OpenMBeanOperationInfo JavaDoc operation, String JavaDoc[] signature, Type JavaDoc type)
388       {
389          this.operation = operation;
390          this.signature = signature;
391          this.type = type;
392       }
393
394       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
395       {
396          MBeanParameterInfo JavaDoc[] parameters = operation.getSignature();
397          Object JavaDoc[] arguments = new Object JavaDoc[args.length];
398          for (int i = 0; i < parameters.length; ++i)
399          {
400             OpenMBeanParameterInfo JavaDoc parameter = (OpenMBeanParameterInfo JavaDoc) parameters[i];
401             arguments[i] = MXBeanUtils.construct(parameter.getOpenType(), args[i], operation.getName());
402          }
403          
404          Object JavaDoc result = mbeanServerConnection.invoke(objectName, operation.getName(), arguments, signature);
405          
406          return MXBeanUtils.reconstruct(operation.getReturnOpenType(), type, result, operation.getName());
407       }
408    }
409
410    private class InvalidAction implements Action
411    {
412       private Method JavaDoc method;
413       
414       public InvalidAction(Method JavaDoc method)
415       {
416          this.method = method;
417       }
418       
419       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
420       {
421          throw new UnsupportedOperationException JavaDoc(method + " is not mapped to the MBeanInfo operations for " + objectName);
422       }
423    }
424    
425    private class EqualsAction implements Action
426    {
427       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
428       {
429          Object JavaDoc object = args[0];
430          if (object == null || object instanceof Proxy JavaDoc == false)
431             return false;
432          InvocationHandler JavaDoc handler = Proxy.getInvocationHandler(object);
433          if (handler instanceof MXBeanInvocationHandler == false)
434             return false;
435          MXBeanInvocationHandler other = (MXBeanInvocationHandler) handler;
436          return mbeanServerConnection.equals(other.mbeanServerConnection) && objectName.equals(other.objectName);
437       }
438    }
439    
440    private class HashCodeAction implements Action
441    {
442       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
443       {
444          return objectName.hashCode();
445       }
446    }
447    
448    private class ToStringAction implements Action
449    {
450       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
451       {
452          return "MXBeanInvocationHandler(" + objectName + ")";
453       }
454    }
455    
456    private class AddNotificationListenerAction implements Action
457    {
458       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
459       {
460          NotificationListener JavaDoc listener = (NotificationListener JavaDoc) args[0];
461          NotificationFilter JavaDoc filter = (NotificationFilter JavaDoc) args[1];
462          Object JavaDoc handback = args[2];
463          mbeanServerConnection.addNotificationListener(objectName, listener, filter, handback);
464          return null;
465       }
466    }
467
468    private class GetNotificationInfoAction implements Action
469    {
470       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
471       {
472          return mbeanServerConnection.getMBeanInfo(objectName).getNotifications();
473       }
474    }
475
476    private class RemoveNotificationListenerAction implements Action
477    {
478       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
479       {
480          NotificationListener JavaDoc listener = (NotificationListener JavaDoc) args[0];
481          mbeanServerConnection.removeNotificationListener(objectName, listener);
482          return null;
483       }
484    }
485
486    private class RemoveNotificationListenerTripletAction implements Action
487    {
488       public Object JavaDoc perform(Object JavaDoc[] args) throws Throwable JavaDoc
489       {
490          NotificationListener JavaDoc listener = (NotificationListener JavaDoc) args[0];
491          NotificationFilter JavaDoc filter = (NotificationFilter JavaDoc) args[1];
492          Object JavaDoc handback = args[2];
493          mbeanServerConnection.removeNotificationListener(objectName, listener, filter, handback);
494          return null;
495       }
496    }
497 }
498
Popular Tags