KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > whirlycott > cache > CacheManager


1 /*
2  Copyright 2004 Philip Jacob <phil@whirlycott.com>
3  Seth Fitzsimmons <seth@note.amherst.edu>
4
5  Licensed under the Apache License, Version 2.0 (the "License");
6  you may not use this file except in compliance with the License.
7  You may obtain a copy of the License at
8
9  http://www.apache.org/licenses/LICENSE-2.0
10
11  Unless required by applicable law or agreed to in writing, software
12  distributed under the License is distributed on an "AS IS" BASIS,
13  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  See the License for the specific language governing permissions and
15  limitations under the License.
16  */

17
18 package com.whirlycott.cache;
19
20 import java.io.InputStream JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.LinkedList JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.w3c.dom.Document JavaDoc;
31 import org.w3c.dom.Element JavaDoc;
32 import org.w3c.dom.NodeList JavaDoc;
33
34 /**
35  * The CacheManager manages caches by creating and deleting them.
36  *
37  * @author Phil Jacob
38  */

39 public class CacheManager {
40
41     /**
42      * Holds a representation of the configuration.
43      */

44     protected final static Map JavaDoc configuration = new HashMap JavaDoc();
45
46     static String JavaDoc defaultCacheName = null;
47
48     /**
49      * Logger.
50      */

51     private final static Log log = LogFactory.getLog(CacheManager.class);
52
53     /*
54      * Got a better idea?
55      * http://www-106.ibm.com/developerworks/java/library/j-dcl.html?dwzone=java
56      */

57     protected final static CacheManager singleton = new CacheManager();
58
59     /**
60      * @return Returns the configurationProperties.
61      */

62     public static Map JavaDoc getConfiguration() {
63         return configuration;
64     }
65
66     /**
67      * Returns an instance of the CacheManager.
68      *
69      * @return An instance of the CacheManager.
70      */

71     public static CacheManager getInstance() {
72         return singleton;
73     }
74
75     /**
76      * Holds a Map of the caches that have been created from the config file.
77      */

78     protected final Map JavaDoc namedCaches = new HashMap JavaDoc();
79
80     /**
81      * Private constructor (singleton pattern).
82      *
83      */

84     private CacheManager() {
85         log.info(Messages.getString("CacheManager.creating_new_cache_manager_singleton")); //$NON-NLS-1$
86

87         try {
88             configure();
89
90         } catch (final CacheException e) {
91             // This should never happen.
92
log.fatal(e.getMessage(), e);
93         }
94     }
95
96     /**
97      * Initializes based on the whirlycache.xml configuration file.
98      *
99      * @throws CacheException
100      * When the CacheManager cannot be configured.
101      */

102     protected void configure() throws CacheException {
103         log.debug(Messages.getString("CacheManager.configuring_the_whirlycache")); //$NON-NLS-1$
104

105         // The ref to store the config file in.
106
Document JavaDoc doc;
107
108         // Try to load the specified conf file.
109
doc = loadConfigFile(Constants.CONFIG_FILE);
110
111         if (doc == null) {
112             log.warn("Could not load " + Constants.CONFIG_FILE + " file. Falling back to defaults."); //$NON-NLS-1$ //$NON-NLS-2$
113

114             // Ok, so go and load up the whirlycache-default.xml file.
115
doc = loadConfigFile(Constants.DEFAULT_CONFIG_FILE);
116
117             // Now this is unusual... can't find *any* config files.
118
if (doc == null) {
119                 final String JavaDoc msg = Messages.getString("CacheManager.cannot_load_default_config_file"); //$NON-NLS-1$
120
// log.fatal(msg);
121
throw new CacheException(msg);
122             }
123         }
124
125         /*
126          * Build a Map of Maps containing key/value pairs of the options in the
127          * config file. Admittedly, this kind of sucks and I would be open to
128          * seeing another way of doing this. - phil.
129          */

130         final Element JavaDoc root = doc.getDocumentElement();
131
132         defaultCacheName = root.getElementsByTagName("default-cache").item(0).getFirstChild().getNodeValue(); //$NON-NLS-1$
133
log.debug(Messages.getString("CacheManager.default_cache_name") + defaultCacheName); //$NON-NLS-1$
134

135         final NodeList JavaDoc caches = root.getElementsByTagName(Constants.CONFIG_CACHE);
136         for (int i = 0; i < caches.getLength(); i++) {
137             final CacheConfiguration configuration = new CacheConfiguration();
138             final Element JavaDoc elementCache = (Element JavaDoc) caches.item(i);
139             final String JavaDoc cacheName = elementCache.getAttribute(Constants.CONFIG_NAME);
140             log.debug(Messages.getString("CacheManager.cache_name") + cacheName); //$NON-NLS-1$
141
configuration.setName(cacheName);
142
143             final NodeList JavaDoc elementCacheAttributes = elementCache.getElementsByTagName("*"); //$NON-NLS-1$
144
for (int j = 0; j < elementCacheAttributes.getLength(); j++) {
145                 final Element JavaDoc att = (Element JavaDoc) elementCacheAttributes.item(j);
146
147                 final String JavaDoc nodeName = att.getNodeName();
148                 final String JavaDoc nodeValue = att.getFirstChild().getNodeValue();
149                 log.debug("Node name: " + nodeName + "; Node value: " + nodeValue);
150
151                 if (Constants.CONFIG_BACKEND.equals(nodeName)) {
152                     configuration.setBackend(nodeValue);
153
154                 } else if (Constants.CONFIG_TUNER_SLEEPTIME.equals(nodeName)) {
155                     configuration.setTunerSleepTime(new Integer JavaDoc(nodeValue).intValue());
156
157                 } else if (Constants.CONFIG_POLICY.equals(nodeName)) {
158                     configuration.setPolicy(nodeValue);
159
160                 } else if (Constants.CONFIG_MAXSIZE.equals(nodeName)) {
161                     configuration.setMaxSize(new Integer JavaDoc(nodeValue).intValue());
162
163                 } else {
164                     //One has to wonder what purpose this serves... - phil.
165
configuration.setAttribute(nodeName, nodeValue);
166                 }
167
168                 log.debug(" - " + nodeName + "=" + nodeValue); //$NON-NLS-1$ //$NON-NLS-2$
169
}
170
171             // Make all the caches listed in the config file.
172
log.debug(Messages.getString("CacheManager.making_named_caches")); //$NON-NLS-1$
173
createCache(configuration);
174
175             // Store the configured information.
176
CacheManager.configuration.put(elementCache.getAttribute(Constants.CONFIG_NAME), configuration);
177         }
178         
179         //Verify that the default cache has been created.
180
if (namedCaches.get(defaultCacheName) == null) {
181             final Object JavaDoc[] args = { defaultCacheName };
182             throw new CacheException(Messages.getCompoundString("CacheManager.nonexistent_default_cache", args)); //$NON-NLS-1$
183
}
184
185     }
186
187     /**
188      * Initialize a Cache.
189      *
190      * @param _configuration
191      * Configuration to initialize cache with.
192      * @return Empty Cache, ready for use.
193      * @throws CacheException
194      * When the cache cannot be initialized.
195      */

196     public Cache createCache(final CacheConfiguration _configuration) throws CacheException {
197         if (_configuration == null || _configuration.getName() == null) {
198             final String JavaDoc msg = Messages.getString("CacheManager.cache_name_cannot_be_null"); //$NON-NLS-1$
199
log.error(msg);
200             throw new CacheException(msg);
201         }
202
203         log.debug("Creating cache: " + _configuration.getName());
204         
205         final Cache c;
206
207         // Try to get an object out of the map
208
final Object JavaDoc o = namedCaches.get(_configuration.getName());
209
210         // If it's null, create one.
211
if (o == null) {
212             try {
213                 final String JavaDoc backend = _configuration.getBackend();
214                 log.debug("Cache backend is " + backend); //$NON-NLS-1$
215

216                 final Object JavaDoc possiblyC = Class.forName(backend).newInstance();
217
218                 if (!(possiblyC instanceof ManagedCache))
219                     throw new CacheException("Problem creating an instance of " + backend + " because it does not implement the ManagedCache interface."); //$NON-NLS-1$ //$NON-NLS-2$
220

221                 final ManagedCache managedCache = (ManagedCache) possiblyC;
222                 final CacheMaintenancePolicy policy = createPolicy(managedCache, _configuration);
223
224                 c = new CacheDecorator(managedCache, _configuration, new CacheMaintenancePolicy[] { policy });
225
226             } catch (final Exception JavaDoc e) {
227                 log.fatal(Messages.getString("CacheManager.cannot_create_instance_of_impl"), e); //$NON-NLS-1$
228
throw new CacheException(e);
229             }
230             namedCaches.put(_configuration.getName(), c);
231         } else {
232             // ... otherwise, return it.
233
c = (Cache) o;
234         }
235         return c;
236     }
237
238     /**
239      * Create a cache policy.
240      *
241      * @param managedCache
242      * @param configuration
243      * @return
244      * @throws CacheException
245      */

246     private CacheMaintenancePolicy createPolicy(final ManagedCache managedCache, final CacheConfiguration configuration) throws CacheException {
247         // Policy class config.
248
final String JavaDoc policyClass = configuration.getPolicy();
249
250         if (null == policyClass)
251             throw new IllegalArgumentException JavaDoc(Messages.getString("CacheManager.cache_config_get_policy_cannot_be_null")); //$NON-NLS-1$
252

253         final CacheMaintenancePolicy policy;
254         try {
255             policy = (CacheMaintenancePolicy) Class.forName(policyClass).newInstance();
256         } catch (Exception JavaDoc e) {
257             throw new CacheException("Cannot make an instance of policy class " + policyClass, e); //$NON-NLS-1$
258
}
259         if (policy != null) {
260             policy.setCache(managedCache);
261             policy.setConfiguration(configuration);
262         }
263
264         return policy;
265     }
266
267     /**
268      * Destroys the default cache.
269      *
270      * @throws CacheException
271      */

272     public void destroy() throws CacheException {
273         destroy(defaultCacheName);
274     }
275
276     /**
277      * Shut down an individual Cache.
278      *
279      * @param _cacheName
280      * cache to shut down.
281      * @throws CacheException
282      * if there was a problem shutting down the cache.
283      */

284     public void destroy(final String JavaDoc _cacheName) throws CacheException {
285         // If there is a cache, we ought to clear it first.
286
final CacheDecorator c = (CacheDecorator) getCache(_cacheName);
287         c.clear();
288         c.shutdown();
289         namedCaches.remove(_cacheName);
290     }
291
292     /**
293      * Gets a reference to the default Cache.
294      *
295      * @throws CacheException
296      * @return A reference to the default Cache.
297      */

298     public Cache getCache() throws CacheException {
299         return getCache(defaultCacheName);
300     }
301
302     /**
303      * Get a Cache by name.
304      *
305      * @param _name
306      * Name of cache to retrieve.
307      * @return Cache, specified by name.
308      * @throws CacheException
309      */

310     public Cache getCache(final String JavaDoc _name) throws CacheException {
311         // Short circuit an invalid name.
312
if (_name == null)
313             throw new IllegalArgumentException JavaDoc(Messages.getString("CacheManager.cannot_get_cache_with_null_name")); //$NON-NLS-1$
314

315         final Cache c = (Cache) namedCaches.get(_name);
316
317         if (c == null)
318             throw new CacheException("There is no cache called '" + _name + "'"); //$NON-NLS-1$ //$NON-NLS-2$
319

320         return c;
321     }
322
323     /**
324      * Loads the specified config file.
325      *
326      * @param _filename
327      * @return a Document object representing the structure of the config file
328      * @throws CacheException
329      */

330     protected Document JavaDoc loadConfigFile(final String JavaDoc _filename) throws CacheException {
331         if (_filename == null) {
332             throw new CacheException(Messages.getString("CacheManager.cannot_load_null_config_file")); //$NON-NLS-1$
333
}
334
335         final InputStream JavaDoc is = getClass().getResourceAsStream(_filename);
336         if (is != null) {
337             try {
338                 return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
339             } catch (final Exception JavaDoc e) {
340                 log.error("Problem loading " + _filename); //$NON-NLS-1$
341
}
342         }
343
344         // If we get this far, it means we haven't found the file.
345
return null;
346     }
347
348     /**
349      * Shuts down the manager of all of the Caches, which in turn shuts down all
350      * of the Caches.
351      *
352      * @throws CacheException
353      * When the Cache cannot be shutdown properly.
354      */

355     public void shutdown() throws CacheException {
356         synchronized (namedCaches) {
357             final Iterator JavaDoc cacheNames = new LinkedList JavaDoc(namedCaches.keySet()).iterator();
358             // Loop and shut down all the individual caches.
359
while (cacheNames.hasNext()) {
360                 try {
361                     destroy((String JavaDoc) cacheNames.next());
362                 } catch (CacheException e) {
363                     throw new CacheException(Messages.getString("CacheManager.problem_shutting_down")); //$NON-NLS-1$
364
}
365             }
366         }
367     }
368
369     /**
370      * Returns an array of the named caches that this CacheManager knows about
371      * (including the default cache).
372      *
373      * @return array of named caches
374      */

375     public String JavaDoc[] getCacheNames() {
376         final Object JavaDoc[] caches = namedCaches.keySet().toArray();
377         final int size = caches.length;
378         final String JavaDoc[] names = new String JavaDoc[size];
379         for (int i = 0; i < size; i++) {
380             names[i] = (String JavaDoc) caches[i];
381         }
382         return names;
383     }
384 }
Popular Tags