1 /**
2 * Copyright 2003-2006 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.Cache;
20 import net.sf.ehcache.Element;
21 import net.sf.ehcache.CacheException;
22 import net.sf.ehcache.distribution.CacheReplicator;
23
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Set;
27
28 /**
29 * Registered listeners for registering and unregistering CacheEventListeners and multicasting notifications to registrants.
30 * <p/>
31 * There is one of these per Cache
32 *
33 * @author Greg Luck
34 * @version $Id: RegisteredEventListeners.java 51 2006-04-24 09:21:10Z gregluck $
35 */
36 public final class RegisteredEventListeners {
37
38 /**
39 * A Map of CacheEventListeners keyed by listener class.
40 * CacheEventListener implementations that will be notified of this cache's events.
41 *
42 * @see CacheEventListener
43 */
44 private final Set cacheEventListeners = new HashSet();
45 private final Cache cache;
46
47 /**
48 * Constructs a new notification service
49 *
50 * @param cache
51 */
52 public RegisteredEventListeners(Cache cache) {
53 this.cache = cache;
54 }
55
56
57 /**
58 * Notifies all registered listeners, in no guaranteed order, that an element was removed
59 *
60 * @param element
61 * @param remoteEvent whether the event came from a remote cache peer
62 * @see CacheEventListener#notifyElementRemoved
63 */
64 public final void notifyElementRemoved(Element element, boolean remoteEvent) throws CacheException {
65 Iterator iterator = cacheEventListeners.iterator();
66 while (iterator.hasNext()) {
67 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
68 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
69 cacheEventListener.notifyElementRemoved(cache, element);
70 }
71 }
72 }
73
74 /**
75 * Notifies all registered listeners, in no guaranteed order, that an element was put into the cache
76 *
77 * @param element
78 * @param remoteEvent whether the event came from a remote cache peer
79 * @see CacheEventListener#notifyElementPut(net.sf.ehcache.Cache,net.sf.ehcache.Element)
80 */
81 public final void notifyElementPut(Element element, boolean remoteEvent) throws CacheException {
82 Iterator iterator = cacheEventListeners.iterator();
83 while (iterator.hasNext()) {
84 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
85 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
86 cacheEventListener.notifyElementPut(cache, element);
87 }
88 }
89 }
90
91 /**
92 * Notifies all registered listeners, in no guaranteed order, that an element in the cache was updated
93 *
94 * @param element
95 * @param remoteEvent whether the event came from a remote cache peer
96 * @see CacheEventListener#notifyElementPut(net.sf.ehcache.Cache,net.sf.ehcache.Element)
97 */
98 public final void notifyElementUpdated(Element element, boolean remoteEvent) {
99 Iterator iterator = cacheEventListeners.iterator();
100 while (iterator.hasNext()) {
101 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
102 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
103 cacheEventListener.notifyElementUpdated(cache, element);
104 }
105 }
106 }
107
108 /**
109 * Notifies all registered listeners, in no guaranteed order, that an element has expired
110 *
111 * @param element
112 * @param remoteEvent whether the event came from a remote cache peer
113 * @see CacheEventListener#notifyElementExpired
114 */
115 public final void notifyElementExpiry(Element element, boolean remoteEvent) {
116 Iterator iterator = cacheEventListeners.iterator();
117 while (iterator.hasNext()) {
118 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
119 if (!isCircularNotification(remoteEvent, cacheEventListener)) {
120 cacheEventListener.notifyElementExpired(cache, element);
121 }
122 }
123 }
124
125
126 /**
127 * CacheReplicators should not be notified of events received remotely, as this would cause
128 * a circular notification
129 *
130 * @param remoteEvent
131 * @param cacheEventListener
132 * @return true is notifiying the listener would cause a circular notification
133 */
134 private static boolean isCircularNotification(boolean remoteEvent, CacheEventListener cacheEventListener) {
135 return remoteEvent && cacheEventListener instanceof CacheReplicator;
136 }
137
138
139 /**
140 * Adds a listener to the notification service. No guarantee is made that listeners will be
141 * notified in the order they were added.
142 *
143 * @param cacheEventListener
144 * @return true if the listener is being added and was not already added
145 */
146 public final boolean registerListener(CacheEventListener cacheEventListener) {
147 if (cacheEventListener == null) {
148 return false;
149 }
150 return cacheEventListeners.add(cacheEventListener);
151 }
152
153 /**
154 * Removes a listener from the notification service.
155 *
156 * @param cacheEventListener
157 * @return true if the listener was present
158 */
159 public final boolean unregisterListener(CacheEventListener cacheEventListener) {
160 return cacheEventListeners.remove(cacheEventListener);
161 }
162
163 /**
164 * Gets a list of the listeners registered to this class
165 *
166 * @return a list of type <code>CacheEventListener</code>
167 */
168 public final Set getCacheEventListeners() {
169 return cacheEventListeners;
170 }
171
172 /**
173 * Tell listeners to dispose themselves.
174 * Because this method is only ever called from a synchronized cache method, it does not itself need to be
175 * synchronized.
176 */
177 public final void dispose() {
178 Iterator iterator = cacheEventListeners.iterator();
179 while (iterator.hasNext()) {
180 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
181 cacheEventListener.dispose();
182 }
183
184 cacheEventListeners.clear();
185 }
186
187 /**
188 * Returns a string representation of the object. In general, the
189 * <code>toString</code> method returns a string that
190 * "textually represents" this object. The result should
191 * be a concise but informative representation that is easy for a
192 * person to read.
193 *
194 * @return a string representation of the object.
195 */
196 public final String toString() {
197 StringBuffer stringBuffer = new StringBuffer(" cacheEventListeners: ");
198 for (Iterator iterator = cacheEventListeners.iterator(); iterator.hasNext();) {
199 CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
200 stringBuffer.append(cacheEventListener.getClass().getName()).append(" ");
201 }
202 return stringBuffer.toString();
203 }
204 }