Commits

Anonymous committed 95563b1

Submitter: Andres March

fix some basic functions.

  • Participants
  • Parent commits 6facee2
  • Branches amarch_sandbox

Comments (0)

Files changed (15)

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

  */
 package com.opensymphony.oscache.core;
 
-import java.text.ParseException;
 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.events.CacheEntryEventListener;
-import com.opensymphony.oscache.events.CacheEventListener;
+import com.opensymphony.oscache.events.CacheListener;
 import com.opensymphony.oscache.events.CacheMapAccessEventListener;
 import com.opensymphony.oscache.events.CacheMapAccessEventType;
-import com.opensymphony.oscache.persistence.PersistenceListener;
-import com.opensymphony.oscache.util.FastCronParser;
 import com.opensymphony.oscache.util.StringUtil;
 
 /**
 			.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.
+	 * A configuration parameter that specifies the initial size of the thread
+	 * pool used for handling asynchronous cache laods. This only needs to be
+	 * specified if the cache has an asynchronous cache loader that doesn't
+	 * implement {@link ConnectorService}.
 	 */
-	public final static String CACHE_MEMORY_KEY = "cache.memory";
+	public static final String MIN_THREADS_PARAM = "minThreads";
+
+	/**
+	 * A configuration parameter that specifies the maximum size of the thread
+	 * pool used for handling asynchronous cache laods. This only needs to be
+	 * specified if the cache has an asynchronous cache loader that doesn't
+	 * implement {@link ConnectorService}.
+	 */
+	public static final String MAX_THREADS_PARAM = "maxThreads";
+
+	private static final int DEFAULT_MIN_LOADER_THREADS = 0;
+
+	private static final int DEFAULT_MAX_LOADER_THREADS = 10;
+
+	private int minThreads = DEFAULT_MIN_LOADER_THREADS;
+
+	private int maxThreads = DEFAULT_MAX_LOADER_THREADS;
 
 	/**
 	 * An integer cache configuration property that specifies the maximum number
 	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";
+	public static final String CACHE_LISTENERS_KEY = "cache.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.
+	 * Holds a list of all the registered listeners. listeners are specified
+	 * using the {@link #CACHE_LISTENERS_KEY} configuration key.
 	 */
-	protected EventListenerList listenerList = new EventListenerList();
+	private List listeners;
 
 	/**
 	 * The algorithm class being used, as specified by the
 	 */
 	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.core.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;
+	private List regions;
 
 	/**
 	 * Create the AbstractCacheAdministrator. This will initialize all values
 		}
 	}
 
-	public Object get(String regionName, Object key) {		
-		return get(regionName, key, 0);
-	}
-	
-	public Object get(String regionName, Object key, int refreshPeriod) {		
-		return get(regionName, key, 0, null);
+	public Object get(String regionName, Object key) {
+		return getCache().get(key);
 	}
 
-	public Object get(String regionName, Object key, int refreshPeriod, String cronExpiry) {
-		CacheMapAccessEventType accessEventType = CacheMapAccessEventType.MISS;
-		Object entry = getCache().get(key);
-		
-		
-		return entry;
+	public Object get(String regionName, Object key, int refreshPeriod) {
+		return getCache().get(key, refreshPeriod);
+	}
+
+	public Object get(String regionName, Object key, int refreshPeriod,
+			String cronExpiry) {
+
+		Object value = getCache().get(key, refreshPeriod, cronExpiry);
+
+		return value;
 	}
 
 	protected void put(Object key, Object value) {
 		getCache().put(key, value);
-			
-			value.notifyAll();
+
 	}
 
-	
 	/**
 	 * Sets the algorithm to use for the cache.
 	 * 
 	}
 
 	/**
-	 * 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.
+	 * Retrieves an array containing instances all of the {@link CacheListener}
+	 * classes that are specified in the OSCache configuration file.
 	 */
