Commits

dr...@81dbac14-341a-0410-aa85-cbcd92e6f43e  committed fd4f1b0

Submitter: Andres March

major refactorings to move towards 3.0. ACRC is gone, yay! basic memory cache in place.

  • Participants
  • Parent commits 7edb993
  • Branches amarch_sandbox

Comments (0)

Files changed (51)

File src/core/java/com/opensymphony/oscache/algorithm/FIFOCache.java

+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.oscache.algorithm;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.opensymphony.oscache.core.MemoryCache;
+
+/**
+ * FIFO (First In First Out) based queue algorithm for the cache.
+ *
+ * No synchronization is required in this class since the
+ * <code>AbstractConcurrentReadCache</code> already takes care of any
+ * synchronization requirements.
+ *
+ * @version        $Revision$
+ * @author        <a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
+ * @author        <a href="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
+ * @author        <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
+ */
+public class FIFOCache extends MemoryCache {
+    /**
+     * A queue containing all cache keys
+     */
+    private Collection list;
+
+    /**
+     * A flag indicating whether we are using a List or a Set for the key collection
+     */
+    private boolean isSet = false;
+
+    /**
+     * Constructs a FIFO Cache.
+     */
+    public FIFOCache() {
+        super();
+
+        // Check if we're running under JRE 1.4+. If so we can use a LinkedHashSet
+        // instead of a LinkedList for a big performance boost when removing elements.
+        try {
+            Class.forName("java.util.LinkedHashSet");
+            list = new LinkedHashSet();
+            isSet = true;
+        } catch (ClassNotFoundException e) {
+            list = new LinkedList();
+        }
+    }
+
+    /**
+     * Constructs a FIFO Cache of the specified capacity.
+     *
+     * @param capacity The maximum cache capacity.
+     */
+    public FIFOCache(int capacity) {
+        super(capacity);
+    }
+
+    /**
+     * An object was retrieved from the cache. This implementation
+     * does noting since this event has no impact on the FIFO algorithm.
+     *
+     * @param key The cache key of the item that was retrieved.
+     */
+    protected void itemRetrieved(Object key) {
+    }
+
+    /**
+     * An object was put in the cache. This implementation just adds
+     * the key to the end of the list if it doesn't exist in the list
+     * already.
+     *
+     * @param key The cache key of the item that was put.
+     */
+    protected void itemPut(Object key) {
+        if (!list.contains(key)) {
+            list.add(key);
+        }
+    }
+
+    /**
+     * An item needs to be removed from the cache. The FIFO implementation
+     * removes the first element in the list (ie, the item that has been in
+     * the cache for the longest time).
+     *
+     * @return The key of whichever item was removed.
+     */
+    protected Object removeItem() {
+        Object toRemove;
+
+        if (isSet) {
+            Iterator it = list.iterator();
+            toRemove = it.next();
+            it.remove();
+        } else {
+            toRemove = ((List) list).remove(0);
+        }
+
+        return toRemove;
+    }
+
+    /**
+     * Remove specified key since that object has been removed from the cache.
+     *
+     * @param key The cache key of the item that was removed.
+     */
+    protected void itemRemoved(Object key) {
+        list.remove(key);
+    }
+}

File src/core/java/com/opensymphony/oscache/algorithm/UnlimitedEvictionAlgorithm.java

+package com.opensymphony.oscache.algorithm;
+
+import java.util.Properties;
+
+import com.opensymphony.oscache.core.EvictionAlgorithm;
+
+/**
+ * An {@link EvictionAlgorithm} that never evicts cache entries - the
+ * cache grows without bound.
+ */
+public class UnlimitedEvictionAlgorithm implements EvictionAlgorithm {
+
+  /**
+   * Initialises the unlimited eviction policy. This policy takes
+   * no parameters, there is nothing to configure.
+   */
+  public void init(Properties params) {
+  }
+
+  /**
+   * Called whenever an object is put in the cache. This implementation
+   * does nothing.
+   */
+  public void put(Object key, Object value) {
+  }
+
+  /**
+   * Called whenever an object is retrieved from the cache. This
+   * implementation does nothing.
+   */
+  public void get(Object key, Object value) {
+  }
+
+  /**
+   * Called whenever an object is removed from the cache. This
+   * implementation does nothing.
+   */
+  public void remove(Object key, Object value) {
+  }
+
+  /**
+   * Because this is an unlimited cache, no cache entries ever get
+   * evicted by this implementation.
+   *
+   * @return always returns <code>null</code>.
+   */
+  public Object evict() {
+    return null;
+  }
+}

