001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.store.impl;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.io.Serializable;
022: import java.util.Arrays;
023: import java.util.Enumeration;
024: import java.util.Properties;
025:
026: import org.apache.avalon.framework.activity.Disposable;
027: import org.apache.avalon.framework.activity.Initializable;
028: import org.apache.avalon.framework.context.Context;
029: import org.apache.avalon.framework.context.ContextException;
030: import org.apache.avalon.framework.context.Contextualizable;
031: import org.apache.avalon.framework.logger.AbstractLogEnabled;
032: import org.apache.avalon.framework.parameters.ParameterException;
033: import org.apache.avalon.framework.parameters.Parameterizable;
034: import org.apache.avalon.framework.parameters.Parameters;
035: import org.apache.avalon.framework.service.ServiceException;
036: import org.apache.avalon.framework.service.ServiceManager;
037: import org.apache.avalon.framework.service.Serviceable;
038: import org.apache.avalon.framework.thread.ThreadSafe;
039: import org.apache.cocoon.Constants;
040: import org.apache.cocoon.util.IOUtils;
041: import org.apache.commons.collections.iterators.IteratorEnumeration;
042: import org.apache.excalibur.store.Store;
043: import org.apache.excalibur.store.StoreJanitor;
044: import org.apache.jcs.access.GroupCacheAccess;
045: import org.apache.jcs.access.exception.CacheException;
046: import org.apache.jcs.engine.control.CompositeCache;
047: import org.apache.jcs.engine.control.CompositeCacheManager;
048: import org.apache.jcs.engine.memory.MemoryCache;
049:
050: /**
051: * This is the default store implementation based on JCS
052: * http://jakarta.apache.org/jcs/BasicJCSConfiguration.html
053: *
054: * @version $Id: JCSDefaultStore.java 433543 2006-08-22 06:22:54Z crossley $
055: */
056: public class JCSDefaultStore extends AbstractLogEnabled implements
057: Store, Contextualizable, Parameterizable, Initializable,
058: Disposable, ThreadSafe, Serviceable {
059:
060: /** The JCS configuration properties */
061: protected Properties properties;
062:
063: /** The JCS region name */
064: protected String region;
065:
066: /** JCS Cache manager */
067: private CompositeCacheManager cacheManager;
068:
069: /** The Java Cache System object */
070: private JCSCacheAccess jcs;
071:
072: /** The location of the JCS default properties file */
073: private static final String DEFAULT_PROPERTIES = "org/apache/cocoon/components/store/default.ccf";
074:
075: /** The context containing the work and the cache directory */
076: private Context context;
077:
078: /** Service Manager */
079: private ServiceManager manager;
080:
081: /** Store janitor */
082: private StoreJanitor janitor;
083:
084: /* (non-Javadoc)
085: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
086: */
087: public void contextualize(Context aContext) throws ContextException {
088: this .context = aContext;
089: }
090:
091: /* (non-Javadoc)
092: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
093: */
094: public void service(ServiceManager aManager)
095: throws ServiceException {
096: this .manager = aManager;
097: this .janitor = (StoreJanitor) this .manager
098: .lookup(StoreJanitor.ROLE);
099: }
100:
101: /* (non-Javadoc)
102: * @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(org.apache.avalon.framework.parameters.Parameters)
103: */
104: public void parameterize(Parameters parameters)
105: throws ParameterException {
106: // TODO describe options
107: this .region = parameters.getParameter("region-name", "main");
108:
109: Properties defaults = new Properties();
110: try {
111: String defaultsFile = this .getDefaultPropertiesFile();
112: if (defaultsFile != null) {
113: defaults.load(Thread.currentThread()
114: .getContextClassLoader().getResourceAsStream(
115: defaultsFile));
116: }
117: } catch (IOException e) {
118: throw new ParameterException(
119: "Failure loading cache defaults", e);
120: }
121:
122: this .properties = new Properties(defaults);
123: String[] names = parameters.getNames();
124: for (int i = 0; i < names.length; i++) {
125: if (names[i].startsWith("jcs.")) {
126: this .properties.put(names[i], parameters
127: .getParameter(names[i]));
128: }
129: }
130:
131: int maxobjects = parameters.getParameterAsInteger("maxobjects",
132: -1);
133: if (maxobjects != -1) {
134: String key = "jcs.region." + region
135: + ".cacheattributes.MaxObjects";
136: this .properties
137: .setProperty(key, String.valueOf(maxobjects));
138: }
139:
140: // get the directory to use
141: try {
142: final File workDir = (File) context
143: .get(Constants.CONTEXT_WORK_DIR);
144: if (parameters.getParameterAsBoolean("use-cache-directory",
145: false)) {
146: final File cacheDir = (File) context
147: .get(Constants.CONTEXT_CACHE_DIR);
148: if (getLogger().isDebugEnabled()) {
149: getLogger().debug(
150: "Using cache directory: " + cacheDir);
151: }
152: setDirectory(cacheDir);
153: } else if (parameters.getParameterAsBoolean(
154: "use-work-directory", false)) {
155: if (getLogger().isDebugEnabled()) {
156: getLogger().debug(
157: "Using work directory: " + workDir);
158: }
159: setDirectory(workDir);
160: } else if (parameters.getParameter("directory", null) != null) {
161: String dir = parameters.getParameter("directory");
162: dir = IOUtils
163: .getContextFilePath(workDir.getPath(), dir);
164: if (getLogger().isDebugEnabled()) {
165: getLogger().debug("Using directory: " + dir);
166: }
167: setDirectory(new File(dir));
168: } else {
169: if (getLogger().isDebugEnabled()) {
170: getLogger().debug(
171: "Using default directory: " + workDir);
172: }
173: setDirectory(workDir);
174: }
175: } catch (ContextException ce) {
176: throw new ParameterException(
177: "Unable to get directory information from context.",
178: ce);
179: } catch (IOException e) {
180: throw new ParameterException("Unable to set directory", e);
181: }
182: }
183:
184: /* (non-Javadoc)
185: * @see org.apache.avalon.framework.activity.Initializable#initialize()
186: */
187: public void initialize() throws Exception {
188: this .cacheManager = CompositeCacheManager
189: .getUnconfiguredInstance();
190: this .cacheManager.configure(this .properties);
191: this .jcs = new JCSCacheAccess(cacheManager.getCache(region));
192: this .janitor.register(this );
193: }
194:
195: /* (non-Javadoc)
196: * @see org.apache.avalon.framework.activity.Disposable#dispose()
197: */
198: public void dispose() {
199: if (this .janitor != null) {
200: this .janitor.unregister(this );
201: }
202: if (this .jcs != null) {
203: this .jcs.dispose();
204: this .jcs = null;
205: }
206: if (this .cacheManager != null) {
207: this .cacheManager.release();
208: this .cacheManager = null;
209: }
210: this .properties = null;
211: if (this .manager != null) {
212: this .manager.release(this .janitor);
213: this .janitor = null;
214: this .manager = null;
215: }
216: }
217:
218: protected String getDefaultPropertiesFile() {
219: return DEFAULT_PROPERTIES;
220: }
221:
222: /**
223: * Sets the disk cache location.
224: */
225: private void setDirectory(final File directory) throws IOException {
226:
227: /* Does directory exist? */
228: if (!directory.exists()) {
229: /* Create it anew */
230: if (!directory.mkdirs()) {
231: throw new IOException(
232: "Error creating store directory '"
233: + directory.getAbsolutePath() + "'. ");
234: }
235: }
236:
237: /* Is given file actually a directory? */
238: if (!directory.isDirectory()) {
239: throw new IOException("'" + directory.getAbsolutePath()
240: + "' is not a directory");
241: }
242:
243: /* Is directory readable and writable? */
244: if (!(directory.canRead() && directory.canWrite())) {
245: throw new IOException("Directory '"
246: + directory.getAbsolutePath()
247: + "' is not readable/writable");
248: }
249:
250: this .properties.setProperty(
251: "jcs.auxiliary.DC.attributes.DiskPath", directory
252: .getAbsolutePath());
253: }
254:
255: // ---------------------------------------------------- Store implementation
256:
257: /* (non-Javadoc)
258: * @see org.apache.excalibur.store.Store#get(java.lang.Object)
259: */
260: public Object get(Object key) {
261: Object value = this .jcs.get(key);
262: if (getLogger().isDebugEnabled()) {
263: if (value != null) {
264: getLogger().debug("Found key: " + key);
265: } else {
266: getLogger().debug("NOT Found key: " + key);
267: }
268: }
269: return value;
270: }
271:
272: /* (non-Javadoc)
273: * @see org.apache.excalibur.store.Store#store(java.lang.Object, java.lang.Object)
274: */
275: public void store(Object key, Object value) throws IOException {
276:
277: if (getLogger().isDebugEnabled()) {
278: getLogger().debug(
279: "Store object " + value + " with key " + key);
280: }
281:
282: try {
283: this .jcs.put(key, value);
284: } catch (CacheException ce) {
285: getLogger().error("Failure storing object ", ce);
286: }
287: }
288:
289: /* (non-Javadoc)
290: * @see org.apache.excalibur.store.Store#free()
291: */
292: public void free() {
293: // TODO Find a better way
294: MemoryCache memoryCache = this .cacheManager.getCache(region)
295: .getMemoryCache();
296: Object[] keys = memoryCache.getKeyArray();
297: if (keys != null && keys.length > 0) {
298: final Object key = keys[0];
299: try {
300: memoryCache.remove((Serializable) key);
301: } catch (Exception ignore) {
302: }
303: }
304: }
305:
306: /* (non-Javadoc)
307: * @see org.apache.excalibur.store.Store#clear()
308: */
309: public void clear() {
310: if (getLogger().isDebugEnabled()) {
311: getLogger().debug("Clearing the store");
312: }
313: try {
314: this .jcs.remove();
315: } catch (CacheException ce) {
316: getLogger().error("Failure clearing store", ce);
317: }
318: }
319:
320: /* (non-Javadoc)
321: * @see org.apache.excalibur.store.Store#remove(java.lang.Object)
322: */
323: public void remove(Object key) {
324: if (getLogger().isDebugEnabled()) {
325: getLogger().debug("Removing item " + key);
326: }
327:
328: try {
329: this .jcs.remove(key);
330: } catch (CacheException ce) {
331: getLogger().error("Failure removing object", ce);
332: }
333: }
334:
335: /* (non-Javadoc)
336: * @see org.apache.excalibur.store.Store#containsKey(java.lang.Object)
337: */
338: public boolean containsKey(Object key) {
339: return this .jcs.get(key) != null;
340: }
341:
342: /* (non-Javadoc)
343: * @see org.apache.excalibur.store.Store#keys()
344: */
345: public Enumeration keys() {
346: // TODO Find a better way
347: final MemoryCache memoryCache = this .cacheManager.getCache(
348: region).getMemoryCache();
349: final Object[] keys = memoryCache.getKeyArray();
350: return new IteratorEnumeration(Arrays.asList(keys).iterator());
351: //return new IteratorEnumeration(this.jcs.getGroupKeys("").iterator());
352: }
353:
354: /* (non-Javadoc)
355: * @see org.apache.excalibur.store.Store#size()
356: */
357: public int size() {
358: // TODO Find a better way
359: MemoryCache memoryCache = this .cacheManager.getCache(region)
360: .getMemoryCache();
361: return memoryCache.getSize();
362: //return this.jcs.getSize();
363: }
364:
365: private static class JCSCacheAccess extends GroupCacheAccess {
366: private JCSCacheAccess(CompositeCache cacheControl) {
367: super (cacheControl);
368: }
369:
370: /*private int getSize() {
371: return super.cacheControl.getSize();
372: }*/
373: }
374: }
|