001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018
019 package org.apache.commons.modeler;
020
021
022 import java.util.ArrayList;
023 import java.util.Iterator;
024
025 import javax.management.ListenerNotFoundException;
026 import javax.management.MBeanNotificationInfo;
027 import javax.management.Notification;
028 import javax.management.NotificationBroadcaster;
029 import javax.management.NotificationFilter;
030 import javax.management.NotificationListener;
031
032
033 /**
034 * <p>Implementation of <code>NotificationBroadcaster</code> for attribute
035 * change notifications. This class is used by <code>BaseModelMBean</code> to
036 * handle notifications of attribute change events to interested listeners.
037 *</p>
038 *
039 * @author Craig R. McClanahan
040 * @author Costin Manolache
041 */
042
043 public class BaseNotificationBroadcaster implements NotificationBroadcaster {
044
045
046 // ----------------------------------------------------------- Constructors
047
048
049 // ----------------------------------------------------- Instance Variables
050
051
052 /**
053 * The set of registered <code>BaseNotificationBroadcasterEntry</code>
054 * entries.
055 */
056 protected ArrayList entries = new ArrayList();
057
058
059 // --------------------------------------------------------- Public Methods
060
061
062 /**
063 * Add a notification event listener to this MBean.
064 *
065 * @param listener Listener that will receive event notifications
066 * @param filter Filter object used to filter event notifications
067 * actually delivered, or <code>null</code> for no filtering
068 * @param handback Handback object to be sent along with event
069 * notifications
070 *
071 * @exception IllegalArgumentException if the listener parameter is null
072 */
073 public void addNotificationListener(NotificationListener listener,
074 NotificationFilter filter,
075 Object handback)
076 throws IllegalArgumentException {
077
078 synchronized (entries) {
079
080 // Optimization to coalesce attribute name filters
081 if (filter instanceof BaseAttributeFilter) {
082 BaseAttributeFilter newFilter = (BaseAttributeFilter) filter;
083 Iterator items = entries.iterator();
084 while (items.hasNext()) {
085 BaseNotificationBroadcasterEntry item =
086 (BaseNotificationBroadcasterEntry) items.next();
087 if ((item.listener == listener) &&
088 (item.filter != null) &&
089 (item.filter instanceof BaseAttributeFilter) &&
090 (item.handback == handback)) {
091 BaseAttributeFilter oldFilter =
092 (BaseAttributeFilter) item.filter;
093 String newNames[] = newFilter.getNames();
094 String oldNames[] = oldFilter.getNames();
095 if (newNames.length == 0) {
096 oldFilter.clear();
097 } else {
098 if (oldNames.length != 0) {
099 for (int i = 0; i < newNames.length; i++)
100 oldFilter.addAttribute(newNames[i]);
101 }
102 }
103 return;
104 }
105 }
106 }
107
108 // General purpose addition of a new entry
109 entries.add(new BaseNotificationBroadcasterEntry
110 (listener, filter, handback));
111 }
112
113 }
114
115
116 /**
117 * Return an <code>MBeanNotificationInfo</code> object describing the
118 * notifications sent by this MBean.
119 */
120 public MBeanNotificationInfo[] getNotificationInfo() {
121
122 return (new MBeanNotificationInfo[0]);
123
124 }
125
126
127 /**
128 * Remove a notification event listener from this MBean.
129 *
130 * @param listener The listener to be removed (any and all registrations
131 * for this listener will be eliminated)
132 *
133 * @exception ListenerNotFoundException if this listener is not
134 * registered in the MBean
135 */
136 public void removeNotificationListener(NotificationListener listener)
137 throws ListenerNotFoundException {
138
139 synchronized (entries) {
140 Iterator items = entries.iterator();
141 while (items.hasNext()) {
142 BaseNotificationBroadcasterEntry item =
143 (BaseNotificationBroadcasterEntry) items.next();
144 if (item.listener == listener)
145 items.remove();
146 }
147 }
148
149 }
150
151
152 /**
153 * Remove a notification event listener from this MBean.
154 *
155 * @param listener The listener to be removed (any and all registrations
156 * for this listener will be eliminated)
157 * @param handback Handback object to be sent along with event
158 * notifications
159 *
160 * @exception ListenerNotFoundException if this listener is not
161 * registered in the MBean
162 */
163 public void removeNotificationListener(NotificationListener listener,
164 Object handback)
165 throws ListenerNotFoundException {
166
167 removeNotificationListener(listener);
168
169 }
170
171
172 /**
173 * Remove a notification event listener from this MBean.
174 *
175 * @param listener The listener to be removed (any and all registrations
176 * for this listener will be eliminated)
177 * @param filter Filter object used to filter event notifications
178 * actually delivered, or <code>null</code> for no filtering
179 * @param handback Handback object to be sent along with event
180 * notifications
181 *
182 * @exception ListenerNotFoundException if this listener is not
183 * registered in the MBean
184 */
185 public void removeNotificationListener(NotificationListener listener,
186 NotificationFilter filter,
187 Object handback)
188 throws ListenerNotFoundException {
189
190 removeNotificationListener(listener);
191
192 }
193
194
195 /**
196 * Send the specified notification to all interested listeners.
197 *
198 * @param notification The notification to be sent
199 */
200 public void sendNotification(Notification notification) {
201
202 synchronized (entries) {
203 Iterator items = entries.iterator();
204 while (items.hasNext()) {
205 BaseNotificationBroadcasterEntry item =
206 (BaseNotificationBroadcasterEntry) items.next();
207 if ((item.filter != null) &&
208 (!item.filter.isNotificationEnabled(notification)))
209 continue;
210 item.listener.handleNotification(notification, item.handback);
211 }
212 }
213
214 }
215
216
217 // -------------------- Internal Extensions --------------------
218
219 // Fast access. First index is the hook type
220 // ( FixedNotificationFilter.getType() ).
221 NotificationListener hooks[][]=new NotificationListener[20][];
222 int hookCount[]=new int[20];
223
224 private synchronized void registerNotifications( FixedNotificationFilter filter ) {
225 String names[]=filter.getNames();
226 Registry reg=Registry.getRegistry();
227 for( int i=0; i<names.length; i++ ) {
228 int code=reg.getId(null, names[i]);
229 if( hooks.length < code ) {
230 // XXX reallocate
231 throw new RuntimeException( "Too many hooks " + code );
232 }
233 NotificationListener listeners[]=hooks[code];
234 if( listeners== null ) {
235
236 }
237
238
239 }
240 }
241
242 }
243
244
245 /**
246 * Utility class representing a particular registered listener entry.
247 */
248
249 class BaseNotificationBroadcasterEntry {
250
251 public BaseNotificationBroadcasterEntry(NotificationListener listener,
252 NotificationFilter filter,
253 Object handback) {
254 this.listener = listener;
255 this.filter = filter;
256 this.handback = handback;
257 }
258
259 public NotificationFilter filter = null;
260
261 public Object handback = null;
262
263 public NotificationListener listener = null;
264
265 }