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 }