-	public boolean isMemoryCaching() {
-		return memoryCaching;
-	}
+	protected CacheListener[] initCacheListeners() {
+		CacheListener[] listeners = null;
 
-	/**
-	 * 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()];
+		List classes = StringUtil.split(
+				config.getProperty(CACHE_LISTENERS_KEY), ',');
+		listeners = new CacheListener[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)) {
+				if (!CacheListener.class.isAssignableFrom(clazz)) {
 					log
 							.error("Specified listener class '"
 									+ className
-									+ "' does not implement CacheEventListener. Ignoring this listener.");
+									+ "' does not implement CacheListener. Ignoring this listener.");
 				} else {
-					listeners[i] = (CacheEventListener) clazz.newInstance();
+					listeners[i] = (CacheListener) clazz.newInstance();
 				}
 			} catch (ClassNotFoundException e) {
-				log.error("CacheEventListener class '" + className
+				log.error("CacheListener class '" + className
 						+ "' not found. Ignoring this listener.", e);
 			} catch (InstantiationException e) {
 				log
 						.error(
-								"CacheEventListener class '"
+								"CacheListener class '"
 										+ className
 										+ "' could not be instantiated because it is not a concrete class. Ignoring this listener.",
 								e);
 			} catch (IllegalAccessException e) {
 				log
 						.error(
-								"CacheEventListener class '"
+								"CacheListener class '"
 										+ className
 										+ "' could not be instantiated because it is not public. Ignoring this listener.",
 								e);
 	}
 
 	/**
-	 * 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}.
 	 * @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) {
+		if (config.getProperty(CACHE_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();
+			CacheListener[] listeners = initCacheListeners();
 
 			for (int i = 0; i < listeners.length; i++) {
 				// Pass through the configuration to those listeners that
 						continue;
 					}
 				}
+				cache.addCacheListener(listeners[i]);
 
-				if (listeners[i] instanceof CacheEntryEventListener) {
-					// cache.addCacheEventListener(listeners[i],
-					// CacheEntryEventListener.class);
-				}
-
-				if (listeners[i] instanceof CacheMapAccessEventListener) {
-					// cache.addCacheEventListener(listeners[i],
-					// CacheMapAccessEventListener.class);
-				}
 			}
 		}
 
 			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);
-		// }
-		// }
-		// }
+		Object[] listeners = initCacheListeners();
+
+		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);
+				}
+			}
+		}
 	}
 
 	/**
 	 * </ul>
 	 */
 	private void initCacheParameters() {
-		algorithmClass = getProperty(CACHE_ALGORITHM_KEY);
+		algorithmClass = config.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);
+		String cacheSize = config.getProperty(CACHE_CAPACITY_KEY);
 
 		try {
 			if ((cacheSize != null) && (cacheSize.length() > 0)) {
 	 * @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;
+		return (Cache) regions.get(0);
 	}
 }

src/core/java/com/opensymphony/oscache/core/BaseCache.java

 package com.opensymphony.oscache.core;
 
 import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 
 import com.opensymphony.oscache.algorithm.UnlimitedEvictionAlgorithm;
-import com.opensymphony.oscache.events.CacheMapAccessEventType;
+import com.opensymphony.oscache.events.CacheEntryEvent;
+import com.opensymphony.oscache.events.CacheEvent;
+import com.opensymphony.oscache.events.CacheListener;
 import com.opensymphony.oscache.util.FastCronParser;
 
 /**
 
 	private String name;
 
+	private final Object LISTENER_LOCK = new Object();
+
+	private List listeners;
+
 	/**
 	 * Initialises the base cache. Valid properties are:
 	 * <ul>
 	public void shutdown() {
 
 	}
-	
+
 	/**
 	 * Retrieves an object from the cache.
 	 * 
 	 * @return the cached object, or <code>null</code> if the object could not
 	 *         be found and could not be loaded.
 	 */
-	public synchronized Object get(Object key, int refreshPeriod, String cronExpiry) {
+	public synchronized Object get(Object key, int refreshPeriod,
+			String cronExpiry) {
 		CacheEntry cacheEntry = getEntry(key);
+		Object content = null;
+		if (cacheEntry != null) {
+			content = cacheEntry.getValue();
+			// 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)) {
+				remove(key);
+				content = null;
+			} else {
+				policy.get(key, cacheEntry);
 
-		Object content = cacheEntry.getValue();
-		CacheMapAccessEventType accessEventType = CacheMapAccessEventType.HIT;
-		// 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)) {
-			remove(key);
-			return null;
-		} else {
-			policy.get(key, cacheEntry);
-			return content;
+			}
 		}
+		return content;
 
-		
 	}
 
 	public synchronized Object remove(Object key) {
 		CacheEntry result = removeInternal(key);
 		if (result != null) {
 			policy.remove(key, result);
+			fireEvent(result, CacheEvent.REMOVE);
 		}
 		return result;
 	}
 	 * @return the previous object that was stored under this key, if any.
 	 */
 	public synchronized Object put(Object key, Object value) {
-
-		CacheEntry result = putInternal(new CacheEntry(key, value));
-		policy.put(key, value);
+		CacheEntry newEntry = new CacheEntry(key, value);
+		CacheEntry oldEntry = putInternal(newEntry);
+		policy.put(key, newEntry);
 
 		// Remove an entry from the cache if the eviction policy says we need to
 		Object evictionKey = policy.evict();
 			removeInternal(evictionKey);
 		}
 
-		return result.getValue();
+	    // fire off a notification message
+	    if (oldEntry == null)
+	    {
+	      fireEvent(newEntry, CacheEvent.ADD);
+	    } else {
+	      fireEvent(newEntry, CacheEvent.UPDATE);
+	    }
+
+	    return  newEntry.getValue();
 	}
 
 	/**
 	public synchronized CacheEntry getEntry(Object key) {
 		return getEntry(key, null, null);
 	}
+
 	/**
 	 * Get an entry from this cache or create one if it doesn't exist.
 	 * 
 	 *            The origin of request (optional)
 	 * @return CacheEntry for the specified key.
 	 */
