View Javadoc

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 }