Clover coverage report - Coverage timestamp: do jan 22 2004 21:12:32 CET FRAMES NO FRAMES |
file stats: | LOC: | 386 |  | Methods: | 14
| NCLOC: | 150 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
AbstractCacheAdministrator.java | 35,7% | 45,6% | 71,4% | 46,4% |

1 |  |
     /*
2 |  |
      * Copyright (c) 2002-2003 by OpenSymphony
3 |  |
      * All rights reserved.
4 |  |
      */
5 |  |
     package com.opensymphony.oscache.base;
6 |  |
7 |  |
     import com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache;
8 |  |
     import com.opensymphony.oscache.base.events.*;
9 |  |
     import com.opensymphony.oscache.base.persistence.PersistenceListener;
10 |  |
     import com.opensymphony.oscache.util.StringUtil;
11 |  |
12 |  |
     import org.apache.commons.logging.Log;
13 |  |
     import org.apache.commons.logging.LogFactory;
14 |  |
15 |  |
     import java.util.*;
16 |  |
17 |  |
     import javax.swing.event.EventListenerList;
18 |  |
19 |  |
     /**
20 |  |
      * An AbstractCacheAdministrator defines an abstract cache administrator, implementing all
21 |  |
      * the basic operations related to the configuration of a cache, including assigning
22 |  |
      * any configured event handlers to cache objects.<p>
23 |  |
      *
24 |  |
      * Extend this class to implement a custom cache administrator.
25 |  |
      *
26 |  |
      * @version        $Revision: 1.6 $
27 |  |
      * @author        a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
28 |  |
      * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
29 |  |
      * @author <a href="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
30 |  |
      * @author <a href="mailto:fabian.crabus@gurulogic.de">Fabian Crabus</a>
31 |  |
      * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
32 |  |
      */
