KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > core > cache > CacheManager


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64
65 package com.jcorporate.expresso.core.cache;
66
67 import com.jcorporate.expresso.core.misc.ConfigManager;
68 import com.jcorporate.expresso.kernel.ComponentLifecycle;
69 import com.jcorporate.expresso.kernel.management.ExpressoRuntimeMap;
70 import com.jcorporate.expresso.kernel.util.LocatorUtils;
71 import org.apache.commons.collections.FastHashMap;
72 import org.apache.log4j.Logger;
73
74 import java.util.Enumeration JavaDoc;
75 import java.util.Iterator JavaDoc;
76 import java.util.Vector JavaDoc;
77
78 /**
79  * CacheManager.java
80  * <p>Copyright 1999-2002 Jcorporate Ltd.</p>
81  * <p/>
82  * Cache Manager is a general-purpose class to handle all different
83  * kinds of caches - it provides both "ordered" caches (stored as a
84  * Vector of objects) and "unordered" caches (stored as a Hashtable).
85  * </p>
86  * <p/>
87  * The amount of data cached can be expressed as a count of items in
88  * the specified list (e.g. cache only so many items) or limited by
89  * the amount of free memory available (e.g. don't go below 10% of
90  * available memory being free). In both cases, the cached items are
91  * removed from the cache according to how frequently they have been
92  * used (e.g. a least-frequently-used algorithm is used to drop items
93  * from the cache).
94  * </p>
95  *
96  * @since Expresso 1.0
97  */

