KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > store > impl > EHDefaultStore


1 /*
2  * Copyright 2004,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not 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.
15  */

16 package org.apache.cocoon.components.store.impl;
17
18 import java.io.File JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.net.URL JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.List JavaDoc;
25
26 import net.sf.ehcache.Cache;
27 import net.sf.ehcache.CacheException;
28 import net.sf.ehcache.CacheManager;
29 import net.sf.ehcache.Element;
30
31 import org.apache.cocoon.Constants;
32 import org.apache.cocoon.util.IOUtils;
33
34 import org.apache.avalon.framework.activity.Disposable;
35 import org.apache.avalon.framework.activity.Initializable;
36 import org.apache.avalon.framework.context.Context;
37 import org.apache.avalon.framework.context.ContextException;
38 import org.apache.avalon.framework.context.Contextualizable;
39 import org.apache.avalon.framework.logger.AbstractLogEnabled;
40 import org.apache.avalon.framework.parameters.ParameterException;
41 import org.apache.avalon.framework.parameters.Parameterizable;
42 import org.apache.avalon.framework.parameters.Parameters;
43 import org.apache.avalon.framework.service.ServiceException;
44 import org.apache.avalon.framework.service.ServiceManager;
45 import org.apache.avalon.framework.service.Serviceable;
46 import org.apache.avalon.framework.thread.ThreadSafe;
47 import org.apache.excalibur.store.Store;
48 import org.apache.excalibur.store.StoreJanitor;
49
50 /**
51  * Store implementation based on EHCache.
52  * (http://ehcache.sourceforge.net/)
53  */

