View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.event;
18  
19  import net.sf.ehcache.CacheException;
20  import net.sf.ehcache.Ehcache;
21  import net.sf.ehcache.Element;
22  import net.sf.ehcache.jcache.JCacheListenerAdaptor;
23  import net.sf.ehcache.distribution.CacheReplicator;
24  
25  import net.sf.jsr107cache.CacheListener;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.Set;
29  
30  /**
31   * Registered listeners for registering and unregistering CacheEventListeners and multicasting notifications to registrants.
32   * <p/>
33   * There is one of these per Cache
34   *
35   * @author Greg Luck
36   * @version $Id: RegisteredEventListeners.java 512 2007-07-10 09:18:45Z gregluck $
37   */
38  public final class RegisteredEventListeners {
39  
40      /**
41       * A Set of CacheEventListeners keyed by listener instance.
42       * CacheEventListener implementations that will be notified of this cache's events.
43       *
44       * @see CacheEventListener
45       */
46      private final Set cacheEventListeners = new HashSet();
47      private final Ehcache cache;
48  
49      /**
50       * Constructs a new notification service
51       *
52       * @param cache
53       */
54      public RegisteredEventListeners(Ehcache cache) {
55          this.cache = cache;
56      }
57  
58  
59      /**
60       * Notifies all registered listeners, in no guaranteed order, that an element was removed
61       *
62       * @param element
63       * @param remoteEvent whether the event came from a remote cache peer
64       * @see CacheEventListener#notifyElementRemoved
65       */
66      public final void notifyElementRemoved(Element element, boolean remoteEvent) throws CacheException {
67          if (hasCacheEventListeners()) {
68              Iterator iterator = cacheEventListeners.iterator();
69              while (iterator.hasNext()) {
70                  CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
71                  if (!isCircularNotification(remoteEvent, cacheEventListener)) {
72                      cacheEventListener.notifyElementRemoved(cache, element);
73                  }
74              }
75          }
76      }
77  
78      /**
79       * Notifies all registered listeners, in no guaranteed order, that an element was put into the cache
80       *
81       * @param element
82       * @param remoteEvent whether the event came from a remote cache peer
83       * @see CacheEventListener#notifyElementPut(net.sf.ehcache.Ehcache,net.sf.ehcache.Element)
84       */
85      public final void notifyElementPut(Element element, boolean remoteEvent) throws CacheException {
86          if (hasCacheEventListeners()) {
87              Iterator iterator = cacheEventListeners.iterator();
88              while (iterator.hasNext()) {
89                  CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
90                  if (!isCircularNotification(remoteEvent, cacheEventListener)) {
91                      cacheEventListener.notifyElementPut(cache, element);
92                  }
93              }
94          }
95      }
96  
97      /**
98       * Notifies all registered listeners, in no guaranteed order, that an element in the cache was updated
99       *
100      * @param element
101      * @param remoteEvent whether the event came from a remote cache peer
102      * @see CacheEventListener#notifyElementPut(net.sf.ehcache.Ehcache,net.sf.ehcache.Element)
103      */
104     public final void notifyElementUpdated(Element element, boolean remoteEvent) {
105         if (hasCacheEventListeners()) {
106             Iterator iterator = cacheEventListeners.iterator();
107             while (iterator.hasNext()) {
108                 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
109                 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
110                     cacheEventListener.notifyElementUpdated(cache, element);
111                 }
112             }
113         }
114     }
115 
116     /**
117      * Notifies all registered listeners, in no guaranteed order, that an element has expired
118      *
119      * @param element     the Element to perform the notification on
120      * @param remoteEvent whether the event came from a remote cache peer
121      * @see CacheEventListener#notifyElementExpired
122      */
123     public final void notifyElementExpiry(Element element, boolean remoteEvent) {
124         if (hasCacheEventListeners()) {
125             Iterator iterator = cacheEventListeners.iterator();
126             while (iterator.hasNext()) {
127                 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
128                 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
129                     cacheEventListener.notifyElementExpired(cache, element);
130                 }
131             }
132         }
133     }
134 
135     /**
136      * Returns whether or not at least one cache event listeners has been registered.
137      *
138      * @return true if a one or more listeners have registered, otherwise false
139      */
140     public final boolean hasCacheEventListeners() {
141         return cacheEventListeners.size() > 0;
142     }
143 
144     /**
145      * Notifies all registered listeners, in no guaranteed order, that an element has been
146      * evicted from the cache
147      *
148      * @param element     the Element to perform the notification on
149      * @param remoteEvent whether the event came from a remote cache peer
150      * @see CacheEventListener#notifyElementEvicted
151      */
152     public void notifyElementEvicted(Element element, boolean remoteEvent) {
153         if (hasCacheEventListeners()) {
154             Iterator iterator = cacheEventListeners.iterator();
155             while (iterator.hasNext()) {
156                 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
157                 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
158                     cacheEventListener.notifyElementEvicted(cache, element);
159                 }
160             }
161         }
162     }
163 
164 
165     /**
166      * Notifies all registered listeners, in no guaranteed order, that removeAll
167      * has been called and all elements cleared
168      *
169      * @param remoteEvent whether the event came from a remote cache peer
170      * @see CacheEventListener#notifyElementEvicted
171      */
172     public void notifyRemoveAll(boolean remoteEvent) {
173         if (hasCacheEventListeners()) {
174 
175             Iterator iterator = cacheEventListeners.iterator();
176             while (iterator.hasNext()) {
177                 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
178                 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
179                     cacheEventListener.notifyRemoveAll(cache);
180                 }
181             }
182         }
183     }
184 
185 
186     /**
187      * CacheReplicators should not be notified of events received remotely, as this would cause
188      * a circular notification
189      *
190      * @param remoteEvent
191      * @param cacheEventListener
192      * @return true is notifiying the listener would cause a circular notification
193      */
194     private static boolean isCircularNotification(boolean remoteEvent, CacheEventListener cacheEventListener) {
195         return remoteEvent && cacheEventListener instanceof CacheReplicator;
196     }
197 
198 
199     /**
200      * Adds a listener to the notification service. No guarantee is made that listeners will be
201      * notified in the order they were added.
202      *
203      * @param cacheEventListener
204      * @return true if the listener is being added and was not already added
205      */
206     public final boolean registerListener(CacheEventListener cacheEventListener) {
207         if (cacheEventListener == null) {
208             return false;
209         }
210         return cacheEventListeners.add(cacheEventListener);
211     }
212 
213     /**
214      * Removes a listener from the notification service.
215      *
216      * @param cacheEventListener
217      * @return true if the listener was present
218      */
219     public final boolean unregisterListener(CacheEventListener cacheEventListener) {
220         if (cacheEventListener instanceof JCacheListenerAdaptor) {
221             removeCacheListenerAdaptor(((JCacheListenerAdaptor)cacheEventListener).getCacheListener());
222         }
223         return cacheEventListeners.remove(cacheEventListener);
224     }
225 
226     private void removeCacheListenerAdaptor(CacheListener cacheListener) {
227         for (Iterator iterator = cacheEventListeners.iterator(); iterator.hasNext();) {
228             CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
229             if (cacheEventListener instanceof JCacheListenerAdaptor) {
230                 if (((JCacheListenerAdaptor)cacheEventListener).getCacheListener() == cacheListener) {
231                     cacheEventListeners.remove(cacheEventListener);
232                     break;
233                 }
234             }
235         }
236     }
237 
238     /**
239      * Gets a list of the listeners registered to this class
240      *
241      * @return a list of type <code>CacheEventListener</code>
242      */
243     public final Set getCacheEventListeners() {
244         return cacheEventListeners;
245     }
246 
247     /**
248      * Tell listeners to dispose themselves.
249      * Because this method is only ever called from a synchronized cache method, it does not itself need to be
250      * synchronized.
251      */
252     public final void dispose() {
253         Iterator iterator = cacheEventListeners.iterator();
254         while (iterator.hasNext()) {
255             CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
256             cacheEventListener.dispose();
257         }
258 
259         cacheEventListeners.clear();
260     }
261 
262     /**
263      * Returns a string representation of the object. In general, the
264      * <code>toString</code> method returns a string that
265      * "textually represents" this object. The result should
266      * be a concise but informative representation that is easy for a
267      * person to read.
268      *
269      * @return a string representation of the object.
270      */
271     public final String toString() {
272         StringBuffer stringBuffer = new StringBuffer(" cacheEventListeners: ");
273         for (Iterator iterator = cacheEventListeners.iterator(); iterator.hasNext();) {
274             CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
275             stringBuffer.append(cacheEventListener.getClass().getName()).append(" ");
276         }
277         return stringBuffer.toString();
278     }
279 
280 
281 }