File src/core/java/com/opensymphony/oscache/base/AbstractCacheAdministrator.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-import java.util.List;
-import java.util.Properties;
-
-import javax.swing.event.EventListenerList;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import com.opensymphony.oscache.base.events.CacheEntryEventListener;
-import com.opensymphony.oscache.base.events.CacheEventListener;
-import com.opensymphony.oscache.base.events.CacheMapAccessEventListener;
-import com.opensymphony.oscache.base.persistence.PersistenceListener;
-import com.opensymphony.oscache.util.StringUtil;
-
-/**
- * An AbstractCacheAdministrator defines an abstract cache administrator, implementing all
- * the basic operations related to the configuration of a cache, including assigning
- * any configured event handlers to cache objects.<p>
- *
- * Extend this class to implement a custom cache administrator.
- *
- * @version        $Revision$
- * @author        a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
- * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
- * @author <a href="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
- * @author <a href="mailto:fabian.crabus@gurulogic.de">Fabian Crabus</a>
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- */
-public abstract class AbstractCacheAdministrator implements java.io.Serializable {
-    private static transient final Log log = LogFactory.getLog(AbstractCacheAdministrator.class);
-
-    /**
-     * A boolean cache configuration property that indicates whether the cache
-     * should cache objects in memory. Set this property to <code>false</code>
-     * to disable in-memory caching.
-     */
-    public final static String CACHE_MEMORY_KEY = "cache.memory";
-
-    /**
-     * An integer cache configuration property that specifies the maximum number
-     * of objects to hold in the cache. Setting this to a negative value will
-     * disable the capacity functionality - there will be no limit to the number
-     * of objects that are held in cache.
-     */
-    public final static String CACHE_CAPACITY_KEY = "cache.capacity";
-
-    /**
-     * A String cache configuration property that specifies the classname of
-     * an alternate caching algorithm. This class must extend
-     * {@link com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache}
-     * By default caches will use {@link com.opensymphony.oscache.base.algorithm.LRUCache} as
-     * the default algorithm if the cache capacity is set to a postive value, or
-     * {@link com.opensymphony.oscache.base.algorithm.UnlimitedCache} if the
-     * capacity is negative (ie, disabled).
-     */
-    public final static String CACHE_ALGORITHM_KEY = "cache.algorithm";
-
-    /**
-     * A boolean cache configuration property that indicates whether the persistent
-     * cache should be unlimited in size, or should be restricted to the same size
-     * as the in-memory cache. Set this property to <code>true</code> to allow the
-     * persistent cache to grow without bound.
-     */
-    public final static String CACHE_DISK_UNLIMITED_KEY = "cache.unlimited.disk";
-
-    /**
-     * The configuration key that specifies whether we should block waiting for new
-     * content to be generated, or just serve the old content instead. The default
-     * behaviour is to serve the old content since that provides the best performance
-     * (at the cost of serving slightly stale data).
-     */
-    public final static String CACHE_BLOCKING_KEY = "cache.blocking";
-
-    /**
-     * A String cache configuration property that specifies the classname that will
-     * be used to provide cache persistence. This class must extend {@link PersistenceListener}.
-     */
-    public static final String PERSISTENCE_CLASS_KEY = "cache.persistence.class";
-
-    /**
-     * A String cache configuration property that specifies if the cache persistence
-     * will only be used in overflow mode, that is, when the memory cache capacity has been reached.
-     */
-    public static final String CACHE_PERSISTENCE_OVERFLOW_KEY = "cache.persistence.overflow.only";
-
-    /**
-     * A String cache configuration property that holds a comma-delimited list of
-     * classnames. These classes specify the event handlers that are to be applied
-     * to the cache.
-     */
-    public static final String CACHE_ENTRY_EVENT_LISTENERS_KEY = "cache.event.listeners";
-    protected Config config = null;
-
-    /**
-     * Holds a list of all the registered event listeners. Event listeners are specified
-     * using the {@link #CACHE_ENTRY_EVENT_LISTENERS_KEY} configuration key.
-     */
-    protected EventListenerList listenerList = new EventListenerList();
-
-    /**
-     * The algorithm class being used, as specified by the {@link #CACHE_ALGORITHM_KEY}
-     * configuration property.
-     */
-    protected String algorithmClass = null;
-
-    /**
-     * The cache capacity (number of entries), as specified by the {@link #CACHE_CAPACITY_KEY}
-     * configuration property.
-     */
-    protected int cacheCapacity = -1;
-
-    /**
-     * Whether the cache blocks waiting for content to be build, or serves stale
-     * content instead. This value can be specified using the {@link #CACHE_BLOCKING_KEY}
-     * configuration property.
-     */
-    private boolean blocking = false;
-
-    /**
-     * Whether or not to store the cache entries in memory. This is configurable using the
-     * {@link com.opensymphony.oscache.base.AbstractCacheAdministrator#CACHE_MEMORY_KEY} property.
-     */
-    private boolean memoryCaching = true;
-
-    /**
-     * Whether the persistent cache should be used immediately or only when the memory capacity
-         * has been reached, ie. overflow only.
-     * This can be set via the {@link #CACHE_PERSISTENCE_OVERFLOW_KEY} configuration property.
-     */
-    private boolean overflowPersistence;
-
-    /**
-     * Whether the disk cache should be unlimited in size, or matched 1-1 to the memory cache.
-     * This can be set via the {@link #CACHE_DISK_UNLIMITED_KEY} configuration property.
-     */
-    private boolean unlimitedDiskCache;
-
-	/**
-	 * Application cache
-	 */
-	protected Cache applicationCache = null;
-
-    /**
-     * Create the AbstractCacheAdministrator.
-     * This will initialize all values and load the properties from oscache.properties.
-     */
-    protected AbstractCacheAdministrator() {
-        this(null);
-    }
-
-    /**
-     * Create the AbstractCacheAdministrator.
-     *
-     * @param p the configuration properties for this cache.
-     */
-    protected AbstractCacheAdministrator(Properties p) {
-        loadProps(p);
-        initCacheParameters();
-
-        if (log.isDebugEnabled()) {
-            log.debug("Constructed AbstractCacheAdministrator()");
-        }
-    }
-    
-    protected Object get(Object key) {
-    		CacheEntry entry = getCache().get(key);
-    		return entry.getContent();
-    }
-    
-    protected void put(Object key, Object value) {
-    		CacheEntry entry = new CacheEntry(key, value);
-		synchronized (entry) {
-			CacheEntry oldEntry = getCache().put(key, entry);
-			// Signal to any threads waiting on this update that it's now ready for
-			// them
-			// in the cache!
-			completeUpdate(entry);
-			entry.notifyAll();
-		}
-    }
-    
-    /**
-	 * Removes the update state for the specified key and notifies any other
-	 * threads that are waiting on this object. This is called automatically by
-	 * the {@link #putInCache} method. This method must be called only when the entry is 
-	 * locked.
-	 * 
-	 * @param key
-	 *            The cache key that is no longer being updated.
-	 */
-	protected void completeUpdate(CacheEntry cacheEntry) {
-
-		if (cacheEntry != null) {
-			if (!cacheEntry.isUpdating()) {
-				cacheEntry.startUpdate();
-			}
-
-			cacheEntry.completeUpdate();
-		}
-	}
-
-    /**
-     * Sets the algorithm to use for the cache.
-     *
-     * @see com.opensymphony.oscache.base.algorithm.LRUCache
-     * @see com.opensymphony.oscache.base.algorithm.FIFOCache
-     * @see com.opensymphony.oscache.base.algorithm.UnlimitedCache
-     * @param newAlgorithmClass The class to use (eg.
-     * <code>"com.opensymphony.oscache.base.algorithm.LRUCache"</code>)
-     */
-    public void setAlgorithmClass(String newAlgorithmClass) {
-        algorithmClass = newAlgorithmClass;
-    }
-
-    /**
-     * Indicates whether the cache will block waiting for new content to
-     * be built, or serve stale content instead of waiting. Regardless of this
-     * setting, the cache will <em>always</em> block if new content is being
-     * created, ie, there's no stale content in the cache that can be served.
-     */
-    public boolean isBlocking() {
-        return blocking;
-    }
-
-    /**
-     * Sets the cache capacity (number of items). Administrator implementations
-     * should override this method to ensure that their {@link Cache} objects
-     * are updated correctly (by calling {@link AbstractConcurrentReadCache#setMaxEntries(int)}}}.
-     *
-     * @param newCacheCapacity The new capacity
-     */
-    protected void setCacheCapacity(int newCacheCapacity) {
-        cacheCapacity = newCacheCapacity;
-    }
-
-    /**
-     * Whether entries are cached in memory or not.
-     * Default is true.
-     * Set by the <code>cache.memory</code> property.
-     *
-     * @return Status whether or not memory caching is used.
-     */
-    public boolean isMemoryCaching() {
-        return memoryCaching;
-    }
-
-    /**
-     * Retrieves the value of one of the configuration properties.
-     *
-     * @param key The key assigned to the property
-     * @return Property value, or <code>null</code> if the property could not be found.
-     */
-    public String getProperty(String key) {
-        return config.getProperty(key);
-    }
-
-    /**
-     * Indicates whether the unlimited disk cache is enabled or not.
-     */
-    public boolean isUnlimitedDiskCache() {
-        return unlimitedDiskCache;
-    }
-
-    /**
-     * Check if we use overflowPersistence
-     *
-     * @return Returns the overflowPersistence.
-     */
-    public boolean isOverflowPersistence() {
-        return this.overflowPersistence;
-    }
-
-    /**
-     * Sets the overflowPersistence flag
-     *
-     * @param overflowPersistence The overflowPersistence to set.
-     */
-    public void setOverflowPersistence(boolean overflowPersistence) {
-        this.overflowPersistence = overflowPersistence;
-    }
-
-    /**
-     * Retrieves an array containing instances all of the {@link CacheEventListener}
-     * classes that are specified in the OSCache configuration file.
-     */
-    protected CacheEventListener[] getCacheEventListeners() {
-        CacheEventListener[] listeners = null;
-
-        List classes = StringUtil.split(config.getProperty(CACHE_ENTRY_EVENT_LISTENERS_KEY), ',');
-        listeners = new CacheEventListener[classes.size()];
-
-        for (int i = 0; i < classes.size(); i++) {
-            String className = (String) classes.get(i);
-
-            try {
-                Class clazz = Class.forName(className);
-
-                if (!CacheEventListener.class.isAssignableFrom(clazz)) {
-                    log.error("Specified listener class '" + className + "' does not implement CacheEventListener. Ignoring this listener.");
-                } else {
-                    listeners[i] = (CacheEventListener) clazz.newInstance();
-                }
-            } catch (ClassNotFoundException e) {
-                log.error("CacheEventListener class '" + className + "' not found. Ignoring this listener.", e);
-            } catch (InstantiationException e) {
-                log.error("CacheEventListener class '" + className + "' could not be instantiated because it is not a concrete class. Ignoring this listener.", e);
-            } catch (IllegalAccessException e) {
-                log.error("CacheEventListener class '" + className + "' could not be instantiated because it is not public. Ignoring this listener.", e);
-            }
-        }
-
-        return listeners;
-    }
-
-    /**
-     * If there is a <code>PersistenceListener</code> in the configuration
-     * it will be instantiated and applied to the given cache object. If the
-     * <code>PersistenceListener</code> cannot be found or instantiated, an
-     * error will be logged but the cache will not have a persistence listener
-     * applied to it and no exception will be thrown.<p>
-     *
-     * A cache can only have one <code>PersistenceListener</code>.
-     *
-     * @param cache the cache to apply the <code>PersistenceListener</code> to.
-     *
-     * @return the same cache object that was passed in.
-     */
-    protected Cache setPersistenceListener(Cache cache) {
-        String persistenceClassname = config.getProperty(PERSISTENCE_CLASS_KEY);
-
-        try {
-            Class clazz = Class.forName(persistenceClassname);
-            PersistenceListener persistenceListener = (PersistenceListener) clazz.newInstance();
-
-//            cache.setPersistenceListener(persistenceListener.configure(config));
-        } catch (ClassNotFoundException e) {
-            log.error("PersistenceListener class '" + persistenceClassname + "' not found. Check your configuration.", e);
-        } catch (Exception e) {
-            log.error("Error instantiating class '" + persistenceClassname + "'", e);
-        }
-
-        return cache;
-    }
-
-    /**
-     * Applies all of the recognised listener classes to the supplied
-     * cache object. Recognised classes are {@link CacheEntryEventListener}
-     * and {@link CacheMapAccessEventListener}.<p>
-     *
-     * @param cache The cache to apply the configuration to.
-     * @return cache The configured cache object.
-     */
-    protected Cache configureStandardListeners(Cache cache) {
-        if (config.getProperty(PERSISTENCE_CLASS_KEY) != null) {
-            cache = setPersistenceListener(cache);
-        }
-
-        if (config.getProperty(CACHE_ENTRY_EVENT_LISTENERS_KEY) != null) {
-            // Grab all the specified listeners and add them to the cache's
-            // listener list. Note that listeners that implement more than
-            // one of the event interfaces will be added multiple times.
-            CacheEventListener[] listeners = getCacheEventListeners();
-
-            for (int i = 0; i < listeners.length; i++) {
-                // Pass through the configuration to those listeners that require it
-                if (listeners[i] instanceof LifecycleAware) {
-                    try {
-                        ((LifecycleAware) listeners[i]).initialize(cache, config);
-                    } catch (InitializationException e) {
-                        log.error("Could not initialize listener '" + listeners[i].getClass().getName() + "'. Listener ignored.", e);
-
-                        continue;
-                    }
-                }
-
-                if (listeners[i] instanceof CacheEntryEventListener) {
-//                    cache.addCacheEventListener(listeners[i], CacheEntryEventListener.class);
-                }
-
-                if (listeners[i] instanceof CacheMapAccessEventListener) {
-//                    cache.addCacheEventListener(listeners[i], CacheMapAccessEventListener.class);
-                }
-            }
-        }
-
-        return cache;
-    }
-
-    /**
-     * Finalizes all the listeners that are associated with the given cache object.
-     * Any <code>FinalizationException</code>s that are thrown by the listeners will
-     * be caught and logged.
-     */
-    protected void finalizeListeners(Cache cache) {
-        // It's possible for cache to be null if getCache() was never called (CACHE-63)
-        if (cache == null) {
-            return;
-        }
-
-//        Object[] listeners = cache.getListenerList().getListenerList();
-//
-//        for (int i = listeners.length - 2; i >= 0; i -= 2) {
-//            if (listeners[i + 1] instanceof LifecycleAware) {
-//                try {
-//                    ((LifecycleAware) listeners[i + 1]).finialize();
-//                } catch (FinalizationException e) {
-//                    log.error("Listener could not be finalized", e);
-//                }
-//            }
-//        }
-    }
-
-    /**
-     * Initialize the core cache parameters from the configuration properties.
-     * The parameters that are initialized are:
-     * <ul>
-     * <li>the algorithm class ({@link #CACHE_ALGORITHM_KEY})</li>
-     * <li>the cache size ({@link #CACHE_CAPACITY_KEY})</li>
-     * <li>whether the cache is blocking or non-blocking ({@link #CACHE_BLOCKING_KEY})</li>
-     * <li>whether caching to memory is enabled ({@link #CACHE_MEMORY_KEY})</li>
-     * <li>whether the persistent cache is unlimited in size ({@link #CACHE_DISK_UNLIMITED_KEY})</li>
-     * </ul>
-     */
-    private void initCacheParameters() {
-        algorithmClass = getProperty(CACHE_ALGORITHM_KEY);
-
-        blocking = "true".equalsIgnoreCase(getProperty(CACHE_BLOCKING_KEY));
-
-        String cacheMemoryStr = getProperty(CACHE_MEMORY_KEY);
-
-        if ((cacheMemoryStr != null) && cacheMemoryStr.equalsIgnoreCase("false")) {
-            memoryCaching = false;
-        }
-
-        unlimitedDiskCache = Boolean.valueOf(config.getProperty(CACHE_DISK_UNLIMITED_KEY)).booleanValue();
-        overflowPersistence = Boolean.valueOf(config.getProperty(CACHE_PERSISTENCE_OVERFLOW_KEY)).booleanValue();
-
-        String cacheSize = getProperty(CACHE_CAPACITY_KEY);
-
-        try {
-            if ((cacheSize != null) && (cacheSize.length() > 0)) {
-                cacheCapacity = Integer.parseInt(cacheSize);
-            }
-        } catch (NumberFormatException e) {
-            log.error("The value supplied for the cache capacity, '" + cacheSize + "', is not a valid number. The cache capacity setting is being ignored.");
-        }
-    }
-
-    /**
-     * Load the properties file from the classpath.
-     */
-    private void loadProps(Properties p) {
-        config = new Config(p);
-    }
-
-	/**
-	 * Grabs a cache
-	 *
-	 * @return The cache
-	 */
-	public Cache getCache() {
-	    return applicationCache;
-	}
-
-	/**
-	 * @return Returns the applicationCache.
-	 */
-	public Cache getApplicationCache() {
-		return applicationCache;
-	}
-
-	/**
-	 * @param applicationCache The applicationCache to set.
-	 */
-	public void setApplicationCache(Cache applicationCache) {
-		this.applicationCache = applicationCache;
-	}
-}