-	public synchronized CacheEntry getEntry(Object key, EntryRefreshPolicy policy,
-			String origin) {
+	public synchronized CacheEntry getEntry(Object key,
+			EntryRefreshPolicy policy, String origin) {
 		CacheEntry cacheEntry = getInternal(key);
 
+		return cacheEntry;
+	}
 
-		return cacheEntry;
+	/**
+	 * Adds a listener that will receive notifications when cache events occur.
+	 * 
+	 * @param listener
+	 *            the listener to receive the events.
+	 */
+	public void addCacheListener(CacheListener listener) {
+		synchronized (LISTENER_LOCK) {
+			if (listeners == null)
+				listeners = new ArrayList();
+			listeners.add(listener);
+		}
+	}
+
+	/**
+	 * Removes a listener from the cache.
+	 * 
+	 * @param listener
+	 *            the listener to remove.
+	 * @return <code>true</code> if the listener was removed successfully,
+	 *         <code>false</code> if the listener could not be found.
+	 */
+	public boolean removeCacheListener(CacheListener listener) {
+		synchronized (LISTENER_LOCK) {
+			if (listeners != null)
+				return listeners.remove(listener);
+			else
+				return false;
+		}
 	}
 
 	/**
 
 		return result;
 	}
+	
+	 /**
+	   * Fires a cache event.
+	   *
+	   * @param key       the key of the object that the event relates to.
+	   * @param value     the object that the event relates to.
+	   * @param eventType the type of event that occurred. See {@link CacheEvent}
+	   *                  for the possible event types.
+	   */
+	  protected void fireEvent(CacheEntry entry, int eventType)
+	  {
+	    synchronized (LISTENER_LOCK)
+	    {
+	      if (listeners != null)
+	      {
+	    	  CacheEntryEvent event = new CacheEntryEvent(this, entry, eventType);
+	        int i = 0;
+	        for (int size = listeners.size(); i < size; i++)
+	        {
+	          CacheListener listener = (CacheListener) listeners.get(i);
+	          listener.onChange(event);
+	        }
+	      }
+	    }
+	  }
+
 
 	/**
 	 * Retrieves the name of this cache instance.

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

 import java.util.Date;
 import java.util.Map;
 
+import com.opensymphony.oscache.events.CacheListener;
+
+
 /**
  * DOCUMENT ME!
  * 
  * @version $Revision$
  */
 public interface Cache extends Map {
-	/**
-	 * 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
 	 * Completely clears the cache.
 	 */
 	public abstract void clear();
+	
+	/**
+	   * Adds a listener that will receive notifications when cache events occur.
+	   * Listeners will be notified of cache events in the same order as they have
+	   * been added to the cache.
+	   *
+	   * @param listener the listener to receive the events.
+	   */
+	  void addCacheListener(CacheListener listener);
+
+	  /**
+	   * Removes a listener from the cache.
+	   *
+	   * @param listener the listener to remove.
+	   * @return <code>true</code> if the listener was removed successfully,
+	   *         <code>false</code> if the listener could not be found.
+	   */
+	  boolean removeCacheListener(CacheListener listener);
 
 }

src/core/java/com/opensymphony/oscache/core/CacheEvent.java

-package com.opensymphony.oscache.core;
-
-import java.util.EventObject;
-
-/**
- * Represents a cache event. Possible event types are:
- * <ul>
- * <li>{@link #ADD_EVENT} - an entry was added to the cache</li>
- * <li>{@link #UPDATE_EVENT} - a cache entry was updated</li>
- * <li>{@link #REMOVE_EVENT} - an entry was removed from the cache</li>
- * <li>{@link #CLEAR_EVENT} - the entire cache was cleared</li>
- * <li>{@link #LOAD_FAILED_EVENT} - a cache load was attempted but the load failed</li>
- * </ul>
- */
-public class CacheEvent extends EventObject {
-  public static final int ADD_EVENT = 1;
-  public static final int UPDATE_EVENT = 2;
-  public static final int REMOVE_EVENT = 3;
-  public static final int CLEAR_EVENT = 4;
-  public static final int LOAD_FAILED_EVENT = -1;
-  private Cache cache;
-  private Object key;
-  private Object value;
-  private int eventType;
-
-  public CacheEvent(Cache source, Object key, Object value, int eventType) {
-    super(source);
-    this.cache = source;
-    this.key = key;
-    this.value = value;
-    this.eventType = eventType;
-  }
-
-  public Cache getCache() {
-    return (Cache) getSource();
-  }
-
-  public Object getKey() {
-    return key;
-  }
-
-  public Object getValue() {
-    return value;
-  }
-
-  public boolean isAddEvent() {
-    return eventType == ADD_EVENT;
-  }
-
-  public boolean isUpdateEvent() {
-    return eventType == UPDATE_EVENT;
-  }
-
-  public boolean isRemoveEvent() {
-    return eventType == REMOVE_EVENT;
-  }
-
-  public boolean isClearEvent() {
-    return eventType == CLEAR_EVENT;
-  }
-
-  public boolean isLoadFailedEvent() {
-    return eventType == LOAD_FAILED_EVENT;
-  }
-
-  public String getEventTypeString() {
-    switch (eventType) {
-      case ADD_EVENT:
-        return "ADD";
-
-      case UPDATE_EVENT:
-        return "UPDATE";
-
-      case REMOVE_EVENT:
-        return "REMOVE";
-
-      case CLEAR_EVENT:
-        return "CLEAR";
-
-      case LOAD_FAILED_EVENT:
-        return "LOAD FAILED";
-    }
-    return "UNKNOWN";
-  }
-
-  public int getEventType() {
-    return eventType;
-  }
-
-  public String toString() {
-    return getClass().getName() + "[" + getEventTypeString() + ": cache=" + getSource() + " key: " + getKey() + "]";
-  }
-}

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

  *
  * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
  *
- * @see com.opensymphony.oscache.core.events.CacheEventListener
+ * @see com.opensymphony.oscache.core.events.CacheListener
  */
 public interface LifecycleAware {
     /**

src/core/java/com/opensymphony/oscache/events/CacheEntryEvent.java

  * @version        $Revision$
  * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
  */
-public final class CacheEntryEvent extends CacheEvent {
+public class CacheEntryEvent extends CacheEvent {
     /**
      * The cache where the entry resides.
      */
      *
      * @param map     The cache map of the cache entry
      * @param entry   The cache entry that the event applies to
+     * @param eventType 
      */
-    public CacheEntryEvent(Cache map, CacheEntry entry) {
-        this(map, entry, null);
+    public CacheEntryEvent(Cache map, CacheEntry entry, int eventType) {
+        this(map, entry, eventType, null);
     }
 
     /**
      * @param entry   The cache entry that the event applies to
      * @param origin  The origin of this event
      */
-    public CacheEntryEvent(Cache map, CacheEntry entry, String origin) {
+    public CacheEntryEvent(Cache map, CacheEntry entry, int eventType, String origin) {
         super(origin);
         this.map = map;
         this.entry = entry;

src/core/java/com/opensymphony/oscache/events/CacheEntryEventListener.java

  * @version        $Revision$
  * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
  */
-public interface CacheEntryEventListener extends CacheEventListener {
+public interface CacheEntryEventListener extends CacheListener {
     /**
      * Event fired when an entry is added to the cache.
      */

src/core/java/com/opensymphony/oscache/events/CacheEvent.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
 package com.opensymphony.oscache.events;
 
+import java.util.EventObject;
+
+import com.opensymphony.oscache.core.Cache;
 
 /**
- * The root event class for all cache events. Each subclasses of this class
- * classifies a particular type of cache event.
- *
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- * Date: 20-May-2003
- * Time: 15:25:02
+ * Represents a cache event. Possible event types are:
+ * <ul>
+ * <li>{@link #ADD_EVENT} - an entry was added to the cache</li>
+ * <li>{@link #UPDATE_EVENT} - a cache entry was updated</li>
+ * <li>{@link #REMOVE_EVENT} - an entry was removed from the cache</li>
+ * <li>{@link #CLEAR_EVENT} - the entire cache was cleared</li>
+ * <li>{@link #LOAD_FAILED_EVENT} - a cache load was attempted but the load failed</li>
+ * </ul>
  */
-public abstract class CacheEvent {
-    /**
-     * An optional tag that can be attached to the event to specify the event's origin.
-     */
-    protected String origin = null;
+public class CacheEvent extends EventObject {
+  public static final int ADD = 0;
+  public static final int UPDATE = 1;
+  public static final int REMOVE = 2;
+  public static final int CLEAR = 4;
+  public static final int LOAD_FAILED = 8;
+  private Cache cache;
+  private int eventType;
 
-    /**
-     * No-argument constructor so subtypes can easily implement <code>Serializable</code>
-     */
-    public CacheEvent() {
+  /**
+   * An optional tag that can be attached to the event to specify the event's origin.
+   */
+  protected String origin = null;
+
+  public CacheEvent(Cache source, int eventType) {
+    super(source);
+    this.cache = source;
+    this.eventType = eventType;
+  }
+  
+
+  /**
+   * Creates a cache event object that came from the specified origin.
+   *
+   * @param origin A string that indicates where this event was fired from.
+   * This value is optional; <code>null</code> can be passed in if an
+   * origin is not required.
+   */
+  public CacheEvent(String origin) {
+	  super(origin);
+      this.origin = origin;
+  }
+
+  /**
+   * Retrieves the origin of this event, if one was specified. This is most
+   * useful when an event handler causes another event to fire - by checking
+   * the origin the handler is able to prevent recursive events being
+   * fired.
+   */
+  public String getOrigin() {
+      return origin;
+  }
+
+  public Cache getCache() {
+    return (Cache) getSource();
+  }
+
+  public boolean isAddEvent() {
+    return eventType == ADD;
+  }
+
+  public boolean isUpdateEvent() {
+    return eventType == UPDATE;
+  }
+
+  public boolean isRemoveEvent() {
+    return eventType == REMOVE;
+  }
+
+  public boolean isClearEvent() {
+    return eventType == CLEAR;
+  }
+
+  public boolean isLoadFailedEvent() {
+    return eventType == LOAD_FAILED;
+  }
+
+  public String getEventTypeString() {
+    switch (eventType) {
+      case ADD:
+        return "ADD";
+
+      case UPDATE:
+        return "UPDATE";
+
+      case REMOVE:
+        return "REMOVE";
+
+      case CLEAR:
+        return "CLEAR";
+
+      case LOAD_FAILED:
+        return "LOAD FAILED";
     }
+    return "UNKNOWN";
+  }
 
-    /**
-     * Creates a cache event object that came from the specified origin.
-     *
-     * @param origin A string that indicates where this event was fired from.
-     * This value is optional; <code>null</code> can be passed in if an
-     * origin is not required.
-     */
-    public CacheEvent(String origin) {
-        this.origin = origin;
-    }
+  public int getEventType() {
+    return eventType;
+  }
 
-    /**
-     * Retrieves the origin of this event, if one was specified. This is most
-     * useful when an event handler causes another event to fire - by checking
-     * the origin the handler is able to prevent recursive events being
-     * fired.
-     */
-    public String getOrigin() {
-        return origin;
-    }
+  public String toString() {
+    return getClass().getName() + "[" + getEventTypeString() + ": cache=" + getSource() + "]";
+  }
 }

src/core/java/com/opensymphony/oscache/events/CacheEventListener.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.events;
-
-import java.util.EventListener;
-
-/**
- * This is the base interface for cache events.
- *
- * @version        $Revision$
- * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
- */
-public interface CacheEventListener extends EventListener {
-}

src/core/java/com/opensymphony/oscache/events/CacheListener.java

+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.oscache.events;
+
+import java.util.EventListener;
+
+/**
+ * This is the base interface for cache events.
+ *
+ * @version        $Revision$
+ * @author <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>
+ */
+public interface CacheListener extends EventListener {
+
+	public void onChange(CacheEvent event);
+	
+}

src/core/java/com/opensymphony/oscache/events/CacheMapAccessEvent.java

  * @version        $Revision$
  * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
  */
-public final class CacheMapAccessEvent extends CacheEvent {
-    /**
-     * The cache entry that the event applies to.
+public class CacheMapAccessEvent extends CacheEntryEvent {
+	  /**
+     * Get an event type for a cache hit.
      */
-    private CacheEntry entry = null;
+    public static int HIT = 16;
 
     /**
-     * Type of the event.
+     * Get an event type for a cache miss.
      */
-    private CacheMapAccessEventType eventType = null;
+    public static int MISS = 32;
+
+    /**
+     * Get an event type for when the data was found in the cache but was stale.
+     */
+    public static int STALE_HIT = 64;
 
     /**
      * Constructor.
      * @param eventType   Type of the event.
      * @param entry       The cache entry that the event applies to.
      */
-    public CacheMapAccessEvent(CacheMapAccessEventType eventType, CacheEntry entry) {
-        this(eventType, entry, null);
+    public CacheMapAccessEvent(int eventType, CacheEntry entry) {
+        super(null, entry, eventType);
     }
 
-    /**
-     * Constructor.
-     * <p>
-     * @param eventType   Type of the event.
-     * @param entry       The cache entry that the event applies to.
-     * @param origin      The origin of the event
-     */
-    public CacheMapAccessEvent(CacheMapAccessEventType eventType, CacheEntry entry, String origin) {
-        super(origin);
-        this.eventType = eventType;
-        this.entry = entry;
-    }
-
-    /**
-     * Retrieve the cache entry that the event applies to.
-     */
-    public CacheEntry getEntry() {
-        return entry;
-    }
-
-    /**
-     * Retrieve the type of the event.
-     */
-    public CacheMapAccessEventType getEventType() {
-        return eventType;
-    }
+  
 }

src/core/java/com/opensymphony/oscache/events/CacheMapAccessEventListener.java

  * @version        $Revision$
  * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
  */
-public interface CacheMapAccessEventListener extends CacheEventListener {
+public interface CacheMapAccessEventListener extends CacheListener {
     /**
      * Event fired when an entry is accessed.
      * Use getEventType to differentiate between access events.

src/core/java/com/opensymphony/oscache/events/CacheMapAccessEventType.java

-/*
- * Copyright (c) 2002-2003 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.oscache.events;
-
-
-/**
- * This is an enumeration of the cache events that represent the
- * various outcomes of cache accesses.
- *
- * @version $Revision$
- * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
- */
-public final class CacheMapAccessEventType {
-    /**
-     * Get an event type for a cache hit.
-     */
-    public static CacheMapAccessEventType HIT = new CacheMapAccessEventType();
-
-    /**
-     * Get an event type for a cache miss.
-     */
-    public static CacheMapAccessEventType MISS = new CacheMapAccessEventType();
-
-    /**
-     * Get an event type for when the data was found in the cache but was stale.
-     */
-    public static CacheMapAccessEventType STALE_HIT = new CacheMapAccessEventType();
-
-    /**
-     * Private constructor to ensure that no object of this type are
-     * created externally.
-     */
-    private CacheMapAccessEventType() {
-    }
-}

src/core/java/com/opensymphony/oscache/events/ScopeEventListener.java

  * @version        $Revision$
  * @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
  */
-public interface ScopeEventListener extends CacheEventListener {
+public interface ScopeEventListener extends CacheListener {
     /**
      * Event fired when a specific or all scopes are flushed.
      * Use getEventType to differentiate between the two.

src/core/java/com/opensymphony/oscache/web/ServletCacheAdministrator.java

 package com.opensymphony.oscache.web;
 
 import com.opensymphony.oscache.core.*;
-import com.opensymphony.oscache.events.CacheEventListener;
+import com.opensymphony.oscache.events.CacheListener;
 import com.opensymphony.oscache.events.ScopeEvent;
 import com.opensymphony.oscache.events.ScopeEventListener;
 import com.opensymphony.oscache.events.ScopeEventType;
 
         if (config.getProperty(CACHE_ENTRY_EVENT_LISTENERS_KEY) != null) {
             // Add any event listeners that have been specified in the configuration
-            CacheEventListener[] listeners = getCacheEventListeners();
+            CacheListener[] listeners = initCacheListeners();
 
             for (int i = 0; i < listeners.length; i++) {
                 if (listeners[i] instanceof ScopeEventListener) {