001: /**
002: * Copyright 2003-2007 Luck Consulting Pty Ltd
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package net.sf.ehcache.event;
016:
017: import net.sf.ehcache.CacheException;
018: import net.sf.ehcache.Ehcache;
019: import net.sf.ehcache.Element;
020:
021: import java.io.Serializable;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.List;
025:
026: /**
027: * Counts listener notifications.
028: * <p/>
029: * The methods also check that we hold the Cache lock.
030: *
031: * @author Greg Luck
032: * @version $Id: CountingCacheEventListener.java 519 2007-07-27 07:11:45Z gregluck $
033: */
034: public class CountingCacheEventListener implements CacheEventListener {
035:
036: private static final List CACHE_ELEMENTS_PUT = Collections
037: .synchronizedList(new ArrayList());
038: private static final List CACHE_ELEMENTS_UPDATED = Collections
039: .synchronizedList(new ArrayList());
040: private static final List CACHE_ELEMENTS_REMOVED = Collections
041: .synchronizedList(new ArrayList());
042: private static final List CACHE_ELEMENTS_EXPIRED = Collections
043: .synchronizedList(new ArrayList());
044: private static final List CACHE_ELEMENTS_EVICTED = Collections
045: .synchronizedList(new ArrayList());
046: private static final List CACHE_REMOVE_ALLS = Collections
047: .synchronizedList(new ArrayList());
048:
049: /**
050: * Accessor
051: */
052: public static List getCacheElementsRemoved(Ehcache cache) {
053: return extractListForGivenCache(CACHE_ELEMENTS_REMOVED, cache);
054: }
055:
056: /**
057: * Accessor
058: */
059: public static List getCacheElementsPut(Ehcache cache) {
060: return extractListForGivenCache(CACHE_ELEMENTS_PUT, cache);
061: }
062:
063: /**
064: * Accessor
065: */
066: public static List getCacheElementsUpdated(Ehcache cache) {
067: return extractListForGivenCache(CACHE_ELEMENTS_UPDATED, cache);
068: }
069:
070: /**
071: * Accessor
072: */
073: public static List getCacheElementsExpired(Ehcache cache) {
074: return extractListForGivenCache(CACHE_ELEMENTS_EXPIRED, cache);
075: }
076:
077: /**
078: * Accessor
079: */
080: public static List getCacheElementsEvicted(Ehcache cache) {
081: return extractListForGivenCache(CACHE_ELEMENTS_EVICTED, cache);
082: }
083:
084: /**
085: * Accessor
086: */
087: public static List getCacheRemoveAlls(Ehcache cache) {
088: return extractListForGivenCache(CACHE_REMOVE_ALLS, cache);
089: }
090:
091: /**
092: * Resets the counters to 0
093: */
094: public static void resetCounters() {
095: synchronized (CACHE_ELEMENTS_REMOVED) {
096: CACHE_ELEMENTS_REMOVED.clear();
097: }
098: synchronized (CACHE_ELEMENTS_PUT) {
099: CACHE_ELEMENTS_PUT.clear();
100: }
101: synchronized (CACHE_ELEMENTS_UPDATED) {
102: CACHE_ELEMENTS_UPDATED.clear();
103: }
104: synchronized (CACHE_ELEMENTS_EXPIRED) {
105: CACHE_ELEMENTS_EXPIRED.clear();
106: }
107: synchronized (CACHE_ELEMENTS_EVICTED) {
108: CACHE_ELEMENTS_EVICTED.clear();
109: }
110: synchronized (CACHE_REMOVE_ALLS) {
111: CACHE_REMOVE_ALLS.clear();
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,
121: Ehcache cache) {
122: ArrayList list = new ArrayList();
123: synchronized (notificationList) {
124: for (int i = 0; i < notificationList.size(); i++) {
125: CounterEntry counterEntry = (CounterEntry) notificationList
126: .get(i);
127: if (counterEntry.cache.equals(cache)) {
128: list.add(counterEntry.getElement());
129: } else if (cache == null) {
130: list.add(counterEntry.getElement());
131: }
132: }
133: }
134: return list;
135: }
136:
137: /**
138: * {@inheritDoc}
139: */
140: public void notifyElementRemoved(final Ehcache cache,
141: final Element element) {
142: checkSynchronizedAccessToCacheOk(cache);
143: CACHE_ELEMENTS_REMOVED.add(new CounterEntry(cache, element));
144: }
145:
146: /**
147: * Called immediately after an element has been put into the cache. The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
148: * will block until this method returns.
149: * <p/>
150: * Implementers may wish to have access to the Element's fields, including value, so the element is provided.
151: * Implementers should be careful not to modify the element. The effect of any modifications is undefined.
152: *
153: * @param cache
154: * @param element the element which was just put into the cache.
155: */
156: public void notifyElementPut(final Ehcache cache,
157: final Element element) {
158: checkSynchronizedAccessToCacheOk(cache);
159: CACHE_ELEMENTS_PUT.add(new CounterEntry(cache, element));
160: }
161:
162: /**
163: * Called immediately after an element has been put into the cache and the element already
164: * existed in the cache. This is thus an update.
165: * <p/>
166: * The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
167: * will block until this method returns.
168: * <p/>
169: * Implementers may wish to have access to the Element's fields, including value, so the element is provided.
170: * Implementers should be careful not to modify the element. The effect of any modifications is undefined.
171: *
172: * @param cache the cache emitting the notification
173: * @param element the element which was just put into the cache.
174: */
175: public void notifyElementUpdated(final Ehcache cache,
176: final Element element) throws CacheException {
177: CACHE_ELEMENTS_UPDATED.add(new CounterEntry(cache, element));
178: }
179:
180: /**
181: * {@inheritDoc}
182: */
183: public void notifyElementExpired(final Ehcache cache,
184: final Element element) {
185: CACHE_ELEMENTS_EXPIRED.add(new CounterEntry(cache, element));
186: }
187:
188: /**
189: * {@inheritDoc}
190: */
191: public void notifyElementEvicted(final Ehcache cache,
192: final Element element) {
193: CACHE_ELEMENTS_EVICTED.add(new CounterEntry(cache, element));
194: }
195:
196: /**
197: * {@inheritDoc}
198: */
199: public void notifyRemoveAll(final Ehcache cache) {
200: CACHE_REMOVE_ALLS.add(new CounterEntry(cache, null));
201: }
202:
203: /**
204: * Give the replicator a chance to cleanup and free resources when no longer needed
205: * <p/>
206: * Clean up static counters
207: */
208: public void dispose() {
209: resetCounters();
210: }
211:
212: /**
213: * This counter should be called from calls synchonized on Cache. These methods should hold the lock
214: * therefore this is ok.
215: *
216: * @param cache
217: */
218: private void checkSynchronizedAccessToCacheOk(Ehcache cache) {
219: try {
220: cache.get("justasyncrhonizationtest");
221: } catch (CacheException e) {
222: throw new RuntimeException(e);
223: }
224: }
225:
226: /**
227: * A Counter entry
228: */
229: public static class CounterEntry {
230:
231: private Ehcache cache;
232: private Element element;
233:
234: /**
235: * Construct a new event
236: *
237: * @param cache
238: * @param element
239: */
240: public CounterEntry(Ehcache cache, Element element) {
241: this .cache = cache;
242: this .element = element;
243: }
244:
245: /**
246: * @return the cache the event relates to
247: */
248: public Ehcache getCache() {
249: return cache;
250: }
251:
252: /**
253: * @return the payload
254: */
255: public Serializable getElement() {
256: return element;
257: }
258:
259: }
260:
261: /**
262: * Creates a clone of this listener. This method will only be called by ehcache before a cache is initialized.
263: * <p/>
264: * This may not be possible for listeners after they have been initialized. Implementations should throw
265: * CloneNotSupportedException if they do not support clone.
266: * <p/>
267: * This class uses static counters. Clones will share the same counters.
268: * @return a clone
269: * @throws CloneNotSupportedException if the listener could not be cloned.
270: */
271: public Object clone() throws CloneNotSupportedException {
272: return super.clone();
273: }
274:
275: }
|