File src/core/java/com/opensymphony/oscache/base/Cache.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-import com.opensymphony.oscache.base.algorithm.UnlimitedCache;
-import com.opensymphony.oscache.base.events.CacheEventListener;
-import com.opensymphony.oscache.base.persistence.PersistenceListener;
-
-import java.util.Date;
-
-import javax.swing.event.EventListenerList;
-
-/**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
- */
-public interface Cache {
-	/**
-	 * An event that origininated from within another event.
-	 */
-	public static final String NESTED_EVENT = "NESTED";
-
-	/**
-	 * Allows the capacity of the cache to be altered dynamically. Note that
-	 * some cache implementations may choose to ignore this setting (eg the
-	 * {@link UnlimitedCache} ignores this call).
-	 * 
-	 * @param capacity
-	 *            the maximum number of items to hold in the cache.
-	 */
-	public abstract void setCapacity(int capacity);
-
-	/**
-	 * Checks if the cache was flushed more recently than the CacheEntry
-	 * provided. Used to determine whether to refresh the particular CacheEntry.
-	 * 
-	 * @param cacheEntry
-	 *            The cache entry which we're seeing whether to refresh
-	 * @return Whether or not the cache has been flushed more recently than this
-	 *         cache entry was updated.
-	 */
-	public abstract boolean isFlushed(CacheEntry cacheEntry);
-
-	/**
-	 * Retrieve an object from the cache specifying its key.
-	 * 
-	 * @param key
-	 *            Key of the object in the cache.
-	 * 
-	 * @return The object from cache
-	 * 
-	 */
-	public abstract CacheEntry get(Object key);
-
-	/**
-	 * Retrieve an object from the cache specifying its key.
-	 * 
-	 * @param key
-	 *            Key of the object in the cache.
-	 * @param refreshPeriod
-	 *            How long before the object needs refresh. To allow the object
-	 *            to stay in the cache indefinitely, supply a value of
-	 *            {@link CacheEntry#INDEFINITE_EXPIRY}.
-	 * 
-	 * @return The object from cache
-	 * 
-	 */
-	public abstract CacheEntry get(Object key, int refreshPeriod);
-
-	/**
-	 * Retrieve an object from the cache specifying its key.
-	 * 
-	 * @param key
-	 *            Key of the object in the cache.
-	 * @param refreshPeriod
-	 *            How long before the object needs refresh. To allow the object
-	 *            to stay in the cache indefinitely, supply a value of
-	 *            {@link CacheEntry#INDEFINITE_EXPIRY}.
-	 * @param cronExpiry
-	 *            A cron expression that specifies fixed date(s) and/or time(s)
-	 *            that this cache entry should expire on.
-	 * 
-	 * @return The object from cache
-	 * 
-	 */
-	public abstract CacheEntry get(Object key, int refreshPeriod, String cronExpiry);
-
-	/**
-	 * Cancels any pending update for this cache entry. This should
-	 * <em>only</em> be called by the thread that is responsible for
-	 * performing the update ie the thread that received the original
-	 * {@link NeedsRefreshException}.<p/> If a cache entry is not updated (via
-	 * {@link #putInCache} and this method is not called to let OSCache know the
-	 * update will not be forthcoming, subsequent requests for this cache entry
-	 * will either block indefinitely (if this is a new cache entry or
-	 * cache.blocking=true), or forever get served stale content. Note however
-	 * that there is no harm in cancelling an update on a key that either does
-	 * not exist or is not currently being updated.
-	 * 
-	 * @param key
-	 *            The key for the cache entry in question.
-	 */
-	public abstract void cancelUpdate(String key);
-
-	/**
-	 * Flush all entries in the cache on the given date/time.
-	 * 
-	 * @param date
-	 *            The date at which all cache entries will be flushed.
-	 */
-	public abstract void flushAll(Date date);
-
-	/**
-	 * Flush all entries in the cache on the given date/time.
-	 * 
-	 * @param date
-	 *            The date at which all cache entries will be flushed.
-	 * @param origin
-	 *            The origin of this flush request (optional)
-	 */
-	public abstract void flushAll(Date date, String origin);
-
-	/**
-	 * Flush the cache entry (if any) that corresponds to the cache key
-	 * supplied. This call will flush the entry from the cache and remove the
-	 * references to it from any cache groups that it is a member of. On
-	 * completion of the flush, a <tt>CacheEntryEventType.ENTRY_FLUSHED</tt>
-	 * event is fired.
-	 * 
-	 * @param key
-	 *            The key of the entry to flush
-	 */
-	public abstract void flushEntry(String key);
-
-	/**
-	 * Flush the cache entry (if any) that corresponds to the cache key
-	 * supplied. This call will mark the cache entry as flushed so that the next
-	 * access to it will cause a {@link NeedsRefreshException}. On completion
-	 * of the flush, a <tt>CacheEntryEventType.ENTRY_FLUSHED</tt> event is
-	 * fired.
-	 * 
-	 * @param key
-	 *            The key of the entry to flush
-	 * @param origin
-	 *            The origin of this flush request (optional)
-	 */
-	public abstract void flushEntry(String key, String origin);
-
-	/**
-	 * Put an object in the cache specifying the key to use.
-	 * 
-	 * @param key
-	 *            Key of the object in the cache.
-	 * @param content
-	 *            The CacheEntry to cache.
-	 */
-	public abstract CacheEntry put(Object key, CacheEntry content);
-
-	/**
-	 * Put an object in the cache specifying the key and refresh policy to use.
-	 * 
-	 * @param key
-	 *            Key of the object in the cache.
-	 * @param content
-	 *            The CacheEntry to cache.
-	 * @param policy
-	 *            Object that implements refresh policy logic
-	 */
-	public abstract CacheEntry put(Object key, CacheEntry content,
-			EntryRefreshPolicy policy);
-
-	/**
-	 * Put an object into the cache specifying both the key to use and the cache
-	 * groups the object belongs to.
-	 * 
-	 * @param key
-	 *            Key of the object in the cache
-	 * @param content
-	 *            The CacheEntry to cache
-	 * @param policy
-	 *            Object that implements the refresh policy logic
-	 */
-	public abstract CacheEntry put(Object key, CacheEntry content,
-			EntryRefreshPolicy policy, String origin);
-
-	/**
-	 * Completely clears the cache.
-	 */
-	public abstract void clear();
-
-	/**
-	 * Completely removes a cache entry from the cache and its associated cache
-	 * groups.
-	 * 
-	 * @param key
-	 *            The key of the entry to remove.
-	 */
-	public abstract CacheEntry removeEntry(String key);
-
-}