54 public class EHDefaultStore extends AbstractLogEnabled
55 implements Store, Contextualizable, Serviceable, Parameterizable, Initializable, Disposable, ThreadSafe {
56
57     // ---------------------------------------------------- Constants
58

59     private static final String JavaDoc CONFIG_FILE = "org/apache/cocoon/components/store/impl/ehcache.xml";
60
61     private static int instanceCount = 0;
62
63     // ---------------------------------------------------- Instance variables
64

65     private Cache cache;
66     private CacheManager cacheManager;
67
68     private final String JavaDoc cacheName;
69
70     // configuration options
71
private int maxObjects;
72     private boolean overflowToDisk;
73
74     /** The service manager */
75     private ServiceManager manager;
76     
77     /** The store janitor */
78     private StoreJanitor storeJanitor;
79
80     private File JavaDoc workDir;
81     private File JavaDoc cacheDir;
82
83     // ---------------------------------------------------- Lifecycle
84

85     public EHDefaultStore() {
86         instanceCount++;
87         this.cacheName = "cocoon-ehcache-" + instanceCount;
88     }
89
90     /* (non-Javadoc)
91      * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
92      */

93     public void contextualize(Context context) throws ContextException {
94         this.workDir = (File JavaDoc)context.get(Constants.CONTEXT_WORK_DIR);
95         this.cacheDir = (File JavaDoc)context.get(Constants.CONTEXT_CACHE_DIR);
96     }
97
98     /* (non-Javadoc)
99      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
100      */

101     public void service(ServiceManager aManager) throws ServiceException {
102         this.manager = aManager;
103         this.storeJanitor = (StoreJanitor) this.manager.lookup(StoreJanitor.ROLE);
104     }
105
106     /**
107      * Configure the store. The following options can be used:
108      * <ul>
109      * <li><code>maxobjects</code> (10000) - The maximum number of in-memory objects.</li>
110      * <li><code>overflow-to-disk</code> (true) - Whether to spool elements to disk after
111      * maxobjects has been exceeded.</li>
112      * <li><code>use-cache-directory</code> (false) - If true the <i>cache-directory</i>
113      * context entry will be used as the location of the disk store.
114      * Within the servlet environment this is set in web.xml.</li>
115      * <li><code>use-work-directory</code> (false) - If true the <i>work-directory</i>
116      * context entry will be used as the location of the disk store.
117      * Within the servlet environment this is set in web.xml.</li>
118      * <li><code>directory</code> - Specify an alternative location of the disk store.
119      * </ul>
120      */

121     public void parameterize(Parameters parameters) throws ParameterException {
122
123         this.maxObjects = parameters.getParameterAsInteger("maxobjects", 10000);
124         this.overflowToDisk = parameters.getParameterAsBoolean("overflow-to-disk", true);
125
126         try {
127             if (parameters.getParameterAsBoolean("use-cache-directory", false)) {
128                 if (this.getLogger().isDebugEnabled()) {
129                     getLogger().debug("Using cache directory: " + cacheDir);
130                 }
131                 setDirectory(cacheDir);
132             }
133             else if (parameters.getParameterAsBoolean("use-work-directory", false)) {
134                 if (this.getLogger().isDebugEnabled()) {
135                     getLogger().debug("Using work directory: " + workDir);
136                 }
137                 setDirectory(workDir);
138             }
139             else if (parameters.getParameter("directory", null) != null) {
140                 String JavaDoc dir = parameters.getParameter("directory");
141                 dir = IOUtils.getContextFilePath(workDir.getPath(), dir);
142                 if (this.getLogger().isDebugEnabled()) {
143                     getLogger().debug("Using directory: " + dir);
144                 }
145                 setDirectory(new File JavaDoc(dir));
146             }
147             else {
148                 try {
149                     // Legacy: use working directory by default
150
setDirectory(workDir);
151                 } catch (IOException JavaDoc e) {
152                 }
153             }
154         } catch (IOException JavaDoc e) {
155             throw new ParameterException("Unable to set directory", e);
156         }
157
158     }
159
160     /**
161      * Sets the cache directory
162      */

163     private void setDirectory(final File JavaDoc directory) throws IOException JavaDoc {
164         
165         /* Save directory path prefix */
166         String JavaDoc directoryPath = getFullFilename(directory);
167         directoryPath += File.separator;
168
169         /* If directory doesn't exist, create it anew */
170         if (!directory.exists()) {
171             if (!directory.mkdir()) {
172                 throw new IOException JavaDoc("Error creating store directory '" + directoryPath + "': ");
173             }
174         }
175
176         /* Is given file actually a directory? */
177         if (!directory.isDirectory()) {
178             throw new IOException JavaDoc("'" + directoryPath + "' is not a directory");
179         }
180
181         /* Is directory readable and writable? */
182         if (!(directory.canRead() && directory.canWrite())) {
183             throw new IOException JavaDoc("Directory '" + directoryPath + "' is not readable/writable");
184         }
185
186         System.setProperty("java.io.tmpdir", directoryPath);
187     }
188
189     /**
190      * Get the complete filename corresponding to a (typically relative)
191      * <code>File</code>.
192      * This method accounts for the possibility of an error in getting
193      * the filename's <i>canonical</i> path, returning the io/error-safe
194      * <i>absolute</i> form instead
195      *
196      * @param file The file
197      * @return The file's absolute filename
198      */

199     private static String JavaDoc getFullFilename(File JavaDoc file) {
200         try {
201             return file.getCanonicalPath();
202         }
203         catch (Exception JavaDoc e) {
204             return file.getAbsolutePath();
205         }
206     }
207
208     /**
209      * Initialize the CacheManager and created the Cache.
210      */

211     public void initialize() throws Exception JavaDoc {
212         URL JavaDoc configFileURL = Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE);
213         this.cacheManager = CacheManager.create(configFileURL);
214         this.cache = new Cache(this.cacheName, this.maxObjects, this.overflowToDisk, true, 0, 0, true, 120);
215         this.cacheManager.addCache(this.cache);
216         this.storeJanitor.register(this);
217     }
218     
219     /**
220      * Shutdown the CacheManager.
221      */

222     public void dispose() {
223         if (this.storeJanitor != null) {
224             this.storeJanitor.unregister(this);
225             this.manager.release(this.storeJanitor);
226             this.storeJanitor = null;
227         }
228         this.manager = null;
229         this.cacheManager.shutdown();
230         this.cacheManager = null;
231         this.cache = null;
232     }
233     
234     // ---------------------------------------------------- Store implementation
235

236     /* (non-Javadoc)
237      * @see org.apache.excalibur.store.Store#free()
238      */

