KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > MBeanServerInvocationHandler


1 /*
2  * @(#)MBeanServerInvocationHandler.java 1.17 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.management;
9
10 import java.lang.reflect.InvocationHandler JavaDoc;
11 import java.lang.reflect.Method JavaDoc;
12 import java.lang.reflect.Proxy JavaDoc;
13
14 /**
15  * <p>{@link InvocationHandler} that forwards methods in an MBean's
16  * management interface through the MBean server to the MBean.</p>
17  *
18  * <p>Given an {@link MBeanServerConnection}, the {@link ObjectName}
19  * of an MBean within that MBean server, and a Java interface
20  * <code>Intf</code> that describes the management interface of the
21  * MBean using the patterns for a Standard MBean, this class can be
22  * used to construct a proxy for the MBean. The proxy implements
23  * the interface <code>Intf</code> such that all of its methods are
24  * forwarded through the MBean server to the MBean.</p>
25  *
26  * <p>If you have an MBean server <code>mbs</code> containing an MBean
27  * with {@link ObjectName} <code>name</code>, and if the MBean's
28  * management interface is described by the Java interface
29  * <code>Intf</code>, you can construct a proxy for the MBean like
30  * this:</p>
31  *
32  * <pre>
33  * Intf proxy = (Intf)
34  * MBeanServerInvocationHandler.{@link #newProxyInstance newProxyInstance}(mbs,
35  * name,
36  * Intf.class,
37  * false);
38  * </pre>
39  *
40  * <p>Suppose, for example, <code>Intf</code> looks like this:</p>
41  *
42  * <pre>
43  * public interface Intf {
44  * public String getSomeAttribute();
45  * public void setSomeAttribute(String value);
46  * public void someOperation(String param1, int param2);
47  * }
48  * </pre>
49  *
50  * <p>Then you can execute:</p>
51  *
52  * <ul>
53  *
54  * <li><code>proxy.getSomeAttribute()</code> which will result in a
55  * call to <code>mbs.</code>{@link MBeanServerConnection#getAttribute
56  * getAttribute}<code>(name, "SomeAttribute")</code>.
57  *
58  * <li><code>proxy.setSomeAttribute("whatever")</code> which will result
59  * in a call to <code>mbs.</code>{@link MBeanServerConnection#setAttribute
60  * setAttribute}<code>(name, new Attribute("SomeAttribute", "whatever"))</code>.
61  *
62  * <li><code>proxy.someOperation("param1", 2)</code> which will be
63  * translated into a call to <code>mbs.</code>{@link
64  * MBeanServerConnection#invoke invoke}<code>(name, "someOperation", &lt;etc&gt;)</code>.
65  *
66  * </ul>
67  *
68  * <p>If the last parameter to {@link #newProxyInstance
69  * newProxyInstance} is <code>true</code>, then the MBean is assumed
70  * to be a {@link NotificationBroadcaster} or {@link
71  * NotificationEmitter} and the returned proxy will implement {@link
72  * NotificationEmitter}. A call to {@link
73  * NotificationBroadcaster#addNotificationListener} on the proxy will
74  * result in a call to {@link
75  * MBeanServerConnection#addNotificationListener(ObjectName,
76  * NotificationListener, NotificationFilter, Object)}, and likewise
77  * for the other methods of {@link NotificationBroadcaster} and {@link
78  * NotificationEmitter}.</p>
79  *
80  * <p>The methods {@link Object#toString()}, {@link Object#hashCode()},
81  * and {@link Object#equals(Object)}, when invoked on a proxy using
82  * this invocation handler, are forwarded to the MBean server as
83  * methods on the proxied MBean. This will only work if the MBean
84  * declares those methods in its management interface.</p>
85  *
86  * @since 1.5
87  * @since.unbundled JMX 1.2
88  */