File src/core/java/com/opensymphony/oscache/base/CacheEntry.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-
-/**
- * A CacheEntry instance represents one entry in the cache. It holds the object that
- * is being cached, along with a host of information about that entry such as the
- * cache key, the time it was cached, whether the entry has been flushed or not and
- * the groups it belongs to.
- *
- * @author        <a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
- * @author        <a href="mailto:tgochenour@peregrine.com">Todd Gochenour</a>
- * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
- * @author <a href="mailto:oscache@andresmarch.com">Andres March</a>
- */
-public class CacheEntry implements Serializable {
-    /**
-	 * 
-	 */
-	private static final long serialVersionUID = -3776911995865680219L;
-
-	/**
- * Default initialization value for the creation time and the last
- * update time. This is a placeholder that indicates the value has
- * not been set yet.
- */
-    private static final byte NOT_YET = -1;
-
-    /**
- * Specifying this as the refresh period for the
- * {@link #needsRefresh(int)} method will ensure
- * an entry does not become stale until it is
- * either explicitly flushed or a custom refresh
- * policy causes the entry to expire.
- */
-    public static final int INDEFINITE_EXPIRY = -1;
-
-	
-
-    /**
- * The entry refresh policy object to use for this cache entry. This is optional.
- */
-    private EntryRefreshPolicy policy = null;
-    
-    
-    
-    private int state;
-    
-    public static final int STATE_VALID = 0;
-    public static final int STATE_STALE = -1;
-    public static final int STATE_UPDATING = 1;
-
-    /**
- * The actual content that is being cached. Wherever possible this object
- * should be serializable. This allows <code>PersistenceListener</code>s
- * to serialize the cache entries to disk or database.
- */
-    private Object content = null;
-
-
-    /**
- *  The unique cache key for this entry
- */
-    private Object key;
-
-    /**
- * <code>true</code> if this entry was flushed
- */
-    private boolean wasFlushed = false;
-
-    /**
- * The time this entry was created.
- */
-    private long created = NOT_YET;
-
-    /**
- * The time this emtry was last updated.
- */
-    private long lastUpdate = NOT_YET;
-
-    /**
- * Construct a new CacheEntry using the key provided.
- *
- * @param key    The key of this CacheEntry
- */
-    public CacheEntry(String key) {
-        this(key, null);
-    }
-
-
-    /**
- * Construct a CacheEntry.
- *
- * @param key     The unique key for this <code>CacheEntry</code>.
- * @param policy  The object that implements the refresh policy logic. This
- * parameter is optional.
- */
-    public CacheEntry(Object key, EntryRefreshPolicy policy) {
-        this.key = key;
-
-        this.policy = policy;
-        this.created = System.currentTimeMillis();
-        this.state = STATE_VALID;
-    }
-
-    public CacheEntry(Object key, Object value) {
-    		this(key, null);
-    		setContent(value);
-	}
-
-
-	/**
- * Sets the actual content that is being cached. Wherever possible this
- * object should be <code>Serializable</code>, however it is not an
- * absolute requirement when using a memory-only cache. Being <code>Serializable</code>
- * allows <code>PersistenceListener</code>s to serialize the cache entries to disk
- * or database.
- *
- * @param value The content to store in this CacheEntry.
- */
-    public synchronized void setContent(Object value) {
-        content = value;
-        lastUpdate = System.currentTimeMillis();
-        wasFlushed = false;
-    }
-
-    /**
- * Get the cached content from this CacheEntry.
- *
- * @return The content of this CacheEntry.
- */
-    public Object getContent() {
-        return content;
-    }
-
-    /**
- * Get the date this CacheEntry was created.
- *
- * @return The date this CacheEntry was created.
- */
-    public long getCreated() {
-        return created;
-    }
-
-
-    /**
- * Get the key of this CacheEntry
- *
- * @return The key of this CacheEntry
- */
-    public Object getKey() {
-        return key;
-    }
-
-    /**
- * Set the date this CacheEntry was last updated.
- *
- * @param update The time (in milliseconds) this CacheEntry was last updated.
- */
-    public void setLastUpdate(long update) {
-        lastUpdate = update;
-    }
-
-    /**
- * Get the date this CacheEntry was last updated.
- *
- * @return The date this CacheEntry was last updated.
- */
-    public long getLastUpdate() {
-        return lastUpdate;
-    }
-
-    /**
- * Indicates whether this CacheEntry is a freshly created one and
- * has not yet been assigned content or placed in a cache.
- *
- * @return <code>true</code> if this entry is newly created
- */
-    public boolean isNew() {
-        return lastUpdate == NOT_YET;
-    }
-
-    /**
- * Get the size of the cache entry in bytes (roughly).<p>
- *
- *
- * @return The approximate size of the entry in bytes, or -1 if the
- * size could not be estimated.
- */
-    public int getSize() {
-    		ByteArrayOutputStream bout = new ByteArrayOutputStream();
-        ObjectOutputStream out;
-		try {
-			out = new ObjectOutputStream(bout);
-			out.writeObject(this);			
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			return -1;
-		}
-		byte[] bytes = bout.toByteArray();
-		return bytes.length;
-        
-    }
-
-    /**
- * Flush the entry from cache.
- * note that flushing the cache doesn't actually remove the cache contents
- * it just tells the CacheEntry that it needs a refresh next time it is asked
- * this is so that the content is still there for a <usecached />.
- */
-    public void flush() {
-        wasFlushed = true;
-    }
-
-    /**
- * Check if this CacheEntry needs to be refreshed.
- *
- * @param refreshPeriod The period of refresh (in seconds). Passing in
- * {@link #INDEFINITE_EXPIRY} will result in the content never becoming
- * stale unless it is explicitly flushed, or expired by a custom
- * {@link EntryRefreshPolicy}. Passing in 0 will always result in a
- * refresh being required.
- *
- * @return Whether or not this CacheEntry needs refreshing.
- */
-    public boolean needsRefresh(int refreshPeriod) {
-        boolean needsRefresh;
-
-        // needs a refresh if it has never been updated
-        if (lastUpdate == NOT_YET) {
-            needsRefresh = true;
-        }
-        // Was it flushed from cache?
-        else if (wasFlushed) {
-            needsRefresh = true;
-        } else if (refreshPeriod == 0) {
-            needsRefresh = true;
-        }
-        // check what the policy has to say if there is one
-        else if (policy != null) {
-            needsRefresh = policy.needsRefresh(this);
-        }
-        // check if the last update + update period is in the past
-        else if ((refreshPeriod >= 0) && (System.currentTimeMillis() >= (lastUpdate + (refreshPeriod * 1000L)))) {
-            needsRefresh = true;
-        } else {
-            needsRefresh = false;
-        }
-
-        return needsRefresh;
-    }
-
-    public int getState() {
-        return state;
-    }
-
-
-	public boolean isUpdating() {
-		return state == STATE_UPDATING;
-	}
-
-
-	public void startUpdate() {
-		
-		state = STATE_UPDATING;
-	}
-	
-	/**
-     * Updates the state to <code>UPDATE_CANCELLED</code>. This should <em>only<em>
-     * be called by the thread that managed to get the update lock.
-     */
-    public void cancelUpdate() {
-        if (state != STATE_UPDATING) {
-            throw new IllegalStateException("Cannot cancel cache update - current state (" + state + ") is not UPDATE_IN_PROGRESS");
-        }
-
-        state = STATE_VALID;
-    }
-    
-    /**
-     * Updates the state to <code>UPDATE_COMPLETE</code>. This should <em>only</em>
-     * be called by the thread that managed to get the update lock.
-     */
-    public void completeUpdate() {
-        if (state != STATE_UPDATING) {
-            throw new IllegalStateException("Cannot complete cache update - current state (" + state + ") is not UPDATE_IN_PROGRESS");
-        }
-
-        state = STATE_VALID;
-    }
-}

