blob: d2bc522afa1af7fcbff68f22d07aeb054b5554cb [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.management;
27
28import com.sun.jmx.mbeanserver.Introspector;
29import java.lang.reflect.InvocationHandler;
30import java.lang.reflect.Proxy;
31
32/**
33 * Static methods from the JMX API. There are no instances of this class.
34 *
35 * @since 1.6
36 */
37public class JMX {
38 /* Code within this package can prove that by providing this instance of
39 * this class.
40 */
41 static final JMX proof = new JMX();
42
43 private JMX() {}
44
45 /**
46 * The name of the <a href="Descriptor.html#defaultValue">{@code
47 * defaultValue}</a> field.
48 */
49 public static final String DEFAULT_VALUE_FIELD = "defaultValue";
50
51 /**
52 * The name of the <a href="Descriptor.html#immutableInfo">{@code
53 * immutableInfo}</a> field.
54 */
55 public static final String IMMUTABLE_INFO_FIELD = "immutableInfo";
56
57 /**
58 * The name of the <a href="Descriptor.html#interfaceClassName">{@code
59 * interfaceClassName}</a> field.
60 */
61 public static final String INTERFACE_CLASS_NAME_FIELD = "interfaceClassName";
62
63 /**
64 * The name of the <a href="Descriptor.html#legalValues">{@code
65 * legalValues}</a> field.
66 */
67 public static final String LEGAL_VALUES_FIELD = "legalValues";
68
69 /**
70 * The name of the <a href="Descriptor.html#maxValue">{@code
71 * maxValue}</a> field.
72 */
73 public static final String MAX_VALUE_FIELD = "maxValue";
74
75 /**
76 * The name of the <a href="Descriptor.html#minValue">{@code
77 * minValue}</a> field.
78 */
79 public static final String MIN_VALUE_FIELD = "minValue";
80
81 /**
82 * The name of the <a href="Descriptor.html#mxbean">{@code
83 * mxbean}</a> field.
84 */
85 public static final String MXBEAN_FIELD = "mxbean";
86
87 /**
88 * The name of the <a href="Descriptor.html#openType">{@code
89 * openType}</a> field.
90 */
91 public static final String OPEN_TYPE_FIELD = "openType";
92
93 /**
94 * The name of the <a href="Descriptor.html#originalType">{@code
95 * originalType}</a> field.
96 */
97 public static final String ORIGINAL_TYPE_FIELD = "originalType";
98
99 /**
100 * <p>Make a proxy for a Standard MBean in a local or remote
101 * MBean Server.</p>
102 *
103 * <p>If you have an MBean Server {@code mbs} containing an MBean
104 * with {@link ObjectName} {@code name}, and if the MBean's
105 * management interface is described by the Java interface
106 * {@code MyMBean}, you can construct a proxy for the MBean like
107 * this:</p>
108 *
109 * <pre>
110 * MyMBean proxy = JMX.newMBeanProxy(mbs, name, MyMBean.class);
111 * </pre>
112 *
113 * <p>Suppose, for example, {@code MyMBean} looks like this:</p>
114 *
115 * <pre>
116 * public interface MyMBean {
117 * public String getSomeAttribute();
118 * public void setSomeAttribute(String value);
119 * public void someOperation(String param1, int param2);
120 * }
121 * </pre>
122 *
123 * <p>Then you can execute:</p>
124 *
125 * <ul>
126 *
127 * <li>{@code proxy.getSomeAttribute()} which will result in a
128 * call to {@code mbs.}{@link MBeanServerConnection#getAttribute
129 * getAttribute}{@code (name, "SomeAttribute")}.
130 *
131 * <li>{@code proxy.setSomeAttribute("whatever")} which will result
132 * in a call to {@code mbs.}{@link MBeanServerConnection#setAttribute
133 * setAttribute}{@code (name, new Attribute("SomeAttribute", "whatever"))}.
134 *
135 * <li>{@code proxy.someOperation("param1", 2)} which will be
136 * translated into a call to {@code mbs.}{@link
137 * MBeanServerConnection#invoke invoke}{@code (name, "someOperation", <etc>)}.
138 *
139 * </ul>
140 *
141 * <p>The object returned by this method is a
142 * {@link Proxy} whose {@code InvocationHandler} is an
143 * {@link MBeanServerInvocationHandler}.</p>
144 *
145 * <p>This method is equivalent to {@link
146 * #newMBeanProxy(MBeanServerConnection, ObjectName, Class,
147 * boolean) newMBeanProxy(connection, objectName, interfaceClass,
148 * false)}.</p>
149 *
150 * @param connection the MBean server to forward to.
151 * @param objectName the name of the MBean within
152 * {@code connection} to forward to.
153 * @param interfaceClass the management interface that the MBean
154 * exports, which will also be implemented by the returned proxy.
155 *
156 * @param <T> allows the compiler to know that if the {@code
157 * interfaceClass} parameter is {@code MyMBean.class}, for
158 * example, then the return type is {@code MyMBean}.
159 *
160 * @return the new proxy instance.
161 */
162 public static <T> T newMBeanProxy(MBeanServerConnection connection,
163 ObjectName objectName,
164 Class<T> interfaceClass) {
165 return newMBeanProxy(connection, objectName, interfaceClass, false);
166 }
167
168 /**
169 * <p>Make a proxy for a Standard MBean in a local or remote MBean
170 * Server that may also support the methods of {@link
171 * NotificationEmitter}.</p>
172 *
173 * <p>This method behaves the same as {@link
174 * #newMBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
175 * additionally, if {@code notificationBroadcaster} is {@code
176 * true}, then the MBean is assumed to be a {@link
177 * NotificationBroadcaster} or {@link NotificationEmitter} and the
178 * returned proxy will implement {@link NotificationEmitter} as
179 * well as {@code interfaceClass}. A call to {@link
180 * NotificationBroadcaster#addNotificationListener} on the proxy
181 * will result in a call to {@link
182 * MBeanServerConnection#addNotificationListener(ObjectName,
183 * NotificationListener, NotificationFilter, Object)}, and
184 * likewise for the other methods of {@link
185 * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
186 *
187 * @param connection the MBean server to forward to.
188 * @param objectName the name of the MBean within
189 * {@code connection} to forward to.
190 * @param interfaceClass the management interface that the MBean
191 * exports, which will also be implemented by the returned proxy.
192 * @param notificationBroadcaster make the returned proxy
193 * implement {@link NotificationEmitter} by forwarding its methods
194 * via {@code connection}.
195 *
196 * @param <T> allows the compiler to know that if the {@code
197 * interfaceClass} parameter is {@code MyMBean.class}, for
198 * example, then the return type is {@code MyMBean}.
199 *
200 * @return the new proxy instance.
201 */
202 public static <T> T newMBeanProxy(MBeanServerConnection connection,
203 ObjectName objectName,
204 Class<T> interfaceClass,
205 boolean notificationBroadcaster) {
206 return MBeanServerInvocationHandler.newProxyInstance(
207 connection,
208 objectName,
209 interfaceClass,
210 notificationBroadcaster);
211 }
212
213 /**
214 * <p>Make a proxy for an MXBean in a local or remote
215 * MBean Server.</p>
216 *
217 * <p>If you have an MBean Server {@code mbs} containing an
218 * MXBean with {@link ObjectName} {@code name}, and if the
219 * MXBean's management interface is described by the Java
220 * interface {@code MyMXBean}, you can construct a proxy for
221 * the MXBean like this:</p>
222 *
223 * <pre>
224 * MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);
225 * </pre>
226 *
227 * <p>Suppose, for example, {@code MyMXBean} looks like this:</p>
228 *
229 * <pre>
230 * public interface MyMXBean {
231 * public String getSimpleAttribute();
232 * public void setSimpleAttribute(String value);
233 * public {@link java.lang.management.MemoryUsage} getMappedAttribute();
234 * public void setMappedAttribute(MemoryUsage memoryUsage);
235 * public MemoryUsage someOperation(String param1, MemoryUsage param2);
236 * }
237 * </pre>
238 *
239 * <p>Then:</p>
240 *
241 * <ul>
242 *
243 * <li><p>{@code proxy.getSimpleAttribute()} will result in a
244 * call to {@code mbs.}{@link MBeanServerConnection#getAttribute
245 * getAttribute}{@code (name, "SimpleAttribute")}.</p>
246 *
247 * <li><p>{@code proxy.setSimpleAttribute("whatever")} will result
248 * in a call to {@code mbs.}{@link
249 * MBeanServerConnection#setAttribute setAttribute}<code>(name,
250 * new Attribute("SimpleAttribute", "whatever"))</code>.<p>
251 *
252 * <p>Because {@code String} is a <em>simple type</em>, in the
253 * sense of {@link javax.management.openmbean.SimpleType}, it
254 * is not changed in the context of an MXBean. The MXBean
255 * proxy behaves the same as a Standard MBean proxy (see
256 * {@link #newMBeanProxy(MBeanServerConnection, ObjectName,
257 * Class) newMBeanProxy}) for the attribute {@code
258 * SimpleAttribute}.</p>
259 *
260 * <li><p>{@code proxy.getMappedAttribute()} will result in a call
261 * to {@code mbs.getAttribute("MappedAttribute")}. The MXBean
262 * mapping rules mean that the actual type of the attribute {@code
263 * MappedAttribute} will be {@link
264 * javax.management.openmbean.CompositeData CompositeData} and
265 * that is what the {@code mbs.getAttribute} call will return.
266 * The proxy will then convert the {@code CompositeData} back into
267 * the expected type {@code MemoryUsage} using the MXBean mapping
268 * rules.</p>
269 *
270 * <li><p>Similarly, {@code proxy.setMappedAttribute(memoryUsage)}
271 * will convert the {@code MemoryUsage} argument into a {@code
272 * CompositeData} before calling {@code mbs.setAttribute}.</p>
273 *
274 * <li><p>{@code proxy.someOperation("whatever", memoryUsage)}
275 * will convert the {@code MemoryUsage} argument into a {@code
276 * CompositeData} and call {@code mbs.invoke}. The value returned
277 * by {@code mbs.invoke} will be also be a {@code CompositeData},
278 * and the proxy will convert this into the expected type {@code
279 * MemoryUsage} using the MXBean mapping rules.</p>
280 *
281 * </ul>
282 *
283 * <p>The object returned by this method is a
284 * {@link Proxy} whose {@code InvocationHandler} is an
285 * {@link MBeanServerInvocationHandler}.</p>
286 *
287 * <p>This method is equivalent to {@link
288 * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
289 * boolean) newMXBeanProxy(connection, objectName, interfaceClass,
290 * false)}.</p>
291 *
292 * @param connection the MBean server to forward to.
293 * @param objectName the name of the MBean within
294 * {@code connection} to forward to.
295 * @param interfaceClass the MXBean interface,
296 * which will also be implemented by the returned proxy.
297 *
298 * @param <T> allows the compiler to know that if the {@code
299 * interfaceClass} parameter is {@code MyMXBean.class}, for
300 * example, then the return type is {@code MyMXBean}.
301 *
302 * @return the new proxy instance.
303 */
304 public static <T> T newMXBeanProxy(MBeanServerConnection connection,
305 ObjectName objectName,
306 Class<T> interfaceClass) {
307 return newMXBeanProxy(connection, objectName, interfaceClass, false);
308 }
309
310 /**
311 * <p>Make a proxy for an MXBean in a local or remote MBean
312 * Server that may also support the methods of {@link
313 * NotificationEmitter}.</p>
314 *
315 * <p>This method behaves the same as {@link
316 * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
317 * additionally, if {@code notificationBroadcaster} is {@code
318 * true}, then the MXBean is assumed to be a {@link
319 * NotificationBroadcaster} or {@link NotificationEmitter} and the
320 * returned proxy will implement {@link NotificationEmitter} as
321 * well as {@code interfaceClass}. A call to {@link
322 * NotificationBroadcaster#addNotificationListener} on the proxy
323 * will result in a call to {@link
324 * MBeanServerConnection#addNotificationListener(ObjectName,
325 * NotificationListener, NotificationFilter, Object)}, and
326 * likewise for the other methods of {@link
327 * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
328 *
329 * @param connection the MBean server to forward to.
330 * @param objectName the name of the MBean within
331 * {@code connection} to forward to.
332 * @param interfaceClass the MXBean interface,
333 * which will also be implemented by the returned proxy.
334 * @param notificationBroadcaster make the returned proxy
335 * implement {@link NotificationEmitter} by forwarding its methods
336 * via {@code connection}.
337 *
338 * @param <T> allows the compiler to know that if the {@code
339 * interfaceClass} parameter is {@code MyMXBean.class}, for
340 * example, then the return type is {@code MyMXBean}.
341 *
342 * @return the new proxy instance.
343 */
344 public static <T> T newMXBeanProxy(MBeanServerConnection connection,
345 ObjectName objectName,
346 Class<T> interfaceClass,
347 boolean notificationBroadcaster) {
348 // Check interface for MXBean compliance
349 //
350 try {
351 Introspector.testComplianceMXBeanInterface(interfaceClass);
352 } catch (NotCompliantMBeanException e) {
353 throw new IllegalArgumentException(e);
354 }
355 InvocationHandler handler = new MBeanServerInvocationHandler(
356 connection, objectName, true);
357 final Class[] interfaces;
358 if (notificationBroadcaster) {
359 interfaces =
360 new Class<?>[] {interfaceClass, NotificationEmitter.class};
361 } else
362 interfaces = new Class[] {interfaceClass};
363 Object proxy = Proxy.newProxyInstance(
364 interfaceClass.getClassLoader(),
365 interfaces,
366 handler);
367 return interfaceClass.cast(proxy);
368 }
369
370 /**
371 * <p>Test whether an interface is an MXBean interface.
372 * An interface is an MXBean interface if it is annotated
373 * {@link MXBean &#64;MXBean} or {@code @MXBean(true)}
374 * or if it does not have an {@code @MXBean} annotation
375 * and its name ends with "{@code MXBean}".</p>
376 *
377 * @param interfaceClass The candidate interface.
378 *
379 * @return true if {@code interfaceClass} is an interface and
380 * meets the conditions described.
381 *
382 * @throws NullPointerException if {@code interfaceClass} is null.
383 */
384 public static boolean isMXBeanInterface(Class<?> interfaceClass) {
385 if (!interfaceClass.isInterface())
386 return false;
387 MXBean a = interfaceClass.getAnnotation(MXBean.class);
388 if (a != null)
389 return a.value();
390 return interfaceClass.getName().endsWith("MXBean");
391 // We don't bother excluding the case where the name is
392 // exactly the string "MXBean" since that would mean there
393 // was no package name, which is pretty unlikely in practice.
394 }
395}