KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > roller > util > cache > CacheManager


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. The ASF licenses this file to You
4  * under the Apache License, Version 2.0 (the "License"); you may not
5  * 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. For additional information regarding
15  * copyright in this work, please see the NOTICE file in the top level
16  * directory of this distribution.
17  */

18
19 package org.apache.roller.util.cache;
20
21 import java.util.Date JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.roller.RollerException;
30 import org.apache.roller.business.runnable.ContinuousWorkerThread;
31 import org.apache.roller.business.runnable.Job;
32 import org.apache.roller.config.RollerConfig;
33 import org.apache.roller.model.RollerFactory;
34 import org.apache.roller.model.UserManager;
35 import org.apache.roller.pojos.BookmarkData;
36 import org.apache.roller.pojos.CommentData;
37 import org.apache.roller.pojos.FolderData;
38 import org.apache.roller.pojos.RefererData;
39 import org.apache.roller.pojos.UserData;
40 import org.apache.roller.pojos.WeblogCategoryData;
41 import org.apache.roller.pojos.WeblogEntryData;
42 import org.apache.roller.pojos.WeblogTemplate;
43 import org.apache.roller.pojos.WebsiteData;
44
45
46 /**
47  * A governing class for Roller cache objects.
48  *
49  * The purpose of the CacheManager is to provide a level of abstraction between
50  * classes that use a cache and the implementations of a cache. This allows
51  * us to create easily pluggable cache implementations.
52  *
53  * The other purpose is to provide a single interface for interacting with all
54  * Roller caches at the same time. This is beneficial because as data
55  * changes in the system we often need to notify all caches that some part of
56  * their cached data needs to be invalidated, and the CacheManager makes that
57  * process easier.
58  */