File src/core/java/com/opensymphony/oscache/base/Config.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.io.InputStream;
-
-import java.util.Properties;
-
-/**
- * Responsible for holding the Cache configuration properties. If the default
- * constructor is used, this class will load the properties from the
- * <code>cache.configuration</code>.
- *
- * @author   <a href="mailto:fabian.crabus@gurulogic.de">Fabian Crabus</a>
- * @version  $Revision$
- */
-public class Config implements java.io.Serializable {
-    private static final transient Log log = LogFactory.getLog(Config.class);
-
-    /**
-     * Name of the properties file.
-     */
-    private final static String PROPERTIES_FILENAME = "/oscache.properties";
-
-    /**
-     * Properties map to hold the cache configuration.
-     */
-    private Properties properties = null;
-
-    /**
-     * Create an OSCache Config that loads properties from oscache.properties.
-     * The file must be present in the root of OSCache's classpath. If the file
-     * cannot be loaded, an error will be logged and the configuration will
-     * remain empty.
-     */
-    public Config() {
-        this(null);
-    }
-
-    /**
-     * Create an OSCache configuration with the specified properties.
-     * Note that it is the responsibility of the caller to provide valid
-     * properties as no error checking is done to ensure that required
-     * keys are present. If you're unsure of what keys should be present,
-     * have a look at a sample oscache.properties file.
-     *
-     * @param p The properties to use for this configuration. If null,
-     * then the default properties are loaded from the <code>oscache.properties</code>
-     * file.
-     */
-    public Config(Properties p) {
-        if (log.isDebugEnabled()) {
-            log.debug("Config() called");
-        }
-
-        if (p == null) {
-            loadProps();
-        } else {
-            this.properties = p;
-        }
-    }
-
-    /**
-     * Retrieve the value of the named configuration property. If the property
-     * cannot be found this method will return <code>null</code>.
-     *
-     * @param key The name of the property.
-     * @return The property value, or <code>null</code> if the value could
-     * not be found.
-     *
-     * @throws IllegalArgumentException if the supplied key is null.
-     */
-    public String getProperty(String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key is null");
-        }
-
-        if (properties == null) {
-            return null;
-        }
-
-        String value = properties.getProperty(key);
-        return value;
-    }
-
-    /**
-     * Retrieves all of the configuration properties. This property set
-     * should be treated as immutable.
-     *
-     * @return The configuration properties.
-     */
-    public Properties getProperties() {
-        return properties;
-    }
-
-    public Object get(Object key) {
-        return properties.get(key);
-    }
-
-    /**
-     * Sets a configuration property.
-     *
-     * @param key   The unique name for this property.
-     * @param value The value assigned to this property.
-     *
-     * @throws IllegalArgumentException if the supplied key is null.
-     */
-    public void set(Object key, Object value) {
-        if (key == null) {
-            throw new IllegalArgumentException("key is null");
-        }
-
-        if (value == null) {
-            return;
-        }
-
-        if (properties == null) {
-            properties = new Properties();
-        }
-
-        properties.put(key, value);
-    }
-
-    /**
-     * Load the properties file (<code>oscache.properties</code>)
-     * from the classpath. If the file cannot be found or loaded, an error
-     * will be logged and no properties will be set.
-     */
-    private void loadProps() {
-        if (log.isDebugEnabled()) {
-            log.debug("Getting Config");
-        }
-
-        properties = new Properties();
-
-        InputStream in = null;
-
-        try {
-            in = Config.class.getResourceAsStream(PROPERTIES_FILENAME);
-            properties.load(in);
-            log.info("Properties " + properties);
-        } catch (Exception e) {
-            log.error("Error reading " + PROPERTIES_FILENAME + " in CacheAdministrator.loadProps() " + e);
-            log.error("Ensure the " + PROPERTIES_FILENAME + " file is readable and in your classpath.");
-        } finally {
-            try {
-                in.close();
-            } catch (Exception e) {
-                // Ignore errors that occur while closing file
-            }
-        }
-    }
-}

