giacomo 02/01/06 09:18:26
Modified: src/scratchpad/src/org/apache/cocoon/jispstore
FilesystemQueueImpl.java JispFilesystemStore.java
JispStringKey.java MRUMemoryStore.java
Log:
fixed EOL encoding
Revision Changes Path
1.3 +241 -1
xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/FilesystemQueueImpl.java
Index: FilesystemQueueImpl.java
===================================================================
RCS file:
/home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/FilesystemQueueImpl.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- FilesystemQueueImpl.java 6 Jan 2002 14:28:10 -0000 1.2
+++ FilesystemQueueImpl.java 6 Jan 2002 17:18:25 -0000 1.3
@@ -1 +1,241 @@
-/*****************************************************************************
*
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.jispstore;
import
org.apache.avalon.framework.activity.Disposable;
import
org.apache.avalon.framework.activity.Startable;
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.logger.AbstractLoggable;
import
org.apache.avalon.framework.parameters.Parameters;
import
org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.components.store.FilesystemQueue;
import
org.apache.cocoon.components.store.FilesystemQueueObject;
import
org.apache.cocoon.components.store.Store;
import org.apache.cocoon.util.IOUtils;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import
java.util.LinkedList;
import java.util.ListIterator;
import
java.util.NoSuchElementException;
/**
* This class provides a asynchron queue for
storing objects on the filesystem.
* Every store component can uses this component
to store object in the
* configured cache directory.
*
* @author Gerhard Froehlich
<a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
*/
public final class
FilesystemQueueImpl
extends AbstractLoggable
implements FilesystemQueue,
Configurable,
Runnable,
ThreadSafe,
Composable,
Disposable,
Startable {
private static boolean doRun = false;
private int handlerinterval;
private int threadpriority;
private int
maxobjects;
private LinkedList linkedList;
private Store fsstore;
private
Thread fsQueueHandler;
private ComponentManager manager;
/**
* Test if
queue is empty.
*
* @return true if queue is empty else false.
*/
public boolean isEmpty() {
return (this.linkedList.size() == 0);
}
/**
* Get components of the ComponentManager
*
* @param manager
Description of Parameter
* @exception ComponentException Description
of Exception
*/
public void compose(ComponentManager manager)
throws
ComponentException {
this.manager = manager;
if
(this.getLogger().isDebugEnabled() == true) {
getLogger().debug("Looking
up " + Store.ROLE + "/JispFilesystemStore");
}
this.fsstore = (Store)
manager.lookup(Store.ROLE + "/JispFilesystemStore");
}
/**
* Dispose
the component
*/
public void dispose() {
if (this.manager != null) {
this.manager.release(this.fsstore);
this.fsstore = null;
}
}
/**
* Configure the Filesystem Queue:
* <UL>
* <LI>
handlerinterval = Interval of the Queue Handler Thread</LI>
* <LI>
threadpriority = Priority of the Queue Handler Thread</LI> >LI>
* maxobjects =
Defines the max. numbers of Objects in the queue</LI>
*
* </UL>
*
*
* @param conf Description of Parameter
*
@exception ConfigurationException Description of Exception
*/
public void
configure(Configuration conf)
throws ConfigurationException {
Parameters params = Parameters.fromConfiguration(conf);
this.handlerinterval =
params.getParameterAsInteger("handlerinterval", 10);
this.threadpriority =
params.getParameterAsInteger("threadpriority", 5);
this.maxobjects =
params.getParameterAsInteger("maxobjects", 100);
if
(this.getLogger().isDebugEnabled() == true) {
this.getLogger().debug("Configure Filesystem Queue");
this.getLogger().debug("handlerinterval=" + handlerinterval);
this.getLogger().debug("threadpriority=" + threadpriority);
}
this.linkedList = new LinkedList();
}
/**
* Starts the Queue Handler
Thread
*/
public void start() {
doRun = true;
this.fsQueueHandler = new Thread(this);
this.fsQueueHandler.setDaemon(true);
this.fsQueueHandler.setPriority(this.threadpriority);
this.fsQueueHandler.setName("fsQueueHandler");
this.fsQueueHandler.start();
}
/**
* Stops the Queue Handler Thread
*/
public void stop() {
doRun = false;
}
/**
* Main processing method for the
FilesystemQueueImpl object
*/
public void run() {
while (doRun) {
while (!this.isEmpty()) {
FilesystemQueueObject
filesystemQueueObject = (FilesystemQueueObject) this.pop();
try {
this.fsstore.store(filesystemQueueObject.getKey(),
filesystemQueueObject.getObject()
);
} catch (IOException e) {
this.getLogger().error("Error in
fsQueueHandler", e);
}
} try {
Thread.currentThread().sleep(this.handlerinterval * 1000);
} catch
(InterruptedException ignore) {;}
}
}
/**
* Clear all elements
from queue.
*/
public void clear() {
if
(this.getLogger().isDebugEnabled() == true) {
this.getLogger().debug("Clearing the FilesystemQueue");
}
ListIterator listIterator = linkedList.listIterator(0);
while
(listIterator.hasNext()) {
this.linkedList.remove(listIterator.nextIndex());
}
}
/**
*
Insert an element into queue.
*
* @param element the element to be
inserted
*/
public void insert(Object element) {
if
(this.linkedList.size() < maxobjects) {
if
(this.getLogger().isDebugEnabled() == true) {
this.getLogger().debug("Insert Element in FilesystemQueue");
}
this.linkedList.addFirst(element);
this.reportSize();
} else {
this.getLogger().warn("Filesystem Queue full!");
}
}
/**
* Return element on top of heap but don't remove it.
*
* @return the
element at top of heap
* @exception NoSuchElementException if isEmpty() == true
*/
public Object peek()
throws NoSuchElementException {
if
(this.getLogger().isDebugEnabled() == true) {
this.getLogger().debug("Peek
Element in FilesystemQueue");
}
return (Comparable)
linkedList.getLast();
}
/**
* Return element on top of heap and remove
it.
*
* @return the element at top of heap
* @exception
NoSuchElementException if isEmpty() == true
*/
public Object pop()
throws NoSuchElementException {
if (this.getLogger().isDebugEnabled() == true)
{
this.getLogger().debug("Pop Element in FilesystemQueue");
}
return (Comparable) linkedList.removeLast();
}
private void reportSize() {
if (this.getLogger().isDebugEnabled() == true) {
this.getLogger().debug("Size of FilesystemQueue="
+
this.linkedList.size());
}
}
}
\ No newline at end of file
+/*****************************************************************************
+ * 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.jispstore;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Startable;
+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.logger.AbstractLoggable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.components.store.FilesystemQueue;
+import org.apache.cocoon.components.store.FilesystemQueueObject;
+import org.apache.cocoon.components.store.Store;
+import org.apache.cocoon.util.IOUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+
+
+/**
+ * This class provides a asynchron queue for storing objects on the filesystem.
+ * Every store component can uses this component to store object in the
+ * configured cache directory.
+ *
+ * @author Gerhard Froehlich <a href="mailto:[EMAIL PROTECTED]">Gerhard
Froehlich</a>
+ */
+
+public final class FilesystemQueueImpl
+extends AbstractLoggable
+
+implements FilesystemQueue,
+ Configurable,
+ Runnable,
+ ThreadSafe,
+ Composable,
+ Disposable,
+ Startable {
+
+ private static boolean doRun = false;
+ private int handlerinterval;
+ private int threadpriority;
+ private int maxobjects;
+ private LinkedList linkedList;
+ private Store fsstore;
+ private Thread fsQueueHandler;
+ private ComponentManager manager;
+
+ /**
+ * Test if queue is empty.
+ *
+ * @return true if queue is empty else false.
+ */
+
+ public boolean isEmpty() {
+ return (this.linkedList.size() == 0);
+ }
+
+ /**
+ * Get components of the ComponentManager
+ *
+ * @param manager Description of Parameter
+ * @exception ComponentException Description of Exception
+ */
+
+ public void compose(ComponentManager manager)
+ throws ComponentException {
+
+ this.manager = manager;
+ if (this.getLogger().isDebugEnabled() == true) {
+ getLogger().debug("Looking up " + Store.ROLE + "/JispFilesystemStore");
+ }
+ this.fsstore = (Store) manager.lookup(Store.ROLE + "/JispFilesystemStore");
+ }
+
+ /**
+ * Dispose the component
+ */
+ public void dispose() {
+ if (this.manager != null) {
+ this.manager.release(this.fsstore);
+ this.fsstore = null;
+ }
+ }
+
+ /**
+ * Configure the Filesystem Queue:
+ * <UL>
+ * <LI> handlerinterval = Interval of the Queue Handler Thread</LI>
+ * <LI> threadpriority = Priority of the Queue Handler Thread</LI> >LI>
+ * maxobjects = Defines the max. numbers of Objects in the queue</LI>
+ *
+ * </UL>
+ *
+ *
+ * @param conf Description of Parameter
+ * @exception ConfigurationException Description of Exception
+ */
+
+ public void configure(Configuration conf)
+ throws ConfigurationException {
+
+ Parameters params = Parameters.fromConfiguration(conf);
+ this.handlerinterval = params.getParameterAsInteger("handlerinterval", 10);
+ this.threadpriority = params.getParameterAsInteger("threadpriority", 5);
+ this.maxobjects = params.getParameterAsInteger("maxobjects", 100);
+
+ if (this.getLogger().isDebugEnabled() == true) {
+ this.getLogger().debug("Configure Filesystem Queue");
+ this.getLogger().debug("handlerinterval=" + handlerinterval);
+ this.getLogger().debug("threadpriority=" + threadpriority);
+ }
+ this.linkedList = new LinkedList();
+ }
+
+ /**
+ * Starts the Queue Handler Thread
+ */
+ public void start() {
+ doRun = true;
+ this.fsQueueHandler = new Thread(this);
+ this.fsQueueHandler.setDaemon(true);
+ this.fsQueueHandler.setPriority(this.threadpriority);
+ this.fsQueueHandler.setName("fsQueueHandler");
+ this.fsQueueHandler.start();
+ }
+
+ /**
+ * Stops the Queue Handler Thread
+ */
+ public void stop() {
+ doRun = false;
+ }
+
+ /**
+ * Main processing method for the FilesystemQueueImpl object
+ */
+ public void run() {
+ while (doRun) {
+ while (!this.isEmpty()) {
+ FilesystemQueueObject filesystemQueueObject =
(FilesystemQueueObject) this.pop();
+ try {
+ this.fsstore.store(filesystemQueueObject.getKey(),
+ filesystemQueueObject.getObject()
+ );
+ } catch (IOException e) {
+ this.getLogger().error("Error in fsQueueHandler", e);
+ }
+ } try {
+ Thread.currentThread().sleep(this.handlerinterval * 1000);
+ } catch (InterruptedException ignore) {;}
+ }
+ }
+
+ /**
+ * Clear all elements from queue.
+ */
+ public void clear() {
+ if (this.getLogger().isDebugEnabled() == true) {
+ this.getLogger().debug("Clearing the FilesystemQueue");
+ }
+
+ ListIterator listIterator = linkedList.listIterator(0);
+ while (listIterator.hasNext()) {
+ this.linkedList.remove(listIterator.nextIndex());
+ }
+ }
+
+ /**
+ * Insert an element into queue.
+ *
+ * @param element the element to be inserted
+ */
+ public void insert(Object element) {
+
+ if (this.linkedList.size() < maxobjects) {
+ if (this.getLogger().isDebugEnabled() == true) {
+ this.getLogger().debug("Insert Element in FilesystemQueue");
+ }
+ this.linkedList.addFirst(element);
+ this.reportSize();
+ } else {
+ this.getLogger().warn("Filesystem Queue full!");
+ }
+ }
+
+ /**
+ * Return element on top of heap but don't remove it.
+ *
+ * @return the element at top of heap
+ * @exception NoSuchElementException if isEmpty() == true
+ */
+ public Object peek()
+ throws NoSuchElementException {
+ if (this.getLogger().isDebugEnabled() == true) {
+ this.getLogger().debug("Peek Element in FilesystemQueue");
+ }
+
+ return (Comparable) linkedList.getLast();
+ }
+
+ /**
+ * Return element on top of heap and remove it.
+ *
+ * @return the element at top of heap
+ * @exception NoSuchElementException if isEmpty() == true
+ */
+ public Object pop()
+ throws NoSuchElementException {
+ if (this.getLogger().isDebugEnabled() == true) {
+ this.getLogger().debug("Pop Element in FilesystemQueue");
+ }
+ return (Comparable) linkedList.removeLast();
+ }
+
+ private void reportSize() {
+ if (this.getLogger().isDebugEnabled() == true) {
+ this.getLogger().debug("Size of FilesystemQueue="
+ + this.linkedList.size());
+ }
+ }
+}
+
+
+
1.3 +357 -1
xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/JispFilesystemStore.java
Index: JispFilesystemStore.java
===================================================================
RCS file:
/home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/JispFilesystemStore.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- JispFilesystemStore.java 6 Jan 2002 14:28:10 -0000 1.2
+++ JispFilesystemStore.java 6 Jan 2002 17:18:26 -0000 1.3
@@ -1 +1,357 @@
-/**
* 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.jispstore;
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.components.store.Store;
import
org.apache.cocoon.util.IOUtils;
import com.coyotegulch.jisp.BTreeIndex;
import
com.coyotegulch.jisp.IndexedObjectDatabase;
import com.coyotegulch.jisp.KeyNotFound;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import
java.util.Enumeration;
/**
* 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 Gerhard
Froehlich
* <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
*/
public
final class JispFilesystemStore
extends AbstractLoggable
implements Store,
Contextualizable,
ThreadSafe,
Initializable,
Parameterizable {
/**
* The directory repository
*/
protected File
mDirectoryFile;
/**
* Description of the Field
*/
protected
volatile String mDirectoryPath;
/**
* The database
*/
private
String mDatabaseName;
private String mIndexName;
private int mOrder;
private IndexedObjectDatabase mDatabase;
private BTreeIndex mIndex;
/**
* Sets the repository's location
*
* @param 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 the new directory
value
* @exception IOException
*/
public void setDirectory(final File
directory)
throws IOException {
this.mDirectoryFile = directory;
/*
* Save directory path prefix
*/
this.mDirectoryPath =
IOUtils.getFullFilename(this.mDirectoryFile);
this.mDirectoryPath +=
File.separator;
/*
* Does directory exist?
*/
if
(!this.mDirectoryFile.exists()) {
/*
* Create it anew
*/
if (!this.mDirectoryFile.mkdir()) {
throw new
IOException(
"Error creating store directory '"
+ this.mDirectoryPath + "': ");
}
}
/*
* Is given file actually a directory?
*/
if
(!this.mDirectoryFile.isDirectory()) {
throw new IOException("'" +
this.mDirectoryPath
+ "' is not a directory");
}
/*
* Is directory readable and writable?
*/
if (!(this.mDirectoryFile.canRead()
&& this.mDirectoryFile.canWrite()))
{
throw new IOException(
"Directory '" +
this.mDirectoryPath
+ "' is not readable/writable"
);
}
}
/**
* Returns the repository's full pathname
*
* @return the directory as String
*/
public String getDirectoryPath() {
return this.mDirectoryPath;
}
/**
* Returns a Object from the
store associated with the Key Object
*
* @param the Key object
*
@return the Object associated with Key Object
*/
public Object get(Object
key) {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("get(): Get file with key: " + key.toString());
}
Object readObj = null;
try {
readObj = mDatabase.read(new
JispStringKey(key.toString()), mIndex);
if (getLogger().isDebugEnabled())
{
if (readObj != null) {
this.getLogger().debug("get(): FOUND!!= " + readObj);
} else {
this.getLogger().debug("get(): NOT_FOUND!!");
}
}
} catch (Exception e) {
getLogger().error("get(..): Exception",
e);
}
return readObj;
}
/**
* Contextualize the
Component
*
* @param the Context of the Application
* @exception
ContextException
*/
public void contextualize(final Context context)
throws ContextException {
try {
setDirectory((File)
context.get(Constants.CONTEXT_WORK_DIR));
} catch (Exception e) {
// ignore
}
}
/**
* Initialize the Component
*/
public
void initialize() {
if (getLogger().isDebugEnabled()) {
getLogger().debug("initialize() JispFilesystemStore");
}
try {
if (getLogger().isDebugEnabled()) {
getLogger().debug("initialize(): Path to Datafile="
+
this.getDirectoryPath() + mDatabaseName);
}
File myFile = new
File(this.getDirectoryPath() + mDatabaseName);
if (myFile.exists()) {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("initialize(): Datafile exists");
}
mDatabase = new IndexedObjectDatabase(getDirectoryPath()
+ mDatabaseName, false);
mIndex = new
BTreeIndex(this.getDirectoryPath() + mIndexName);
mDatabase.attachIndex(mIndex);
mIndex.dumpTree();
} else {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("initialize(): Datafile not exists");
}
mDatabase = new IndexedObjectDatabase(getDirectoryPath()
+ mDatabaseName, false);
mIndex = new
BTreeIndex(this.getDirectoryPath() + mIndexName,
mOrder, new
JispStringKey(), false);
mDatabase.attachIndex(mIndex);
mIndex.dumpTree();
}
} catch (KeyNotFound ignore) {
}
catch (Exception e) {
getLogger().error("initialize(..) Exception", e);
}
}
/**
* Configure the Component. A few options can be used :
* <UL>
* <LI> mDatabaseName = the name of the data file (Default:
cocoon.dat)
* </LI>
* <LI> mIndexName = the name of the index file
(Default: cocoon.idx)
* </LI>
* <LI> mOrder = The page size of the
B-Tree</LI>
* </UL>
*
*
* @param The Configuration Paramter
* @exception ParameterException
*/
public void parameterize(Parameters
params)
throws ParameterException {
mDatabaseName =
params.getParameter("datafile", "cocoon.dat");
mIndexName =
params.getParameter("indexfile", "cocoon.idx");
mOrder =
params.getParameterAsInteger("order", 1001);
if
(getLogger().isDebugEnabled()) {
this.getLogger().debug("parameterize(..):
mDatabaseName="
+ mDatabaseName);
this.getLogger().debug("parameterize(..): mIndexName="
+ mIndexName);
this.getLogger().debug("parameterize(..): mOrder=" +
mOrder);
}
}
/**
* Store the given Object in the indexed data
file.
*
* @param the Key Object
* @param 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());
}
if (value instanceof Serializable) {
try {
JispStringKey[] keyArray = new JispStringKey[1];
keyArray[0] = new JispStringKey(key.toString());
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
the Key Object
* @param 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
*/
public void free() {
//TODO: implementation
}
/**
*
Removes a value from the data file with the given key.
*
* @param the Key
Object
*/
public void remove(Object key) {
if
(getLogger().isDebugEnabled()) {
this.getLogger().debug("remove(..) Remove
item");
}
try {
JispStringKey[] keyArray = new
JispStringKey[1];
keyArray[0] = new JispStringKey(key.toString());
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 the Key Object
* @return true if Key exists and false if not
*/
public boolean containsKey(Object key) {
long res = -1;
try {
res = mIndex.findKey(new JispStringKey(key.toString()));
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
*
*
@return Enumeration Object with all existing keys
*/
public Enumeration
keys() {
//TODO: Implementation
return null;
}
}
\ No newline at end of file
+/**
+ * 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.jispstore;
+
+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.components.store.Store;
+import org.apache.cocoon.util.IOUtils;
+
+import com.coyotegulch.jisp.BTreeIndex;
+import com.coyotegulch.jisp.IndexedObjectDatabase;
+import com.coyotegulch.jisp.KeyNotFound;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Enumeration;
+
+/**
+ * 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 Gerhard Froehlich
+ * <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
+ */
+
+public final class JispFilesystemStore
+extends AbstractLoggable
+implements Store,
+ Contextualizable,
+ ThreadSafe,
+ Initializable,
+ Parameterizable {
+
+ /**
+ * The directory repository
+ */
+ protected File mDirectoryFile;
+
+ /**
+ * Description of the Field
+ */
+ protected volatile String mDirectoryPath;
+
+
+
+ /**
+ * The database
+ */
+ private String mDatabaseName;
+ private String mIndexName;
+ private int mOrder;
+ private IndexedObjectDatabase mDatabase;
+ private BTreeIndex mIndex;
+
+ /**
+ * Sets the repository's location
+ *
+ * @param 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 the new directory value
+ * @exception IOException
+ */
+
+ public void setDirectory(final File directory)
+ throws IOException {
+ this.mDirectoryFile = directory;
+
+ /*
+ * Save directory path prefix
+ */
+ this.mDirectoryPath = IOUtils.getFullFilename(this.mDirectoryFile);
+ this.mDirectoryPath += File.separator;
+
+ /*
+ * Does directory exist?
+ */
+ if (!this.mDirectoryFile.exists()) {
+ /*
+ * Create it anew
+ */
+ if (!this.mDirectoryFile.mkdir()) {
+ throw new IOException(
+ "Error creating store directory '"
+ + this.mDirectoryPath + "': ");
+ }
+ }
+
+ /*
+ * Is given file actually a directory?
+ */
+ if (!this.mDirectoryFile.isDirectory()) {
+ throw new IOException("'" + this.mDirectoryPath
+ + "' is not a directory");
+ }
+
+ /*
+ * Is directory readable and writable?
+ */
+ if (!(this.mDirectoryFile.canRead()
+ && this.mDirectoryFile.canWrite())) {
+ throw new IOException(
+ "Directory '" + this.mDirectoryPath
+ + "' is not readable/writable"
+ );
+ }
+ }
+
+ /**
+ * Returns the repository's full pathname
+ *
+ * @return the directory as String
+ */
+ public String getDirectoryPath() {
+ return this.mDirectoryPath;
+ }
+
+ /**
+ * Returns a Object from the store associated with the Key Object
+ *
+ * @param the Key object
+ * @return the Object associated with Key Object
+ */
+ public Object get(Object key) {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("get(): Get file with key: " + key.toString());
+ }
+ Object readObj = null;
+
+ try {
+ readObj = mDatabase.read(new JispStringKey(key.toString()), mIndex);
+ if (getLogger().isDebugEnabled()) {
+ if (readObj != null) {
+ this.getLogger().debug("get(): FOUND!!= " + readObj);
+ } else {
+ this.getLogger().debug("get(): NOT_FOUND!!");
+ }
+ }
+ } catch (Exception e) {
+ getLogger().error("get(..): Exception", e);
+ }
+ return readObj;
+ }
+
+ /**
+ * Contextualize the Component
+ *
+ * @param the Context of the Application
+ * @exception ContextException
+ */
+ public void contextualize(final Context context)
+ throws ContextException {
+ try {
+ setDirectory((File) context.get(Constants.CONTEXT_WORK_DIR));
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ /**
+ * Initialize the Component
+ */
+ public void initialize() {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("initialize() JispFilesystemStore");
+ }
+
+ try {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("initialize(): Path to Datafile="
+ + this.getDirectoryPath() + mDatabaseName);
+ }
+ File myFile = new File(this.getDirectoryPath() + mDatabaseName);
+ if (myFile.exists()) {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("initialize(): Datafile exists");
+ }
+ mDatabase = new IndexedObjectDatabase(getDirectoryPath()
+ + mDatabaseName, false);
+ mIndex = new BTreeIndex(this.getDirectoryPath() + mIndexName);
+ mDatabase.attachIndex(mIndex);
+ mIndex.dumpTree();
+ } else {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("initialize(): Datafile not exists");
+ }
+ mDatabase = new IndexedObjectDatabase(getDirectoryPath()
+ + mDatabaseName, false);
+ mIndex = new BTreeIndex(this.getDirectoryPath() + mIndexName,
+ mOrder, new JispStringKey(), false);
+ mDatabase.attachIndex(mIndex);
+ mIndex.dumpTree();
+ }
+ } catch (KeyNotFound ignore) {
+ } catch (Exception e) {
+ getLogger().error("initialize(..) Exception", e);
+ }
+ }
+
+ /**
+ * Configure the Component. A few options can be used :
+ * <UL>
+ * <LI> mDatabaseName = the name of the data file (Default: cocoon.dat)
+ * </LI>
+ * <LI> mIndexName = the name of the index file (Default: cocoon.idx)
+ * </LI>
+ * <LI> mOrder = The page size of the B-Tree</LI>
+ * </UL>
+ *
+ *
+ * @param The Configuration Paramter
+ * @exception ParameterException
+ */
+ public void parameterize(Parameters params)
+ throws ParameterException {
+ mDatabaseName = params.getParameter("datafile", "cocoon.dat");
+ mIndexName = params.getParameter("indexfile", "cocoon.idx");
+ mOrder = params.getParameterAsInteger("order", 1001);
+
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("parameterize(..): mDatabaseName="
+ + mDatabaseName);
+ this.getLogger().debug("parameterize(..): mIndexName="
+ + mIndexName);
+ this.getLogger().debug("parameterize(..): mOrder=" + mOrder);
+ }
+ }
+
+ /**
+ * Store the given Object in the indexed data file.
+ *
+ * @param the Key Object
+ * @param 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());
+ }
+
+ if (value instanceof Serializable) {
+ try {
+ JispStringKey[] keyArray = new JispStringKey[1];
+ keyArray[0] = new JispStringKey(key.toString());
+ 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 the Key Object
+ * @param 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
+ */
+ public void free() {
+ //TODO: implementation
+ }
+
+ /**
+ * Removes a value from the data file with the given key.
+ *
+ * @param the Key Object
+ */
+ public void remove(Object key) {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("remove(..) Remove item");
+ }
+
+ try {
+ JispStringKey[] keyArray = new JispStringKey[1];
+ keyArray[0] = new JispStringKey(key.toString());
+ 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 the Key Object
+ * @return true if Key exists and false if not
+ */
+ public boolean containsKey(Object key) {
+ long res = -1;
+
+ try {
+ res = mIndex.findKey(new JispStringKey(key.toString()));
+ 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
+ *
+ * @return Enumeration Object with all existing keys
+ */
+ public Enumeration keys() {
+ //TODO: Implementation
+ return null;
+ }
+}
+
+
+
1.3 +114 -1
xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/JispStringKey.java
Index: JispStringKey.java
===================================================================
RCS file:
/home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/jispstore/JispStringKey.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- JispStringKey.java 6 Jan 2002 14:28:10 -0000 1.2
+++ JispStringKey.java 6 Jan 2002 17:18:26 -0000 1.3
@@ -1 +1,114 @@
-/*****************************************************************************
*
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.jispstore;
import com.coyotegulch.jisp.KeyObject;
import
java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
*
Wrapper class to make our cache Key compatible with the Jisp KeyObject NOTE:
* This
Wrapper is only for String Keys.
*
* @author Gerhard Froehlich <a
href="mailto:[EMAIL PROTECTED]">
* [EMAIL PROTECTED]</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 the Value of the Key as String
*/
public JispStringKey(String
keyValue) {
mKey = keyValue;
}
/**
* Compares two Keys
*
* @param 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();
}
/**
*
*
* @param out Description of Parameter
* @exception IOException
Description of Exception
*/
public void writeExternal(ObjectOutput out)
throws IOException {
String outKey;
outKey = new String(mKey);
out.writeUTF(outKey);
}
/**
* Description of the Method
*
*
@param in Description of Parameter
* @exception
IOException Description of Exception
* @exception
ClassNotFoundException Description of Exception
*/
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;
}
}
\ No newline at end of file
+/*****************************************************************************
+ * 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.jispstore;
+
+import com.coyotegulch.jisp.KeyObject;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * Wrapper class to make our cache Key compatible with the Jisp KeyObject NOTE:
+ * This Wrapper is only for String Keys.
+ *
+ * @author Gerhard Froehlich <a href="mailto:[EMAIL PROTECTED]">
+ * [EMAIL PROTECTED]</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 the Value of the Key as String
+ */
+ public JispStringKey(String keyValue) {
+ mKey = keyValue;
+ }
+
+ /**
+ * Compares two Keys
+ *
+ * @param 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();
+ }
+
+ /**
+ *
+ *
+ * @param out Description of Parameter
+ * @exception IOException Description of Exception
+ */
+ public void writeExternal(ObjectOutput out)
+ throws IOException {
+ String outKey;
+ outKey = new String(mKey);
+ out.writeUTF(outKey);
+ }
+
+ /**
+ * Description of the Method
+ *
+ * @param in Description of Parameter
+ * @exception IOException Description of Exception
+ * @exception ClassNotFoundException Description of Exception
+ */
+
+ 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.3 +301 -1
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.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- MRUMemoryStore.java 6 Jan 2002 14:28:10 -0000 1.2
+++ MRUMemoryStore.java 6 Jan 2002 17:18:26 -0000 1.3
@@ -1 +1,301 @@
-/*****************************************************************************
*
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.jispstore;
import org.apache.avalon.framework.activity.Disposable;
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.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.components.store.FilesystemQueue;
import
org.apache.cocoon.components.store.FilesystemQueueObject;
import
org.apache.cocoon.components.store.Store;
import
org.apache.cocoon.components.store.StoreJanitor;
import
org.apache.cocoon.util.ClassUtils;
import java.util.Enumeration;
import
java.util.Hashtable;
import java.util.LinkedList;
/**
* This class provides a cache
algorithm for the requested documents. It
* combines a HashMap and a LinkedList to
create a so called MRU (Most Recently
* Used) cache.
*
* @author <a
href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
* @author <a
href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
*/
public final class
MRUMemoryStore
extends AbstractLoggable
implements Store,
Parameterizable,
ThreadSafe,
Composable,
Disposable {
private int
mMaxobjects;
private boolean mFilesystem;
private Hashtable mCache;
private LinkedList mMRUList;
private Store mFsstore;
private StoreJanitor
mStorejanitor;
private FilesystemQueue mFilesystemQueue;
private
ComponentManager mComponetManager;
/**
* Get the object associated to the
given unique key.
*
* @param the Key Object
* @return the Object
associated with Key Object
*/
public Object get(Object key) {
if
(getLogger().isDebugEnabled()) {
this.getLogger().debug("Getting object
from memory. Key: " + key);
}
Object tmpobject = this.mCache.get(key);
if (tmpobject != null) {
this.mMRUList.remove(key);
this.mMRUList.addFirst(key);
return tmpobject;
}
this.getLogger().debug("Object not found in memory");
if (this.mFilesystem) {
tmpobject = this.mFsstore.get(key);
if (tmpobject == null) {
if (getLogger().isDebugEnabled()) {
this.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");
}
if (!this.mCache.containsKey(key)) {
this.hold(key, tmpobject);
}
return tmpobject;
}
}
return null;
}
/**
* Get components of the ComponentManager
*
* @param the Component Manager
* @exception ComponentException
*/
public void compose(ComponentManager manager)
throws ComponentException {
this.mComponetManager = manager;
if (getLogger().isDebugEnabled()) {
getLogger().debug("Looking up "
+ Store.ROLE +
"/JispFilesystemStore");
}
this.mFsstore = (Store)
manager.lookup(Store.ROLE
+
"/JispFilesystemStore");
if (getLogger().isDebugEnabled()) {
getLogger().debug("Looking up " + StoreJanitor.ROLE);
}
this.mStorejanitor = (StoreJanitor) manager.lookup(StoreJanitor.ROLE);
if
(getLogger().isDebugEnabled()) {
getLogger().debug("Looking up " +
FilesystemQueue.ROLE);
}
this.mFilesystemQueue = (FilesystemQueue)
manager.lookup(FilesystemQueue.ROLE);
}
/**
* Configure the
MRUMemoryStore. A few options can be used :
* <UL>
* <LI> mMaxobjects =
how many objects will be stored in memory (Default:
* 10 objects)</LI>
*
<LI> mFilesystem = use filesystem storage to keep object persistent
*
(Default: false)</LI>
* </UL>
*
*
* @param the Configuration
Parameters
* @exception ParameterException
*/
public void
parameterize(Parameters params)
throws ParameterException {
this.mMaxobjects = params.getParameterAsInteger("maxobjects", 100);
this.mFilesystem = params.getParameterAsBoolean("filesystem", false);
if
((this.mMaxobjects < 1)) {
throw new ParameterException("MRUMemoryStore
maxobjects must be "
+ "at least 1 milli
second!");
}
this.mCache = new Hashtable((int) (this.mMaxobjects *
1.2));
this.mMRUList = new LinkedList();
this.mStorejanitor.register(this);
}
/**
* Dispose the component
*/
public void dispose() {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("dispose()");
}
if (this.mComponetManager !=
null) {
this.mComponetManager.release(this.mStorejanitor);
this.mStorejanitor = null;
this.mComponetManager.release(this.mFilesystemQueue);
this.mFilesystemQueue = null;
this.mComponetManager.release(this.mFsstore);
this.mFsstore = null;
}
}
/**
* Store the given object in a persistent state. It is up to
the caller to
* ensure that the key has a persistent state across different JVM
* executions.
*
* @param the Key Object
* @param the Value Object
*/
public void store(Object key, Object value) {
if (this.mFilesystem)
{
if (this.checkSerializable(value) &&
!this.mFsstore.containsKey(key)) {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("Storing object on fs");
}
try {
this.mFilesystemQueue.insert(new
FilesystemQueueObject(key, value));
} catch (Exception e) {
this.getLogger().error("Error storing Object on fs", e);
}
}
}
}
/**
* This method holds the requested object in
a HashMap combined with a
* LinkedList to create the MRU. It also stores objects
onto the filesystem
* if configured.
*
* @param the Key Object
*
@param the Value Object
*/
public void hold(Object key, Object value) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Holding object in
memory. key: " + key);
getLogger().debug("Holding object in memory. value:
" + value);
}
while (this.mMRUList.size() >= this.mMaxobjects) {
this.free();
}
this.mCache.put(key, value);
this.mMRUList.remove(key);
this.mMRUList.addFirst(key);
if
(getLogger().isDebugEnabled()) {
this.getLogger().debug("Cache size=" +
mCache.size());
}
}
/**
* Remove the object associated to the
given key.
*
* @param the Key object
*/
public void remove(Object
key) {
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("Removing object from store");
}
this.mCache.remove(key);
this.mMRUList.remove(key);
if
(this.mFilesystem && key != null) {
this.mFsstore.remove(key);
}
}
/**
* Indicates if the given key is associated to a contained object.
*
* @param the Key Object
* @return true if Key exists and false if not
*/
public boolean containsKey(Object key) {
if (mFilesystem) {
return (this.mCache.containsKey(key)
||
this.mFsstore.containsKey(key));
} else {
return
this.mCache.containsKey(key);
}
}
/**
* Returns the list of
used keys as an Enumeration.
*
* @return the enumeration of the cache
*/
public Enumeration keys() {
return this.mCache.keys();
}
/**
* Frees some of the fast memory used by this store. It removes the last
*
element in the store.
*/
public void free() {
try {
if
(this.mCache.size() > 0) {
this.getLogger().debug("Freeing cache");
this.mCache.remove(this.mMRUList.getLast());
this.mMRUList.removeLast();
if (getLogger().isDebugEnabled()) {
this.getLogger().debug("Cache size=" + mCache.size());
}
}
} catch (Exception e) {
this.getLogger().error("Error
in free()", e);
}
}
/**
* This method checks if an object is
seriazable. FIXME: In the moment only
* CachedEventObject or CachedStreamObject
are stored.
*
* @param the Object to be tested
* @return true if the
object is storeable
*/
private boolean checkSerializable(Object object) {
try {
if (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"))) {
return true;
} else {
return false;
}
} catch (Exception
e) {
this.getLogger().error("Error in checkSerializable()!", e);
return false;
}
}
}
\ No newline at end of file
+/*****************************************************************************
+ * 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.jispstore;
+
+import org.apache.avalon.framework.activity.Disposable;
+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.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.components.store.FilesystemQueue;
+import org.apache.cocoon.components.store.FilesystemQueueObject;
+import org.apache.cocoon.components.store.Store;
+import org.apache.cocoon.components.store.StoreJanitor;
+import org.apache.cocoon.util.ClassUtils;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedList;
+
+/**
+ * This class provides a cache algorithm for the requested documents. It
+ * combines a HashMap and a LinkedList to create a so called MRU (Most Recently
+ * Used) cache.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
+ */
+public final class MRUMemoryStore
+extends AbstractLoggable
+implements Store,
+ Parameterizable,
+ ThreadSafe,
+ Composable,
+ Disposable {
+
+ private int mMaxobjects;
+ private boolean mFilesystem;
+ private Hashtable mCache;
+ private LinkedList mMRUList;
+ private Store mFsstore;
+ private StoreJanitor mStorejanitor;
+ private FilesystemQueue mFilesystemQueue;
+ private ComponentManager mComponetManager;
+
+ /**
+ * Get the object associated to the given unique key.
+ *
+ * @param the Key Object
+ * @return the Object associated with Key Object
+ */
+ public Object get(Object key) {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("Getting object from memory. Key: " + key);
+ }
+ Object tmpobject = this.mCache.get(key);
+ if (tmpobject != null) {
+ this.mMRUList.remove(key);
+ this.mMRUList.addFirst(key);
+ return tmpobject;
+ }
+
+ this.getLogger().debug("Object not found in memory");
+ if (this.mFilesystem) {
+ tmpobject = this.mFsstore.get(key);
+ if (tmpobject == null) {
+ if (getLogger().isDebugEnabled()) {
+ this.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");
+ }
+ if (!this.mCache.containsKey(key)) {
+ this.hold(key, tmpobject);
+ }
+ return tmpobject;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get components of the ComponentManager
+ *
+ * @param the Component Manager
+ * @exception ComponentException
+ */
+ public void compose(ComponentManager manager)
+ throws ComponentException {
+ this.mComponetManager = manager;
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Looking up "
+ + Store.ROLE + "/JispFilesystemStore");
+ }
+
+ this.mFsstore = (Store) manager.lookup(Store.ROLE
+ + "/JispFilesystemStore");
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Looking up " + StoreJanitor.ROLE);
+ }
+ this.mStorejanitor = (StoreJanitor) manager.lookup(StoreJanitor.ROLE);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Looking up " + FilesystemQueue.ROLE);
+ }
+ this.mFilesystemQueue = (FilesystemQueue)
manager.lookup(FilesystemQueue.ROLE);
+ }
+
+ /**
+ * Configure the MRUMemoryStore. A few options can be used :
+ * <UL>
+ * <LI> mMaxobjects = how many objects will be stored in memory (Default:
+ * 10 objects)</LI>
+ * <LI> mFilesystem = use filesystem storage to keep object persistent
+ * (Default: false)</LI>
+ * </UL>
+ *
+ *
+ * @param the Configuration Parameters
+ * @exception ParameterException
+ */
+
+ public void parameterize(Parameters params)
+ throws ParameterException {
+ this.mMaxobjects = params.getParameterAsInteger("maxobjects", 100);
+ this.mFilesystem = params.getParameterAsBoolean("filesystem", false);
+ if ((this.mMaxobjects < 1)) {
+ throw new ParameterException("MRUMemoryStore maxobjects must be "
+ + "at least 1 milli second!");
+ }
+ this.mCache = new Hashtable((int) (this.mMaxobjects * 1.2));
+ this.mMRUList = new LinkedList();
+ this.mStorejanitor.register(this);
+ }
+
+ /**
+ * Dispose the component
+ */
+ public void dispose() {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("dispose()");
+ }
+
+ if (this.mComponetManager != null) {
+ this.mComponetManager.release(this.mStorejanitor);
+ this.mStorejanitor = null;
+ this.mComponetManager.release(this.mFilesystemQueue);
+ this.mFilesystemQueue = null;
+ this.mComponetManager.release(this.mFsstore);
+ this.mFsstore = null;
+ }
+ }
+
+ /**
+ * Store the given object in a persistent state. It is up to the caller to
+ * ensure that the key has a persistent state across different JVM
+ * executions.
+ *
+ * @param the Key Object
+ * @param the Value Object
+ */
+ public void store(Object key, Object value) {
+ if (this.mFilesystem) {
+ if (this.checkSerializable(value) &&
+ !this.mFsstore.containsKey(key)) {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("Storing object on fs");
+ }
+ try {
+ this.mFilesystemQueue.insert(new FilesystemQueueObject(key,
value));
+ } catch (Exception e) {
+ this.getLogger().error("Error storing Object on fs", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method holds the requested object in a HashMap combined with a
+ * LinkedList to create the MRU. It also stores objects onto the filesystem
+ * if configured.
+ *
+ * @param the Key Object
+ * @param the Value Object
+ */
+ public void hold(Object key, Object value) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Holding object in memory. key: " + key);
+ getLogger().debug("Holding object in memory. value: " + value);
+ }
+
+ while (this.mMRUList.size() >= this.mMaxobjects) {
+ this.free();
+ }
+
+ this.mCache.put(key, value);
+ this.mMRUList.remove(key);
+ this.mMRUList.addFirst(key);
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("Cache size=" + mCache.size());
+ }
+ }
+
+ /**
+ * Remove the object associated to the given key.
+ *
+ * @param the Key object
+ */
+ public void remove(Object key) {
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("Removing object from store");
+ }
+ this.mCache.remove(key);
+ this.mMRUList.remove(key);
+ if (this.mFilesystem && key != null) {
+ this.mFsstore.remove(key);
+ }
+ }
+
+ /**
+ * Indicates if the given key is associated to a contained object.
+ *
+ * @param the Key Object
+ * @return true if Key exists and false if not
+ */
+ public boolean containsKey(Object key) {
+ if (mFilesystem) {
+ return (this.mCache.containsKey(key)
+ || this.mFsstore.containsKey(key));
+ } else {
+ return this.mCache.containsKey(key);
+ }
+ }
+
+ /**
+ * Returns the list of used keys as an Enumeration.
+ *
+ * @return the enumeration of the cache
+ */
+ public Enumeration keys() {
+ return this.mCache.keys();
+ }
+
+ /**
+ * Frees some of the fast memory used by this store. It removes the last
+ * element in the store.
+ */
+ public void free() {
+ try {
+ if (this.mCache.size() > 0) {
+ this.getLogger().debug("Freeing cache");
+ this.mCache.remove(this.mMRUList.getLast());
+ this.mMRUList.removeLast();
+ if (getLogger().isDebugEnabled()) {
+ this.getLogger().debug("Cache size=" + mCache.size());
+ }
+ }
+ } catch (Exception e) {
+ this.getLogger().error("Error in free()", e);
+ }
+ }
+
+ /**
+ * This method checks if an object is seriazable. FIXME: In the moment only
+ * CachedEventObject or CachedStreamObject are stored.
+ *
+ * @param the Object to be tested
+ * @return true if the object is storeable
+ */
+ private boolean checkSerializable(Object object) {
+ try {
+ if (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"))) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception e) {
+ this.getLogger().error("Error in checkSerializable()!", e);
+ return false;
+ }
+ }
+}
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]