KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mx > remoting > MoveableMBean


1 /***************************************
2  * *
3  * JBoss: The OpenSource J2EE WebOS *
4  * *
5  * Distributable under LGPL license. *
6  * See terms of license at gnu.org. *
7  * *
8  ***************************************/

9 package org.jboss.mx.remoting;
10
11 import java.io.IOException JavaDoc;
12 import java.io.Serializable JavaDoc;
13 import java.lang.reflect.InvocationHandler JavaDoc;
14 import java.lang.reflect.Method JavaDoc;
15 import java.lang.reflect.Proxy JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.WeakHashMap JavaDoc;
19 import javax.management.Attribute JavaDoc;
20 import javax.management.InstanceNotFoundException JavaDoc;
21 import javax.management.MBeanException JavaDoc;
22 import javax.management.ReflectionException JavaDoc;
23 import org.jboss.remoting.loading.ClassUtil;
24
25 /**
26  * MoveableMBean is a Dynamic Proxy to an MBean that exists on a JMX Network. This object
27  * can be created an cast to the appropriate set of interfaces that the MBean implements and can
28  * be serialized and past across the network and serialization and remote invocation will be
29  * handled as if the Object was local to the JVM. <P>
30  * <p/>
31  * Example usage:
32  * <p/>
33  * <CODE><PRE>
34  * <p/>
35  * TestMBean mybean=(TestMBean)MoveableMBean.create(mbeanLocator,TestMBean.class);
36  * <p/>
37  * // transport method
38  * mybean.myMethod();
39  * <p/>
40  * // transport a method against a remote JMX server and pass the TestMBean object
41  * // it will be serialized and passed to the remote server .. on the other side, the
42  * // JVM will de-serialize, create a local DynamicProxy and then invocations against the
43  * // parameter, will be invoked remotely back to the mbeanLocator above
44  * remoteserver.transport(new ObjectName(":test=MyObject"),"myMethod",new Object[]{mybean},new String[]{TestMBean.class.getName()});
45  * <p/>
46  * </PRE></CODE>
47  * <p/>
48  * You can also cache attribute values in the local proxy, in the case where the values are fixed
49  * and you don't want to remote overhead associated with sending the invocation remotely. In this case,
50  * you can pass in a Map of attribute/value pairs which will be always returned in any getter method invocation
51  * against the attribute.
52  *
53  * @author <a HREF="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
54  * @version $Revision: 30392 $
55  */