33 |  |
     public abstract class AbstractCacheAdministrator implements java.io.Serializable {
34 |  |
         private static transient final Log log = LogFactory.getLog(AbstractCacheAdministrator.class);
35 |  |
36 |  |
         /**
37 |  |
          * A boolean cache configuration property that indicates whether the cache
38 |  |
          * should cache objects in memory. Set this property to <code>false</code>
39 |  |
          * to disable in-memory caching.
40 |  |
          */
41 |  |
         protected final static String CACHE_MEMORY_KEY = "cache.memory";
42 |  |
43 |  |
         /**
44 |  |
          * An integer cache configuration property that specifies the maximum number
45 |  |
          * of objects to hold in the cache. Setting this to a negative value will
46 |  |
          * disable the capacity functionality - there will be no limit to the number
47 |  |
          * of objects that are held in cache.
48 |  |
          */
49 |  |
         protected final static String CACHE_CAPACITY_KEY = "cache.capacity";
50 |  |
51 |  |
         /**
52 |  |
          * A String cache configuration property that specifies the classname of
53 |  |
          * an alternate caching algorithm. This class must extend
54 |  |
          * {@link com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache}
55 |  |
          * By default caches will use {@link com.opensymphony.oscache.base.algorithm.LRUCache} as
56 |  |
          * the default algorithm if the cache capacity is set to a postive value, or
57 |  |
          * {@link com.opensymphony.oscache.base.algorithm.UnlimitedCache} if the
58 |  |
          * capacity is negative (ie, disabled).
59 |  |
          */
60 |  |
         protected final static String CACHE_ALGORITHM_KEY = "cache.algorithm";
61 |  |
62 |  |
         /**
63 |  |
          * A boolean cache configuration property that indicates whether the persistent
64 |  |
          * cache should be unlimited in size, or should be restricted to the same size
65 |  |
          * as the in-memory cache. Set this property to <code>true</code> to allow the
66 |  |
          * persistent cache to grow without bound.
67 |  |
          */
68 |  |
         protected final static String CACHE_DISK_UNLIMITED_KEY = "cache.unlimited.disk";
69 |  |
70 |  |
         /**
71 |  |
          * The configuration key that specifies whether we should block waiting for new
72 |  |
          * content to be generated, or just serve the old content instead. The default
73 |  |
          * behaviour is to serve the old content since that provides the best performance
74 |  |
          * (at the cost of serving slightly stale data).
75 |  |
          */
76 |  |
         protected final static String CACHE_BLOCKING_KEY = "cache.blocking";
77 |  |
78 |  |
         /**
79 |  |
          * A String cache configuration property that specifies the classname that will
80 |  |
          * be used to provide cache persistence. This class must extend {@link PersistenceListener}.
81 |  |
          */
82 |  |
         protected static final String PERSISTENCE_CLASS = "cache.persistence.class";
83 |  |
84 |  |
         /**
85 |  |
          * A String cache configuration property that holds a comma-delimited list of
86 |  |
          * classnames. These classes specify the event handlers that are to be applied
87 |  |
          * to the cache.
88 |  |
          */
89 |  |
         protected static final String CACHE_ENTRY_EVENT_LISTENERS = "cache.event.listeners";
90 |  |
         protected Config config = null;
91 |  |
92 |  |
         /**
93 |  |
          * Holds a list of all the registered event listeners. Event listeners are specified
94 |  |
          * using the {@link #CACHE_ENTRY_EVENT_LISTENERS} configuration key.
95 |  |
          */
96 |  |
         protected EventListenerList listenerList = new EventListenerList();
97 |  |
98 |  |
         /**
99 |  |
          * The algorithm class being used, as specified by the {@link #CACHE_ALGORITHM_KEY}
100 |  |
          * configuration property.
101 |  |
          */
102 |  |
         protected String algorithmClass = null;
103 |  |
104 |  |
         /**
105 |  |
          * The cache capacity (number of entries), as specified by the {@link #CACHE_CAPACITY_KEY}
106 |  |
          * configuration property.
107 |  |
          */
108 |  |
         protected int cacheCapacity = -1;
109 |  |
110 |  |
         /**
111 |  |
          * Whether the cache blocks waiting for content to be build, or serves stale
112 |  |
          * content instead. This value can be specified using the {@link #CACHE_BLOCKING_KEY}
113 |  |
          * configuration property.
114 |  |
          */
115 |  |
         private boolean blocking = false;
116 |  |
117 |  |
         /**
118 |  |
          * Whether or not to store the cache entries in memory. This is configurable using the
119 |  |
          * {@link com.opensymphony.oscache.base.AbstractCacheAdministrator#CACHE_MEMORY_KEY} property.
120 |  |
          */
121 |  |
         private boolean memoryCaching = true;
122 |  |
123 |  |
         /**
124 |  |
          * Whether the disk cache should be unlimited in size, or matched 1-1 to the memory cache.
125 |  |
          * This can be set via the {@link #CACHE_DISK_UNLIMITED_KEY} configuration property.
126 |  |
          */
127 |  |
         private boolean unlimitedDiskCache;
128 |  |
129 |  |
         /**
130 |  |
          * Create the AbstractCacheAdministrator.
131 |  |
          * This will initialize all values and load the properties from oscache.properties.
132 |  |
          */
133 | 0 |
         protected AbstractCacheAdministrator() {
134 | 0 |
             this(null);
135 |  |
         }
136 |  |
137 |  |
         /**
138 |  |
          * Create the AbstractCacheAdministrator.
139 |  |
          *
140 |  |
          * @param p the configuration properties for this cache.
141 |  |
          */
142 | 54 |
         protected AbstractCacheAdministrator(Properties p) {
143 | 54 |
             loadProps(p);
144 | 54 |
             initCacheParameters();
145 |  |
146 | 54 |
             if (log.isDebugEnabled()) {
147 | 0 |
                 log.debug("Constructed AbstractCacheAdministrator()");
148 |  |
             }
149 |  |
         }
150 |  |
151 |  |
         /**
152 |  |
          * Sets the algorithm to use for the cache.
153 |  |
          *
154 |  |
          * @see com.opensymphony.oscache.base.algorithm.LRUCache
155 |  |
          * @see com.opensymphony.oscache.base.algorithm.FIFOCache
156 |  |
          * @see com.opensymphony.oscache.base.algorithm.UnlimitedCache
157 |  |
          * @param newAlgorithmClass The class to use (eg.
158 |  |
          * <code>"com.opensymphony.oscache.base.algorithm.LRUCache"</code>)
159 |  |
          */
160 | 0 |
         public void setAlgorithmClass(String newAlgorithmClass) {
161 | 0 |
             algorithmClass = newAlgorithmClass;
162 |  |
         }
163 |  |
164 |  |
         /**
165 |  |
          * Indicates whether the cache will block waiting for new content to
166 |  |
          * be built, or serve stale content instead of waiting. Regardless of this
167 |  |
          * setting, the cache will <em>always</em> block if new content is being
168 |  |
          * created, ie, there's no stale content in the cache that can be served.
169 |  |
          */
170 | 60 |
         public boolean isBlocking() {
171 | 60 |
             return blocking;
172 |  |
         }
173 |  |
174 |  |
         /**
175 |  |
          * Sets the cache capacity (number of items). Administrator implementations
176 |  |
          * should override this method to ensure that their {@link Cache} objects
177 |  |
          * are updated correctly (by calling {@link AbstractConcurrentReadCache#setMaxEntries(int)}}}.
178 |  |
          *
179 |  |
          * @param newCacheCapacity The new capacity
180 |  |
          */
181 | 0 |
         protected void setCacheCapacity(int newCacheCapacity) {
182 | 0 |
             cacheCapacity = newCacheCapacity;
183 |  |
         }
184 |  |
185 |  |
         /**
186 |  |
          * Whether entries are cached in memory or not.
187 |  |
          * Default is true.
188 |  |
          * Set by the <code>cache.memory</code> property.
189 |  |
          *
190 |  |
          * @return Status whether or not memory caching is used.
191 |  |
          */
192 | 63 |
         public boolean isMemoryCaching() {
193 | 63 |
             return memoryCaching;
194 |  |
         }
195 |  |
196 |  |
         /**
197 |  |
          * Retrieves the value of one of the configuration properties.
198 |  |
          *
199 |  |
          * @param key The key assigned to the property
200 |  |
          * @return Property value, or <code>null</code> if the property could not be found.
201 |  |
          */
202 | 225 |
         public String getProperty(String key) {
203 | 225 |
             return config.getProperty(key);
204 |  |
         }
205 |  |
206 |  |
         /**
207 |  |
          * Indicates whether the unlimited disk cache is enabled or not.
208 |  |
          */
209 | 63 |
         public boolean isUnlimitedDiskCache() {
210 | 63 |
             return unlimitedDiskCache;
211 |  |
         }
212 |  |
213 |  |
         /**
214 |  |
          * Retrieves an array containing instances all of the {@link CacheEventListener}
215 |  |
          * classes that are specified in the OSCache configuration file.
216 |  |
          */
217 | 0 |
         protected CacheEventListener[] getCacheEventListeners() {
218 | 0 |
             CacheEventListener[] listeners = null;
219 |  |
220 | 0 |
             List classes = StringUtil.split(config.getProperty(CACHE_ENTRY_EVENT_LISTENERS), ',');
221 | 0 |
             listeners = new CacheEventListener[classes.size()];
222 |  |
223 | 0 |
             for (int i = 0; i < classes.size(); i++) {
224 | 0 |
                 String className = (String) classes.get(i);
225 |  |
226 | 0 |
                 try {
227 | 0 |
                     Class clazz = Class.forName(className);
228 |  |
229 | 0 |
                     if (!CacheEventListener.class.isAssignableFrom(clazz)) {
230 | 0 |
                         log.error("Specified listener class '" + className + "' does not implement CacheEventListener. Ignoring this listener.");
231 |  |
                     } else {
232 | 0 |
                         listeners[i] = (CacheEventListener) clazz.newInstance();
233 |  |
                     }
234 |  |
                 } catch (ClassNotFoundException e) {
235 | 0 |
                     log.error("CacheEventListener class '" + className + "' not found. Ignoring this listener.", e);
236 |  |
                 } catch (InstantiationException e) {
237 | 0 |
                     log.error("CacheEventListener class '" + className + "' could not be instantiated because it is not a concrete class. Ignoring this listener.", e);
238 |  |
                 } catch (IllegalAccessException e) {
239 | 0 |
                     log.error("CacheEventListener class '" + className + "' could not be instantiated because it is not public. Ignoring this listener.", e);
240 |  |
                 }
241 |  |
             }
242 |  |
243 | 0 |
             return listeners;
244 |  |
         }
245 |  |
246 |  |
         /**
247 |  |
          * If there is a <code>PersistenceListener</code> in the configuration
248 |  |
          * it will be instantiated and applied to the given cache object. If the
249 |  |
          * <code>PersistenceListener</code> cannot be found or instantiated, an
250 |  |
          * error will be logged but the cache will not have a persistence listener
251 |  |
          * applied to it and no exception will be thrown.<p>
252 |  |
          *
253 |  |
          * A cache can only have one <code>PersistenceListener</code>.
254 |  |
          *
255 |  |
          * @param cache the cache to apply the <code>PersistenceListener</code> to.
256 |  |
          *
257 |  |
          * @return the same cache object that was passed in.
258 |  |
          */
259 | 34 |
         protected Cache setPersistenceListener(Cache cache) {
260 | 34 |
             String persistenceClassname = config.getProperty(PERSISTENCE_CLASS);
261 |  |
262 | 34 |
             try {
263 | 34 |
                 Class clazz = Class.forName(persistenceClassname);
264 | 34 |
                 PersistenceListener persistenceListener = (PersistenceListener) clazz.newInstance();
265 |  |
266 | 34 |
                 cache.setPersistenceListener(persistenceListener.configure(config));
267 |  |
             } catch (ClassNotFoundException e) {
268 | 0 |
                 log.error("PersistenceListener class '" + persistenceClassname + "' not found. Check your configuration.", e);
269 |  |
             } catch (Exception e) {
270 | 0 |
                 log.error("Error instantiating class '" + persistenceClassname + "'", e);
271 |  |
             }
272 |  |
273 | 34 |
             return cache;
274 |  |
         }
275 |  |
276 |  |
         /**
277 |  |
          * Applies all of the recognised listener classes to the supplied
278 |  |
          * cache object. Recognised classes are {@link CacheEntryEventListener}
279 |  |
          * and {@link CacheMapAccessEventListener}.<p>
280 |  |
          *
281 |  |
          * @param cache The cache to apply the configuration to.
282 |  |
          * @return cache The configured cache object.
283 |  |
          */
284 | 54 |
         protected Cache configureStandardListeners(Cache cache) {
285 | 54 |
             if (config.getProperty(PERSISTENCE_CLASS) != null) {
286 | 34 |
                 cache = setPersistenceListener(cache);
287 |  |
             }
288 |  |
289 | 54 |
             if (config.getProperty(CACHE_ENTRY_EVENT_LISTENERS) != null) {
290 |  |
                 // Grab all the specified listeners and add them to the cache's
291 |  |
                 // listener list. Note that listeners that implement more than
292 |  |
                 // one of the event interfaces will be added multiple times.
293 | 0 |
                 CacheEventListener[] listeners = getCacheEventListeners();
294 |  |
295 | 0 |
                 for (int i = 0; i < listeners.length; i++) {
296 |  |
                     // Pass through the configuration to those listeners that require it
297 | 0 |
                     if (listeners[i] instanceof LifecycleAware) {
298 | 0 |
                         try {
299 | 0 |
                             ((LifecycleAware) listeners[i]).initialize(cache, config);
300 |  |
                         } catch (InitializationException e) {
301 | 0 |
                             log.error("Could not initialize listener '" + listeners[i].getClass().getName() + "'. Listener ignored.", e);
302 |  |
303 | 0 |
                             continue;
304 |  |
                         }
305 |  |
                     }
306 |  |
307 | 0 |
                     if (listeners[i] instanceof CacheEntryEventListener) {
308 | 0 |
                         cache.addCacheEventListener(listeners[i], CacheEntryEventListener.class);
309 |  |
                     }
310 |  |
311 | 0 |
                     if (listeners[i] instanceof CacheMapAccessEventListener) {
312 | 0 |
                         cache.addCacheEventListener(listeners[i], CacheMapAccessEventListener.class);
313 |  |
                     }
314 |  |
                 }
315 |  |
             }
316 |  |
317 | 54 |
             return cache;
318 |  |
         }
319 |  |
320 |  |
         /**
321 |  |
          * Finalizes all the listeners that are associated with the given cache object.
322 |  |
          * Any <code>FinalizationException</code>s that are thrown by the listeners will
323 |  |
          * be caught and logged.
324 |  |
          */
325 | 3 |
         protected void finalizeListeners(Cache cache) {
326 |  |
             // It's possible for cache to be null if getCache() was never called (CACHE-63)
327 | 3 |
             if (cache == null) {
328 | 0 |
                 return;
329 |  |
             }
330 |  |
331 | 3 |
             Object[] listeners = cache.listenerList.getListenerList();
332 |  |
333 | 3 |
             for (int i = listeners.length - 2; i >= 0; i -= 2) {
334 | 0 |
                 if (listeners[i + 1] instanceof LifecycleAware) {
335 | 0 |
                     try {
336 | 0 |
                         ((LifecycleAware) listeners[i + 1]).finialize();
337 |  |
                     } catch (FinalizationException e) {
338 | 0 |
                         log.error("Listener could not be finalized", e);
339 |  |
                     }
340 |  |
                 }
341 |  |
             }
342 |  |
         }
343 |  |
344 |  |
         /**
345 |  |
          * Initialize the core cache parameters from the configuration properties.
346 |  |
          * The parameters that are initialized are:
347 |  |
          * <ul>
348 |  |
          * <li>the algorithm class ({@link #CACHE_ALGORITHM_KEY})</li>
349 |  |
          * <li>the cache size ({@link #CACHE_CAPACITY_KEY})</li>
350 |  |
          * <li>whether the cache is blocking or non-blocking ({@link #CACHE_BLOCKING_KEY})</li>
351 |  |
          * <li>whether caching to memory is enabled ({@link #CACHE_MEMORY_KEY})</li>
352 |  |
          * <li>whether the persistent cache is unlimited in size ({@link #CACHE_DISK_UNLIMITED_KEY})</li>
353 |  |
          * </ul>
354 |  |
          */
355 | 54 |
         private void initCacheParameters() {
356 | 54 |
             algorithmClass = getProperty(CACHE_ALGORITHM_KEY);
357 |  |
358 | 54 |
             blocking = "true".equalsIgnoreCase(getProperty(CACHE_BLOCKING_KEY));
359 |  |
360 | 54 |
             String cacheMemoryStr = getProperty(CACHE_MEMORY_KEY);
361 |  |
362 | 54 |
             if ((cacheMemoryStr != null) && cacheMemoryStr.equalsIgnoreCase("false")) {
363 | 17 |
                 memoryCaching = false;
364 |  |
             }
365 |  |
366 | 54 |
             unlimitedDiskCache = Boolean.valueOf(config.getProperty(CACHE_DISK_UNLIMITED_KEY)).booleanValue();
367 |  |
368 | 54 |
             String cacheSize = getProperty(CACHE_CAPACITY_KEY);
369 |  |
370 | 54 |
             try {
371 | 54 |
                 if ((cacheSize != null) && (cacheSize.length() > 0)) {
372 | 34 |
                     cacheCapacity = Integer.parseInt(cacheSize);
373 |  |
                 }
374 |  |
             } catch (NumberFormatException e) {
375 | 0 |
                 log.error("The value supplied for the cache capacity, '" + cacheSize + "', is not a valid number. The cache capacity setting is being ignored.");
376 |  |
             }
377 |  |
         }
378 |  |
379 |  |
         /**
380 |  |
          * Load the properties file from the classpath.
381 |  |
          */
382 | 54 |
         private void loadProps(Properties p) {
383 | 54 |
             config = new Config(p);
384 |  |
         }
385 |  |
     }
386 |  |