File src/core/java/com/opensymphony/oscache/base/EntryRefreshPolicy.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-import java.io.Serializable;
-
-/**
- * Interface that allows custom code to be called when checking to see if a cache entry
- * has expired. This is useful when the rules that determine when content needs refreshing
- * are beyond the base funtionality offered by OSCache.
- *
- * @version        $Revision$
- * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
- */
-public interface EntryRefreshPolicy extends Serializable {
-    /**
-     * Indicates whether the supplied <code>CacheEntry</code> needs to be refreshed.
-     * This will be called when retrieving an entry from the cache - if this method
-     * returns <code>true</code> then a <code>NeedsRefreshException</code> will be
-     * thrown.
-     *
-     * @param entry The cache entry that is being tested.
-     * @return <code>true</code> if the content needs refreshing, <code>false</code> otherwise.
-     *
-     * @see NeedsRefreshException
-     * @see CacheEntry
-     */
-    public boolean needsRefresh(CacheEntry entry);
-}

File src/core/java/com/opensymphony/oscache/base/EntryUpdateState.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-
-/**
- * Holds the state of a Cache Entry that is in the process of being (re)generated.
- * This is not synchronized; the synchronization must be handled by the calling
- * classes.
- *
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- * @author Author: $
- * @version Revision: $
- */
-public class EntryUpdateState {
-    /**
-     * The initial state when this object is first created
-     */
-    public static final int NOT_YET_UPDATING = -1;
-
-    /**
-     * Update in progress state
-     */
-    public static final int UPDATE_IN_PROGRESS = 0;
-
-    /**
-     * Update complete state
-     */
-    public static final int UPDATE_COMPLETE = 1;
-
-    /**
-     * Update cancelled state
-     */
-    public static final int UPDATE_CANCELLED = 2;
-
-    /**
-     * Current update state
-     */
-    int state = NOT_YET_UPDATING;
-
-    /**
-     * This is the initial state when an instance this object is first created.
-     * It indicates that a cache entry needs updating, but no thread has claimed
-     * responsibility for updating it yet.
-     */
-    public boolean isAwaitingUpdate() {
-        return state == NOT_YET_UPDATING;
-    }
-
-    /**
-     * The thread that was responsible for updating the cache entry (ie, the thread
-     * that managed to grab the update lock) has decided to give up responsibility
-     * for performing the update. OSCache will notify any other threads that are
-     * waiting on the update so one of them can take over the responsibility.
-     */
-    public boolean isCancelled() {
-        return state == UPDATE_CANCELLED;
-    }
-
-    /**
-     * The update of the cache entry has been completed.
-     */
-    public boolean isComplete() {
-        return state == UPDATE_COMPLETE;
-    }
-
-    /**
-     * The cache entry is currently being generated by the thread that got hold of
-     * the update lock.
-     */
-    public boolean isUpdating() {
-        return state == UPDATE_IN_PROGRESS;
-    }
-
-
-    /**
-     * Attempt to change the state to <code>UPDATE_IN_PROGRESS</code>. Calls
-     * to this method must be synchronized on the EntryUpdateState instance.
-     */
-    public void startUpdate() {
-        if ((state != NOT_YET_UPDATING) && (state != UPDATE_CANCELLED) && (state != UPDATE_COMPLETE)) {
-            throw new IllegalStateException("Cannot begin cache update - current state (" + state + ") is not NOT_YET_UPDATING or UPDATE_CANCELLED");
-        }
-
-        state = UPDATE_IN_PROGRESS;
-    }
-}

