History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/management/NotificationBroadcasterSupport.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/management/NotificationBroadcasterSupport.java+354−0
@@ -0,0 +1,354 @@
1+/*
2+ * Copyright (c) 1999, 2007, 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+import java.util.Collections;
29+import java.util.List;
30+import java.util.concurrent.CopyOnWriteArrayList;
31+import java.util.concurrent.Executor;
32+
33+import com.sun.jmx.remote.util.ClassLogger;
34+
35+/**
36+ * <p>Provides an implementation of {@link
37+ * javax.management.NotificationEmitter NotificationEmitter}
38+ * interface. This can be used as the super class of an MBean that
39+ * sends notifications.</p>
40+ *
41+ * <p>By default, the notification dispatch model is synchronous.
42+ * That is, when a thread calls sendNotification, the
43+ * <code>NotificationListener.handleNotification</code> method of each listener
44+ * is called within that thread. You can override this default
45+ * by overriding <code>handleNotification</code> in a subclass, or by passing an
46+ * Executor to the constructor.</p>
47+ *
48+ * <p>If the method call of a filter or listener throws an {@link Exception},
49+ * then that exception does not prevent other listeners from being invoked. However,
50+ * if the method call of a filter or of {@code Executor.execute} or of
51+ * {@code handleNotification} (when no {@code Excecutor} is specified) throws an
52+ * {@link Error}, then that {@code Error} is propagated to the caller of
53+ * {@link #sendNotification sendNotification}.</p>
54+ *
55+ * <p>Remote listeners added using the JMX Remote API (see JMXConnector) are not
56+ * usually called synchronously. That is, when sendNotification returns, it is
57+ * not guaranteed that any remote listeners have yet received the notification.</p>
58+ *
59+ * @since 1.5
60+ */
61+public class NotificationBroadcasterSupport implements NotificationEmitter {
62+ /**
63+ * Constructs a NotificationBroadcasterSupport where each listener is invoked by the
64+ * thread sending the notification. This constructor is equivalent to
65+ * {@link NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
66+ * MBeanNotificationInfo[] info) NotificationBroadcasterSupport(null, null)}.
67+ */
68+ public NotificationBroadcasterSupport() {
69+ this(null, (MBeanNotificationInfo[]) null);
70+ }
71+
72+ /**
73+ * Constructs a NotificationBroadcasterSupport where each listener is invoked using
74+ * the given {@link java.util.concurrent.Executor}. When {@link #sendNotification
75+ * sendNotification} is called, a listener is selected if it was added with a null
76+ * {@link NotificationFilter}, or if {@link NotificationFilter#isNotificationEnabled
77+ * isNotificationEnabled} returns true for the notification being sent. The call to
78+ * <code>NotificationFilter.isNotificationEnabled</code> takes place in the thread
79+ * that called <code>sendNotification</code>. Then, for each selected listener,
80+ * {@link Executor#execute executor.execute} is called with a command
81+ * that calls the <code>handleNotification</code> method.
82+ * This constructor is equivalent to
83+ * {@link NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
84+ * MBeanNotificationInfo[] info) NotificationBroadcasterSupport(executor, null)}.
85+ * @param executor an executor used by the method <code>sendNotification</code> to
86+ * send each notification. If it is null, the thread calling <code>sendNotification</code>
87+ * will invoke the <code>handleNotification</code> method itself.
88+ * @since 1.6
89+ */
90+ public NotificationBroadcasterSupport(Executor executor) {
91+ this(executor, (MBeanNotificationInfo[]) null);
92+ }
93+
94+ /**
95+ * <p>Constructs a NotificationBroadcasterSupport with information
96+ * about the notifications that may be sent. Each listener is
97+ * invoked by the thread sending the notification. This
98+ * constructor is equivalent to {@link
99+ * NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
100+ * MBeanNotificationInfo[] info)
101+ * NotificationBroadcasterSupport(null, info)}.</p>
102+ *
103+ * <p>If the <code>info</code> array is not empty, then it is
104+ * cloned by the constructor as if by {@code info.clone()}, and
105+ * each call to {@link #getNotificationInfo()} returns a new
106+ * clone.</p>
107+ *
108+ * @param info an array indicating, for each notification this
109+ * MBean may send, the name of the Java class of the notification
110+ * and the notification type. Can be null, which is equivalent to
111+ * an empty array.
112+ *
113+ * @since 1.6
114+ */
115+ public NotificationBroadcasterSupport(MBeanNotificationInfo... info) {
116+ this(null, info);
117+ }
118+
119+ /**
120+ * <p>Constructs a NotificationBroadcasterSupport with information about the notifications that may be sent,
121+ * and where each listener is invoked using the given {@link java.util.concurrent.Executor}.</p>
122+ *
123+ * <p>When {@link #sendNotification sendNotification} is called, a
124+ * listener is selected if it was added with a null {@link
125+ * NotificationFilter}, or if {@link
126+ * NotificationFilter#isNotificationEnabled isNotificationEnabled}
127+ * returns true for the notification being sent. The call to
128+ * <code>NotificationFilter.isNotificationEnabled</code> takes
129+ * place in the thread that called
130+ * <code>sendNotification</code>. Then, for each selected
131+ * listener, {@link Executor#execute executor.execute} is called
132+ * with a command that calls the <code>handleNotification</code>
133+ * method.</p>
134+ *
135+ * <p>If the <code>info</code> array is not empty, then it is
136+ * cloned by the constructor as if by {@code info.clone()}, and
137+ * each call to {@link #getNotificationInfo()} returns a new
138+ * clone.</p>
139+ *
140+ * @param executor an executor used by the method
141+ * <code>sendNotification</code> to send each notification. If it
142+ * is null, the thread calling <code>sendNotification</code> will
143+ * invoke the <code>handleNotification</code> method itself.
144+ *
145+ * @param info an array indicating, for each notification this
146+ * MBean may send, the name of the Java class of the notification
147+ * and the notification type. Can be null, which is equivalent to
148+ * an empty array.
149+ *
150+ * @since 1.6
151+ */
152+ public NotificationBroadcasterSupport(Executor executor,
153+ MBeanNotificationInfo... info) {
154+ this.executor = (executor != null) ? executor : defaultExecutor;
155+
156+ notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();
157+ }
158+
159+ /**
160+ * Adds a listener.
161+ *
162+ * @param listener The listener to receive notifications.
163+ * @param filter The filter object. If filter is null, no
164+ * filtering will be performed before handling notifications.
165+ * @param handback An opaque object to be sent back to the
166+ * listener when a notification is emitted. This object cannot be
167+ * used by the Notification broadcaster object. It should be
168+ * resent unchanged with the notification to the listener.
169+ *
170+ * @exception IllegalArgumentException thrown if the listener is null.
171+ *
172+ * @see #removeNotificationListener
173+ */
174+ public void addNotificationListener(NotificationListener listener,
175+ NotificationFilter filter,
176+ Object handback) {
177+
178+ if (listener == null) {
179+ throw new IllegalArgumentException ("Listener can't be null") ;
180+ }
181+
182+ listenerList.add(new ListenerInfo(listener, filter, handback));
183+ }
184+
185+ public void removeNotificationListener(NotificationListener listener)
186+ throws ListenerNotFoundException {
187+
188+ ListenerInfo wildcard = new WildcardListenerInfo(listener);
189+ boolean removed =
190+ listenerList.removeAll(Collections.singleton(wildcard));
191+ if (!removed)
192+ throw new ListenerNotFoundException("Listener not registered");
193+ }
194+
195+ public void removeNotificationListener(NotificationListener listener,
196+ NotificationFilter filter,
197+ Object handback)
198+ throws ListenerNotFoundException {
199+
200+ ListenerInfo li = new ListenerInfo(listener, filter, handback);
201+ boolean removed = listenerList.remove(li);
202+ if (!removed) {
203+ throw new ListenerNotFoundException("Listener not registered " +
204+ "(with this filter and " +
205+ "handback)");
206+ // or perhaps not registered at all
207+ }
208+ }
209+
210+ public MBeanNotificationInfo[] getNotificationInfo() {
211+ if (notifInfo.length == 0)
212+ return notifInfo;
213+ else
214+ return notifInfo.clone();
215+ }
216+
217+
218+ /**
219+ * Sends a notification.
220+ *
221+ * If an {@code Executor} was specified in the constructor, it will be given one
222+ * task per selected listener to deliver the notification to that listener.
223+ *
224+ * @param notification The notification to send.
225+ */
226+ public void sendNotification(Notification notification) {
227+
228+ if (notification == null) {
229+ return;
230+ }
231+
232+ boolean enabled;
233+
234+ for (ListenerInfo li : listenerList) {
235+ try {
236+ enabled = li.filter == null ||
237+ li.filter.isNotificationEnabled(notification);
238+ } catch (Exception e) {
239+ if (logger.debugOn()) {
240+ logger.debug("sendNotification", e);
241+ }
242+
243+ continue;
244+ }
245+
246+ if (enabled) {
247+ executor.execute(new SendNotifJob(notification, li));
248+ }
249+ }
250+ }
251+
252+ /**
253+ * <p>This method is called by {@link #sendNotification
254+ * sendNotification} for each listener in order to send the
255+ * notification to that listener. It can be overridden in
256+ * subclasses to change the behavior of notification delivery,
257+ * for instance to deliver the notification in a separate
258+ * thread.</p>
259+ *
260+ * <p>The default implementation of this method is equivalent to
261+ * <pre>
262+ * listener.handleNotification(notif, handback);
263+ * </pre>
264+ *
265+ * @param listener the listener to which the notification is being
266+ * delivered.
267+ * @param notif the notification being delivered to the listener.
268+ * @param handback the handback object that was supplied when the
269+ * listener was added.
270+ *
271+ */
272+ protected void handleNotification(NotificationListener listener,
273+ Notification notif, Object handback) {
274+ listener.handleNotification(notif, handback);
275+ }
276+
277+ // private stuff
278+ private static class ListenerInfo {
279+ NotificationListener listener;
280+ NotificationFilter filter;
281+ Object handback;
282+
283+ ListenerInfo(NotificationListener listener,
284+ NotificationFilter filter,
285+ Object handback) {
286+ this.listener = listener;
287+ this.filter = filter;
288+ this.handback = handback;
289+ }
290+
291+ public boolean equals(Object o) {
292+ if (!(o instanceof ListenerInfo))
293+ return false;
294+ ListenerInfo li = (ListenerInfo) o;
295+ if (li instanceof WildcardListenerInfo)
296+ return (li.listener == listener);
297+ else
298+ return (li.listener == listener && li.filter == filter
299+ && li.handback == handback);
300+ }
301+ }
302+
303+ private static class WildcardListenerInfo extends ListenerInfo {
304+ WildcardListenerInfo(NotificationListener listener) {
305+ super(listener, null, null);
306+ }
307+
308+ public boolean equals(Object o) {
309+ assert (!(o instanceof WildcardListenerInfo));
310+ return o.equals(this);
311+ }
312+ }
313+
314+ private List<ListenerInfo> listenerList =
315+ new CopyOnWriteArrayList<ListenerInfo>();
316+
317+ // since 1.6
318+ private final Executor executor;
319+ private final MBeanNotificationInfo[] notifInfo;
320+
321+ private final static Executor defaultExecutor = new Executor() {
322+ // DirectExecutor using caller thread
323+ public void execute(Runnable r) {
324+ r.run();
325+ }
326+ };
327+
328+ private static final MBeanNotificationInfo[] NO_NOTIFICATION_INFO =
329+ new MBeanNotificationInfo[0];
330+
331+ private class SendNotifJob implements Runnable {
332+ public SendNotifJob(Notification notif, ListenerInfo listenerInfo) {
333+ this.notif = notif;
334+ this.listenerInfo = listenerInfo;
335+ }
336+
337+ public void run() {
338+ try {
339+ handleNotification(listenerInfo.listener,
340+ notif, listenerInfo.handback);
341+ } catch (Exception e) {
342+ if (logger.debugOn()) {
343+ logger.debug("SendNotifJob-run", e);
344+ }
345+ }
346+ }
347+
348+ private final Notification notif;
349+ private final ListenerInfo listenerInfo;
350+ }
351+
352+ private static final ClassLogger logger =
353+ new ClassLogger("javax.management", "NotificationBroadcasterSupport");
354+}