001/* JMX.java -- Static methods pertaining to the management API.
002   Copyright (C) 2007 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package javax.management;
039
040import 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 */
049public 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  // Suppress warnings as we know an instance of T will be returned.
328  @SuppressWarnings("unchecked")
329  public static <T> T newMXBeanProxy(MBeanServerConnection conn,
330                                    ObjectName name, Class<T> iface,
331                                    boolean bcast)
332  {
333    if (bcast)
334      return (T) Proxy.newProxyInstance(iface.getClassLoader(),
335                                        new Class[] { iface,
336                                                      NotificationEmitter.class },
337                                        new MBeanServerInvocationHandler(conn,name,true));
338    else
339      return (T) Proxy.newProxyInstance(iface.getClassLoader(),
340                                        new Class[] { iface },
341                                        new MBeanServerInvocationHandler(conn,name,true));
342  }
343
344}