You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by un...@apache.org on 2004/09/30 13:05:21 UTC

svn commit: rev 47575 - in cocoon/branches/BRANCH_2_1_X: lib lib/core src/java/org/apache/cocoon src/java/org/apache/cocoon/components/store/impl src/webapp/WEB-INF

Author: unico
Date: Thu Sep 30 04:05:19 2004
New Revision: 47575

Added:
   cocoon/branches/BRANCH_2_1_X/lib/core/ehcache-1.0.jar
      - copied unchanged from rev 47396, cocoon/branches/BRANCH_2_1_X/src/blocks/scratchpad/lib/ehcache-1.0.jar
   cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/store/impl/EHDefaultStore.java   (contents, props changed)
   cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/store/impl/ehcache.xml
      - copied unchanged from rev 47573, cocoon/branches/BRANCH_2_1_X/src/blocks/scratchpad/java/org/apache/cocoon/components/store/ehcache.xml
Modified:
   cocoon/branches/BRANCH_2_1_X/lib/jars.xml
   cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/cocoon.roles
   cocoon/branches/BRANCH_2_1_X/src/webapp/WEB-INF/cocoon.xconf
Log:
move ehcache based store to the core and make it the default

Modified: cocoon/branches/BRANCH_2_1_X/lib/jars.xml
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/lib/jars.xml	(original)
+++ cocoon/branches/BRANCH_2_1_X/lib/jars.xml	Thu Sep 30 04:05:19 2004
@@ -568,7 +568,7 @@
     <title>EHCache</title>
     <description>Easy Hibernate Cache</description>
     <used-by>EHCache Store</used-by>
