1 /*
2  * Copyright (c) 2005, 2015, 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 }
316