89 public class MBeanServerInvocationHandler implements InvocationHandler JavaDoc {
90     /**
91      * <p>Invocation handler that forwards methods through an MBean
92      * server. This constructor may be called instead of relying on
93      * {@link #newProxyInstance}, for instance if you need to supply a
94      * different {@link ClassLoader} to {@link
95      * Proxy#newProxyInstance Proxy.newProxyInstance}.</p>
96      *
97      * @param connection the MBean server connection through which all
98      * methods of a proxy using this handler will be forwarded.
99      *
100      * @param objectName the name of the MBean within the MBean server
101      * to which methods will be forwarded.
102      */

103     public MBeanServerInvocationHandler(MBeanServerConnection JavaDoc connection,
104                     ObjectName JavaDoc objectName) {
105     this.connection = connection;
106     this.objectName = objectName;
107     /* Could check here whether the MBean exists. */
108     }
109
110     /**
111      * <p>Return a proxy that implements the given interface by
112      * forwarding its methods through the given MBean server to the
113      * named MBean.</p>
114      *
115      * <p>This method is equivalent to {@link Proxy#newProxyInstance
116      * Proxy.newProxyInstance}<code>(interfaceClass.getClassLoader(),
117      * interfaces, handler)</code>. Here <code>handler</code> is the
118      * result of {@link #MBeanServerInvocationHandler new
119      * MBeanServerInvocationHandler(connection, objectName)}, and
120      * <code>interfaces</code> is an array that has one element if
121      * <code>notificationBroadcaster</code> is false and two if it is
122      * true. The first element of <code>interfaces</code> is
123      * <code>interfaceClass</code> and the second, if present, is
124      * <code>NotificationEmitter.class</code>.
125      *
126      * @param connection the MBean server to forward to.
127      * @param objectName the name of the MBean within
128      * <code>connection</code> to forward to.
129      * @param interfaceClass the management interface that the MBean
130      * exports, which will also be implemented by the returned proxy.
131      * @param notificationBroadcaster make the returned proxy
132      * implement {@link NotificationEmitter} by forwarding its methods
133      * via <code>connection</code>.
134      *
135      * @return the new proxy instance.
136      */

137     public static Object JavaDoc newProxyInstance(MBeanServerConnection JavaDoc connection,
138                       ObjectName JavaDoc objectName,
139                       Class JavaDoc interfaceClass,
140                       boolean notificationBroadcaster) {
141     final InvocationHandler JavaDoc handler =
142         new MBeanServerInvocationHandler JavaDoc(connection, objectName);
143     final Class JavaDoc[] interfaces;
144     if (notificationBroadcaster) {
145         interfaces =
146         new Class JavaDoc[] {interfaceClass, NotificationEmitter JavaDoc.class};
147     } else
148         interfaces = new Class JavaDoc[] {interfaceClass};
149     return Proxy.newProxyInstance(interfaceClass.getClassLoader(),
150                       interfaces,
151                       handler);
152     }
153
154     public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
155         throws Throwable JavaDoc {
156     final Class JavaDoc methodClass = method.getDeclaringClass();
157
158     if (methodClass.equals(NotificationBroadcaster JavaDoc.class)
159         || methodClass.equals(NotificationEmitter JavaDoc.class))
160         return invokeBroadcasterMethod(proxy, method, args);
161
162     final String JavaDoc methodName = method.getName();
163     final Class JavaDoc[] paramTypes = method.getParameterTypes();
164     final Class JavaDoc returnType = method.getReturnType();
165
166     /* Inexplicably, InvocationHandler specifies that args is null
167        when the method takes no arguments rather than a
168        zero-length array. */

169     final int nargs = (args == null) ? 0 : args.length;
170
171     if (methodName.startsWith("get")
172         && methodName.length() > 3
173         && nargs == 0
174         && !returnType.equals(Void.TYPE)) {
175         return connection.getAttribute(objectName,
176                        methodName.substring(3));
177     }
178
179     if (methodName.startsWith("is")
180         && methodName.length() > 2
181         && nargs == 0
182         && (returnType.equals(Boolean.TYPE)
183         || returnType.equals(Boolean JavaDoc.class))) {
184         return connection.getAttribute(objectName,
185                        methodName.substring(2));
186     }
187
188     if (methodName.startsWith("set")
189         && methodName.length() > 3
190         && nargs == 1
191         && returnType.equals(Void.TYPE)) {
192         Attribute JavaDoc attr = new Attribute JavaDoc(methodName.substring(3), args[0]);
193         connection.setAttribute(objectName, attr);
194         return null;
195     }
196
197     final String JavaDoc[] signature = new String JavaDoc[paramTypes.length];
198     for (int i = 0; i < paramTypes.length; i++)
199         signature[i] = paramTypes[i].getName();
200     try {
201         return connection.invoke(objectName, methodName, args, signature);
202     } catch (MBeanException JavaDoc e) {
203         throw e.getTargetException();
204     }
205     /* The invoke may fail because it can't get to the MBean, with
206        one of the these exceptions declared by
207        MBeanServerConnection.invoke:
208        - RemoteException: can't talk to MBeanServer;
209        - InstanceNotFoundException: objectName is not registered;
210        - ReflectionException: objectName is registered but does not
211          have the method being invoked.
212        In all of these cases, the exception will be wrapped by the
213        proxy mechanism in an UndeclaredThrowableException unless
214        it happens to be declared in the "throws" clause of the
215        method being invoked on the proxy.
216     */

217     }
218
219     private Object JavaDoc invokeBroadcasterMethod(Object JavaDoc proxy, Method JavaDoc method,
220                        Object JavaDoc[] args) throws Exception JavaDoc {
221     final String JavaDoc methodName = method.getName();
222     final int nargs = (args == null) ? 0 : args.length;
223
224     if (methodName.equals("addNotificationListener")) {
225         /* The various throws of IllegalArgumentException here
226            should not happen, since we know what the methods in
227            NotificationBroadcaster and NotificationEmitter
228            are. */

229         if (nargs != 3) {
230         final String JavaDoc msg =
231             "Bad arg count to addNotificationListener: " + nargs;
232         throw new IllegalArgumentException JavaDoc(msg);
233         }
234         /* Other inconsistencies will produce ClassCastException
235            below. */

236
237         NotificationListener JavaDoc listener = (NotificationListener JavaDoc) args[0];
238         NotificationFilter JavaDoc filter = (NotificationFilter JavaDoc) args[1];
239         Object JavaDoc handback = args[2];
240         connection.addNotificationListener(objectName,
241                            listener,
242                            filter,
243                            handback);
244         return null;
245
246     } else if (methodName.equals("removeNotificationListener")) {
247
248         /* NullPointerException if method with no args, but that
249            shouldn't happen because removeNL does have args. */

250         NotificationListener JavaDoc listener = (NotificationListener JavaDoc) args[0];
251
252         switch (nargs) {
253         case 1:
254         connection.removeNotificationListener(objectName, listener);
255         return null;
256
257         case 3:
258         NotificationFilter JavaDoc filter = (NotificationFilter JavaDoc) args[1];
259         Object JavaDoc handback = args[2];
260         connection.removeNotificationListener(objectName,
261                               listener,
262                               filter,
263                               handback);
264         return null;
265
266         default:
267         final String JavaDoc msg =
268             "Bad arg count to removeNotificationListener: " + nargs;
269         throw new IllegalArgumentException JavaDoc(msg);
270         }
271
272     } else if (methodName.equals("getNotificationInfo")) {
273
274         if (args != null) {
275         throw new IllegalArgumentException JavaDoc("getNotificationInfo has " +
276                            "args");
277         }
278
279         MBeanInfo JavaDoc info = connection.getMBeanInfo(objectName);
280         return info.getNotifications();
281
282     } else {
283         throw new IllegalArgumentException JavaDoc("Bad method name: " +
284                            methodName);
285     }
286     }
287
288     private final MBeanServerConnection JavaDoc connection;
289     private final ObjectName JavaDoc objectName;
290 }
291
Popular Tags