56 public class MoveableMBean implements InvocationHandler JavaDoc, Serializable JavaDoc
57 {
58    static final long serialVersionUID = -7506487379354274551L;
59    
60    private transient static Map JavaDoc methodArgs = new WeakHashMap JavaDoc();
61
62    // preloaded Method objects for the methods in java.lang.Object
63
private static transient Method JavaDoc hashCodeMethod;
64    private static transient Method JavaDoc equalsMethod;
65    private static transient Method JavaDoc toStringMethod;
66    private static transient Method JavaDoc notifyAllMethod;
67    private static transient Method JavaDoc notifyMethod;
68    private static transient Method JavaDoc wait0Method;
69    private static transient Method JavaDoc wait1Method;
70    private static transient Method JavaDoc wait2Method;
71
72    protected MBeanLocator locator;
73    protected Integer JavaDoc hashCode;
74    protected Map JavaDoc staticAttributes;
75
76    static
77    {
78       try
79       {
80          // SETUP Method objects from the Object class
81
hashCodeMethod = Object JavaDoc.class.getMethod("hashCode", null);
82          equalsMethod = Object JavaDoc.class.getMethod("equals", new Class JavaDoc[]{Object JavaDoc.class});
83          toStringMethod = Object JavaDoc.class.getMethod("toString", null);
84          notifyMethod = Object JavaDoc.class.getMethod("notify", null);
85          notifyAllMethod = Object JavaDoc.class.getMethod("notifyAll", null);
86          notifyMethod = Object JavaDoc.class.getMethod("notify", null);
87          wait0Method = Object JavaDoc.class.getMethod("wait", null);
88          wait1Method = Object JavaDoc.class.getMethod("wait", new Class JavaDoc[]{Long.TYPE});
89          wait2Method = Object JavaDoc.class.getMethod("wait", new Class JavaDoc[]{Long.TYPE, Integer.TYPE});
90       }
91       catch(NoSuchMethodException JavaDoc e)
92       {
93          throw new InternalError JavaDoc(e.getMessage());
94       }
95    }
96
97
98    protected MoveableMBean(MBeanLocator locator, Map JavaDoc staticAttributes)
99    {
100       this.locator = locator;
101       this.staticAttributes = staticAttributes;
102       this.hashCode = new Integer JavaDoc(System.identityHashCode(locator));
103    }
104
105    /**
106     * return the locator that the mbean references
107     *
108     * @return
109     */

110    public final MBeanLocator getMBeanLocator()
111    {
112       return locator;
113    }
114
115    public static Object JavaDoc create(MBeanLocator locator, ClassLoader JavaDoc loader, Class JavaDoc interfaceClass)
116    {
117       Class JavaDoc classes[] = ClassUtil.getInterfacesFor(interfaceClass);
118       return create(locator, loader, classes, null);
119    }
120
121    public static Object JavaDoc create(MBeanLocator locator, ClassLoader JavaDoc loader, Class JavaDoc interfaceClass, Map JavaDoc staticAttributes)
122    {
123       Class JavaDoc classes[] = ClassUtil.getInterfacesFor(interfaceClass);
124       return create(locator, loader, classes, staticAttributes);
125    }
126
127    public static Object JavaDoc create(MBeanLocator locater, Class JavaDoc interfaceClass)
128    {
129       Class JavaDoc classes[] = ClassUtil.getInterfacesFor(interfaceClass);
130       return create(locater, classes);
131    }
132
133    public static Object JavaDoc create(MBeanLocator locator, Class JavaDoc interfaces[])
134    {
135       ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
136       if(loader == null)
137       {
138          loader = interfaces[0].getClassLoader();
139       }
140       return create(locator, loader, interfaces, null);
141    }
142
143    public static Object JavaDoc create(MBeanLocator locator, ClassLoader JavaDoc loader, Class JavaDoc interfaces[], Map JavaDoc staticAttributes)
144    {
145       Class JavaDoc _inf[] = interfaces;
146       boolean found = false;
147       for(int c = 0; c < interfaces.length; c++)
148       {
149          if(interfaces[c] == LocationAware.class)
150          {
151             found = true;
152             break;
153          }
154       }
155       if(found == false)
156       {
157          _inf = new Class JavaDoc[interfaces.length + 1];
158          System.arraycopy(interfaces, 0, _inf, 0, interfaces.length);
159          // always add location aware interface so you can cast this mbean to that interface
160
_inf[interfaces.length] = LocationAware.class;
161       }
162       return Proxy.newProxyInstance(loader, _inf, new MoveableMBean(locator, staticAttributes));
163    }
164
165    /**
166     * add a map of static attributes, with each key being the attributeName and the value being the
167     * value to return for every invocation to this attribute getter
168     *
169     * @param values
170     */

171    public void addStaticAttributes(Map JavaDoc values)
172    {
173       if(staticAttributes == null)
174       {
175          staticAttributes = values;
176       }
177       else
178       {
179          staticAttributes.putAll(values);
180       }
181    }
182
183    /**
184     * add a static attribute
185     *
186     * @param name
187     * @param value
188     */

189    public void addStaticAttribute(String JavaDoc name, Object JavaDoc value)
190    {
191       if(staticAttributes == null)
192       {
193          staticAttributes = new HashMap JavaDoc(1);
194       }
195       staticAttributes.put(name, value);
196    }
197
198    protected Object JavaDoc handleLocationMethods(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
199          throws Throwable JavaDoc
200    {
201       return locator;
202    }
203
204    /**
205     * Processes a method invocation on a proxy instance and returns
206     * the result. This method will be invoked on an invocation handler
207     * when a method is invoked on a proxy instance that it is
208     * associated with.
209     *
210     * @param proxy the proxy instance that the method was invoked on
211     * @param method the <code>Method</code> instance corresponding to
212     * the interface method invoked on the proxy instance. The declaring
213     * class of the <code>Method</code> object will be the interface that
214     * the method was declared in, which may be a superinterface of the
215     * proxy interface that the proxy class inherits the method through.
216     * @param args an array of objects containing the values of the
217     * arguments passed in the method invocation on the proxy instance,
218     * or <code>null</code> if interface method takes no arguments.
219     * Arguments of primitive types are wrapped in instances of the
220     * appropriate primitive wrapper class, such as
221     * <code>java.lang.Integer</code> or <code>java.lang.Boolean</code>.
222     * @return the value to return from the method invocation on the
223     * proxy instance. If the declared return type of the interface
224     * method is a primitive type, then the value returned by
225     * this method must be an instance of the corresponding primitive
226     * wrapper class; otherwise, it must be a type assignable to the
227     * declared return type. If the value returned by this method is
228     * <code>null</code> and the interface method's return type is
229     * primitive, then a <code>NullPointerException</code> will be
230     * thrown by the method invocation on the proxy instance. If the
231     * value returned by this method is otherwise not compatible with
232     * the interface method's declared return type as described above,
233     * a <code>ClassCastException</code> will be thrown by the method
234     * invocation on the proxy instance.
235     * @throws java.lang.Throwable the exception to throw from the method
236     * invocation on the proxy instance. The exception's type must be
237     * assignable either to any of the exception types declared in the
238     * <code>throws</code> clause of the interface method or to the
239     * unchecked exception types <code>java.lang.RuntimeException</code>
240     * or <code>java.lang.Error</code>. If a checked exception is
241     * thrown by this method that is not assignable to any of the
242     * exception types declared in the <code>throws</code> clause of
243     * the interface method, then an
244     * {@link java.lang.reflect.UndeclaredThrowableException} containing the
245     * exception that was thrown by this method will be thrown by the
246     * method invocation on the proxy instance.
247     * @see java.lang.reflect.UndeclaredThrowableException
248     */

249    public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
250          throws Throwable JavaDoc
251    {
252       if(method.getDeclaringClass() == Object JavaDoc.class)
253       {
254          return handleObjectMethods(proxy, method, args);
255       }
256       if(method.getDeclaringClass() == LocationAware.class)
257       {
258          return handleLocationMethods(proxy, method, args);
259       }
260       try
261       {
262          String JavaDoc name = method.getName();
263          if(name.startsWith("get") && name.length() > 3 && (args == null || args.length <= 0))
264          {
265             // getter
266
// example: getListeningPoint "ListeningPoint"
267
String JavaDoc attributeName = method.getName().substring(3);
268             if(staticAttributes != null)
269             {
270                // check to see if we want a static attribute value to
271
// come from the local cache version, rather than from
272
// remote
273
if(staticAttributes.containsKey(attributeName))
274                {
275                   return staticAttributes.get(attributeName);
276                }
277             }
278             return locator.getMBeanServer().getAttribute(locator.getObjectName(), attributeName);
279          }
280          else if(name.startsWith("set") && name.length() > 3)
281          {
282             // setter
283
String JavaDoc attributeName = method.getName().substring(3);
284
285             // first transport remotely, to make sure that this doesn't fail ..
286
locator.getMBeanServer().setAttribute(locator.getObjectName(), new Attribute JavaDoc(attributeName, (args == null ? null : args[0])));
287
288             // if the transport succeeded and we need to update our local cache copy ..
289
if(staticAttributes != null)
290             {
291                // check to see if we want a static attribute value to
292
// come from the local cache version, rather than from
293
// remote, and if so, store it local as well as transport remotely
294
if(staticAttributes.containsKey(attributeName))
295                {
296                   return staticAttributes.put(attributeName, (args == null ? null : args[0]));
297                }
298             }
299             return null;
300          }
301          else
302          {
303             return locator.getMBeanServer().invoke(locator.getObjectName(), method.getName(), args, makeArgSignature(method, args));
304          }
305       }
306       catch(InstanceNotFoundException JavaDoc inf)
307       {
308          throw inf;
309       }
310       catch(MBeanException JavaDoc mbe)
311       {
312          throw mbe.getTargetException();
313       }
314       catch(ReflectionException JavaDoc re)
315       {
316          throw re.getTargetException();
317       }
318    }
319
320    protected Boolean JavaDoc proxyEquals(Object JavaDoc proxy, Object JavaDoc other)
321    {
322       return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
323    }
324
325    protected String JavaDoc proxyToString(Object JavaDoc proxy)
326    {
327       return (locator == null ? ("MoveableMBean [Proxy" + "@" + proxy.hashCode() + "]") : locator.toString());
328    }
329
330    protected Integer JavaDoc proxyHashCode(Object JavaDoc proxy)
331    {
332       return hashCode;
333    }
334
335    protected Object JavaDoc handleObjectMethods(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc args[])
336          throws Exception JavaDoc
337    {
338       if(method.equals(hashCodeMethod))
339       {
340          return proxyHashCode(proxy);
341       }
342       else if(method.equals(equalsMethod))
343       {
344          return proxyEquals(proxy, args[0]);
345       }
346       else if(method.equals(toStringMethod))
347       {
348          return proxyToString(proxy);
349       }
350       else if(method.equals(notifyAllMethod))
351       {
352          notifyAll();
353          return null;
354       }
355       else if(method.equals(notifyMethod))
356       {
357          notify();
358          return null;
359       }
360       else if(method.equals(wait0Method))
361       {
362          wait();
363          return null;
364       }
365       else if(method.equals(wait1Method))
366       {
367          wait(((Long JavaDoc) args[0]).longValue());
368          return null;
369       }
370       else if(method.equals(wait2Method))
371       {
372          wait(((Long JavaDoc) args[0]).longValue(), ((Integer JavaDoc) args[1]).intValue());
373          return null;
374       }
375
376       else
377       {
378          throw new InternalError JavaDoc("unexpected Object method dispatched: " + method);
379       }
380    }
381
382    /**
383     * convert the method to a String array for the signature of the MBean invocation
384     *
385     * @param method
386     * @param args
387     * @return
388     */

389    protected synchronized String JavaDoc[] makeArgSignature(Method JavaDoc method, Object JavaDoc args[])
390    {
391       if(methodArgs.containsKey(method))
392       {
393          return (String JavaDoc[]) methodArgs.get(method);
394       }
395       Class JavaDoc pt[] = method.getParameterTypes();
396       if(pt == null || pt.length <= 0)
397       {
398          return null;
399       }
400       String JavaDoc sig[] = new String JavaDoc[args.length];
401       for(int c = 0; c < pt.length; c++)
402       {
403          sig[c] = pt[c].getName();
404       }
405       methodArgs.put(method, sig);
406       return sig;
407    }
408
409    /**
410     * resolve the proxy interfaces
411     *
412     * @param interfaces
413     * @return
414     * @throws IOException
415     * @throws ClassNotFoundException
416     */

417    protected Class JavaDoc resolveProxyClass(String JavaDoc[] interfaces)
418          throws IOException JavaDoc, ClassNotFoundException JavaDoc
419    {
420       ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
421       if(cl == null)
422       {
423          cl = MoveableMBean.class.getClassLoader();
424       }
425       Class JavaDoc inf[] = new Class JavaDoc[interfaces.length];
426       for(int c = 0; c < interfaces.length; c++)
427       {
428          inf[c] = cl.loadClass(interfaces[c]);
429       }
430       return java.lang.reflect.Proxy.getProxyClass(cl, inf);
431    }
432
433 }
434
Popular Tags