59 public class CacheManager {
60     
61     private static Log log = LogFactory.getLog(CacheManager.class);
62     
63     private static final String JavaDoc DEFAULT_FACTORY =
64             "org.apache.roller.util.cache.ExpiringLRUCacheFactoryImpl";
65     
66     // a reference to the cache factory in use
67
private static CacheFactory cacheFactory = null;
68     
69     // a set of all registered cache handlers
70
private static Set JavaDoc cacheHandlers = new HashSet JavaDoc();
71     
72     // a map of all registered caches
73
private static Map JavaDoc caches = new HashMap JavaDoc();
74     
75     private static ContinuousWorkerThread futureInvalidationsThread = null;
76     
77     
78     static {
79         // lookup what cache factory we want to use
80
String JavaDoc classname = RollerConfig.getProperty("cache.defaultFactory");
81         
82         // use reflection to instantiate our factory class
83
try {
84             Class JavaDoc factoryClass = Class.forName(classname);
85             cacheFactory = (CacheFactory) factoryClass.newInstance();
86         } catch(ClassCastException JavaDoc cce) {
87             log.error("It appears that your factory does not implement "+
88                     "the CacheFactory interface",cce);
89         } catch(Exception JavaDoc e) {
90             log.error("Unable to instantiate cache factory ["+classname+"]"+
91                     " falling back on default", e);
92         }
93         
94         if(cacheFactory == null) try {
95             // hmm ... failed to load the specified cache factory
96
// lets try our default
97
Class JavaDoc factoryClass = Class.forName(DEFAULT_FACTORY);
98             cacheFactory = (CacheFactory) factoryClass.newInstance();
99         } catch(Exception JavaDoc e) {
100             log.fatal("Failed to instantiate a cache factory", e);
101             throw new RuntimeException JavaDoc(e);
102         }
103         
104         log.info("Cache Manager Initialized.");
105         log.info("Cache Factory = "+cacheFactory.getClass().getName());
106         
107         
108         // add custom handlers
109
String JavaDoc customHandlers = RollerConfig.getProperty("cache.customHandlers");
110         if(customHandlers != null && customHandlers.trim().length() > 0) {
111             
112             String JavaDoc[] cHandlers = customHandlers.split(",");
113             for(int i=0; i < cHandlers.length; i++) {
114                 // use reflection to instantiate the handler class
115
try {
116                     Class JavaDoc handlerClass = Class.forName(cHandlers[i]);
117                     CacheHandler customHandler =
118                             (CacheHandler) handlerClass.newInstance();
119                     
120                     cacheHandlers.add(customHandler);
121                 } catch(ClassCastException JavaDoc cce) {
122                     log.error("It appears that your handler does not implement "+
123                             "the CacheHandler interface",cce);
124                 } catch(Exception JavaDoc e) {
125                     log.error("Unable to instantiate cache handler ["+cHandlers[i]+"]", e);
126                 }
127             }
128         }
129         
130         // determine future invalidations peering window
131
Integer JavaDoc peerTime = new Integer JavaDoc(5);
132         String JavaDoc peerTimeString = RollerConfig.getProperty("cache.futureInvalidations.peerTime");
133         try {
134             peerTime = new Integer JavaDoc(peerTimeString);
135         } catch(NumberFormatException JavaDoc nfe) {
136             // bad input from config file, default already set
137
}
138         
139         // thread time is always 10 secs less than peer time to make sure
140
// there is a little overlap so we don't miss any entries
141
// this means every XX seconds we peer XX + 10 seconds into the future
142
int threadTime = (peerTime.intValue() * 60 * 1000) - (10 * 1000);
143         
144         // start up future invalidations job, running continuously
145
futureInvalidationsThread = new ContinuousWorkerThread("future invalidations thread", threadTime);
146         Job futureInvalidationsJob = new FuturePostingsInvalidationJob();
147         
148         // inputs
149
Map JavaDoc inputs = new HashMap JavaDoc();
150         inputs.put("peerTime", peerTime);
151         futureInvalidationsJob.input(inputs);
152         
153         // set job and start it
154
futureInvalidationsThread.setJob(futureInvalidationsJob);
155         futureInvalidationsThread.start();
156     }
157     
158     
159     // a non-instantiable class
160
private CacheManager() {}
161     
162     
163     /**
164      * Ask the CacheManager to construct a cache.
165      *
166      * Normally the CacheManager will use whatever CacheFactory has been
167      * chosen for the system via the cache.defaultFactory property.
168      * However, it is possible to override the use of the default factory by
169      * supplying a "factory" property to this method. The value should
170      * be the full classname for the factory you want to use for constructing
171      * the cache.
172      *
173      * example:
174      * factory -> org.apache.roller.util.cache.LRUCacheFactoryImpl
175      *
176      * This allows Roller admins the ability to choose a caching strategy to
177      * use for the whole system, but override it in certain places where they
178      * see fit. It also allows users to write their own caching modifications
179      * and have them used only by specific caches.
180      */

181     public static Cache constructCache(CacheHandler handler, Map JavaDoc properties) {
182         
183         log.debug("Constructing new cache with props "+properties);
184         
185         Cache cache = null;
186         
187         if(properties != null && properties.containsKey("factory")) {
188             // someone wants a custom cache instance
189
String JavaDoc classname = (String JavaDoc) properties.get("factory");
190             
191             try {
192                 // use reflection to instantiate the factory class
193
Class JavaDoc factoryClass = Class.forName(classname);
194                 CacheFactory factory = (CacheFactory) factoryClass.newInstance();
195                 
196                 // now ask for a new cache
197
cache = factory.constructCache(properties);
198             } catch(ClassCastException JavaDoc cce) {
199                 log.error("It appears that your factory ["+classname+
200                         "] does not implement the CacheFactory interface",cce);
201             } catch(Exception JavaDoc e) {
202                 log.error("Unable to instantiate cache factory ["+classname+
203                         "] falling back on default", e);
204             }
205         }
206         
207         if(cache == null) {
208             // ask our default cache factory for a new cache instance
209
cache = cacheFactory.constructCache(properties);
210         }
211         
212         if(cache != null) {
213             caches.put(cache.getId(), cache);
214             
215             // register the handler for this new cache
216
if(handler != null) {
217                 cacheHandlers.add(handler);
218             }
219         }
220
221         return cache;
222     }
223     
224     
225     /**
226      * Register a CacheHandler to listen for object invalidations.
227      *
228      * This is here so that it's possible to to add classes which would respond
229      * to object invalidations without necessarily having to create a cache.
230      *
231      * An example would be a handler designed to notify other machines in a
232      * cluster when an object has been invalidated, or possibly the search
233      * index management classes are interested in knowing when objects are
234      * invalidated.
235      */

236     public static void registerHandler(CacheHandler handler) {
237         
238         log.debug("Registering handler "+handler);
239         
240         if(handler != null) {
241             cacheHandlers.add(handler);
242         }
243     }
244     
245     
246     public static void invalidate(WeblogEntryData entry) {
247         
248         log.debug("invalidating entry = "+entry.getAnchor());
249         
250         Iterator JavaDoc handlers = cacheHandlers.iterator();
251         while(handlers.hasNext()) {
252             ((CacheHandler) handlers.next()).invalidate(entry);
253         }
254     }
255     
256     
257     public static void invalidate(WebsiteData website) {
258         
259         log.debug("invalidating website = "+website.getHandle());
260         
261         Iterator JavaDoc handlers = cacheHandlers.iterator();
262         while(handlers.hasNext()) {
263             ((CacheHandler) handlers.next()).invalidate(website);
264         }
265     }
266     
267     
268     public static void invalidate(BookmarkData bookmark) {
269         
270         log.debug("invalidating bookmark = "+bookmark.getId());
271         
272         Iterator JavaDoc handlers = cacheHandlers.iterator();
273         while(handlers.hasNext()) {
274             ((CacheHandler) handlers.next()).invalidate(bookmark);
275         }
276     }
277     
278     
279     public static void invalidate(FolderData folder) {
280         
281         log.debug("invalidating folder = "+folder.getId());
282         
283         Iterator JavaDoc handlers = cacheHandlers.iterator();
284         while(handlers.hasNext()) {
285             ((CacheHandler) handlers.next()).invalidate(folder);
286         }
287     }
288     
289     
290     public static void invalidate(CommentData comment) {
291         
292         log.debug("invalidating comment = "+comment.getId());
293         
294         Iterator JavaDoc handlers = cacheHandlers.iterator();
295         while(handlers.hasNext()) {
296             ((CacheHandler) handlers.next()).invalidate(comment);
297         }
298     }
299     
300     
301     public static void invalidate(RefererData referer) {
302         
303         log.debug("invalidating referer = "+referer.getId());
304         
305         // NOTE: Invalidating an entire website for each referer is not
306
// good for our caching. This may need reevaluation later.
307
//lastExpiredCache.put(referer.getWebsite().getHandle(), new Date());
308

309         Iterator JavaDoc handlers = cacheHandlers.iterator();
310         while(handlers.hasNext()) {
311             ((CacheHandler) handlers.next()).invalidate(referer);
312         }
313     }
314     
315     
316     public static void invalidate(UserData user) {
317         
318         log.debug("invalidating user = "+user.getUserName());
319         
320         Iterator JavaDoc handlers = cacheHandlers.iterator();
321         while(handlers.hasNext()) {
322             ((CacheHandler) handlers.next()).invalidate(user);
323         }
324     }
325     
326     
327     public static void invalidate(WeblogCategoryData category) {
328         
329         log.debug("invalidating category = "+category.getId());
330         
331         Iterator JavaDoc handlers = cacheHandlers.iterator();
332         while(handlers.hasNext()) {
333             ((CacheHandler) handlers.next()).invalidate(category);
334         }
335     }
336     
337     
338     public static void invalidate(WeblogTemplate template) {
339         
340         log.debug("invalidating template = "+template.getId());
341         
342         Iterator JavaDoc handlers = cacheHandlers.iterator();
343         while(handlers.hasNext()) {
344             ((CacheHandler) handlers.next()).invalidate(template);
345         }
346     }
347
348     
349     /**
350      * Flush the entire cache system.
351      */

352     public static void clear() {
353         
354         // loop through all caches and trigger a clear
355
Cache cache = null;
356         Iterator JavaDoc cachesIT = caches.values().iterator();
357         while(cachesIT.hasNext()) {
358             cache = (Cache) cachesIT.next();
359             
360             cache.clear();
361         }
362     }
363     
364     
365     /**
366      * Flush a single cache.
367      */

368     public static void clear(String JavaDoc cacheId) {
369         
370         Cache cache = (Cache) caches.get(cacheId);
371         if(cache != null) {
372             cache.clear();
373         }
374     }
375     
376     
377     /**
378      * Compile stats from all registered caches.
379      *
380      * This is basically a hacky version of instrumentation which is being
381      * thrown in because we don't have a full instrumentation strategy yet.
382      * This is here with the full expectation that it will be replaced by
383      * something a bit more elaborate, like JMX.
384      */

385     public static Map JavaDoc getStats() {
386         
387         Map JavaDoc allStats = new HashMap JavaDoc();
388         
389         Cache cache = null;
390         Iterator JavaDoc cachesIT = caches.values().iterator();
391         while(cachesIT.hasNext()) {
392             cache = (Cache) cachesIT.next();
393             
394             allStats.put(cache.getId(), cache.getStats());
395         }
396         
397         return allStats;
398     }
399     
400     
401     /**
402      * Place to do any cleanup tasks for cache system.
403      */

404     public static void shutdown() {
405         
406         // stop our future invalidations thread
407
if(futureInvalidationsThread != null) {
408             futureInvalidationsThread.interrupt();
409         }
410     }
411     
412 }
413
Popular Tags