1 /*
   2  * Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.management;
  27 
  28 /**
  29  * <p>An MBean whose management interface is determined by reflection
  30  * on a Java interface, and that emits notifications.</p>
  31  *
  32  * <p>The following example shows how to use the public constructor
  33  * {@link #StandardEmitterMBean(Object, Class, NotificationEmitter)
  34  * StandardEmitterMBean(implementation, mbeanInterface, emitter)} to
  35  * create an MBean emitting notifications with any
  36  * implementation class name <i>Impl</i>, with a management
  37  * interface defined (as for current Standard MBeans) by any interface
  38  * <i>Intf</i>, and with any implementation of the interface
  39  * {@link NotificationEmitter}. The example uses the class
  40  * {@link NotificationBroadcasterSupport} as an implementation
  41  * of the interface {@link NotificationEmitter}.</p>
  42  *
  43  *     <pre>
  44  *     MBeanServer mbs;
  45  *     ...
  46  *     final String[] types = new String[] {"sun.disc.space","sun.disc.alarm"};
  47  *     final MBeanNotificationInfo info = new MBeanNotificationInfo(
  48  *                                          types,
  49  *                                          Notification.class.getName(),
  50  *                                          "Notification about disc info.");
  51  *     final NotificationEmitter emitter =
  52  *                    new NotificationBroadcasterSupport(info);
  53  *
  54  *     final Intf impl = new Impl(...);
  55  *     final Object mbean = new StandardEmitterMBean(
  56  *                                     impl, Intf.class, emitter);
  57  *     mbs.registerMBean(mbean, objectName);
  58  *     </pre>
  59  *
  60  * @see StandardMBean
  61  *
  62  * @since 1.6
  63  */
  64 public class StandardEmitterMBean extends StandardMBean
  65         implements NotificationEmitter {
  66 
  67     private static final MBeanNotificationInfo[] NO_NOTIFICATION_INFO =
  68         new MBeanNotificationInfo[0];
  69 
  70     private final NotificationEmitter emitter;
  71     private final MBeanNotificationInfo[] notificationInfo;
  72 
  73     /**
  74      * <p>Make an MBean whose management interface is specified by
  75      * {@code mbeanInterface}, with the given implementation and
  76      * where notifications are handled by the given {@code NotificationEmitter}.
  77      * The resultant MBean implements the {@code NotificationEmitter} interface
  78      * by forwarding its methods to {@code emitter}.  It is legal and useful
  79      * for {@code implementation} and {@code emitter} to be the same object.</p>
  80      *
  81      * <p>If {@code emitter} is an instance of {@code
  82      * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
  83      * sendNotification} method will call {@code emitter.}{@link
  84      * NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
  85      *
  86      * <p>The array returned by {@link #getNotificationInfo()} on the
  87      * new MBean is a copy of the array returned by
  88      * {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo
  89      * getNotificationInfo()} at the time of construction.  If the array
  90      * returned by {@code emitter.getNotificationInfo()} later changes,
  91      * that will have no effect on this object's
  92      * {@code getNotificationInfo()}.</p>
  93      *
  94      * @param <T> the implementation type of the MBean
  95      * @param implementation the implementation of the MBean interface.
  96      * @param mbeanInterface a Standard MBean interface.
  97      * @param emitter the object that will handle notifications.
  98      *
  99      * @throws IllegalArgumentException if the {@code mbeanInterface}
 100      *    does not follow JMX design patterns for Management Interfaces, or
 101      *    if the given {@code implementation} does not implement the
 102      *    specified interface, or if {@code emitter} is null.
 103      */
 104     public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface,
 105                                     NotificationEmitter emitter) {
 106         this(implementation, mbeanInterface, false, emitter);
 107     }
 108 
 109     /**
 110      * <p>Make an MBean whose management interface is specified by
 111      * {@code mbeanInterface}, with the given implementation and where
 112      * notifications are handled by the given {@code
 113      * NotificationEmitter}.  This constructor can be used to make
 114      * either Standard MBeans or MXBeans.  The resultant MBean
 115      * implements the {@code NotificationEmitter} interface by
 116      * forwarding its methods to {@code emitter}.  It is legal and
 117      * useful for {@code implementation} and {@code emitter} to be the
 118      * same object.</p>
 119      *
 120      * <p>If {@code emitter} is an instance of {@code
 121      * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
 122      * sendNotification} method will call {@code emitter.}{@link
 123      * NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
 124      *
 125      * <p>The array returned by {@link #getNotificationInfo()} on the
 126      * new MBean is a copy of the array returned by
 127      * {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo
 128      * getNotificationInfo()} at the time of construction.  If the array
 129      * returned by {@code emitter.getNotificationInfo()} later changes,
 130      * that will have no effect on this object's
 131      * {@code getNotificationInfo()}.</p>
 132      *
 133      * @param <T> the implementation type of the MBean
 134      * @param implementation the implementation of the MBean interface.
 135      * @param mbeanInterface a Standard MBean interface.
 136      * @param isMXBean If true, the {@code mbeanInterface} parameter
 137      * names an MXBean interface and the resultant MBean is an MXBean.
 138      * @param emitter the object that will handle notifications.
 139      *
 140      * @throws IllegalArgumentException if the {@code mbeanInterface}
 141      *    does not follow JMX design patterns for Management Interfaces, or
 142      *    if the given {@code implementation} does not implement the
 143      *    specified interface, or if {@code emitter} is null.
 144      */
 145     public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface,
 146                                     boolean isMXBean,
 147                                     NotificationEmitter emitter) {
 148         super(implementation, mbeanInterface, isMXBean);
 149         if (emitter == null)
 150             throw new IllegalArgumentException("Null emitter");
 151         this.emitter = emitter;
 152         MBeanNotificationInfo[] infos = emitter.getNotificationInfo();
 153         if (infos == null || infos.length == 0) {
 154             this.notificationInfo = NO_NOTIFICATION_INFO;
 155         } else {
 156             this.notificationInfo = infos.clone();
 157         }
 158     }
 159 
 160     /**
 161      * <p>Make an MBean whose management interface is specified by
 162      * {@code mbeanInterface}, and
 163      * where notifications are handled by the given {@code NotificationEmitter}.
 164      * The resultant MBean implements the {@code NotificationEmitter} interface
 165      * by forwarding its methods to {@code emitter}.</p>
 166      *
 167      * <p>If {@code emitter} is an instance of {@code
 168      * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
 169      * sendNotification} method will call {@code emitter.}{@link
 170      * NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
 171      *
 172      * <p>The array returned by {@link #getNotificationInfo()} on the
 173      * new MBean is a copy of the array returned by
 174      * {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo
 175      * getNotificationInfo()} at the time of construction.  If the array
 176      * returned by {@code emitter.getNotificationInfo()} later changes,
 177      * that will have no effect on this object's
 178      * {@code getNotificationInfo()}.</p>
 179      *
 180      * <p>This constructor must be called from a subclass that implements
 181      * the given {@code mbeanInterface}.</p>
 182      *
 183      * @param mbeanInterface a StandardMBean interface.
 184      * @param emitter the object that will handle notifications.
 185      *
 186      * @throws IllegalArgumentException if the {@code mbeanInterface}
 187      *    does not follow JMX design patterns for Management Interfaces, or
 188      *    if {@code this} does not implement the specified interface, or
 189      *    if {@code emitter} is null.
 190      */
 191     protected StandardEmitterMBean(Class<?> mbeanInterface,
 192                                    NotificationEmitter emitter) {
 193         this(mbeanInterface, false, emitter);
 194     }
 195 
 196     /**
 197      * <p>Make an MBean whose management interface is specified by
 198      * {@code mbeanInterface}, and where notifications are handled by
 199      * the given {@code NotificationEmitter}.  This constructor can be
 200      * used to make either Standard MBeans or MXBeans.  The resultant
 201      * MBean implements the {@code NotificationEmitter} interface by
 202      * forwarding its methods to {@code emitter}.</p>
 203      *
 204      * <p>If {@code emitter} is an instance of {@code
 205      * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
 206      * sendNotification} method will call {@code emitter.}{@link
 207      * NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
 208      *
 209      * <p>The array returned by {@link #getNotificationInfo()} on the
 210      * new MBean is a copy of the array returned by
 211      * {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo
 212      * getNotificationInfo()} at the time of construction.  If the array
 213      * returned by {@code emitter.getNotificationInfo()} later changes,
 214      * that will have no effect on this object's
 215      * {@code getNotificationInfo()}.</p>
 216      *
 217      * <p>This constructor must be called from a subclass that implements
 218      * the given {@code mbeanInterface}.</p>
 219      *
 220      * @param mbeanInterface a StandardMBean interface.
 221      * @param isMXBean If true, the {@code mbeanInterface} parameter
 222      * names an MXBean interface and the resultant MBean is an MXBean.
 223      * @param emitter the object that will handle notifications.
 224      *
 225      * @throws IllegalArgumentException if the {@code mbeanInterface}
 226      *    does not follow JMX design patterns for Management Interfaces, or
 227      *    if {@code this} does not implement the specified interface, or
 228      *    if {@code emitter} is null.
 229      */
 230     protected StandardEmitterMBean(Class<?> mbeanInterface, boolean isMXBean,
 231                                    NotificationEmitter emitter) {
 232         super(mbeanInterface, isMXBean);
 233         if (emitter == null)
 234             throw new IllegalArgumentException("Null emitter");
 235         this.emitter = emitter;
 236         MBeanNotificationInfo[] infos = emitter.getNotificationInfo();
 237         if (infos == null || infos.length == 0) {
 238             this.notificationInfo = NO_NOTIFICATION_INFO;
 239         } else {
 240             this.notificationInfo = infos.clone();
 241         }
 242     }
 243 
 244     public void removeNotificationListener(NotificationListener listener)
 245             throws ListenerNotFoundException {
 246         emitter.removeNotificationListener(listener);
 247     }
 248 
 249     public void removeNotificationListener(NotificationListener listener,
 250                                            NotificationFilter filter,
 251                                            Object handback)
 252             throws ListenerNotFoundException {
 253         emitter.removeNotificationListener(listener, filter, handback);
 254     }
 255 
 256     public void addNotificationListener(NotificationListener listener,
 257                                         NotificationFilter filter,
 258                                         Object handback) {
 259         emitter.addNotificationListener(listener, filter, handback);
 260     }
 261 
 262     public MBeanNotificationInfo[] getNotificationInfo() {
 263         // this getter might get called from the super constructor
 264         // when the notificationInfo has not been properly set yet
 265         if (notificationInfo == null) {
 266             return NO_NOTIFICATION_INFO;
 267         }
 268         if (notificationInfo.length == 0) {
 269             return notificationInfo;
 270         } else {
 271             return notificationInfo.clone();
 272         }
 273     }
 274 
 275     /**
 276      * <p>Sends a notification.</p>
 277      *
 278      * <p>If the {@code emitter} parameter to the constructor was an
 279      * instance of {@code NotificationBroadcasterSupport} then this
 280      * method will call {@code emitter.}{@link
 281      * NotificationBroadcasterSupport#sendNotification
 282      * sendNotification}.</p>
 283      *
 284      * @param n the notification to send.
 285      *
 286      * @throws ClassCastException if the {@code emitter} parameter to the
 287      * constructor was not a {@code NotificationBroadcasterSupport}.
 288      */
 289     public void sendNotification(Notification n) {
 290         if (emitter instanceof NotificationBroadcasterSupport)
 291             ((NotificationBroadcasterSupport) emitter).sendNotification(n);
 292         else {
 293             final String msg =
 294                 "Cannot sendNotification when emitter is not an " +
 295                 "instance of NotificationBroadcasterSupport: " +
 296                 emitter.getClass().getName();
 297             throw new ClassCastException(msg);
 298         }
 299     }
 300 
 301     /**
 302      * <p>Get the MBeanNotificationInfo[] that will be used in the
 303      * MBeanInfo returned by this MBean.</p>
 304      *
 305      * <p>The default implementation of this method returns
 306      * {@link #getNotificationInfo()}.</p>
 307      *
 308      * @param info The default MBeanInfo derived by reflection.
 309      * @return the MBeanNotificationInfo[] for the new MBeanInfo.
 310      */
 311     @Override
 312     MBeanNotificationInfo[] getNotifications(MBeanInfo info) {
 313         return getNotificationInfo();
 314     }
 315 }