File src/core/java/com/opensymphony/oscache/base/FinalizationException.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-
-/**
- * Thrown by {@link LifecycleAware} listeners that are not able to finalize
- * themselves.
- *
- * @version $Revision$
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- */
-public class FinalizationException extends Exception {
-    public FinalizationException() {
-        super();
-    }
-
-    public FinalizationException(String message) {
-        super(message);
-    }
-}

File src/core/java/com/opensymphony/oscache/base/InitializationException.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-
-/**
- * Thrown by {@link LifecycleAware} listeners that are not able to initialize
- * themselves.
- *
- * @version $Revision$
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- */
-public class InitializationException extends Exception {
-    public InitializationException() {
-        super();
-    }
-
-    public InitializationException(String message) {
-        super(message);
-    }
-}

File src/core/java/com/opensymphony/oscache/base/LifecycleAware.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-
-/**
- * Event handlers implement this so they can be notified when a cache
- * is created and also when it is destroyed. This allows event handlers
- * to load any configuration and/or resources they need on startup and
- * then release them again when the cache is shut down.
- *
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- *
- * @see com.opensymphony.oscache.base.events.CacheEventListener
- */
-public interface LifecycleAware {
-    /**
-    * Called by the cache administrator class when a cache is instantiated.
-    *
-    * @param cache the cache instance that this listener is attached to.
-    * @param config The cache's configuration details. This allows the event handler
-    * to initialize itself based on the cache settings, and also to receive <em>additional</em>
-    * settings that were part of the cache configuration but that the cache
-    * itself does not care about. If you are using <code>cache.properties</code>
-    * for your configuration, simply add any additional properties that your event
-    * handler requires and they will be passed through in this parameter.
-    *
-    * @throws InitializationException thrown when there was a problem initializing the
-    * listener. The cache administrator will log this error and disable the listener.
-    */
-    public void initialize(Cache cache, Config config) throws InitializationException;
-
-    /**
-    * Called by the cache administrator class when a cache is destroyed.
-    *
-    * @throws FinalizationException thrown when there was a problem finalizing the
-    * listener. The cache administrator will catch and log this error.
-    */
-    public void finialize() throws FinalizationException;
-}

