1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
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
23 import java.io.Serializable;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27
28 /***
29 * Counts listener notifications.
30 * <p/>
31 * The methods also check that we hold the Cache lock.
32 *
33 * @author Greg Luck
34 * @version $Id: CountingCacheEventListener.java 2154 2010-04-06 02:45:52Z cdennis $
35 */
36 public class CountingCacheEventListener implements CacheEventListener {
37
38 private static final List CACHE_ELEMENTS_PUT = Collections.synchronizedList(new ArrayList());
39 private static final List CACHE_ELEMENTS_UPDATED = Collections.synchronizedList(new ArrayList());
40 private static final List CACHE_ELEMENTS_REMOVED = Collections.synchronizedList(new ArrayList());
41 private static final List CACHE_ELEMENTS_EXPIRED = Collections.synchronizedList(new ArrayList());
42 private static final List CACHE_ELEMENTS_EVICTED = Collections.synchronizedList(new ArrayList());
43 private static final List CACHE_REMOVE_ALLS = Collections.synchronizedList(new ArrayList());
44
45
46 /***
47 * Accessor
48 */
49 public static List getCacheElementsRemoved(Ehcache cache) {
50 return extractListForGivenCache(CACHE_ELEMENTS_REMOVED, cache);
51 }
52
53
54 /***
55 * Accessor
56 */
57 public static List getCacheElementsPut(Ehcache cache) {
58 return extractListForGivenCache(CACHE_ELEMENTS_PUT, cache);
59 }
60
61 /***
62 * Accessor
63 */
64 public static List getCacheElementsUpdated(Ehcache cache) {
65 return extractListForGivenCache(CACHE_ELEMENTS_UPDATED, cache);
66 }
67
68 /***
69 * Accessor
70 */
71 public static List getCacheElementsExpired(Ehcache cache) {
72 return extractListForGivenCache(CACHE_ELEMENTS_EXPIRED, cache);
73 }
74
75 /***
76 * Accessor
77 */
78 public static List getCacheElementsEvicted(Ehcache cache) {
79 return extractListForGivenCache(CACHE_ELEMENTS_EVICTED, cache);
80 }
81
82 /***
83 * Accessor
84 */
85 public static List getCacheRemoveAlls(Ehcache cache) {
86 return extractListForGivenCache(CACHE_REMOVE_ALLS, cache);
87 }
88
89
90 /***
91 * Resets the counters to 0
92 */
93 public static void resetCounters() {
94 synchronized (CACHE_ELEMENTS_REMOVED) {
95 CACHE_ELEMENTS_REMOVED.clear();
96 }
97 synchronized (CACHE_ELEMENTS_PUT) {
98 CACHE_ELEMENTS_PUT.clear();
99 }
100 synchronized (CACHE_ELEMENTS_UPDATED) {
101 CACHE_ELEMENTS_UPDATED.clear();
102 }
103 synchronized (CACHE_ELEMENTS_EXPIRED) {
104 CACHE_ELEMENTS_EXPIRED.clear();
105 }
106 synchronized (CACHE_ELEMENTS_EVICTED) {
107 CACHE_ELEMENTS_EVICTED.clear();
108 }
109 synchronized (CACHE_REMOVE_ALLS) {
110 CACHE_REMOVE_ALLS.clear();
111 }
112 }
113
114
115 /***
116 * @param notificationList
117 * @param cache the cache to filter on. If null, there is not filtering and all entries are returned.
118 * @return a list of notifications for the cache
119 */
120 private static List extractListForGivenCache(List notificationList, Ehcache cache) {
121 ArrayList list = new ArrayList();
122 synchronized (notificationList) {
123 for (int i = 0; i < notificationList.size(); i++) {
124 CounterEntry counterEntry = (CounterEntry) notificationList.get(i);
125 if (counterEntry.cache.equals(cache)) {
126 list.add(counterEntry.getElement());
127 } else if (cache == null) {
128 list.add(counterEntry.getElement());
129 }
130 }
131 }
132 return list;
133 }
134
135
136 /***
137 * {@inheritDoc}
138 */
139 public void notifyElementRemoved(final Ehcache cache, final Element element) {
140 checkSynchronizedAccessToCacheOk(cache);
141 CACHE_ELEMENTS_REMOVED.add(new CounterEntry(cache, element));
142 }
143
144 /***
145 * Called immediately after an element has been put into the cache. The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
146 * will block until this method returns.
147 * <p/>
148 * Implementers may wish to have access to the Element's fields, including value, so the element is provided.
149 * Implementers should be careful not to modify the element. The effect of any modifications is undefined.
150 *
151 * @param cache
152 * @param element the element which was just put into the cache.
153 */
154 public void notifyElementPut(final Ehcache cache, final Element element) {
155 checkSynchronizedAccessToCacheOk(cache);
156 CACHE_ELEMENTS_PUT.add(new CounterEntry(cache, element));
157 }
158
159
160 /***
161 * Called immediately after an element has been put into the cache and the element already
162 * existed in the cache. This is thus an update.
163 * <p/>
164 * The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
165 * will block until this method returns.
166 * <p/>
167 * Implementers may wish to have access to the Element's fields, including value, so the element is provided.
168 * Implementers should be careful not to modify the element. The effect of any modifications is undefined.
169 *
170 * @param cache the cache emitting the notification
171 * @param element the element which was just put into the cache.
172 */
173 public void notifyElementUpdated(final Ehcache cache, final Element element) throws CacheException {
174 CACHE_ELEMENTS_UPDATED.add(new CounterEntry(cache, element));
175 }
176
177 /***
178 * {@inheritDoc}
179 */
180 public void notifyElementExpired(final Ehcache cache, final Element element) {
181 CACHE_ELEMENTS_EXPIRED.add(new CounterEntry(cache, element));
182 }
183
184
185 /***
186 * {@inheritDoc}
187 */
188 public void notifyElementEvicted(final Ehcache cache, final Element element) {
189 CACHE_ELEMENTS_EVICTED.add(new CounterEntry(cache, element));
190 }
191
192 /***
193 * {@inheritDoc}
194 */
195 public void notifyRemoveAll(final Ehcache cache) {
196 CACHE_REMOVE_ALLS.add(new CounterEntry(cache, null));
197 }
198
199 /***
200 * Give the replicator a chance to cleanup and free resources when no longer needed
201 * <p/>
202 * Clean up static counters
203 */
204 public void dispose() {
205 resetCounters();
206 }
207
208 /***
209 * This counter should be called from calls synchonized on Cache. These methods should hold the lock
210 * therefore this is ok.
211 *
212 * @param cache
213 */
214 private void checkSynchronizedAccessToCacheOk(Ehcache cache) {
215 try {
216 cache.get("justasyncrhonizationtest");
217 } catch (CacheException e) {
218 throw new RuntimeException(e);
219 }
220 }
221
222 /***
223 * A Counter entry
224 */
225 public static class CounterEntry {
226
227 private Ehcache cache;
228 private Element element;
229
230 /***
231 * Construct a new event
232 *
233 * @param cache
234 * @param element
235 */
236 public CounterEntry(Ehcache cache, Element element) {
237 this.cache = cache;
238 this.element = element;
239 }
240
241 /***
242 * @return the cache the event relates to
243 */
244 public Ehcache getCache() {
245 return cache;
246 }
247
248 /***
249 * @return the payload
250 */
251 public Serializable getElement() {
252 return element;
253 }
254
255
256 }
257
258
259 /***
260 * Creates a clone of this listener. This method will only be called by ehcache before a cache is initialized.
261 * <p/>
262 * This may not be possible for listeners after they have been initialized. Implementations should throw
263 * CloneNotSupportedException if they do not support clone.
264 * <p/>
265 * This class uses static counters. Clones will share the same counters.
266 *
267 * @return a clone
268 * @throws CloneNotSupportedException if the listener could not be cloned.
269 */
270 public Object clone() throws CloneNotSupportedException {
271 return super.clone();
272 }
273
274
275 }