KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mx > util > JMXInvocationHandler


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, 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.util;
23
24 import java.io.Serializable JavaDoc;
25
26 import java.lang.reflect.InvocationHandler JavaDoc;
27 import java.lang.reflect.Method JavaDoc;
28 import java.lang.reflect.Proxy JavaDoc;
29
30 import java.util.HashMap JavaDoc;
31
32 import javax.management.Attribute JavaDoc;
33 import javax.management.AttributeList JavaDoc;
34 import javax.management.AttributeNotFoundException JavaDoc;
35 import javax.management.DynamicMBean JavaDoc;
36 import javax.management.InstanceNotFoundException JavaDoc;
37 import javax.management.IntrospectionException JavaDoc;
38 import javax.management.InvalidAttributeValueException JavaDoc;
39 import javax.management.MBeanAttributeInfo JavaDoc;
40 import javax.management.MBeanException JavaDoc;
41 import javax.management.MBeanInfo JavaDoc;
42 import javax.management.MBeanOperationInfo JavaDoc;
43 import javax.management.MBeanServer JavaDoc;
44 import javax.management.ObjectName JavaDoc;
45 import javax.management.ReflectionException JavaDoc;
46 import javax.management.RuntimeErrorException JavaDoc;
47 import javax.management.RuntimeMBeanException JavaDoc;
48 import javax.management.RuntimeOperationsException JavaDoc;
49
50 /**
51  * Invocation handler for MBean proxies.
52  *
53  * @author <a HREF="mailto:juha@jboss.org">Juha Lindfors</a>.
54  * @version $Revision: 37459 $
55  *
56  */