239     public Object JavaDoc get(Object JavaDoc key) {
240         Object JavaDoc value = null;
241         try {
242             final Element element = this.cache.get((Serializable JavaDoc) key);
243             if (element != null) {
244                 value = element.getValue();
245             }
246         }
247         catch (CacheException e) {
248             getLogger().error("Failure retrieving object from store", e);
249         }
250         if (getLogger().isDebugEnabled()) {
251             if (value != null) {
252                 getLogger().debug("Found key: " + key);
253             }
254             else {
255                 getLogger().debug("NOT Found key: " + key);
256             }
257         }
258         return value;
259     }
260
261     /* (non-Javadoc)
262      * @see org.apache.excalibur.store.Store#free()
263      */

264     public void store(Object JavaDoc key, Object JavaDoc value) throws IOException JavaDoc {
265         if (getLogger().isDebugEnabled()) {
266             getLogger().debug("Store object " + value + " with key "+ key);
267         }
268
269         // without these checks we get cryptic "ClassCastException" messages
270
if(!(key instanceof Serializable JavaDoc)) {
271             throw new IOException JavaDoc("Key of class " + key.getClass().getName() + " is not Serializable");
272         }
273         if(!(value instanceof Serializable JavaDoc)) {
274             throw new IOException JavaDoc("Value of class " + value.getClass().getName() + " is not Serializable");
275         }
276
277         final Element element = new Element((Serializable JavaDoc) key, (Serializable JavaDoc) value);
278         this.cache.put(element);
279     }
280
281     /* (non-Javadoc)
282      * @see org.apache.excalibur.store.Store#free()
283      */

284     public void free() {
285         try {
286             final List JavaDoc keys = this.cache.getKeysNoDuplicateCheck();
287             if (!keys.isEmpty()) {
288                 // TODO find a way to get to the LRU one.
289
final Serializable JavaDoc key = (Serializable JavaDoc) keys.get(0);
290                 if (getLogger().isDebugEnabled()) {
291                     getLogger().debug("Freeing cache");
292                     getLogger().debug("key: " + key);
293                     getLogger().debug("value: " + this.cache.get(key));
294                 }
295                 if (!this.cache.remove(key)) {
296                     if (getLogger().isInfoEnabled()) {
297                         getLogger().info("Concurrency condition in free()");
298                     }
299                 }
300             }
301         }
302         catch (CacheException e) {
303             if (getLogger().isWarnEnabled()) {
304                 getLogger().warn("Error in free()", e);
305             }
306         }
307     }
308
309     /* (non-Javadoc)
310      * @see org.apache.excalibur.store.Store#remove(java.lang.Object)
311      */

312     public void remove(Object JavaDoc key) {
313         if (getLogger().isDebugEnabled()) {
314             getLogger().debug("Removing item " + key);
315         }
316         this.cache.remove((Serializable JavaDoc) key);
317     }
318
319     /* (non-Javadoc)
320      * @see org.apache.excalibur.store.Store#clear()
321      */

322     public void clear() {
323         if (getLogger().isDebugEnabled()) {
324             getLogger().debug("Clearing the store");
325         }
326         try {
327             this.cache.removeAll();
328         }
329         catch (IOException JavaDoc e) {
330             getLogger().error("Failure to clearing store", e);
331         }
332     }
333
334     /* (non-Javadoc)
335      * @see org.apache.excalibur.store.Store#containsKey(java.lang.Object)
336      */

337     public boolean containsKey(Object JavaDoc key) {
338         try {
339             return this.cache.get((Serializable JavaDoc) key) != null;
340         }
341         catch (CacheException e) {
342             getLogger().error("Failure retrieving object from store",e);
343         }
344         return false;
345     }
346
347     /* (non-Javadoc)
348      * @see org.apache.excalibur.store.Store#keys()
349      */

350     public Enumeration JavaDoc keys() {
351         List JavaDoc keys = null;
352         try {
353             keys = this.cache.getKeys();
354         }
355         catch (CacheException e) {
356             if (getLogger().isWarnEnabled()) {
357                 getLogger().warn("Error while getting cache keys", e);
358             }
359             keys = Collections.EMPTY_LIST;
360         }
361         return Collections.enumeration(keys);
362     }
363
364     /* (non-Javadoc)
365      * @see org.apache.excalibur.store.Store#size()
366      */

367     public int size() {
368         try {
369             return this.cache.getSize();
370         }
371         catch (CacheException e) {
372             if (getLogger().isWarnEnabled()) {
373                 getLogger().warn("Error while getting cache size", e);
374             }
375             return 0;
376         }
377     }
378
379 }
380
Popular Tags