001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.org
004: * Distributable under GNU LGPL license
005: * See the GNU Lesser General Public License for more details.
006: */
007:
008: package javax.management;
009:
010: import java.util.ArrayList;
011: import java.util.List;
012: import java.util.Iterator;
013:
014: /**
015: * <p>Provides an implementation of {@link
016: * javax.management.NotificationEmitter NotificationEmitter}
017: * interface. This can be used as the super class of an MBean that
018: * sends notifications.</p>
019: *
020: * <p>It is not specified whether the notification dispatch model is
021: * synchronous or asynchronous. That is, when a thread calls {@link
022: * #sendNotification sendNotification}, the {@link
023: * NotificationListener#handleNotification
024: * NotificationListener.handleNotification} method of each listener
025: * may be called within that thread (a synchronous model) or within
026: * some other thread (an asynchronous model).</p>
027: *
028: * <p>Applications should not depend on notification dispatch being
029: * synchronous or being asynchronous. Thus:</p>
030: *
031: * <ul>
032: *
033: * <li>Applications should not assume a synchronous model. When the
034: * {@link #sendNotification sendNotification} method returns, it is
035: * not guaranteed that every listener's {@link
036: * NotificationListener#handleNotification handleNotification} method
037: * has been called. It is not guaranteed either that a listener will
038: * see notifications in the same order as they were generated.
039: * Listeners that depend on order should use the sequence number of
040: * notifications to determine their order (see {@link
041: * Notification#getSequenceNumber()}).
042: *
043: * <li>Applications should not assume an asynchronous model. If the
044: * actions performed by a listener are potentially slow, the listener
045: * should arrange for them to be performed in another thread, to avoid
046: * holding up other listeners and the caller of {@link
047: * #sendNotification sendNotification}.
048: *
049: * </ul>
050: *
051: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
052: */
053:
054: public class NotificationBroadcasterSupport implements
055: NotificationEmitter {
056:
057: /**
058: * Current list of listeners, a List of ListenerInfo. The object
059: * referenced by this field is never modified. Instead, the field
060: * is set to a new object when a listener is added or removed,
061: * within a synchronized(this). In this way, there is no need to
062: * synchronize when traversing the list to send a notification to
063: * the listeners in it. That avoids potential deadlocks if the
064: * listeners end up depending on other threads that are themselves
065: * accessing this NotificationBroadcasterSupport.
066: */
067: private List listeners = new ArrayList();
068:
069: public NotificationBroadcasterSupport() {
070:
071: }
072:
073: /**
074: * Adds a listener.
075: *
076: * @param listener The listener to receive notifications.
077: * @param filter The filter object. If filter is null, no filtering will be performed before handling notifications.
078: * @param handback An opaque object to be sent back to the listener when a notification is emitted. This object
079: * cannot be used by the Notification broadcaster object. It should be resent unchanged with the notification
080: * to the listener.
081: *
082: * @exception IllegalArgumentException thrown if the istener is null.
083: *
084: * @see #removeNotificationListener
085: */
086: public void addNotificationListener(NotificationListener listener,
087: NotificationFilter filter, Object handback) {
088: if (listener == null)
089: throw new IllegalArgumentException("Listener can't be null");
090: synchronized (listeners) {
091: listeners.add(new ListenerInfo(listener, filter, handback));
092: }
093: }
094:
095: /**
096: * Removes a listener. Note that if the listener has been registered with different handback
097: * objects or notification filters, all entries corresponding to the listener will be removed.
098: * @param listener the listener to receive notifications.
099: * @throws ListenerNotFoundException
100: */
101: public synchronized void removeNotificationListener(
102: NotificationListener listener)
103: throws ListenerNotFoundException {
104: if (listener == null)
105: return;
106: List listenersFound = new ArrayList();
107: for (Iterator iter = listeners.iterator(); iter.hasNext();) {
108: ListenerInfo listenerInfo = (ListenerInfo) iter.next();
109: if (listenerInfo.listener == listener) {
110: listenersFound.add(listenerInfo);
111: }
112: }
113: if (listenersFound.isEmpty())
114: throw new ListenerNotFoundException(
115: "The user specified listener is not found.");
116:
117: listeners.removeAll(listenersFound);
118: }
119:
120: public synchronized void removeNotificationListener(
121: NotificationListener listener, NotificationFilter filter,
122: Object handback) throws ListenerNotFoundException {
123: if (listener == null)
124: return;
125: List listenersFound = new ArrayList();
126: for (Iterator iter = listeners.iterator(); iter.hasNext();) {
127: ListenerInfo li = (ListenerInfo) iter.next();
128: if (li.listener == listener && li.filter == filter
129: && li.handback == handback) {
130: listenersFound.add(li);
131: }
132: }
133:
134: if (listenersFound.isEmpty()) {
135: throw new ListenerNotFoundException("NotificationListener "
136: + listener + " with NotificationFilter " + filter
137: + " and HandBack" + handback + " not found ");
138: }
139: listeners.removeAll(listenersFound);
140: }
141:
142: /**
143: * Returns a NotificationInfo object contaning the name of the Java class of the notification
144: * and the notification types sent.
145: */
146: public MBeanNotificationInfo[] getNotificationInfo() {
147: return new MBeanNotificationInfo[0];
148: }
149:
150: /**
151: * Sends a notification. A listener will be removed if an exception appears when calling
152: * the listener's handleNotification method.
153: *
154: * @param notification
155: */
156: public void sendNotification(Notification notification) {
157: if (notification == null)
158: return;
159: synchronized (listeners) {
160: List exceptionListeners = new ArrayList();
161: for (Iterator iter = listeners.iterator(); iter.hasNext();) {
162: ListenerInfo listenerInfo = (ListenerInfo) iter.next();
163: if (listenerInfo.filter == null
164: || listenerInfo.filter
165: .isNotificationEnabled(notification)) {
166: try {
167: this .handleNotification(listenerInfo.listener,
168: notification, listenerInfo.handback);
169: // listenerInfo.listener.handleNotification(notification, listenerInfo.handback);
170: } catch (Exception e) {
171: e.printStackTrace();
172: exceptionListeners.add(listenerInfo);
173: }
174: }
175: }
176: // remove wrong listener
177: listeners.removeAll(exceptionListeners);
178: }
179: }
180:
181: /**
182: * <p>This method is called by {@link #sendNotification
183: * sendNotification} for each listener in order to send the
184: * notification to that listener. It can be overridden in
185: * subclasses to change the behaviour of notification delivery,
186: * for instance to deliver the notification in a separate
187: * thread.</p>
188: *
189: * <p>It is not guaranteed that this method is called by the same
190: * thread as the one that called {@link #sendNotification
191: * sendNotification}.</p>
192: *
193: * <p>The default implementation of this method is equivalent to
194: * <pre>
195: * listener.handleNotification(notif, handback);
196: * </pre>
197: *
198: * @param listener the listener to which the notification is being
199: * delivered.
200: * @param notif the notification being delivered to the listener.
201: * @param handback the handback object that was supplied when the
202: * listener was added.
203: *
204: * @since JMX 1.2
205: */
206: protected void handleNotification(NotificationListener listener,
207: Notification notif, Object handback) {
208: listener.handleNotification(notif, handback);
209: }
210:
211: private class ListenerInfo {
212: NotificationListener listener;
213: NotificationFilter filter;
214: Object handback;
215:
216: public ListenerInfo(NotificationListener notificationlistener,
217: NotificationFilter notificationfilter, Object obj) {
218: listener = notificationlistener;
219: filter = notificationfilter;
220: handback = obj;
221: }
222:
223: }
224:
225: }
|