001    /* JMX.java -- Static methods pertaining to the management API.
002       Copyright (C) 2007 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.management;
039    
040    import java.lang.reflect.Proxy;
041    
042    /**
043     * Common static methods pertaining to the management
044     * API.  There are no instances of this class.
045     *
046     * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
047     * @since 1.6
048     */
049    public class JMX
050    {
051    
052      /**
053       * The name of the defaultValue field.
054       */
055      public static final String DEFAULT_VALUE_FIELD = "defaultValue";
056    
057      /**
058       * The name of the immutableInfo field.
059       */
060      public static final String  IMMUTABLE_INFO_FIELD = "immutableInfo";
061    
062      /**
063       * The name of the interfaceClassName field.
064       */
065      public static final String  INTERFACE_CLASS_NAME_FIELD = "interfaceClassName";
066    
067      /**
068       * The name of the legalValues field.
069       */
070      public static final String  LEGAL_VALUES_FIELD = "legalValues";
071    
072      /**
073       * The name of the maxValue field.
074       */
075      public static final String  MAX_VALUE_FIELD = "maxValue";
076    
077      /**
078       * The name of the minValue field.
079       */
080      public static final String  MIN_VALUE_FIELD = "minValue";
081    
082      /**
083       * The name of the mxbean field.
084       */
085      public static final String  MXBEAN_FIELD = "mxbean";
086    
087      /**
088       * The name of the openType field.
089       */
090      public static final String  OPEN_TYPE_FIELD = "openType";
091    
092      /**
093       * The name of the originalType field.
094       */
095      public static final String  ORIGINAL_TYPE_FIELD = "originalType";
096    
097      /**
098       * Prevent instance creation.
099       */
100      private JMX()
101      {
102      }
103    
104      /**
105       * <p>
106       * Returns true if the given class represents an {@link MXBean}
107       * interface.  An interface is an {@link MXBean interface} if:
108       * </p>
109       * <ul>
110       * <li>It is annotated with {@code @MXBean} or
111       * {@code @MXBean(true)}</li>.
112       * <li>Its name ends in {@code "MXBean"} and it does not
113       * have an {@link MXBean} annotation.</li>
114       * </ul>
115       * 
116       * @param iface the interface class that is to be checked
117       *              for {@link MXBean} status.
118       * @return true if the interface represents an {@link MXBean}.
119       * @throws NullPointerException if {@code iface} is {@code null}.
120       */
121      public static boolean isMXBeanInterface(Class<?> iface)
122      {
123        MXBean annotation = iface.getAnnotation(MXBean.class);
124        if (annotation != null)
125          return annotation.value();
126        return iface.getName().endsWith("MXBean");
127      }
128    
129      /**
130       * <p>
131       * Returns a proxy for a standard management bean, using
132       * the specified connection to access the named implementation.
133       * To create a proxy for the bean, {@code SomethingMBean}, a call to
134       * {@code JMX.newMBeanProxy(server, name, SomethingMBean.class)}
135       * is made, where {@code server} is a local or remote management
136       * server, and {@code name} is the registered {@link ObjectName}
137       * of the implementation of {@code SomethingMBean} to use.
138       * </p>
139       * <p>
140       * The proxy redirects calls to the methods of the interface,
141       * {@link SomethingMBean}, to the appropriate methods of the
142       * management server.  If {@link SomethingMBean} is specified
143       * as follows:
144       * </p>
145       * <pre>
146       * public interface SomethingMBean
147       * {
148       *   String getName();
149       *   void setName(String name);
150       *   void doStuff();
151       * }
152       * </pre>
153       * <p>
154       * The proxy created above will provide these three methods
155       * using an instance of {@link MBeanServerInvocationHandler}.
156       * The two methods, {@code getName} and {@code setName} define
157       * an attribute, {@code Name}, so a call to {@code getName()}
158       * will return the value of {@code server.getAttribute(name,
159       * "Name")}, while {@code setName(newName)} will result in a
160       * call to {@code server.setAttribute(name, new Attribute("Name",
161       * newName))}.  Finally, {@code doStuff()}, as an operation,
162       * will cause the proxy to call {@link MBeanServer#invoke(ObjectName,
163       * String, Object[], String[])} as
164       * {@code server.invoke(name, "doStuff", null, null)}.
165       * </p>
166       * <p>
167       * Calling this method is equivalent to calling
168       * {@link #newMBeanProxy(MBeanServerConnection, ObjectName, Class,
169       * boolean)}.
170       * </p>
171       *
172       * @param conn the server connection over which to forward calls to
173       *             the bean.
174       * @param name the registered name of the bean to use to implement
175       *             the given interface.
176       * @param iface the interface to provide a proxy for.
177       * @return a proxy implementing the specified interface using calls
178       *         to the methods of the bean registered with the supplied
179       *         server using the given name.
180       * @see #newMBeanProxy(MBeanServerConnection, ObjectName, Class,
181       *      boolean)
182       */
183      public static <T> T newMBeanProxy(MBeanServerConnection conn,
184                                        ObjectName name, Class<T> iface)
185      {
186        return newMBeanProxy(conn, name, iface, false);
187      }
188    
189      /**
190       * Returns a proxy for a standard management bean, using
191       * the specified connection to access the named implementation,
192       * as with {@link #newMBeanProxy(MBeanServerConnection, ObjectName,
193       * Class)}.  In addition, the proxy returned by this method will
194       * also implement {@link NotificationEmitter} if {@code bcast} is
195       * true, under the assumption that the implementation referenced by
196       * {@code name} implements this interface.  Calls to the methods of
197       * {@link NotificationEmitter} will be forwarded to the bean
198       * implementation via the appropriate server methods.
199       *
200       * @param conn the server connection over which to forward calls to
201       *             the bean.
202       * @param name the registered name of the bean to use to implement
203       *             the given interface.
204       * @param iface the interface to provide a proxy for.
205       * @param bcast true if the proxy should implement
206       *              {@link NotificationEmitter}.
207       * @return a proxy implementing the specified interface using calls
208       *         to the methods of the bean registered with the supplied
209       *         server using the given name.
210       * @see #newMBeanProxy(MBeanServerConnection, ObjectName, Class)
211       */
212      public static <T> T newMBeanProxy(MBeanServerConnection conn,
213                                        ObjectName name, Class<T> iface,
214                                        boolean bcast)
215      {
216        return MBeanServerInvocationHandler.newProxyInstance(conn, name,
217                                                             iface, bcast);
218      }
219    
220      /**
221       * <p>
222       * Returns a proxy for a {@link MXBean}, using the specified
223       * connection to access the named implementation.
224       * To create a proxy for the bean, {@code SomethingMXBean}, a call to
225       * {@code JMX.newMXBeanProxy(server, name, SomethingMXBean.class)}
226       * is made, where {@code server} is a local or remote management
227       * server, and {@code name} is the registered {@link ObjectName}
228       * of the implementation of {@code SomethingMBean} to use.
229       * </p>
230       * <p>
231       * The proxy redirects calls to the methods of the interface,
232       * {@link SomethingMXBean}, to the appropriate methods of the
233       * management server with appropriate conversion between
234       * Java and open types, according to the MXBean rules.  If
235       * {@link SomethingMXBean} is specified as follows:
236       * </p>
237       * <pre>
238       * public interface SomethingMXBean
239       * {
240       *   String getName();
241       *   void setName(String name);
242       *   List<Double> getStatistics();
243       *   void setStatistics(List<Double> statistics);
244       *   List<Double> getNamedStatistics(String, Map<String,Integer>);
245       * }
246       * </pre>
247       * <p>
248       * The proxy created above will provide these five methods
249       * using an instance of {@link MBeanServerInvocationHandler}.
250       * The two methods, {@code getName} and {@code setName} define
251       * an attribute, {@code Name}, so a call to {@code getName()}
252       * will return the value of {@code server.getAttribute(name,
253       * "Name")}, while {@code setName(newName)} will result in a
254       * call to {@code server.setAttribute(name, new Attribute("Name",
255       * newName))}.  As this uses a simple type, {@link String}, no
256       * conversion is necessary.
257       * </p>
258       * <p>
259       * The two methods, {@code getStatistics} and {@code setStatistics}
260       * similarly define another attribute, {@code Statistics}.  Calling
261       * {@code getStatistics()} will cause a call to the server to be
262       * made as before, {@code server.getAttribute(name, "Statistics")}.
263       * However, the type of the return value from this call will be
264       * an array of {@link Double} objects, as per the {@link MXBean}
265       * rules.  The proxy converts this back in to a {@link java.util.List}
266       * of {@link Double} objects before returning it.
267       * </p>
268       * <p>
269       * The same process is applied in reverse for
270       * {@code setStatistics(newStats)}.  The list is converted into
271       * an appropriate array before the call to
272       * {@link MBeanServerConnection#setAttribute(ObjectName, Attribute)}
273       * is made.  Finally, a call to {@code getNamedStatistics} will require
274       * both a Java to open type conversion on the arguments, and then
275       * an open type to Java conversion of the return value.  Thus, a proxy
276       * enables an {@link MXBean} to be used in cases where the appropriate
277       * Java types are available and the user wishes to access the bean
278       * using the types directly defined in its interface, just as with
279       * standard management beans.
280       * </p>
281       * <p>
282       * Calling this method is equivalent to calling
283       * {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
284       * boolean)}.
285       * </p>
286       *
287       * @param conn the server connection over which to forward calls to
288       *             the bean.
289       * @param name the registered name of the bean to use to implement
290       *             the given interface.
291       * @param iface the interface to provide a proxy for.
292       * @return a proxy implementing the specified interface using calls
293       *         to the methods of the bean registered with the supplied
294       *         server using the given name.
295       * @see #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
296       *      boolean)
297       */
298      public static <T> T newMXBeanProxy(MBeanServerConnection conn,
299                                         ObjectName name, Class<T> iface)
300      {
301        return newMXBeanProxy(conn, name, iface, false);
302      }
303    
304      /**
305       * Returns a proxy for a {@link MXBean}, using
306       * the specified connection to access the named implementation,
307       * as with {@link #newMXBeanProxy(MBeanServerConnection, ObjectName,
308       * Class)}.  In addition, the proxy returned by this method will
309       * also implement {@link NotificationEmitter} if {@code bcast} is
310       * true, under the assumption that the implementation referenced by
311       * {@code name} implements this interface.  Calls to the methods of
312       * {@link NotificationEmitter} will be forwarded to the bean
313       * implementation via the appropriate server methods.
314       *
315       * @param conn the server connection over which to forward calls to
316       *             the bean.
317       * @param name the registered name of the bean to use to implement
318       *             the given interface.
319       * @param iface the interface to provide a proxy for.
320       * @param bcast true if the proxy should implement
321       *              {@link NotificationEmitter}.
322       * @return a proxy implementing the specified interface using calls
323       *         to the methods of the bean registered with the supplied
324       *         server using the given name.
325       * @see #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)
326       */
327      public static <T> T newMXBeanProxy(MBeanServerConnection conn,
328                                        ObjectName name, Class<T> iface,
329                                        boolean bcast)
330      {
331        if (bcast)
332          return (T) Proxy.newProxyInstance(iface.getClassLoader(),
333                                            new Class[] { iface,
334                                                          NotificationEmitter.class },
335                                            new MBeanServerInvocationHandler(conn,name,true));
336        else
337          return (T) Proxy.newProxyInstance(iface.getClassLoader(),
338                                            new Class[] { iface },
339                                            new MBeanServerInvocationHandler(conn,name,true));
340      }
341    
342    }