98 public class CacheManager {
99
100     /* cacheLists is a hashtable keyed by context that contains the hashtables */
101     /* for each context. Each entry in the enclosed hashtable is a Cache */
102     private volatile static FastHashMap cacheLists = null;
103
104     /**
105      * The one and only instance of this Cache Manager
106      */

107     private static CacheManager theInstance = null;
108
109
110     private static String JavaDoc thisContextPath = null;
111
112     /**
113      * The one and only log4j log class.
114      */

115     private static Logger log = Logger.getLogger(CacheManager.class);
116
117
118     /**
119      * Flag to tell quickly whether this was initialized by the new or
120      * old configuration system.
121      */

122     private static boolean runtimeInitialized = false;
123
124     private static CacheCleaner cacheCleaner;
125
126     /**
127      * Default Constructor. Should actually only really be called by getInstance(), and
128      * it will eventually become protected
129      */

130     public CacheManager() {
131         super();
132
133         runtimeInitialized = (ExpressoRuntimeMap.getDefaultRuntime() != null);
134
135         if (!runtimeInitialized) {
136             cacheLists = new FastHashMap();
137             thisContextPath = ConfigManager.getWebAppDir();
138             cacheCleaner = new CacheCleaner();
139             cacheLists.setFast(false);
140
141             for (Enumeration JavaDoc e = ConfigManager.getAllConfigKeys(); e.hasMoreElements();) {
142                 String JavaDoc oneContext = (String JavaDoc) e.nextElement();
143                 DefaultCacheManager dcm = new DefaultCacheManager();
144                 dcm.initialize();
145                 cacheLists.put(oneContext, dcm);
146                 cacheCleaner.registerCacheSystem(dcm);
147             }
148             cacheLists.setFast(true);
149             cacheCleaner.setDaemon(true);
150             cacheCleaner.setName("Cache Cleaner");
151             cacheCleaner.setPriority(Thread.MIN_PRIORITY);
152             cacheCleaner.start();
153         }
154     } /* CacheManager() */
155
156     /**
157      * <p/>
158      * Singleton instantiation. First step in migrating away from
159      * static methods.</p>
160      * <p/>
161      * Ideally call this and operate on the instance() instead of the static
162      * member variables.</p>
163      *
164      * @return the instance of the CacheManager
165      */

166     public synchronized static CacheManager getInstance() {
167         if (theInstance == null) {
168             theInstance = new CacheManager();
169         }
170
171         return theInstance;
172     }
173
174     /**
175      * Retrieve the cache system appropriate for the data context
176      *
177      * @param dataContext the data context to retrieve the cache system for
178      * @return Cache system or null in the Component system when caching is
179      * not enabled.
180      */

181     public final static CacheSystem getCacheSystem(String JavaDoc dataContext) {
182         if (dataContext == null || dataContext.length() == 0) {
183             dataContext = "default";
184         }
185
186         if (CacheManager.runtimeInitialized) {
187             LocatorUtils lc = new LocatorUtils(ExpressoRuntimeMap.getDefaultRuntime());
188             return (CacheSystem) lc.locateComponent(dataContext + ".Cache");
189         } else {
190             return (CacheSystem) cacheLists.get(dataContext);
191         }
192     }
193
194     /**
195      * Destroys the CacheManager. clears all caches, closes all cache sync instances
196      * and all the other miscellaneous cleanup.
197      */

198     public synchronized static void destroy() {
199         if (runtimeInitialized) {
200 //The component system itself takes care of the runtime
201
return;
202         } else {
203             cacheCleaner.interrupt();
204             try {
205                 cacheCleaner.join();
206             } catch (InterruptedException JavaDoc ex) {
207                 log.info("Interrupted while waiting for cache cleaner to exit");
208             }
209
210             for (Iterator JavaDoc i = cacheLists.values().iterator(); i.hasNext();) {
211                 CacheSystem cs = (CacheSystem) i.next();
212                 if (cs instanceof ComponentLifecycle) {
213                     ((ComponentLifecycle) cs).destroy();
214                 }
215             }
216
217             cacheLists.clear();
218         }
219
220         System.gc(); //Clean up the memory that cache manager held.
221
}
222
223     /**
224      * Adds a <code>Cacheable</code> item into the cache
225      *
226      * @param dataContext the data context that this item is to reside in.
227      * @param cacheName The name of the cache.
228      * @param newItem The new item to add to the cache
229      * @throws CacheException upon error inserting into the system
230      */

231     public static void addItem(String JavaDoc dataContext, String JavaDoc cacheName,
232                                Cacheable newItem)
233             throws CacheException {
234         CacheSystem cs = getCacheSystem(dataContext);
235         if (cs == null) {
236             return;
237         } else {
238             cs.addItem(cacheName, newItem);
239         }
240     } /* addItem(String, String, Cacheable) */
241
242
243     /**
244      * Adds an item to the cache named by parameter cacheName
245      *
246      * @param dataContext The data context that this cache is for
247      * @param cacheName The name of the cache to store the object in
248      * @param newItem The new item to add to the cache
249      * @param expiry The time in miliseconds that this cache item will expire
250      * @throws CacheException if there's an error inserting the item into the
251      * cache
252      */

253     public static void addItem(String JavaDoc dataContext, String JavaDoc cacheName,
254                                Cacheable newItem, long expiry)
255             throws CacheException {
256         CacheSystem cs = getCacheSystem(dataContext);
257         if (cs == null) {
258             return;
259         } else {
260             cs.addItem(cacheName, newItem, expiry);
261         }
262     } /* addItem(String, String, Cacheable, long) */
263
264
265     /**
266      * Specify a relationship between caches. Whenever an add clear or
267      * remove event is sent to the specified cache, the listener is
268      * cleared as well. Adding a listener implies the relationship between
269      * the caches for ALL db contexts.
270      *
271      * @param listener The classname of the listener
272      * @param listenTo The name of the cache to listen to.
273      */

274     public static void addListener(String JavaDoc listener, String JavaDoc listenTo) {
275
276         for (Enumeration JavaDoc e = ConfigManager.getAllConfigKeys(); e.hasMoreElements();) {
277             String JavaDoc oneContext = (String JavaDoc) e.nextElement();
278             CacheSystem cs = getCacheSystem(oneContext);
279             if (cs == null) {
280                 continue;
281             } else {
282                 cs.addListener(listener, listenTo);
283             }
284         }
285     } /* addListener(String, String) */
286
287     /**
288      * Removes all cache items for a particular data context
289      *
290      * @param dataContext The data context to clear all items for.
291      * @throws CacheException CacheException if there's an error clearing the
292      * cache
293      */

294     public static void clear(String JavaDoc dataContext)
295             throws CacheException {
296         CacheSystem cs = getCacheSystem(dataContext);
297         if (cs == null) {
298             log.warn("Unable to locate cache system for data context " + dataContext);
299             return;
300         } else {
301             cs.clear();
302         }
303     } /* clear(String) */
304
305
306     /**
307      * Clears all caches in this db context but doesn't notify any listeners
308      *
309      * @param dataContext The data context that this cache is mapped to
310      */

311     public static void clearNoNotify(String JavaDoc dataContext) {
312         CacheSystem cs = getCacheSystem(dataContext);
313         if (cs == null) {
314             log.warn("Unable to locate cache system for data context " + dataContext);
315             return;
316         } else {
317             cs.clearNoNotify();
318         }
319     } /* clearNoNotify(String) */
320
321
322     /**
323      * Clear's the named cache.
324      *
325      * @param dataContext The dbContext of the cache
326      * @param cacheName The name of the cache to clear
327      * @throws CacheException if there's an error clearing the cache.
328      */

329     public static void clear(String JavaDoc dataContext, String JavaDoc cacheName)
330             throws CacheException {
331         CacheSystem cs = getCacheSystem(dataContext);
332         if (cs == null) {
333             log.warn("Unable to locate cache system for data context " + dataContext);
334             return;
335         } else {
336             cs.clear(cacheName);
337         }
338     } /* clear(String, String) */
339
340     /**
341      * Clear the named cache, but don't send the remote system notifications.
342      * This method actually removes the cache from the list of available caches
343      *
344      * @param dataContext The dbContext that the cache is attached to
345      * @param cacheName The name of the cache
346      */

347     public static void clearNoNotify(String JavaDoc dataContext, String JavaDoc cacheName) {
348         CacheSystem cs = getCacheSystem(dataContext);
349         if (cs == null) {
350             return;
351         } else {
352             cs.clearNoNotify(cacheName);
353         }
354     } /* clearNoNotify(String, String) */
355
356
357     /**
358      * Creates a cache as specified by the parameters listed.
359      * Creation date: (9/7/00 2:18:09 PM)
360      *
361      * @param dataContext java.lang.String The data context for your app
362      * @param cacheName java.lang.String the name of the cache
363      * @param ordered boolean true if you want an ordered cache such as for
364      * ValidValues
365      * @return the newly instantiated Cache
366      */

367     public static Cache createCache(String JavaDoc dataContext, String JavaDoc cacheName,
368                                     boolean ordered)
369             throws CacheException {
370         CacheSystem cs = getCacheSystem(dataContext);
371         if (cs == null) {
372             log.warn("Unable to locate cache system for data context " + dataContext);
373             return null;
374         } else {
375             return cs.createCache(cacheName, ordered);
376         }
377
378     } /* createCache(String, String, boolean) */
379
380
381     /**
382      * Creates a cache defined by whether the cache is to be ordered, it's name
383      * and it's maximum size.
384      * Creation date: (9/7/00 2:18:09 PM)
385      *
386      * @param dataContext java.lang.String The dbcontext that this cache is for
387      * @param cacheName java.lang.String The name of the cache
388      * @param ordered boolean True if you wish for an ordered cache.
389      * @param maxSize The maximum size of the cache
390      * @return the newly instantiated cache
391      */

392     public static Cache createCache(String JavaDoc dataContext, String JavaDoc cacheName,
393                                     boolean ordered, int maxSize)
394             throws CacheException {
395
396         CacheSystem cs = getCacheSystem(dataContext);
397         if (cs == null) {
398             log.warn("Unable to locate cache system for data context " + dataContext);
399             return null;
400         } else {
401             return cs.createCache(cacheName, ordered, maxSize);
402         }
403
404     } /* createCache(String, String, boolean, int) */
405
406
407     /**
408      * Displays the cache status. Currently this is only really used for
409      * debugging purposes.
410      * Creation date: (9/7/00 2:44:05 PM)
411      */

412     public static void displayStatus() {
413         Runtime JavaDoc r = Runtime.getRuntime();
414         double avail = r.totalMemory();
415         double free = r.freeMemory();
416         double pfree = ((free / avail) * 100.000);
417
418         if (log.isInfoEnabled()) {
419             log.info("Cache Status");
420             log.info("Free memory " + free + ", Available " + avail +
421                     ", Percent free " + pfree + "%");
422         }
423
424         String JavaDoc oneConfigKey = null;
425
426         for (Enumeration JavaDoc e = ConfigManager.getAllConfigKeys();
427              e.hasMoreElements();) {
428             oneConfigKey = (String JavaDoc) e.nextElement();
429             CacheSystem cs = CacheManager.getCacheSystem(oneConfigKey);
430             if (cs != null) {
431                 cs.displayStatus();
432             } else {
433                 continue;
434             }
435 // ((DefaultCacheManager)getCacheSystem(oneConfigKey)).displayStatus();
436
} /* for each config key */
437
438     } /* displayStatus() */
439
440     /**
441      * Checks to see if the cache already exists. One big note about this is
442      * that unless you already have a ReadLock, the cache may or may not exist
443      * once you go to put your data in the cache. Buyer beware.
444      *
445      * @param dataContext The dbContext that this cache is hooked to
446      * @param cacheName The name of the cache
447      * @return true if the named cache already exists in this data context
448      */

449     public static boolean existsCache(String JavaDoc dataContext, String JavaDoc cacheName) {
450         CacheSystem cs = getCacheSystem(dataContext);
451         if (cs == null) {
452             return false;
453         } else {
454             return cs.existsCache(cacheName);
455         }
456 // return getCacheSystem(dataContext).existsCache(cacheName);
457
} /* existsCache(String, String) */
458
459     /**
460      * Get the names of all of the Caches being held for a particular context
461      *
462      * @param dataContext The dbContext to get the cache names for.
463      * @return java.util.Iterator
464      */

465     public static Iterator JavaDoc getAllCacheNamesIterator(String JavaDoc dataContext) {
466         CacheSystem cs = getCacheSystem(dataContext);
467         if (cs == null) {
468             return new java.util.ArrayList JavaDoc(0).iterator();
469         } else {
470             return cs.getAllCacheNames().iterator();
471         }
472     } /* getAllCacheNames(String) */
473
474
475     /**
476      * Get a particular item in the cache
477      *
478      * @param dataContext The dbContext for this cache
479      * @param cacheName The name of the cache
480      * @param valueKey The particular item within the cache to get
481      * @return a Cacheable object or null if it doesn't exist in the cache
482      */

483     public static Cacheable getItem(String JavaDoc dataContext, String JavaDoc cacheName,
484                                     String JavaDoc valueKey) {
485         CacheSystem cs = getCacheSystem(dataContext);
486         if (cs == null) {
487             return null;
488         } else {
489             return cs.getItem(cacheName, valueKey);
490         }
491
492 // return getCacheSystem(dataContext).getItem(cacheName,valueKey);
493
} /* getItem(String, String, String) */
494
495     /**
496      * Return all of the items in a cache. If the cache was created as an ordered
497      * cache, the items will be in the order they were added. If not, they will be
498      * in no particular order.
499      * If there is no such cache or no items, null will be returned.
500      *
501      * @param dataContext The dbcontext for this cache
502      * @param cacheName The name of the cache to retrieve
503      * @return java.util.Vector of Cacheable items
504      */

505     public static Vector JavaDoc getItems(String JavaDoc dataContext, String JavaDoc cacheName) {
506         CacheSystem cs = getCacheSystem(dataContext);
507         if (cs == null) {
508             return null;
509         } else {
510             java.util.List JavaDoc l = getCacheSystem(dataContext).getItems(cacheName);
511             if (l == null) {
512                 return null;
513             } else {
514                 if (l instanceof java.util.Vector JavaDoc) {
515                     return (Vector JavaDoc) l;
516                 } else {
517                     return new Vector JavaDoc(l);
518                 }
519             }
520         }
521
522 // java.util.List l = getCacheSystem(dataContext).getItems(cacheName);
523
// if (l == null) {
524
// return null;
525
// } else {
526
// return new Vector(l);
527
// }
528
// return new Vector(getCacheSystem(dataContext).getItems(cacheName));
529
} /* getItems(String, String) */
530
531     /**
532      * Return a count of the number of items in a cache. Return 0 if there is
533      * no such item
534      *
535      * @param dataContext the dbContext to retrieve from.
536      * @param cacheName The name of the cache
537      * @return an item count or zero if the cache doesn't exist or is empty;
538      */

539     public static int getItemCount(String JavaDoc dataContext, String JavaDoc cacheName) {
540         CacheSystem cs = getCacheSystem(dataContext);
541         if (cs == null) {
542             return 0;
543         } else {
544             return cs.getItemCount(cacheName);
545         }
546
547 // return getCacheSystem(dataContext).getItemCount(cacheName);
548
} /* getItemCount(String, String) */
549
550
551     /**
552      * Removes an item from the cache
553      *
554      * @param dataContext The data context for the cache
555      * @param cacheName The name of the cache
556      * @param itemToRemove the key of the item to remove
557      */

558     public static void removeItem(String JavaDoc dataContext, String JavaDoc cacheName,
559                                   Cacheable itemToRemove)
560             throws CacheException {
561         CacheSystem cs = getCacheSystem(dataContext);
562         if (cs == null) {
563             return;
564         } else {
565             cs.removeItem(cacheName, itemToRemove);
566         }
567 // getCacheSystem(dataContext).removeItem(cacheName,itemToRemove);
568

569     } /* removeItem(String, String, Cacheable) */
570
571
572     /**
573      * Removes an item out of the cache without notifying the cache listeners
574      *
575      * @param dataContext The name of the data context
576      * @param cacheName The cache name
577      * @param itemToRemove the key in the cache that has been modified
578      * @throws CacheException Upon error removing the item from the cache
579      */

580     public static void removeItemNoNotify(String JavaDoc dataContext, String JavaDoc cacheName,
581                                           Cacheable itemToRemove)
582             throws CacheException {
583         CacheSystem cs = getCacheSystem(dataContext);
584         if (cs == null) {
585             return;
586         } else {
587             cs.removeItemNoNotify(cacheName, itemToRemove);
588         }
589
590 // getCacheSystem(dataContext).removeItemNoNotify(cacheName,itemToRemove);
591
} /* removeItemNoNotify(String, String, Cacheable) */
592
593
594     /**
595      * Sets a cache to have the particular items specified in itemList.
596      *
597      * @param dataContext The dbContext for the cache
598      * @param cacheName The name of the cache
599      * @param itemList The items to set into the cache
600      * @throws CacheException if there's an error setting the items.
601      */

602     public static void setItems(String JavaDoc dataContext, String JavaDoc cacheName,
603                                 Vector JavaDoc itemList)
604             throws CacheException {
605         CacheSystem cs = getCacheSystem(dataContext);
606         if (cs == null) {
607             return;
608         } else {
609             cs.setItems(cacheName, itemList);
610         }
611
612 // getCacheSystem(dataContext).setItems(cacheName,itemList);
613
} /* setItems(String, String, Vector) */
614 }
615
616 /* CacheManager */
617
Popular Tags