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.jcache;
18  
19  import net.sf.ehcache.AbstractCacheTest;
20  import net.sf.ehcache.CacheException;
21  import net.sf.jsr107cache.Cache;
22  
23  import java.io.IOException;
24  import java.io.Serializable;
25  import java.util.Date;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  /**
31   * Tests cache listeners, using the test package CountingCacheListener
32   *
33   * @author Greg Luck
34   * @version $Id: CacheListenerTest.java 512 2007-07-10 09:18:45Z gregluck $
35   */
36  public class CacheListenerTest extends AbstractCacheTest {
37  
38      /**
39       * setup test
40       */
41      protected void setUp() throws Exception {
42          super.setUp();
43  
44      }
45  
46      /**
47       * teardown
48       * limits to what we can do here under jsr107
49       */
50      protected void tearDown() throws Exception {
51          getTest1Cache().clear();
52      }
53  
54  
55      /**
56       * Gets the sample cache 1
57       * <cache name="sampleCache1"
58       * maxElementsInMemory="10000"
59       * maxElementsOnDisk="1000"
60       * eternal="false"
61       * timeToIdleSeconds="360"
62       * timeToLiveSeconds="1000"
63       * overflowToDisk="true"
64       * memoryStoreEvictionPolicy="LRU">
65       * <cacheEventListenerFactory class="net.sf.ehcache.event.NullCacheEventListenerFactory"/>
66       * </cache>
67       */
68      protected Cache getTest1Cache() throws net.sf.jsr107cache.CacheException {
69          Cache cache = net.sf.jsr107cache.CacheManager.getInstance().getCache("listenerTest1");
70          if (cache == null) {
71              //sampleCache1
72              Map env = new HashMap();
73              env.put("name", "test1");
74              env.put("maxElementsInMemory", "10000");
75              env.put("maxElementsOnDisk", "1000");
76              env.put("memoryStoreEvictionPolicy", "LRU");
77              env.put("overflowToDisk", "true");
78              env.put("eternal", "false");
79              env.put("timeToLiveSeconds", "1");
80              env.put("timeToIdleSeconds", "1");
81              env.put("diskPersistent", "false");
82              env.put("diskExpiryThreadIntervalSeconds", "120");
83              env.put("cacheLoaderFactoryClassName", "net.sf.ehcache.jcache.CountingCacheLoaderFactory");
84              cache = net.sf.jsr107cache.CacheManager.getInstance().getCacheFactory().createCache(env);
85              net.sf.jsr107cache.CacheManager.getInstance().registerCache("listenerTest1", cache);
86          }
87          return net.sf.jsr107cache.CacheManager.getInstance().getCache("listenerTest1");
88      }
89  
90      /**
91       * Tests operations not normally called.
92       * @throws net.sf.jsr107cache.CacheException
93       * @throws CloneNotSupportedException
94       */
95      public void testSundryOperations() throws net.sf.jsr107cache.CacheException, CloneNotSupportedException {
96  
97          Cache cache = getTest1Cache();
98          cache.put("1", new Date());
99          CountingCacheListener countingCacheListener = new CountingCacheListener();
100         JCacheListenerAdaptor jCacheListenerAdaptor = new JCacheListenerAdaptor(countingCacheListener);
101         try {
102             jCacheListenerAdaptor.clone();
103         } catch (CloneNotSupportedException e) {
104             assertEquals("Cannot clone JCacheListenerAdaptor", e.getMessage());
105         }
106 
107         assertEquals(countingCacheListener, jCacheListenerAdaptor.getCacheListener());
108 
109         //this calls a noop. For completeness
110         jCacheListenerAdaptor.dispose();
111     }
112 
113     /**
114      * Tests the put listener.
115      */
116     public void testPutNotifications() throws net.sf.jsr107cache.CacheException {
117 
118         Cache cache = getTest1Cache();
119         cache.put("1", new Date());
120         CountingCacheListener countingCacheListener = new CountingCacheListener();
121         cache.addListener(countingCacheListener);
122 
123         cache.put("2", new Date());
124 
125         List notifications = countingCacheListener.getCacheElementsPut();
126 
127         //The one put before we registered the listener should not have been received
128         assertTrue(notifications.size() == 1);
129         assertEquals("2", notifications.get(0));
130 
131         //A put which updates records as two puts, because JCache does not have an update notification
132         cache.put("2", new Date());
133         notifications = countingCacheListener.getCacheElementsPut();
134         assertTrue(notifications.size() == 2);
135 
136         cache.removeListener(countingCacheListener);
137 
138         //Now put another value. It should not be received
139         cache.put("3", new Date());
140         notifications = countingCacheListener.getCacheElementsPut();
141         assertTrue(notifications.size() == 2);
142 
143 
144     }
145 
146 
147     /**
148      * Tests the remove notifier
149      */
150     public void testRemoveNotifications() throws net.sf.jsr107cache.CacheException {
151 
152         Serializable key = "1";
153         Serializable value = new Date();
154 
155         Cache cache = getTest1Cache();
156         CountingCacheListener countingCacheListener = new CountingCacheListener();
157         cache.addListener(countingCacheListener);
158 
159         //Put
160         cache.put(key, value);
161 
162         //Check removal from MemoryStore
163         cache.remove(key);
164 
165 
166         List notifications = countingCacheListener.getCacheElementsRemoved();
167         assertEquals(key, notifications.get(0));
168 
169         //An unsuccessful remove should notify
170         cache.remove(key);
171         notifications = countingCacheListener.getCacheElementsRemoved();
172         assertEquals(2, notifications.size());
173 
174         //check for NPE
175         cache.remove(null);
176 
177     }
178 
179     /**
180      * Tests the expiry notifier. These are mapped to evictions in the JCache adaptor.
181      */
182     public void testExpiryNotifications() throws InterruptedException, net.sf.jsr107cache.CacheException {
183 
184         Serializable key = "1";
185         Serializable value = new Date();
186 
187         Cache cache = getTest1Cache();
188         CountingCacheListener countingCacheListener = new CountingCacheListener();
189         cache.addListener(countingCacheListener);
190 
191         //Put
192         cache.put(key, value);
193 
194         //expire
195         Thread.sleep(1020);
196 
197         //force expiry
198         Object expired = cache.get(key);
199         assertEquals(new Integer(0), expired);
200 
201         //Check counting listener
202         List notifications = countingCacheListener.getCacheElementsEvicted();
203         assertEquals(1, notifications.size());
204 
205         //check for NPE
206         cache.remove(null);
207 
208     }
209 
210 
211     /**
212      * Tests the eviction notifier.
213      * sampleCache2 does not overflow, so an evict should trigger a notification
214      */
215     public void testEvictNotificationsWhereNoOverflow() {
216 
217         JCache cache2 = new JCache(manager.getCache("sampleCache2"), null);
218         CountingCacheListener countingCacheListener = new CountingCacheListener();
219         cache2.addListener(countingCacheListener);
220 
221         //1 should be evicted
222         for (int i = 0; i < 1001; i++) {
223             cache2.put("" + i, new Date());
224         }
225 
226         List notifications = countingCacheListener.getCacheElementsEvicted();
227         assertEquals(1, notifications.size());
228     }
229 
230     /**
231      * Tests the eviction notifier.
232      * sampleCache1 overflows, so the evict should overflow to disk and not trigger a notification
233      */
234     public void testEvictNotificationsWhereOverflow() {
235 
236 
237         JCache cache1 = new JCache(manager.getCache("sampleCache1"), null);
238         CountingCacheListener countingCacheListener = new CountingCacheListener();
239         cache1.addListener(countingCacheListener);
240 
241         //1 should be evicted
242         for (int i = 0; i < 10001; i++) {
243             cache1.put("" + i, new Date());
244         }
245 
246         List notifications = countingCacheListener.getCacheElementsEvicted();
247         assertEquals(0, notifications.size());
248     }
249 
250     /**
251      * Tests the removeAll notifier.
252      */
253     public void testClearNotification() {
254 
255         JCache cache2 = new JCache(manager.getCache("sampleCache2"), null);
256         CountingCacheListener countingCacheListener = new CountingCacheListener();
257         cache2.addListener(countingCacheListener);
258 
259         //Put 11.
260         for (int i = 0; i < 11; i++) {
261             cache2.put("" + i, new Date());
262         }
263 
264         List notifications = countingCacheListener.getCacheRemoveAlls();
265         assertEquals(0, notifications.size());
266 
267         //Remove all
268         cache2.clear();
269         notifications = countingCacheListener.getCacheRemoveAlls();
270         assertEquals(1, notifications.size());
271     }
272 
273 
274     /**
275      * Tests the remove notifier where the element does not exist in the local cache.
276      * Listener notification is required for correct operation of cluster invalidation.
277      */
278     public void testRemoveNotificationWhereElementDidNotExist() throws net.sf.jsr107cache.CacheException {
279 
280         Serializable key = "1";
281 
282         Cache cache = getTest1Cache();
283         CountingCacheListener countingCacheListener = new CountingCacheListener();
284         cache.addListener(countingCacheListener);
285 
286         //Don't Put
287         //cache.put(element);
288 
289         //Check removal from MemoryStore
290         cache.remove(key);
291 
292 
293         List notifications = countingCacheListener.getCacheElementsRemoved();
294         assertEquals(key, notifications.get(0));
295 
296         //An unsuccessful remove should notify
297         cache.remove(key);
298         notifications = countingCacheListener.getCacheElementsRemoved();
299         assertEquals(2, notifications.size());
300 
301         //check for NPE
302         cache.remove(null);
303 
304     }
305 
306     /**
307      * When the <code>MemoryStore</code> overflows, and there is no disk
308      * store, then the element gets automatically evicted. This should
309      * trigger an eviction notification.
310      */
311     public void testEvictionFromLRUMemoryStoreNotSerializable() throws IOException, CacheException, InterruptedException {
312         String sampleCache1 = "sampleCache1";
313         Cache cache = new JCache(manager.getCache(sampleCache1), null);
314         cache.clear();
315         CountingCacheListener countingCacheListener = new CountingCacheListener();
316         cache.addListener(countingCacheListener);
317 
318         //should trigger a removal notification because it is not Serializable and will be evicted
319         cache.put("non-serializable", new Object());
320 
321         for (int i = 0; i < 10000; i++) {
322             cache.put(i + "", new Date());
323         }
324 
325         List evictionNotifications = countingCacheListener.getCacheElementsEvicted();
326         assertEquals(1, evictionNotifications.size());
327     }
328 
329     /**
330      * When the <code>MemoryStore</code> overflows, and there is no disk
331      * store, then the element gets automatically removed. This should
332      * trigger a remove notification.
333      * <p/>
334      * If the element has expired, it should not trigger an eviction notification.
335      */
336     public void testEvictionFromLRUMemoryStoreExpiry() throws IOException, CacheException, InterruptedException {
337         String sampleCache2 = "sampleCache1";
338         Cache cache = new JCache(manager.getCache(sampleCache2), null);
339         cache.clear();
340         CountingCacheListener countingCacheListener = new CountingCacheListener();
341         cache.addListener(countingCacheListener);
342         for (int i = 0; i < 10000; i++) {
343             cache.put(i + "", new Date());
344         }
345 
346         Thread.sleep(1030);
347         cache.put("new", new Date());
348 
349         List removalNotifications = countingCacheListener.getCacheElementsEvicted();
350         assertEquals(0, removalNotifications.size());
351 
352     }
353 
354 }