-    <lib>scratchpad/lib/ehcache-1.0.jar</lib>
+    <lib>core/ehcache-1.0.jar</lib>
     <homepage>http://ehcache.sourceforge.net/</homepage>
   </file>
 

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/cocoon.roles
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/cocoon.roles	(original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/cocoon.roles	Thu Sep 30 04:05:19 2004
@@ -77,7 +77,7 @@
   <!-- Stores: -->
   <role name="org.apache.excalibur.store.Store"
        shorthand="store"
-       default-class="org.apache.cocoon.components.store.impl.JCSDefaultStore"/>
+       default-class="org.apache.cocoon.components.store.impl.EHDefaultStore"/>
 
   <role name="org.apache.excalibur.store.Store/TransientStore"
         shorthand="transient-store"

Added: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/store/impl/EHDefaultStore.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/store/impl/EHDefaultStore.java	Thu Sep 30 04:05:19 2004
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2004,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.store.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheException;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.util.IOUtils;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameterizable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.excalibur.store.Store;
+import org.apache.excalibur.store.StoreJanitor;
+
+/**
+ * Store implementation based on EHCache.
+ * (http://ehcache.sourceforge.net/)
+ */
+public class EHDefaultStore extends AbstractLogEnabled 
+implements Store, Contextualizable, Serviceable, Parameterizable, Initializable, Disposable, ThreadSafe {
+
+    // ---------------------------------------------------- Constants
+
+    private static final String CONFIG_FILE = "org/apache/cocoon/components/store/impl/ehcache.xml";
+
+    private static int instanceCount = 0;
+
+    // ---------------------------------------------------- Instance variables
+
+    private Cache cache;
+    private CacheManager cacheManager;
+
+    private final String cacheName;
+
+    // configuration options
+    private int maxObjects;
+    private boolean overflowToDisk;
+
+    /** The service manager */
+    private ServiceManager manager;
+    
+    /** The store janitor */
+    private StoreJanitor storeJanitor;
+
+    private File workDir;
+    private File cacheDir;
+
+    // ---------------------------------------------------- Lifecycle
+
+    public EHDefaultStore() {
+        instanceCount++;
+        this.cacheName = "cocoon-ehcache-" + instanceCount;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
+     */
+    public void contextualize(Context context) throws ContextException {
+        this.workDir = (File)context.get(Constants.CONTEXT_WORK_DIR);
+        this.cacheDir = (File)context.get(Constants.CONTEXT_CACHE_DIR);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+     */
+    public void service(ServiceManager aManager) throws ServiceException {
+        this.manager = aManager;
+        this.storeJanitor = (StoreJanitor) this.manager.lookup(StoreJanitor.ROLE);
+    }
+
+    /**
+     * Configure the store. The following options can be used:
+     * <ul>
+     *  <li><code>maxobjects</code> (10000) - The maximum number of in-memory objects.</li>
+     *  <li><code>overflow-to-disk</code> (true) - Whether to spool elements to disk after
+     *   maxobjects has been exceeded.</li>
+     *  <li><code>use-cache-directory</code> (false) - If true the <i>cache-directory</i>
+     *   context entry will be used as the location of the disk store. 
+     *   Within the servlet environment this is set in web.xml.</li>
+     *  <li><code>use-work-directory</code> (false) - If true the <i>work-directory</i>
+     *   context entry will be used as the location of the disk store.
+     *   Within the servlet environment this is set in web.xml.</li>
+     *  <li><code>directory</code> - Specify an alternative location of the disk store.
+     * </ul>
+     */
+    public void parameterize(Parameters parameters) throws ParameterException {
+
+        this.maxObjects = parameters.getParameterAsInteger("maxobjects", 10000);
+        this.overflowToDisk = parameters.getParameterAsBoolean("overflow-to-disk", true);
+
+        try {
+            if (parameters.getParameterAsBoolean("use-cache-directory", false)) {
+                if (this.getLogger().isDebugEnabled()) {
+                    getLogger().debug("Using cache directory: " + cacheDir);
+                }
+                setDirectory(cacheDir);
+            }
+            else if (parameters.getParameterAsBoolean("use-work-directory", false)) {
+                if (this.getLogger().isDebugEnabled()) {
+                    getLogger().debug("Using work directory: " + workDir);
+                }
+                setDirectory(workDir);
+            }
+            else if (parameters.getParameter("directory", null) != null) {
+                String dir = parameters.getParameter("directory");
+                dir = IOUtils.getContextFilePath(workDir.getPath(), dir);
+                if (this.getLogger().isDebugEnabled()) {
+                    getLogger().debug("Using directory: " + dir);
+                }
+                setDirectory(new File(dir));
+            }
+            else {
+                try {
+                    // Legacy: use working directory by default
+                    setDirectory(workDir);
+                } catch (IOException e) {
+                }
+            }
+        } catch (IOException e) {
+            throw new ParameterException("Unable to set directory", e);
+        }
+
+    }
+
+    /**
+     * Sets the cache directory
+     */
+    private void setDirectory(final File directory) throws IOException  {
+        
+        /* Save directory path prefix */
+        String directoryPath = getFullFilename(directory);
+        directoryPath += File.separator;
+
+        /* If directory doesn't exist, create it anew */
+        if (!directory.exists()) {
+            if (!directory.mkdir()) {
+                throw new IOException("Error creating store directory '" + directoryPath + "': ");
+            }
+        }
+
+        /* Is given file actually a directory? */
+        if (!directory.isDirectory()) {
+            throw new IOException("'" + directoryPath + "' is not a directory");
+        }
+
+        /* Is directory readable and writable? */
+        if (!(directory.canRead() && directory.canWrite())) {
+            throw new IOException("Directory '" + directoryPath + "' is not readable/writable");
+        }
+
+        System.setProperty("java.io.tmpdir", directoryPath);
+    }
+
+    /**
+     * Get the complete filename corresponding to a (typically relative)
+     * <code>File</code>.
+     * This method accounts for the possibility of an error in getting
+     * the filename's <i>canonical</i> path, returning the io/error-safe
+     * <i>absolute</i> form instead
+     *
+     * @param file The file
+     * @return The file's absolute filename
+     */
+    private static String getFullFilename(File file) {
+        try {
+            return file.getCanonicalPath();
+        }
+        catch (Exception e) {
+            return file.getAbsolutePath();
+        }
+    }
+
+    /**
+     * Initialize the CacheManager and created the Cache.
+     */
+    public void initialize() throws Exception {
+        URL configFileURL = Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE);
+        this.cacheManager = CacheManager.create(configFileURL);
+        this.cache = new Cache(this.cacheName, this.maxObjects, this.overflowToDisk, true, 0, 0, true, 120);
+        this.cacheManager.addCache(this.cache);
+        this.storeJanitor.register(this);
+    }
+    
+    /**
+     * Shutdown the CacheManager.
+     */
+    public void dispose() {
+        if (this.storeJanitor != null) {
+            this.storeJanitor.unregister(this);
+            this.manager.release(this.storeJanitor);
+            this.storeJanitor = null;
+        }
+        this.manager = null;
+        this.cacheManager.shutdown();
+        this.cacheManager = null;
+        this.cache = null;
+    }
+    
+    // ---------------------------------------------------- Store implementation
+    
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#free()
+     */
+    public Object get(Object key) {
+        Object value = null;
+        try {
+            final Element element = this.cache.get((Serializable) key);
+            if (element != null) {
+                value = element.getValue();
+            }
+        }
+        catch (CacheException e) {
+            getLogger().error("Failure retrieving object from store", e);
+        }
+        if (getLogger().isDebugEnabled()) {
+            if (value != null) {
+                getLogger().debug("Found key: " + key);
+            } 
+            else {
+                getLogger().debug("NOT Found key: " + key);
+            }
+        }
+        return value;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#free()
+     */
+    public void store(Object key, Object value) throws IOException {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Store object " + value + " with key "+ key);
+        }
+        final Element element = new Element((Serializable) key, (Serializable) value);
+        this.cache.put(element);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#free()
+     */
+    public void free() {
+        try {
+            final List keys = this.cache.getKeysNoDuplicateCheck();
+            if (!keys.isEmpty()) {
+            	// TODO find a way to get to the LRU one.
+                final Serializable key = (Serializable) keys.get(0);
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("Freeing cache");
+                    getLogger().debug("key: " + key);
+                    getLogger().debug("value: " + this.cache.get(key));
+                }
+                if (!this.cache.remove(key)) {
+                    if (getLogger().isInfoEnabled()) {
+                        getLogger().info("Concurrency condition in free()");
+                    }
+                }
+            }
+        }
+        catch (CacheException e) {
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("Error in free()", e);
+            }
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#remove(java.lang.Object)
+     */
+    public void remove(Object key) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Removing item " + key);
+        }
+        this.cache.remove((Serializable) key);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#clear()
+     */
+    public void clear() {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Clearing the store");
+        }
+        try {
+            this.cache.removeAll();
+        }
+        catch (IOException e) {
+            getLogger().error("Failure to clearing store", e);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#containsKey(java.lang.Object)
+     */
+    public boolean containsKey(Object key) {
+        try {
+            return this.cache.get((Serializable) key) != null;
+        }
+        catch (CacheException e) {
+            getLogger().error("Failure retrieving object from store",e);
+        }
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#keys()
+     */
+    public Enumeration keys() {
+        List keys = null;
+        try {
+            keys = this.cache.getKeys();
+        }
+        catch (CacheException e) {
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("Error while getting cache keys", e);
+            }
+            keys = Collections.EMPTY_LIST;
+        }
+        return Collections.enumeration(keys);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.excalibur.store.Store#size()
+     */
+    public int size() {
+        try {
+            return this.cache.getSize();
+        }
+        catch (CacheException e) {
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("Error while getting cache size", e);
+            }
+            return 0;
+        }
+    }
+
+}

Modified: cocoon/branches/BRANCH_2_1_X/src/webapp/WEB-INF/cocoon.xconf
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/webapp/WEB-INF/cocoon.xconf	(original)
+++ cocoon/branches/BRANCH_2_1_X/src/webapp/WEB-INF/cocoon.xconf	Thu Sep 30 04:05:19 2004
@@ -428,7 +428,7 @@
   
   <!--+
       | Store: generic store. The default implementation is an in-memory store
-      | backed by a disk store (based on JCS). This forms a two-stage
+      | backed by a disk store (based on EHCache). This forms a two-stage
       | cache composed of a fast in-memory MRU front-end and a persistent
       | back-end which stores the less-used objects.
       |