You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by vg...@apache.org on 2002/02/02 03:42:40 UTC
cvs commit: xml-cocoon2/src/webapp cocoon.xconf
vgritsenko 02/02/01 18:42:40
Modified: . changes.xml
src/java/org/apache/cocoon Cocoon.java cocoon.roles
src/java/org/apache/cocoon/components/store
FilesystemStore.java MRUMemoryStore.java
src/scratchpad/src/org/apache/cocoon/jispstore
MRUMemoryStore.java
src/webapp cocoon.xconf
Added: src/scratchpad/src/org/apache/cocoon/components/store
JispFilesystemStore.java JispStringKey.java
Removed: src/scratchpad/src/org/apache/cocoon/jispstore
JispFilesystemStore.java JispStringKey.java
cocoon.roles cocoon.xconf
Log:
Some refactoring of Stores:
- Decouple Cocoon from FilesystemStore
- Define FilesystemStore in the cocoon.xconf
- Define cache-persistent and cache-transient shorthands
- MRUMemoryStore to use cache-persistent component
- Remove all directory - related code from the MRUMemoryStore
- Add directory configuration to the FilesystemStore
- Move Jisp store to store package
- MRUMemoryStore now can work with any persistent store - filesystem or Jisp
Revision Changes Path
1.94 +11 -1 xml-cocoon2/changes.xml
Index: changes.xml
===================================================================
RCS file: /home/cvs/xml-cocoon2/changes.xml,v
retrieving revision 1.93
retrieving revision 1.94
diff -u -r1.93 -r1.94
--- changes.xml 1 Feb 2002 15:14:54 -0000 1.93
+++ changes.xml 2 Feb 2002 02:42:39 -0000 1.94
@@ -4,7 +4,7 @@
<!--
History of Cocoon changes
- $Id: changes.xml,v 1.93 2002/02/01 15:14:54 sylvain Exp $
+ $Id: changes.xml,v 1.94 2002/02/02 02:42:39 vgritsenko Exp $
-->
<changes title="History of Changes">
@@ -31,6 +31,16 @@
</devs>
<release version="@version@" date="@date@">
+ <action dev="VG" type="update">
+ Cache relies on two types of store components: (1) transient cache,
+ with cache-transient shorthand, and (2) persistent cache, with
+ cache-persistent shorthand.
+ </action>
+ <action dev="VG" type="update">
+ FilesystemStore (used as programs repository) now is created as all other
+ components from the cocoon.xconf, and can be configured to use working
+ directory, cache directory, or any other directory.
+ </action>
<action dev="SW" type="update">
Calling getInputStream() on a "cocoon:" source now returns the same output
as an external call instead of always using an XML serializer.
1.7 +1 -14 xml-cocoon2/src/java/org/apache/cocoon/Cocoon.java
Index: Cocoon.java
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/Cocoon.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Cocoon.java 1 Feb 2002 15:48:08 -0000 1.6
+++ Cocoon.java 2 Feb 2002 02:42:39 -0000 1.7
@@ -103,7 +103,7 @@
* @author <a href="mailto:fumagalli@exoffice.com">Pierpaolo Fumagalli</a> (Apache Software Foundation, Exoffice Technologies)
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:leo.sutic@inspireinfrastructure.com">Leo Sutic</a>
- * @version CVS $Revision: 1.6 $ $Date: 2002/02/01 15:48:08 $
+ * @version CVS $Revision: 1.7 $ $Date: 2002/02/02 02:42:39 $
*/
public class Cocoon
extends AbstractLoggable
@@ -243,19 +243,6 @@
} catch (Exception e) {
getLogger().error("Could not load parser, Cocoon object not created.", e);
throw new ConfigurationException("Could not load parser " + parser, e);
- }
-
- try {
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("Creating Repository with this directory: " + this.workDir);
- }
- FilesystemStore repository = new FilesystemStore();
- repository.setLogger(getLogger());
- repository.setDirectory(this.workDir);
- this.componentManager.addComponentInstance(Store.ROLE + "/Filesystem", repository);
- } catch (IOException e) {
- getLogger().error("Could not create repository!", e);
- throw new ConfigurationException("Could not create the repository!", e);
}
if (getLogger().isDebugEnabled()) {
1.5 +5 -1 xml-cocoon2/src/java/org/apache/cocoon/cocoon.roles
Index: cocoon.roles
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/cocoon.roles,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- cocoon.roles 30 Jan 2002 17:13:24 -0000 1.4
+++ cocoon.roles 2 Feb 2002 02:42:39 -0000 1.5
@@ -41,11 +41,15 @@
default-class="org.apache.cocoon.sitemap.SitemapManager"/>
<role name="org.apache.cocoon.components.store.Store"
- shorthand="store"
+ shorthand="cache-transient"
default-class="org.apache.cocoon.components.store.MRUMemoryStore"/>
<role name="org.apache.cocoon.components.store.Store/Filesystem"
shorthand="repository"
+ default-class="org.apache.cocoon.components.store.FilesystemStore"/>
+
+ <role name="org.apache.cocoon.components.store.Store/PersistentCache"
+ shorthand="cache-persistent"
default-class="org.apache.cocoon.components.store.FilesystemStore"/>
<role name="org.apache.cocoon.components.store.StoreJanitor"
1.4 +58 -11 xml-cocoon2/src/java/org/apache/cocoon/components/store/FilesystemStore.java
Index: FilesystemStore.java
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/store/FilesystemStore.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- FilesystemStore.java 1 Feb 2002 13:27:32 -0000 1.3
+++ FilesystemStore.java 2 Feb 2002 02:42:39 -0000 1.4
@@ -12,6 +12,9 @@
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.avalon.framework.parameters.Parameterizable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.cocoon.Constants;
import org.apache.cocoon.util.IOUtils;
@@ -19,9 +22,20 @@
import java.io.IOException;
import java.util.Enumeration;
+/**
+ * Stores objects on the filesystem: String objects as text files,
+ * all other objects are serialized.
+ *
+ * @author ?
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
+ * @version CVS $Revision: 1.4 $ $Date: 2002/02/02 02:42:39 $
+ */
public final class FilesystemStore
extends AbstractLoggable
-implements Contextualizable, Store, ThreadSafe {
+implements Store, Contextualizable, Parameterizable, ThreadSafe {
+
+ protected File workDir;
+ protected File cacheDir;
/** The directory repository */
protected File directoryFile;
@@ -37,10 +51,37 @@
public void contextualize(final Context context)
throws ContextException {
+ this.workDir = (File)context.get(Constants.CONTEXT_WORK_DIR);
+ this.cacheDir = (File)context.get(Constants.CONTEXT_CACHE_DIR);
+ }
+
+ public void parameterize(Parameters params)
+ throws ParameterException {
try {
- setDirectory((File) context.get(Constants.CONTEXT_WORK_DIR));
- } catch (Exception e) {
- // ignore
+ if (params.getParameterAsBoolean("use-cache-directory", false)) {
+ if (this.getLogger().isDebugEnabled())
+ getLogger().debug("Using cache directory: " + cacheDir);
+ setDirectory(cacheDir);
+ } else if (params.getParameterAsBoolean("use-work-directory", false)) {
+ if (this.getLogger().isDebugEnabled())
+ getLogger().debug("Using work directory: " + workDir);
+ setDirectory(workDir);
+ } else if (params.getParameter("directory", null) != null) {
+ String dir = params.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) {
+ // Legacy: Always was ignored
+ }
+ }
+ } catch (IOException e) {
+ throw new ParameterException("Unable to set directory", e);
}
}
@@ -85,18 +126,22 @@
}
/**
- * Get the file associated with the given unique key name.
+ * Get the File object associated with the given unique key name.
*/
public Object get(final Object key) {
- if (this.getLogger().isDebugEnabled())
- getLogger().debug("FilesystemStore get(): Get file with key: " + key.toString());
final File file = fileFromKey(key);
if (file != null && file.exists()) {
- if (this.getLogger().isDebugEnabled())
- getLogger().debug("FilesystemStore get(): Found file with key: " + key.toString());
+ if (this.getLogger().isDebugEnabled()) {
+ getLogger().debug("Found file: " + key);
+ }
return file;
+ } else {
+ if (this.getLogger().isDebugEnabled()) {
+ getLogger().debug("NOT Found file: " + key);
+ }
}
+
return null;
}
@@ -126,9 +171,11 @@
}
file.mkdir();
- } else if (value instanceof String) { /* Text file */
+ } else if (value instanceof String) {
+ /* Text file */
IOUtils.serializeString(file, (String) value);
- } else { /* Serialized Object */
+ } else {
+ /* Serialized Object */
IOUtils.serializeObject(file, value);
}
}
1.8 +120 -145 xml-cocoon2/src/java/org/apache/cocoon/components/store/MRUMemoryStore.java
Index: MRUMemoryStore.java
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/store/MRUMemoryStore.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- MRUMemoryStore.java 1 Feb 2002 14:40:45 -0000 1.7
+++ MRUMemoryStore.java 2 Feb 2002 02:42:39 -0000 1.8
@@ -1,5 +1,6 @@
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
@@ -7,22 +8,16 @@
*****************************************************************************/
package org.apache.cocoon.components.store;
-import org.apache.avalon.excalibur.collections.SynchronizedPriorityQueue;
import org.apache.avalon.framework.activity.Disposable;
-import org.apache.avalon.excalibur.collections.SynchronizedPriorityQueue;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-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.AbstractLoggable;
import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.thread.ThreadSafe;
-import org.apache.cocoon.Constants;
+
import org.apache.cocoon.util.ClassUtils;
import org.apache.cocoon.util.IOUtils;
@@ -32,6 +27,7 @@
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
+import java.util.NoSuchElementException;
/**
* This class provides a cache algorithm for the requested documents.
@@ -43,26 +39,18 @@
*
* @author <a href="mailto:g-froehlich@gmx.de">Gerhard Froehlich</a>
* @author <a href="mailto:dims@yahoo.com">Davanum Srinivas</a>
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
*/
public final class MRUMemoryStore
extends AbstractLoggable
-implements Store,
- Configurable,
- ThreadSafe,
- Composable,
- Disposable,
- Contextualizable {
+implements Store, Parameterizable, Composable, Disposable, ThreadSafe {
private int maxobjects;
- private boolean filesystem;
+ private boolean persistent;
private Hashtable cache;
private LinkedList mrulist;
- private File cachefile;
- private Store fsstore;
- private StoreJanitor storejanitor;
- private File cachedir;
- private File workdir;
- private String cachedirstr;
+ private Store persistentStore;
+ private StoreJanitor storeJanitor;
private ComponentManager manager;
/**
@@ -72,55 +60,36 @@
*/
public void compose(ComponentManager manager) throws ComponentException {
this.manager = manager;
- this.fsstore = (Store)manager.lookup(Store.ROLE + "/Filesystem");
- this.storejanitor = (StoreJanitor)manager.lookup(StoreJanitor.ROLE);
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("Looking up " + Store.ROLE + "/Filesystem");
- getLogger().debug("Looking up " + StoreJanitor.ROLE);
- }
- }
-
- /**
- * Get the context
- *
- * @param the Context of the application
- */
- public void contextualize(Context context) throws ContextException {
- this.cachedir = (File)context.get(Constants.CONTEXT_CACHE_DIR);
- this.workdir = (File)context.get(Constants.CONTEXT_WORK_DIR);
- this.cachedirstr = IOUtils.getContextFilePath(this.workdir.getPath(),
- this.cachedir.getPath());
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("cachedir=" + this.cachedir);
- this.getLogger().debug("workdir=" + this.workdir);
- this.getLogger().debug("cachedirstr=" + this.cachedirstr);
- this.getLogger().debug("Context path="
- + IOUtils.getContextFilePath(this.workdir.getPath(),this.cachedir.getPath()));
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Looking up " + Store.ROLE + "/PersistentCache");
+ getLogger().debug("Looking up " + StoreJanitor.ROLE);
}
+ this.persistentStore = (Store)manager.lookup(Store.ROLE + "/PersistentCache");
+ this.storeJanitor = (StoreJanitor)manager.lookup(StoreJanitor.ROLE);
}
/**
* Initialize the MRUMemoryStore.
- * A few options can be used :
+ * A few options can be used:
* <UL>
- * <LI>maxobjects = how many objects will be stored in memory (Default: 10 objects)</LI>
- * <LI>filesystem = use filesystem storage to keep object persistent (Default: false)</LI>
+ * <LI>maxobjects: Maximum number of objects stored in memory (Default: 100 objects)</LI>
+ * <LI>use-persistent-cache: Use persistent cache to keep objects persisted after
+ * container shutdown or not (Default: false)</LI>
* </UL>
*
* @param the Configuration of the application
* @exception ConfigurationException
*/
- public void configure(Configuration conf) throws ConfigurationException {
- Parameters params = Parameters.fromConfiguration(conf);
- this.maxobjects = params.getParameterAsInteger("maxobjects",100);
- this.filesystem = params.getParameterAsBoolean("filesystem",false);
+ public void parameterize(Parameters params) throws ParameterException {
+ this.maxobjects = params.getParameterAsInteger("maxobjects", 100);
+ this.persistent = params.getParameterAsBoolean("use-persistent-cache", false);
if ((this.maxobjects < 1)) {
- throw new ConfigurationException("MRUMemoryStore maxobjects must be at least 1 milli second!");
+ throw new ParameterException("MRUMemoryStore maxobjects must be at least 1!");
}
this.cache = new Hashtable((int)(this.maxobjects * 1.2));
- this.mrulist = new LinkedList();
- this.storejanitor.register(this);
+ this.mrulist = new LinkedList();
+ this.storeJanitor.register(this);
}
/**
@@ -128,29 +97,38 @@
*/
public void dispose() {
if (this.manager != null) {
- this.getLogger().debug("Disposing component!");
- this.manager.release(this.storejanitor);
- this.storejanitor = null;
- this.manager.release(this.fsstore);
-
- //save all cache entries to filesystem
- this.getLogger().debug("Final cache size=" + this.cache.size());
- Enumeration enum = this.cache.keys();
- while(enum.hasMoreElements()) {
- Object tmp = enum.nextElement();
- try {
- if(tmp != null
- && checkSerializable(this.cache.get(tmp))) {
- this.fsstore.store(this.getFileName(tmp.toString()),
- this.cache.remove(tmp));
+ getLogger().debug("Disposing component!");
+
+ if (this.storeJanitor != null)
+ this.storeJanitor.unregister(this);
+ this.manager.release(this.storeJanitor);
+ this.storeJanitor = null;
+
+ // save all cache entries to filesystem
+ if (this.persistent) {
+ getLogger().debug("Final cache size: " + this.cache.size());
+ Enumeration enum = this.cache.keys();
+ while (enum.hasMoreElements()) {
+ Object key = enum.nextElement();
+ if (key == null) {
+ continue;
+ }
+ try {
+ Object value = this.cache.remove(key);
+ if(checkSerializable(value)) {
+ persistentStore.store(getFileName(key.toString()),
+ value);
+ }
+ } catch (IOException ioe) {
+ getLogger().error("Error in dispose()", ioe);
}
- } catch (IOException ioe) {
- this.getLogger().error("Error in dispose():",ioe);
}
}
-
- this.fsstore = null;
+ this.manager.release(this.persistentStore);
+ this.persistentStore = null;
}
+
+ this.manager = null;
}
/**
@@ -174,9 +152,10 @@
* @param the object to be stored
*/
public void hold(Object key, Object value) {
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("Holding object in memory. key: " + key);
- getLogger().debug("Holding object in memory. value: " + value);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Holding object in memory:");
+ getLogger().debug(" key: " + key);
+ getLogger().debug(" value: " + value);
}
/** ...first test if the max. objects in cache is reached... */
while (this.mrulist.size() >= this.maxobjects) {
@@ -187,9 +166,6 @@
this.cache.put(key, value);
this.mrulist.remove(key);
this.mrulist.addFirst(key);
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Cache size=" + cache.size());
- }
}
/**
@@ -199,48 +175,42 @@
* @return the requested object
*/
public Object get(Object key) {
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Getting object from memory. Key: " + key);
- }
- Object tmpobject = this.cache.get(key);
- if ( tmpobject != null ) {
+ Object value = this.cache.get(key);
+ if (value != null) {
/** put the accessed key on top of the linked list */
this.mrulist.remove(key);
this.mrulist.addFirst(key);
- return tmpobject;
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Found key: " + key.toString());
+ }
+ return value;
}
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Object not found in memory");
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("NOT Found key: " + key.toString());
}
+
/** try to fetch from filesystem */
- if(this.filesystem) {
- tmpobject = this.fsstore.get(getFileName(key.toString()));
- if (tmpobject == null) {
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug( "Object was NOT found on fs. Looked for: "
- + getFileName(key.toString()));
- }
- return null;
- } else {
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Object was found on fs");
- }
+ if (this.persistent) {
+ value = this.persistentStore.get(getFileName(key.toString()));
+ if (value != null) {
try {
- tmpobject = IOUtils.deserializeObject((File)tmpobject);
+ // FIXME (VG): This is hack for FilesystemStore which returns file
+ if (value instanceof File) {
+ value = IOUtils.deserializeObject((File)value);
+ }
+
if(!this.cache.containsKey(key)) {
- this.hold(key,tmpobject);
+ this.hold(key, value);
}
- return tmpobject;
- } catch (ClassNotFoundException ce) {
- this.getLogger().error("Error in get()!", ce);
- return null;
- } catch (IOException ioe) {
- this.getLogger().error("Error in get()!", ioe);
+ return value;
+ } catch (Exception e) {
+ getLogger().error("Error in get()!", e);
return null;
}
}
}
+
return null;
}
@@ -250,13 +220,14 @@
* @param the key of to be removed object
*/
public void remove(Object key) {
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Removing object from store");
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Removing object from store");
+ getLogger().debug(" key: " + key);
}
this.cache.remove(key);
this.mrulist.remove(key);
- if(this.filesystem && key != null) {
- this.fsstore.remove(getFileName(key.toString()));
+ if(this.persistent && key != null) {
+ this.persistentStore.remove(getFileName(key.toString()));
}
}
@@ -267,10 +238,10 @@
* @return true if the key exists
*/
public boolean containsKey(Object key) {
- if(filesystem) {
- return (this.cache.containsKey(key) || this.fsstore.containsKey(key));
+ if(persistent) {
+ return (cache.containsKey(key) || persistentStore.containsKey(key));
} else {
- return this.cache.containsKey(key);
+ return cache.containsKey(key);
}
}
@@ -287,8 +258,7 @@
* Returns count of the objects in the store, or -1 if could not be
* obtained.
*/
- public int size()
- {
+ public int size() {
return this.cache.size();
}
@@ -298,29 +268,36 @@
*/
public void free() {
try {
- if(this.cache.size() > 0) {
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Freeing cache");
+ if (this.cache.size() > 0) {
+ // This can throw NoSuchElementException
+ Object key = this.mrulist.removeLast();
+ Object value = this.cache.remove(key);
+ if (value == null) {
+ getLogger().warn("Concurrency condition in free()");
}
- // Swapping object on fs.
- if(this.filesystem) {
- if(checkSerializable(this.cache.get(this.mrulist.getLast()))) {
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Freeing cache.");
+ getLogger().debug(" key: " + key);
+ getLogger().debug(" value: " + value);
+ }
+
+ if (this.persistent) {
+ // Swap object on fs.
+ if(checkSerializable(value)) {
try {
- this.fsstore.store(this.getFileName(this.mrulist.getLast().toString()),
- this.cache.get(this.mrulist.getLast()));
+ this.persistentStore.store(
+ getFileName(key.toString()), value);
} catch(Exception e) {
- this.getLogger().error("Error storing Object on fs",e);
+ getLogger().error("Error storing object on fs", e);
}
}
}
- this.cache.remove(this.mrulist.getLast());
- this.mrulist.removeLast();
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Cache size=" + cache.size());
- }
}
+ } catch (NoSuchElementException e) {
+ getLogger().warn("Concurrency error in free()", e);
} catch (Exception e) {
- this.getLogger().error("Error in free()", e);
+ getLogger().error("Error in free()", e);
}
}
@@ -333,19 +310,21 @@
* @return true if the object is storeable
*/
private boolean checkSerializable(Object object) {
+
+ if (object == null) return false;
+
try {
- if (this.getLogger().isDebugEnabled()) {
- this.getLogger().debug("Object=" + object);
- }
- if((object.getClass().getName().equals("org.apache.cocoon.caching.CachedEventObject"))
- || (object.getClass().getName().equals("org.apache.cocoon.caching.CachedStreamObject"))
- || (ClassUtils.implementsInterface(object.getClass().getName(),"org.apache.cocoon.caching.CacheValidity"))) {
+ String clazz = object.getClass().getName();
+ // FIXME (VG): Can class identity check work here (==)? It will be faster.
+ if((clazz.equals("org.apache.cocoon.caching.CachedEventObject"))
+ || (clazz.equals("org.apache.cocoon.caching.CachedStreamObject"))
+ || (ClassUtils.implementsInterface(clazz, "org.apache.cocoon.caching.CacheValidity"))) {
return true;
} else {
return false;
}
} catch (Exception e) {
- this.getLogger().error("Error in checkSerializable()!", e);
+ getLogger().error("Error in checkSerializable()!", e);
return false;
}
}
@@ -359,11 +338,7 @@
* @return the filename of the key
*/
private String getFileName(String key) {
- return new StringBuffer()
- .append(this.cachedirstr)
- .append(File.separator)
- .append(URLEncoder.encode(key.toString()))
- .toString();
+ return URLEncoder.encode(key.toString());
}
}
1.1 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/components/store/JispFilesystemStore.java
Index: JispFilesystemStore.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.components.store;
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.AbstractLoggable;
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.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.util.IOUtils;
import com.coyotegulch.jisp.BTreeIndex;
import com.coyotegulch.jisp.IndexedObjectDatabase;
import com.coyotegulch.jisp.KeyNotFound;
import com.coyotegulch.jisp.KeyObject;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Vector;
/**
* This store is based on the Jisp library
* (http://www.coyotegulch.com/jisp/index.html). This store uses B-Tree indexes
* to access variable-length serialized data stored in files.
*
* @author <a href="mailto:g-froehlich@gmx.de">Gerhard Froehlich</a>
* @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
*/
public final class JispFilesystemStore
extends AbstractLoggable
implements Store, Contextualizable, ThreadSafe, Initializable, Parameterizable {
protected File workDir;
protected File cacheDir;
/**
* The directory repository
*/
protected File directoryFile;
protected volatile String directoryPath;
/**
* The database
*/
private File databaseFile;
private File indexFile;
private int mOrder;
private IndexedObjectDatabase mDatabase;
private BTreeIndex mIndex;
/**
* Sets the repository's location
*
* @param directory the new directory value
* @exception IOException
*/
public void setDirectory(final String directory)
throws IOException {
this.setDirectory(new File(directory));
}
/**
* Sets the repository's location
*
* @param directory the new directory value
* @exception IOException
*/
public void setDirectory(final File directory)
throws IOException {
this.directoryFile = directory;
/* Save directory path prefix */
this.directoryPath = IOUtils.getFullFilename(this.directoryFile);
this.directoryPath += File.separator;
if (!this.directoryFile.exists()) {
/* Create it new */
if (!this.directoryFile.mkdir()) {
throw new IOException("Error creating store directory '" +
this.directoryPath + "'");
}
}
/* Is given file actually a directory? */
if (!this.directoryFile.isDirectory()) {
throw new IOException("'" + this.directoryPath + "' is not a directory");
}
/* Is directory readable and writable? */
if (!(this.directoryFile.canRead() && this.directoryFile.canWrite())) {
throw new IOException("Directory '" + this.directoryPath +
"' is not readable/writable");
}
}
/**
* Contextualize the Component
*
* @param context the Context of the Application
* @exception ContextException
*/
public void contextualize(final Context context) throws ContextException {
this.workDir = (File)context.get(Constants.CONTEXT_WORK_DIR);
this.cacheDir = (File)context.get(Constants.CONTEXT_CACHE_DIR);
}
/**
* Configure the Component.<br>
* A few options can be used
* <UL>
* <LI> datafile = the name of the data file (Default: cocoon.dat)
* </LI>
* <LI> indexfile = the name of the index file (Default: cocoon.idx)
* </LI>
* <LI> order = The page size of the B-Tree</LI>
* </UL>
*
* @param params the configuration paramters
* @exception ParameterException
*/
public void parameterize(Parameters params) throws ParameterException {
try {
if (params.getParameterAsBoolean("use-cache-directory", false)) {
if (this.getLogger().isDebugEnabled())
getLogger().debug("Using cache directory: " + cacheDir);
setDirectory(cacheDir);
} else if (params.getParameterAsBoolean("use-work-directory", false)) {
if (this.getLogger().isDebugEnabled())
getLogger().debug("Using work directory: " + workDir);
setDirectory(workDir);
} else if (params.getParameter("directory", null) != null) {
String dir = params.getParameter("directory");
dir = IOUtils.getContextFilePath(workDir.getPath(), dir);
if (this.getLogger().isDebugEnabled())
getLogger().debug("Using directory: " + dir);
setDirectory(new File(dir));
} else {
try {
// Default
setDirectory(workDir);
} catch (IOException e) {
// Ignored
}
}
} catch (IOException e) {
throw new ParameterException("Unable to set directory", e);
}
String databaseName = params.getParameter("datafile", "cocoon.dat");
String indexName = params.getParameter("indexfile", "cocoon.idx");
mOrder = params.getParameterAsInteger("order", 301);
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("Database file name = " + databaseName);
this.getLogger().debug("Index file name = " + indexName);
this.getLogger().debug("Order=" + mOrder);
}
databaseFile = new File(directoryFile, databaseName);
indexFile = new File(directoryFile, indexName);
}
/**
* Initialize the Component
*/
public void initialize() {
if (getLogger().isDebugEnabled()) {
getLogger().debug("initialize() JispFilesystemStore");
}
try {
if (databaseFile.exists()) {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("initialize(): Datafile exists");
}
mDatabase = new IndexedObjectDatabase(databaseFile.toString(), false);
mIndex = new BTreeIndex(indexFile.toString());
mDatabase.attachIndex(mIndex);
} else {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("initialize(): Datafile does not exist");
}
mDatabase = new IndexedObjectDatabase(databaseFile.toString(), false);
mIndex = new BTreeIndex(indexFile.toString(),
mOrder, new JispStringKey(), false);
mDatabase.attachIndex(mIndex);
}
} catch (KeyNotFound ignore) {
} catch (Exception e) {
getLogger().error("initialize(..) Exception", e);
}
}
/**
* Returns the repository's full pathname
*
* @return the directory as String
*/
public String getDirectoryPath() {
return this.directoryPath;
}
/**
* Returns a Object from the store associated with the Key Object
*
* @param key the Key object
* @return the Object associated with Key Object
*/
public Object get(Object key) {
Object value = null;
try {
value = mDatabase.read(this.wrapKeyObject(key), mIndex);
if (getLogger().isDebugEnabled()) {
if (value != null) {
getLogger().debug("Found key: " + key);
} else {
getLogger().debug("NOT Found key: " + key);
}
}
} catch (Exception e) {
getLogger().error("get(..): Exception", e);
}
return value;
}
/**
* Store the given object in the indexed data file.
*
* @param key the key object
* @param value the value object
* @exception IOException
*/
public void store(Object key, Object value)
throws IOException {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("store(): Store file with key: "
+ key.toString());
this.getLogger().debug("store(): Store file with value: "
+ value.toString());
}
if (value instanceof Serializable) {
try {
KeyObject[] keyArray = new KeyObject[1];
keyArray[0] = this.wrapKeyObject(key);
mDatabase.write(keyArray, (Serializable) value);
} catch (Exception e) {
this.getLogger().error("store(..): Exception", e);
}
} else {
throw new IOException("Object not Serializable");
}
}
/**
* Holds the given object in the indexed data file.
*
* @param key the key object
* @param value the value object
* @exception IOException
*/
public void hold(Object key, Object value)
throws IOException {
this.store(key, value);
}
/**
* Frees some values of the data file.<br>
* TODO: implementation
*/
public void free() {
//TODO: implementation
}
/**
* Removes a value from the data file with the given key.
*
* @param key the key object
*/
public void remove(Object key) {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("remove(..) Remove item");
}
try {
KeyObject[] keyArray = new KeyObject[1];
keyArray[0] = this.wrapKeyObject(key);
mDatabase.remove(keyArray);
} catch (KeyNotFound ignore) {
} catch (Exception e) {
this.getLogger().error("remove(..): Exception", e);
}
}
/**
* Test if the the index file contains the given key
*
* @param key the key object
* @return true if Key exists and false if not
*/
public boolean containsKey(Object key) {
long res = -1;
try {
res = mIndex.findKey(this.wrapKeyObject(key));
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("containsKey(..): res=" + res);
}
} catch (KeyNotFound ignore) {
} catch (Exception e) {
this.getLogger().error("containsKey(..): Exception", e);
}
if (res > 0) {
return true;
} else {
return false;
}
}
/**
* Returns a Enumeration of all Keys in the indexed file.<br>
*
* @return Enumeration Object with all existing keys
*/
public Enumeration keys() {
// TODO: Implementation
return new Vector(0).elements();
}
public int size() {
// TODO: Unsupported
return 0;
}
/**
* This method wraps around the key Object a Jisp KeyObject.
*
* @param key the key object
* @return the wrapped key object
*/
private KeyObject wrapKeyObject(Object key) {
// TODO: Implementation of Integer and Long keys
String skey = String.valueOf(key);
return new JispStringKey(key.toString());
}
}
1.1 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/components/store/JispStringKey.java
Index: JispStringKey.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.components.store;
import com.coyotegulch.jisp.KeyObject;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Wrapper class for String Keys to be compatible with the
* Jisp KeyObject.
*
* @author <a href="mailto:g-froehlich@gmx.de">Gerhard Froehlich</a>
*/
final class JispStringKey extends KeyObject {
final static long serialVersionUID = -6894793231339165076L;
private String mKey;
/**
* Constructor for the JispStringKey object
*/
public JispStringKey() {
mKey = new String("");
}
/**
* Constructor for the JispStringKey object
*
* @param keyValue the Value of the Key as String
*/
public JispStringKey(String keyValue) {
mKey = keyValue;
}
/**
* Compares two String Keys
*
* @param key the KeyObject to be compared
* @return 0 if equal, 1 if greater, -1 if less
*/
public int compareTo(KeyObject key) {
if (key instanceof JispStringKey) {
int comp = mKey.trim().compareTo(((JispStringKey) key).mKey.trim());
if (comp == 0) {
return KEY_EQUAL;
} else {
if (comp < 0) {
return KEY_LESS;
} else {
return KEY_MORE;
}
}
} else {
return KEY_ERROR;
}
}
/**
* Composes a null Kewy
*
* @return a null Key
*/
public KeyObject makeNullKey() {
return new JispStringKey();
}
/**
* The object implements the writeExternal method to save its contents
* by calling the methods of DataOutput for its primitive values or
* calling the writeObject method of ObjectOutput for objects, strings,
* and arrays.
*
* @param out the stream to write the object to
* @exception IOException
*/
public void writeExternal(ObjectOutput out)
throws IOException {
String outKey;
outKey = new String(mKey);
out.writeUTF(outKey);
}
/**
* The object implements the readExternal method to restore its contents
* by calling the methods of DataInput for primitive types and readObject
* for objects, strings and arrays. The readExternal method must read the
* values in the same sequence and with the same types as were written by writeExternal.
*
* @param in the stream to read data from in order to restore the object
* @exception IOException
* @exception ClassNotFoundException
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
mKey = in.readUTF();
}
/**
* Overrides the toString() method
*
* @return the Key as String
*/
public String toString() {
return mKey;
}
}
1.6 +4 -4 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/MRUMemoryStore.java
Index: MRUMemoryStore.java
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/MRUMemoryStore.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- MRUMemoryStore.java 1 Feb 2002 13:27:32 -0000 1.5
+++ MRUMemoryStore.java 2 Feb 2002 02:42:40 -0000 1.6
@@ -61,7 +61,7 @@
*/
public Object get(Object key) {
if (getLogger().isDebugEnabled()) {
- this.getLogger().debug("Getting object from memory. Key: " + key);
+ getLogger().debug("Getting object from memory. Key: " + key);
}
Object tmpobject = this.mCache.get(key);
if (tmpobject != null) {
@@ -70,18 +70,18 @@
return tmpobject;
}
- this.getLogger().debug("Object not found in memory");
+ getLogger().debug("Object not found in memory");
tmpobject = this.mFsstore.get(key);
if (tmpobject == null) {
if (getLogger().isDebugEnabled()) {
- this.getLogger().debug("Object was NOT found on fs. "
+ getLogger().debug("Object was NOT found on fs. "
+ "Looked for: " + key);
}
return null;
} else {
if (getLogger().isDebugEnabled()) {
- this.getLogger().debug("Object was found on fs");
+ getLogger().debug("Object was found on fs");
}
if (!this.mCache.containsKey(key)) {
this.hold(key, tmpobject);
1.15 +52 -10 xml-cocoon2/src/webapp/cocoon.xconf
Index: cocoon.xconf
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/webapp/cocoon.xconf,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- cocoon.xconf 28 Jan 2002 19:58:13 -0000 1.14
+++ cocoon.xconf 2 Feb 2002 02:42:40 -0000 1.15
@@ -27,21 +27,63 @@
<!-- ============================ STORE ============================ -->
+ <!-- Store for the generated code. Used by compiled sitemap engine and
+ XSP engine. Must be pointing to the work directory as generated
+ classes are expected to be in this directory.
+ -->
+ <repository class="org.apache.cocoon.components.store.FilesystemStore"
+ logger="core.store.repository">
+ <parameter name="use-work-directory" value="true"/>
+ </repository>
+
+ <!-- Persistent store for the cache. Two store implementations to choose
+ from:
+ * FilesystemStore: Simple. Dependable. Thorougly tested.
+ * JispFilesystemStore: Scalable. New kid on the block.
+
+ Common configuration parameters:
+ use-cache-directory: Indicates that cache directory specified in
+ web.xml should be used.
+ use-work-directory: Indicates that work directory specified in
+ web.xml should be used.
+ directory: Specifies directory to use. Absolute or relative to the
+ work directory.
+
+ JispFilesystemStore configuration:
+ datafile: name of the store file to use.
+ indexfile: name of the index file to use.
+ order: FIXME: put description here.
+ -->
+ <cache-persistent class="org.apache.cocoon.components.store.FilesystemStore"
+ logger="core.store.persistent">
+ <parameter name="use-cache-directory" value="true"/>
+ </cache-persistent>
+ <!--
+ <cache-persistent class="org.apache.cocoon.components.store.JispFilesystemStore"
+ logger="core.store.persistent">
+ <parameter name="use-cache-directory" value="true"/>
+ <parameter name="datafile" value="cocoon-cache.dat"/>
+ <parameter name="indexfile" value="cocoon-cache.idx"/>
+ <parameter name="order" value="301"/>
+ </cache-persistent>
+ -->
+
<!-- Memory Storing: -->
- <store class="org.apache.cocoon.components.store.MRUMemoryStore"
- logger="core.store">
+ <cache-transient class="org.apache.cocoon.components.store.MRUMemoryStore"
+ logger="core.store.transient">
<!-- Indicates how many objects will be hold in the cache.
When the number of maxobjects has been reached. The last object in the
cache will be thrown out. -->
<parameter name="maxobjects" value="100"/>
- <!-- Turns the filesystem swapping on and off -->
- <parameter name="filesystem" value="true"/>
- </store>
+
+ <!-- Turns the swapping of the objects into persistent cache on
+ and off. -->
+ <parameter name="use-persistent-cache" value="true"/>
+ </cache-transient>
<!-- Store Janitor:
- Be careful with the heapsize and freememory paramters. Wrong values can
- cause high cpu usage.
- Example configuration:
+ Be careful with the heapsize and freememory parameters. Wrong values can
+ cause high cpu usage. Example configuration:
Jvm settings:
-Xms100000000 -Xmx200000000
store-janitor settings:
@@ -55,7 +97,7 @@
amount of memory necessary for normal application operation.
-->
<store-janitor class="org.apache.cocoon.components.store.StoreJanitorImpl"
- logger="core.store-janitor">
+ logger="core.store.janitor">
<!-- How much free memory shall be available in the jvm -->
<parameter name="freememory" value="1000000"/>
<!-- Indicates the limit of the jvm memory consumption. The default max
@@ -66,7 +108,7 @@
<!-- Indicates the thread priority of the cleanup thread -->
<parameter name="threadpriority" value="5"/>
<!-- How much percent of the elements of each registered Store shall
- be removed. Default 10% -->
+ be removed when low on memory. Default 10% -->
<parameter name="percent_to_free" value="10"/>
</store-janitor>
<!-- ============================ STORE END ========================= -->
----------------------------------------------------------------------
In case of troubles, e-mail: webmaster@xml.apache.org
To unsubscribe, e-mail: cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org