1   // 
2   //Copyright (c) 2003, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   //All rights reserved. 
4   //   
5   //Redistribution and use in source and binary forms, with or without modification,  
6   //are permitted provided that the following conditions are met: 
7   //   
8   //* Redistributions of source code must retain the above copyright notice,  
9   //this list of conditions and the following disclaimer. 
10  //* Redistributions in binary form must reproduce the above copyright notice,  
11  //this list of conditions and the following disclaimer in the documentation  
12  //and/or other materials provided with the distribution. 
13  //* Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  //nor the names of its contributors may be used to endorse or promote products  
15  //derived from this software without specific prior written permission. 
16  // 
17  //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  //IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  //INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  //OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  //WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  //POSSIBILITY OF SUCH DAMAGE. 
27  //
28  
29  package org.objectledge.cache;
30  
31  import java.io.PrintWriter;
32  import java.io.StringWriter;
33  import java.util.HashMap;
34  import java.util.Map;
35  
36  import javax.sql.DataSource;
37  
38  import org.jcontainer.dna.Configuration;
39  import org.jcontainer.dna.Logger;
40  import org.jcontainer.dna.impl.DefaultConfiguration;
41  import org.jcontainer.dna.impl.Log4JLogger;
42  import org.objectledge.cache.impl.DelegateMap;
43  import org.objectledge.cache.spi.CacheFactorySPI;
44  import org.objectledge.cache.spi.LRUMap;
45  import org.objectledge.cache.spi.StatisticsMap;
46  import org.objectledge.context.Context;
47  import org.objectledge.database.Database;
48  import org.objectledge.database.DefaultDatabase;
49  import org.objectledge.database.HsqldbDataSource;
50  import org.objectledge.database.IdGenerator;
51  import org.objectledge.database.JotmTransaction;
52  import org.objectledge.database.persistence.DefaultPersistence;
53  import org.objectledge.database.persistence.Persistence;
54  import org.objectledge.filesystem.ClasspathFileSystemProvider;
55  import org.objectledge.filesystem.FileSystem;
56  import org.objectledge.filesystem.FileSystemProvider;
57  import org.objectledge.filesystem.LocalFileSystemProvider;
58  import org.objectledge.notification.Notification;
59  import org.objectledge.pipeline.Valve;
60  import org.objectledge.threads.ThreadPool;
61  import org.objectledge.utils.LedgeTestCase;
62  
63  /**
64   * @author <a href="mailto:pablo@caltha.pl">Pawel Potempski</a>
65   *
66   */
67  public class CachingTest extends LedgeTestCase
68  {
69      private CacheFactorySPI caching;
70  
71      private Notification notification;
72  
73      public void setUp()
74      throws Exception
75      {
76          Context context = new Context();
77          Valve cleanup = null;
78          Configuration config = new DefaultConfiguration("config", "", "/config");
79          Logger logger = new Log4JLogger(org.apache.log4j.Logger.getLogger(getClass()));
80          ThreadPool pool = new ThreadPool(cleanup, context, config, logger);
81          DataSource dataSource = getDataSource();
82          IdGenerator idGenerator = new IdGenerator(dataSource);
83          JotmTransaction transaction = new JotmTransaction(0, 120, new Context(), logger, null);
84          Database database = new DefaultDatabase(dataSource, idGenerator, transaction);
85          Persistence persistence = new DefaultPersistence(database, logger);
86          notification = new Notification();
87  
88          FileSystemProvider lfs = new LocalFileSystemProvider("local", "src/test/resources");
89          FileSystemProvider cfs = new ClasspathFileSystemProvider("classpath", 
90                                                  getClass().getClassLoader());
91          FileSystem fs = new FileSystem(new FileSystemProvider[] { lfs, cfs }, 4096, 4096);
92          config = getConfig(fs, "config/org.objectledge.cache.CacheFactory.xml");
93          caching = new DefaultCacheFactory(config, logger, pool, notification, persistence);
94      }
95  
96      public void testCaching()
97      {
98          assertNotNull(caching);
99      }
100 
101     public void testGetMap()
102     {
103         Map map = caching.getMap("LRUMap");
104         assertNotNull(map);
105         assertNotNull(caching.getMap("foo"));
106         try
107         {
108             caching.getMap("bar");
109             fail("should throw the exception");
110         }
111         catch (IllegalArgumentException e)
112         {
113             //ok!
114         }
115     }
116 
117     /*
118      * Test for Map getInstance(String)
119      */
120     public void testGetInstanceString()
121     {
122         Object cache = caching.getInstance("instance1"); 
123         assertNotNull(cache);
124         assertNotNull(((DelegateMap)cache).getDelegate());
125         assertNotNull(caching.getInstance("instance2"));
126         try
127         {
128             caching.getInstance("not_configured");
129             fail("should throw the exception");    
130         }
131         catch(IllegalArgumentException e)
132         {
133             //ok!
134         }
135     }
136 
137     /*
138      * Test for Map getInstance(String, String)
139      */
140     public void testGetInstanceStringString()
141         throws Exception
142     {
143         Object cache = caching.getInstance("not_configured","alias1"); 
144         assertNotNull(cache);
145         assertNotNull(((DelegateMap)cache).getDelegate());
146         Object cache2 = caching.getInstance("not_configured","aliasXXX");
147         assertNotNull(cache2);
148         assertEquals(cache, cache2);
149         assertEquals(caching.getInstance("not_configured"),cache);
150         try
151         {
152             caching.getInstance("not_configured_2","alias_not_configured");
153             fail("should throw the exception");    
154         }
155         catch(IllegalArgumentException e)
156         {
157             //ok!
158         }
159     }
160     
161     public void testGetMaps()
162     {
163         assertNotNull(caching.getHashMap());
164         assertNotNull(caching.getLRUMap(4));
165         assertNotNull(caching.getSoftMap(4));
166         assertNotNull(caching.getStatisticsMap("xxx",new HashMap()));
167         assertNotNull(caching.getTimeoutMap(1000));
168         ValueFactory valueFactory = caching.getPersitenceValueFactory(TestValue.class); 
169         assertNotNull(valueFactory);
170         assertNotNull(caching.getFactoryMap(valueFactory, new HashMap()));
171         assertNotNull(caching.getDistributedMap("yyy", new HashMap()));
172     }
173     
174     
175 
176     public void testHash()
177     {
178         caching.getInstance("hash");
179     }
180 
181     public void testTimeout()
182     {
183         try
184         {
185             Map map = caching.getInstance("timeout");
186             map.put("k1","v");
187             Thread.sleep(500);
188             assertNotNull("@500", map.get("k1"));
189             Thread.sleep(1500);
190             assertNull("@2000", map.get("k1"));
191         }
192         catch(InterruptedException e)
193         {
194             fail("thread was interrupted?!");
195         }
196     }
197 
198     public void testLRU()
199     {
200         Map map = caching.getInstance("LRU");
201         map.put("k1","v");
202         map.put("k2","v");
203         map.put("k3","v");
204         map.put("k4","v");
205         map.put("k5","v");
206         map.get("k3");
207         map.get("k4");
208         map.get("k2");
209         map.get("k1");
210         map.get("k5");
211         map.put("k6", "v");
212         assertNotNull("k1 in", map.get("k1"));
213         assertNotNull("k2 in", map.get("k2"));
214         assertNull("k3 out", map.get("k3"));
215         assertNotNull("k4 in", map.get("k4"));
216         assertNotNull("k5 in", map.get("k5"));
217         assertNotNull("k6 in",map.get("k6"));
218     }
219 
220     public void testSoft()
221     {
222         Map map = caching.getInstance("soft");
223         // allocate 100MB. The test fails with OutOfMemoryError when the
224         // "hash" instance is used instead.
225         int count = 100;
226         for(int i=0; i<count; i++)
227         {
228              map.put(new Integer(i), new byte[1024*1024]);
229         }
230         for(int i=1; i<=5; i++)
231         {
232             assertNotNull("last - "+i, map.get(new Integer(count-i)));
233         }
234         for(int i=0; i<count; i++)
235         {
236              map.remove(new Integer(i));
237         }        
238     }
239 
240     private String stats = "statistics: 3 items, 3 requests, 2 hits, 1 misses, 67% hit ratio\n";
241 
242     public void testStatistics()
243     {
244         Map map = caching.getInstance("statistics");
245         map.put("k1","v");
246         map.put("k2","v");
247         map.put("k3","v");
248         map.get("k1");
249         map.get("k2");
250         map.get("k4");
251         assertEquals(stats,((StatisticsMap)map).getStatistics());
252     }
253 
254     public void testDistributed()
255     {
256         Map map = caching.getInstance("distributed");
257         /*
258         byte[] msg = "proceed".getBytes();
259         map.put("k","v");
260         //TODO when notification implemented
261         notification.sendNotification(TEST_CHANNEL, msg, false);
262         try
263         {
264             // wait for the things to settle down
265             Thread.sleep(500);
266         }
267         catch(InterruptedException e)
268         {
269             // oh really
270         }
271         assertNull("remote remove", map.get("k"));
272         notification.sendNotification(TEST_CHANEL, msg, false);
273         */
274     }
275     
276     public void testFactory()
277     {
278         Map map = caching.getInstance("factory");
279         /***
280         TestValue v = (TestValue)map.get(new Long(1));
281         assertNotNull("v@1",v);
282         assertEquals("apples",v.getName());
283         v = (TestValue)map.get(new Long(11));
284         assertNull("v@11",v);
285         */
286     }
287 
288     public void testGlobalStatistics()
289     {
290         StringWriter sw = new StringWriter();
291         PrintWriter pw = new PrintWriter(sw, true);
292         caching.getStatus(pw);
293         String status = sw.getBuffer().toString();
294         //you dont know the test sequence
295         //assertEquals("global stats", stats, status);
296     }
297 
298     public void testConfigAlias()
299     {
300         Map map = caching.getInstance("shared");
301         assertTrue("shared=LRUMap", LRUMap.class.isAssignableFrom(map.getClass()));
302     }
303 
304     public void testCustom()
305     {
306         Map map = caching.getInstance("custom");
307         assertTrue("custom=LRUMap", LRUMap.class.isAssignableFrom(map.getClass()));
308     }
309 
310     private int updateCounter = 0;
311 
312     private class Delayed
313         implements DelayedUpdate
314     {
315         public long getUpdateLatency()
316         {
317             return 100;
318         }
319         
320         public void update()
321         {
322             updateCounter++;    
323         }
324     }           
325 
326     public void testDelayedUpdate()
327     {
328         try
329         {
330             Delayed d = new Delayed();
331             caching.register(d);
332             Thread.sleep(200);
333             caching.register(d);
334             Thread.sleep(200);
335             caching.register(d);
336             Thread.sleep(200);
337             assertEquals("delayed 3", 3, updateCounter);
338             caching.register(d);
339             Thread.sleep(20);
340             caching.register(d);
341             Thread.sleep(20);
342             caching.register(d);
343             Thread.sleep(200);
344             assertEquals("delayed 4", 4, updateCounter);
345         }
346         catch(InterruptedException e)
347         {
348             // oh really?
349         }
350     }
351 
352     public void testGetNotification()
353     {
354         assertNotNull(caching.getNotification());
355     }
356 
357     // private
358     private DataSource getDataSource() throws Exception
359     {
360         DefaultConfiguration conf = new DefaultConfiguration("config", "", "/");
361         DefaultConfiguration url = new DefaultConfiguration("url", "", "/config");
362         url.setValue("jdbc:hsqldb:.");
363         conf.addChild(url);
364         DefaultConfiguration user = new DefaultConfiguration("user", "", "/config");
365         user.setValue("sa");
366         conf.addChild(user);
367         return new HsqldbDataSource(conf);
368     }
369 }