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    }