File src/core/java/com/opensymphony/oscache/base/MemoryCache.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.base;
-
-import java.io.Serializable;
-import java.text.ParseException;
-import java.util.Date;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import com.opensymphony.oscache.base.events.CacheMapAccessEventType;
-import com.opensymphony.oscache.util.FastCronParser;
-
-import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Provides an interface to the cache itself. Creating an instance of this class
- * will create a cache that behaves according to its construction parameters.
- * The public API provides methods to manage objects in the cache and configure
- * any cache event listeners.
- * 
- * @version $Revision$
- * @author <a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
- * @author <a href="mailto:tgochenour@peregrine.com">Todd Gochenour</a>
- * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
- * @author <a
- *         href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris
- *         Miller</a>
- */
-public class MemoryCache implements Serializable, Cache {
-	private static transient final Log log = LogFactory
-			.getLog(MemoryCache.class);
-
-	/**
-	 * Date of last complete cache flush.
-	 */
-	private Date flushDateTime = null;
-
-	/**
-	 * The actual cache map. This is where the cached objects are held.
-	 */
-	private Map cacheMap = new ConcurrentHashMap();
-	
-	private int capacity; 
-
-	/**
-	 * 
-	 */
-	public MemoryCache() {
-
-		// TODO Auto-generated constructor stub
-	}
-	
-	/**
-	 * 
-	 */
-	public MemoryCache(int capacity) {
-
-		this.capacity = capacity;
-	}
-
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see com.opensymphony.oscache.base.Cache#isFlushed(com.opensymphony.oscache.base.CacheEntry)
-	 */
-	public boolean isFlushed(CacheEntry cacheEntry) {
-		if (flushDateTime != null) {
-			long lastUpdate = cacheEntry.getLastUpdate();
-
-			return (flushDateTime.getTime() >= lastUpdate);
-		} else {
-			return false;
-		}
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see com.opensymphony.oscache.base.CacheAPI#getFromCache(java.lang.String)
-	 */
-	public CacheEntry get(Object key) {
-		return get(key, CacheEntry.INDEFINITE_EXPIRY, null);
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see com.opensymphony.oscache.base.CacheAPI#getFromCache(java.lang.String,
-	 *      int)
-	 */
-	public CacheEntry get(Object key, int refreshPeriod) {
-		return get(key, refreshPeriod, null);
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see com.opensymphony.oscache.base.CacheAPI#getFromCache(java.lang.String,
-	 *      int, java.lang.String)
-	 */
-	public CacheEntry get(Object key, int refreshPeriod, String cronExpiry) {
-		CacheEntry cacheEntry = getCacheEntry(key, null, null);
-
-		Object content = cacheEntry.getContent();
-		CacheMapAccessEventType accessEventType = CacheMapAccessEventType.HIT;
-
-		boolean reload = false;
-
-		// Check if this entry has expired or has not yet been added to the
-		// cache. If
-		// so, we need to decide whether to block or serve stale content
-		if (this.isStale(cacheEntry, refreshPeriod, cronExpiry)) {
-
-			synchronized (cacheEntry) {
-				if (!cacheEntry.isUpdating()) {
-					// No one else is currently updating this entry - grab
-					// ownership
-					cacheEntry.startUpdate();
-
-					if (cacheEntry.isNew()) {
-						accessEventType = CacheMapAccessEventType.MISS;
-					} else {
-						accessEventType = CacheMapAccessEventType.STALE_HIT;
-					}
-				} else {
-					// Another thread is already updating the cache. We block if
-					// this
-					// is a new entry, or blocking mode is enabled. Either
-					// putInCache()
-					// or cancelUpdate() can cause this thread to resume.
-					if (cacheEntry.isNew()) {
-						do {
-							try {
-								cacheEntry.wait();
-							} catch (InterruptedException e) {
-							}
-						} while (cacheEntry.isUpdating());
-						
-							// The updating thread cancelled the update, let
-							// this one have a go.
-						cacheEntry.startUpdate();
-
-						if (cacheEntry.isNew()) {
-							accessEventType = CacheMapAccessEventType.MISS;
-						} else {
-							accessEventType = CacheMapAccessEventType.STALE_HIT;
-						}						
-						
-					}
-					reload = true;
-				} 
-			}
-		}
-
-		// If reload is true then another thread must have successfully rebuilt
-		// the cache entry
-		if (reload) {
-			cacheEntry = (CacheEntry) cacheMap.get(key);
-
-			if (cacheEntry != null) {
-				content = cacheEntry.getContent();
-			} else {
-				log
-						.error("Could not reload cache entry after waiting for it to be rebuilt");
-			}
-		}
-
-
-		// If we didn't end up getting a hit then we need to throw a NRE
-		if (accessEventType != CacheMapAccessEventType.HIT) {
-			
-		}
-
-		return cacheEntry;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see com.opensymphony.oscache.base.CacheAPI#cancelUpdate(java.lang.String)
-	 */
-	public void cancelUpdate(String key) {
-
-		if (key != null) {
-			CacheEntry cacheEntry = (CacheEntry) cacheMap.get(key);
-
-			if (cacheEntry != null) {
-				synchronized (cacheEntry) {
-					cacheEntry.cancelUpdate();
-					cacheEntry.notify();
-				}
-			}
-		}
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see com.opensymphony.oscache.base.CacheAPI#flushAll(java.util.Date)
-	 */
-	public void flushAll(Date date) {
-		flushAll(date, null);