57 public class JMXInvocationHandler
58       implements ProxyContext, InvocationHandler JavaDoc, Serializable JavaDoc
59 {
60    private static final long serialVersionUID = 3714728148040623702L;
61    
62    // Attributes -------------------------------------------------
63

64    /**
65     * Reference to the MBean server this proxy connects to.
66     */

67    protected MBeanServer JavaDoc server = null;
68    
69    /**
70     * The object name of the MBean this proxy represents.
71     */

72    protected ObjectName JavaDoc objectName = null;
73    
74    /**
75     * Default exception handler for the proxy.
76     */

77    private ProxyExceptionHandler handler = new DefaultExceptionHandler();
78    
79    /**
80     * MBean attribute meta data.
81     */

82    private HashMap JavaDoc attributeMap = new HashMap JavaDoc();
83    
84    /**
85     * Indicates whether Object.toString() should be delegated to the resource
86     * or handled by the proxy.
87     */

88    private boolean delegateToStringToResource = false;
89
90    /**
91     * Indicates whether Object.equals() should be delegated to the resource
92     * or handled by the proxy.
93     */

94    private boolean delegateEqualsToResource = false;
95
96    /**
97     * Indicates whether Object.hashCode() should be delegated to the resource
98     * or handled by the proxy.
99     */

100    private boolean delegateHashCodeToResource = false;
101    
102    
103    // Constructors -----------------------------------------------
104

105    /**
106     * Constructs a new JMX MBean Proxy invocation handler.
107     *
108     * @param server reference to the MBean server this proxy connects to
109     * @param name object name of the MBean this proxy represents
110     *
111     * @throws MBeanProxyCreationException wraps underlying JMX exceptions in
112     * case the proxy creation fails
113     */

114    public JMXInvocationHandler(MBeanServer JavaDoc server, ObjectName JavaDoc name)
115       throws MBeanProxyCreationException
116    {
117       try
118       {
119          if (server == null)
120             throw new MBeanProxyCreationException("null agent reference");
121             
122          this.server = server;
123          this.objectName = name;
124          
125          MBeanInfo JavaDoc info = server.getMBeanInfo(objectName);
126          MBeanAttributeInfo JavaDoc[] attributes = info.getAttributes();
127          MBeanOperationInfo JavaDoc[] operations = info.getOperations();
128          
129          // collect the MBean attribute metadata for standard mbean proxies
130
for (int i = 0; i < attributes.length; ++i)
131             attributeMap.put(attributes[i].getName(), attributes[i]);
132          
133          // Check whether the target resource exposes the common object methods.
134
// Dynamic Proxy will delegate these methods automatically to the
135
// invoke() implementation.
136
for (int i = 0; i < operations.length; ++i)
137          {
138             if (operations[i].getName().equals("toString") &&
139                 operations[i].getReturnType().equals("java.lang.String") &&
140                 operations[i].getSignature().length == 0)
141             {
142                delegateToStringToResource = true;
143             }
144             
145             else if (operations[i].getName().equals("equals") &&
146                      operations[i].getReturnType().equals(Boolean.TYPE.getName()) &&
147                      operations[i].getSignature().length == 1 &&
148                      operations[i].getSignature() [0].getType().equals("java.lang.Object"))
149             {
150                delegateEqualsToResource = true;
151             }
152             
153             else if (operations[i].getName().equals("hashCode") &&
154                      operations[i].getReturnType().equals(Integer.TYPE.getName()) &&
155                      operations[i].getSignature().length == 0)
156             {
157                delegateHashCodeToResource = true;
158             }
159          }
160       }
161       catch (InstanceNotFoundException JavaDoc e)
162       {
163          throw new MBeanProxyCreationException("Object name " + name + " not found: " + e.toString());
164       }
165       catch (IntrospectionException JavaDoc e)
166       {
167          throw new MBeanProxyCreationException(e.toString());
168       }
169       catch (ReflectionException JavaDoc e)
170       {
171          throw new MBeanProxyCreationException(e.toString());
172       }
173    }
174    
175    
176    // InvocationHandler implementation ---------------------------
177

178    public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
179       throws Exception JavaDoc
180    {
181       Class JavaDoc declaringClass = method.getDeclaringClass();
182       
183       // Handle methods from Object class. If the target resource exposes
184
// operation metadata with same signature then the invocations will be
185
// delegated to the target. Otherwise this instance of invocation handler
186
// will execute them.
187
if (declaringClass == Object JavaDoc.class)
188          return handleObjectMethods(method, args);
189       
190       // Check methods from ProxyContext interface. If invoked, delegate
191
// to the context implementation part of this invocation handler.
192
if (declaringClass == ProxyContext.class)
193          return method.invoke(this, args);
194       
195       // Check methods from DynamicMBean interface. This allows the proxy
196
// to be used in cases where the underlying metadata has changed (a la
197
// Dynamic MBean).
198
if (declaringClass == DynamicMBean JavaDoc.class)
199          return handleDynamicMBeanInvocation(method, args);
200       
201       try
202       {
203          String JavaDoc methodName = method.getName();
204          
205          // Assume a get/setAttribute convention on the typed proxy interface.
206
// If the MBean metadata exposes a matching attribute then use the
207
// MBeanServer attribute accessors to read/modify the value. If not,
208
// fallback to MBeanServer.invoke() assuming this is an operation
209
// invocation despite the accessor naming convention.
210

211          // getter
212
if (methodName.startsWith("get") && args == null)
213          {
214             String JavaDoc attrName = methodName.substring(3, methodName.length());
215             
216             // check that the metadata exists
217
MBeanAttributeInfo JavaDoc info = (MBeanAttributeInfo JavaDoc)attributeMap.get(attrName);
218             if (info != null)
219             {
220                String JavaDoc retType = method.getReturnType().getName();
221       
222                // check for correct return type on the getter
223
if (retType.equals(info.getType()))
224                {
225                   return server.getAttribute(objectName, attrName);
226                }
227             }
228          }
229          
230          // boolean getter
231
else if (methodName.startsWith("is") && args == null)
232          {
233             String JavaDoc attrName = methodName.substring(2, methodName.length());
234             
235             // check that the metadata exists
236
MBeanAttributeInfo JavaDoc info = (MBeanAttributeInfo JavaDoc)attributeMap.get(attrName);
237             if (info != null && info.isIs())
238             {
239                Class JavaDoc retType = method.getReturnType();
240                
241                // check for correct return type on the getter
242
if (retType.equals(Boolean JavaDoc.class) || retType.equals(Boolean.TYPE))
243                {
244                   return server.getAttribute(objectName, attrName);
245                }
246             }
247          }
248          
249          // setter
250
else if (methodName.startsWith("set") && args != null && args.length == 1)
251          {
252             String JavaDoc attrName = methodName.substring(3, methodName.length());
253             
254             // check that the metadata exists
255
MBeanAttributeInfo JavaDoc info = (MBeanAttributeInfo JavaDoc)attributeMap.get(attrName);
256             if (info != null && method.getReturnType().equals(Void.TYPE))
257             {
258                ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
259                
260                Class JavaDoc signatureClass = null;
261                String JavaDoc classType = info.getType();
262                
263                if (isPrimitive(classType))
264                   signatureClass = getPrimitiveClass(classType);
265                else
266                   signatureClass = cl.loadClass(info.getType());
267                
268                if (signatureClass.isAssignableFrom(args[0].getClass()))
269                {
270                   server.setAttribute(objectName, new Attribute JavaDoc(attrName, args[0]));
271                   return null;
272                }
273             }
274          }
275
276          String JavaDoc[] signature = null;
277          
278          if (args != null)
279          {
280             signature = new String JavaDoc[args.length];
281             Class JavaDoc[] sign = method.getParameterTypes();
282             
283             for (int i = 0; i < sign.length; ++i)
284                signature[i] = sign[i].getName();
285          }
286          
287          return server.invoke(objectName, methodName, args, signature);
288       }
289       catch (InstanceNotFoundException JavaDoc e)
290       {
291          return getExceptionHandler().handleInstanceNotFound(this, e, method, args);
292       }
293       catch (AttributeNotFoundException JavaDoc e)
294       {
295          return getExceptionHandler().handleAttributeNotFound(this, e, method, args);
296       }
297       catch (InvalidAttributeValueException JavaDoc e)
298       {
299          return getExceptionHandler().handleInvalidAttributeValue(this, e, method, args);
300       }
301       catch (MBeanException JavaDoc e)
302       {
303          return getExceptionHandler().handleMBeanException(this, e, method, args);
304       }
305       catch (ReflectionException JavaDoc e)
306       {
307          return getExceptionHandler().handleReflectionException(this, e, method, args);
308       }
309       catch (RuntimeOperationsException JavaDoc e)
310       {
311          return getExceptionHandler().handleRuntimeOperationsException(this, e, method, args);
312       }
313       catch (RuntimeMBeanException JavaDoc e)
314       {
315          return getExceptionHandler().handleRuntimeMBeanException(this, e, method, args);
316       }
317       catch (RuntimeErrorException JavaDoc e)
318       {
319          return getExceptionHandler().handleRuntimeError(this, e, method, args);
320       }
321    }
322
323    public ProxyExceptionHandler getExceptionHandler()
324    {
325       return handler;
326    }
327    
328    
329    // ProxyContext implementation -----------------------------------
330

331    // The proxy provides an access point for the client to methods not part
332
// of the MBean's management interface. It can be used to configure the
333
// invocation (with context, client side interceptors, RPC), exception
334
// handling, act as an access point to MBean server interface and so on.
335

336    public void setExceptionHandler(ProxyExceptionHandler handler)
337    {
338       this.handler = handler;
339    }
340    
341    public MBeanServer JavaDoc getMBeanServer()
342    {
343       return server;
344    }
345
346    public ObjectName JavaDoc getObjectName()
347    {
348       return objectName;
349    }
350    
351    
352    // Object overrides ----------------------------------------------
353

354    public String JavaDoc toString()
355    {
356       return "MBeanProxy for " + objectName + " (Agent ID: " + AgentID.get(server) + ")";
357    }
358    
359    
360    // Private -------------------------------------------------------
361

362    private Object JavaDoc handleObjectMethods(Method JavaDoc method, Object JavaDoc[] args)
363       throws InstanceNotFoundException JavaDoc, ReflectionException JavaDoc,
364       IntrospectionException JavaDoc, MBeanException JavaDoc
365    {
366       if (method.getName().equals("toString"))
367       {
368          if (delegateToStringToResource)
369             return server.invoke(objectName, "toString", null, null);
370          else
371             return toString();
372       }
373       
374       else if (method.getName().equals("equals"))
375       {
376          if (delegateEqualsToResource)
377          {
378             return server.invoke(objectName, "equals",
379                                  new Object JavaDoc[] { args[0] },
380                                  new String JavaDoc[] { "java.lang.Object" }
381             );
382          }
383          else if (Proxy.isProxyClass(args[0].getClass()))
384          {
385             Proxy JavaDoc prxy = (Proxy JavaDoc)args[0];
386             return new Boolean JavaDoc(this.equals(Proxy.getInvocationHandler(prxy)));
387          }
388          else
389          {
390             return new Boolean JavaDoc(this.equals(args[0]));
391          }
392       }
393       
394       else if (method.getName().equals("hashCode"))
395       {
396          if (delegateHashCodeToResource)
397             return server.invoke(objectName, "hashCode", null, null);
398          else
399             return new Integer JavaDoc(this.hashCode());
400       }
401       
402       else throw new Error JavaDoc("Unexpected method invocation!");
403    }
404    
405    private Object JavaDoc handleDynamicMBeanInvocation(Method JavaDoc method, Object JavaDoc[] args)
406       throws InstanceNotFoundException JavaDoc, ReflectionException JavaDoc,
407       IntrospectionException JavaDoc, MBeanException JavaDoc, AttributeNotFoundException JavaDoc,
408       InvalidAttributeValueException JavaDoc
409    {
410       String JavaDoc methodName = method.getName();
411       
412       if (methodName.equals("setAttribute"))
413       {
414          server.setAttribute(objectName, (Attribute JavaDoc)args[0]);
415          return null;
416       }
417       else if (methodName.equals("setAttributes"))
418          return server.setAttributes(objectName, (AttributeList JavaDoc)args[0]);
419       else if (methodName.equals("getAttribute"))
420          return server.getAttribute(objectName, (String JavaDoc)args[0]);
421       else if (methodName.equals("getAttributes"))
422          return server.getAttributes(objectName, (String JavaDoc[])args[0]);
423       else if (methodName.equals("invoke"))
424          return server.invoke(objectName, (String JavaDoc)args[0], (Object JavaDoc[])args[1], (String JavaDoc[])args[2]);
425       else if (methodName.equals("getMBeanInfo"))
426          return server.getMBeanInfo(objectName);
427       
428       else throw new Error JavaDoc("Unexpected method invocation!");
429    }
430
431    private boolean isPrimitive(String JavaDoc type)
432    {
433       if (type.equals(Integer.TYPE.getName())) return true;
434       if (type.equals(Long.TYPE.getName())) return true;
435       if (type.equals(Boolean.TYPE.getName())) return true;
436       if (type.equals(Byte.TYPE.getName())) return true;
437       if (type.equals(Character.TYPE.getName())) return true;
438       if (type.equals(Short.TYPE.getName())) return true;
439       if (type.equals(Float.TYPE.getName())) return true;
440       if (type.equals(Double.TYPE.getName())) return true;
441       if (type.equals(Void.TYPE.getName())) return true;
442       
443       return false;
444    }
445
446    private Class JavaDoc getPrimitiveClass(String JavaDoc type)
447    {
448       if (type.equals(Integer.TYPE.getName())) return Integer.TYPE;
449       if (type.equals(Long.TYPE.getName())) return Long.TYPE;
450       if (type.equals(Boolean.TYPE.getName())) return Boolean.TYPE;
451       if (type.equals(Byte.TYPE.getName())) return Byte.TYPE;
452       if (type.equals(Character.TYPE.getName()))return Character.TYPE;
453       if (type.equals(Short.TYPE.getName())) return Short.TYPE;
454       if (type.equals(Float.TYPE.getName())) return Float.TYPE;
455       if (type.equals(Double.TYPE.getName())) return Double.TYPE;
456       if (type.equals(Void.TYPE.getName())) return Void.TYPE;
457       
458       return null;
459    }
460    
461 }
462       
463
464
465
Popular Tags