Index: kernel-impl/src/test/java/org/sakai/memory/impl/test/CacheTest.java
===================================================================
--- kernel-impl/src/test/java/org/sakai/memory/impl/test/CacheTest.java (revision 0)
+++ kernel-impl/src/test/java/org/sakai/memory/impl/test/CacheTest.java (revision 0)
@@ -0,0 +1,107 @@
+package org.sakai.memory.impl.test;
+
+import java.util.Observer;
+
+import junit.framework.TestCase;
+import net.sf.ehcache.CacheManager;
+
+import org.sakaiproject.event.api.Event;
+import org.sakaiproject.memory.api.Cache;
+import org.sakaiproject.memory.api.MultiRefCache;
+
+public class CacheTest extends TestCase {
+
+ private MockEventTrackingService eventTrackingService;
+ private MockSecurityService securityService;
+ private MockUsageSessionService usageSessionService;
+ private MockAuthzGroupService authzGroupService;
+ private MockBasicMemoryService basicMemoryService;
+ private CacheManager cacheManager;
+
+ public CacheTest() {
+ super();
+ System.setProperty("net.sf.ehcache.enableShutdownHook", "true");
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ eventTrackingService = new MockEventTrackingService();
+ securityService = new MockSecurityService();
+ usageSessionService = new MockUsageSessionService();
+ authzGroupService = new MockAuthzGroupService();
+ basicMemoryService = new MockBasicMemoryService(eventTrackingService,
+ securityService, usageSessionService, authzGroupService);
+ cacheManager = new CacheManager(this.getClass().getResourceAsStream(
+ "ehcache.xml"));
+ basicMemoryService.setCacheManager(cacheManager);
+ }
+
+ public void tearDown() throws Exception {
+ super.tearDown();
+ cacheManager.shutdown();
+ }
+
+ public void testEviction() throws Exception {
+ final Cache cache = basicMemoryService
+ .newCache("a test", "prefix");
+
+ for (int count = 0; count < 10000; count++) {
+
+ cache.put("prefix/asd", "value");
+ Event evict = new MockEvent("1", true, 1, "prefix/asd", "1",
+ "admin", null);
+ ((Observer) cache).update(null, evict);
+ assertFalse(cache.containsKey("prefix/asd"));
+ }
+ }
+
+ /**
+ * Shows that eviction doesn't always work.
+ *
+ */
+ public void testMultipleThreads() throws Exception {
+ final Cache cache = basicMemoryService
+ .newCache("another test", "Thread ");
+
+ final Thread unitThread = Thread.currentThread();
+
+ Thread threads[] = new Thread[10];
+ for (int thread = 0; thread < threads.length; thread++) {
+ final int thisThread = thread;
+ threads[thread] = new Thread() {
+
+ public void run() {
+ String threadKey = "Thread "+ thisThread;
+ for (int count = 0; count < 10000; count++) {
+ cache.put(threadKey, count);
+ Event evict = new MockEvent("1", true, 1,
+ threadKey, "1", "admin", null);
+ ((Observer) cache).update(null, evict);
+ Object entry = cache.get(threadKey);
+ boolean failed = entry != null;
+ if (failed) {
+ setFailed();
+ System.out.println("Thread " + threadKey +", count " + count
+ + ", found key in cache "+ entry);
+ unitThread.interrupt();
+ }
+ }
+ }
+
+ };
+ threads[thread].start();
+ }
+
+ for (int thread = 0; thread < threads.length; thread++) {
+ threads[thread].join();
+ }
+ }
+
+ void setFailed() {
+ failed = true;
+ }
+
+ private boolean failed;
+
+}
Property changes on: kernel-impl/src/test/java/org/sakai/memory/impl/test/CacheTest.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Index: kernel-impl/src/test/java/org/sakai/memory/impl/test/MockAuthzGroupService.java
===================================================================
--- kernel-impl/src/test/java/org/sakai/memory/impl/test/MockAuthzGroupService.java (revision 76793)
+++ kernel-impl/src/test/java/org/sakai/memory/impl/test/MockAuthzGroupService.java (working copy)
@@ -63,8 +63,7 @@
}
public String authzGroupReference(String id) {
- // TODO Auto-generated method stub
- return null;
+ return id;
}
public int countAuthzGroups(String criteria) {
Index: kernel-impl/src/test/java/org/sakai/memory/impl/test/MockEvent.java
===================================================================
--- kernel-impl/src/test/java/org/sakai/memory/impl/test/MockEvent.java (revision 0)
+++ kernel-impl/src/test/java/org/sakai/memory/impl/test/MockEvent.java (revision 0)
@@ -0,0 +1,55 @@
+package org.sakai.memory.impl.test;
+
+import org.sakaiproject.event.api.Event;
+
+public class MockEvent implements Event {
+
+ String event;
+ boolean modify;
+ int priority;
+ String resource;
+ String sessionId;
+ String userId;
+ String context;
+
+ public MockEvent(String event, boolean modify, int priority, String resource, String sessionId, String userId, String context) {
+ this.event = event;
+ this.modify = modify;
+ this.priority = priority;
+ this.resource = resource;
+ this.sessionId = sessionId;
+ this.userId = userId;
+ this.context = context;
+ }
+
+
+ public String getEvent() {
+ return event;
+ }
+
+ public boolean getModify() {
+ return modify;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public String getResource() {
+ return resource;
+ }
+
+ public String getSessionId() {
+ return sessionId;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+
+ public String getContext() {
+ return context;
+ }
+
+}
Property changes on: kernel-impl/src/test/java/org/sakai/memory/impl/test/MockEvent.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Index: kernel-impl/src/test/java/org/sakai/memory/impl/test/MultiRefCacheTest.java
===================================================================
--- kernel-impl/src/test/java/org/sakai/memory/impl/test/MultiRefCacheTest.java (revision 0)
+++ kernel-impl/src/test/java/org/sakai/memory/impl/test/MultiRefCacheTest.java (revision 0)
@@ -0,0 +1,82 @@
+package org.sakai.memory.impl.test;
+
+import java.util.Arrays;
+import java.util.Observer;
+
+import junit.framework.TestCase;
+import net.sf.ehcache.CacheManager;
+
+import org.sakaiproject.event.api.Event;
+import org.sakaiproject.memory.api.MultiRefCache;
+
+@SuppressWarnings("deprecation")
+public class MultiRefCacheTest extends TestCase {
+
+ private MockEventTrackingService eventTrackingService;
+ private MockSecurityService securityService;
+ private MockUsageSessionService usageSessionService;
+ private MockAuthzGroupService authzGroupService;
+ private MockBasicMemoryService basicMemoryService;
+ private CacheManager cacheManager;
+
+ public MultiRefCacheTest() {
+ super();
+ System.setProperty("net.sf.ehcache.enableShutdownHook", "true");
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ eventTrackingService = new MockEventTrackingService();
+ securityService = new MockSecurityService();
+ usageSessionService = new MockUsageSessionService();
+ authzGroupService = new MockAuthzGroupService();
+ basicMemoryService = new MockBasicMemoryService(eventTrackingService,
+ securityService, usageSessionService, authzGroupService);
+ cacheManager = new CacheManager(this.getClass().getResourceAsStream(
+ "ehcache.xml"));
+ basicMemoryService.setCacheManager(cacheManager);
+ }
+
+ public void tearDown() throws Exception {
+ super.tearDown();
+ cacheManager.shutdown();
+ }
+
+ public void testEviction() throws Exception {
+ final MultiRefCache cache = basicMemoryService
+ .newMultiRefCache("eviction");
+ cache.put("asd", "value", 10, "clashingref", null);
+ Event evict = new MockEvent("1", true, 1, "clashingref", "1",
+ "admin", null);
+ ((Observer) cache).update(null, evict); // Evict the event.
+ assertFalse(cache.containsKey("asd"));
+ }
+
+ public void testAuthzEviction() throws Exception {
+ final MultiRefCache cache = basicMemoryService.newMultiRefCache("authz eviction");
+ cache.put("key", "value", 100, "ref", Arrays.asList("authzref"));
+ ((Observer)cache).update(null, new MockEvent("1", true, 1, "authzref", "sessionId", "userId", null));
+ assertFalse(cache.containsKey("key"));
+ cache.put("key", "value", 100, "ref", Arrays.asList("firstref", "secondref", "thirdref"));
+ ((Observer)cache).update(null, new MockEvent("1", true, 1, "nonmatching", "sessionId", "userId", null));
+ assertTrue(cache.containsKey("key"));
+ ((Observer)cache).update(null, new MockEvent("1", true, 1, "secondref", "sessionId", "userId", null));
+ assertFalse(cache.containsKey("key"));
+ }
+
+ public void testPersistence() throws Exception {
+ final MultiRefCache cache = basicMemoryService.newMultiRefCache("persistence");
+ cache.put("key", "value", 100,"ref", null);
+ assertTrue(cache.containsKey("key"));
+ }
+
+ public void testReplacement() throws Exception {
+ final MultiRefCache cache = basicMemoryService.newMultiRefCache("replacement");
+ cache.put("key", "value", 100, "ref", null);
+ assertEquals("value", cache.get("key"));
+ cache.put("key", "other", 100, "ref", null);
+ assertEquals("other", cache.get("key"));
+ }
+
+}
Property changes on: kernel-impl/src/test/java/org/sakai/memory/impl/test/MultiRefCacheTest.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Index: kernel-impl/src/main/java/org/sakaiproject/memory/impl/MemCache.java
===================================================================
--- kernel-impl/src/main/java/org/sakaiproject/memory/impl/MemCache.java (revision 76793)
+++ kernel-impl/src/main/java/org/sakaiproject/memory/impl/MemCache.java (working copy)
@@ -582,6 +582,7 @@
if (disabled()) return;
+ // We could get things wrong here.
final Object value = get(key);
boolean found = cache.remove(key);
Index: kernel-impl/src/main/java/org/sakaiproject/memory/impl/GenericMultiRefCacheImpl.java
===================================================================
--- kernel-impl/src/main/java/org/sakaiproject/memory/impl/GenericMultiRefCacheImpl.java (revision 76175)
+++ kernel-impl/src/main/java/org/sakaiproject/memory/impl/GenericMultiRefCacheImpl.java (working copy)
@@ -26,8 +26,9 @@
import java.util.List;
import java.util.Map;
import java.util.Observable;
-import java.util.Vector;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import net.sf.ehcache.CacheException;
@@ -37,10 +38,9 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.sakaiproject.authz.api.AuthzGroupService;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
-import org.sakaiproject.memory.api.MultiRefCache;
+import org.sakaiproject.memory.api.GenericMultiRefCache;
/**
*
@@ -52,18 +52,15 @@
* The cache map itself becomes synchronized when it's manipulated (not when reads occur), so this added sync. for the refs fits the existing pattern.
*
*/
-public class MultiRefCacheImpl extends MemCache implements MultiRefCache,
+public class GenericMultiRefCacheImpl extends MemCache implements GenericMultiRefCache,
CacheEventListener
{
/** Our logger. */
- private static Log M_log = LogFactory.getLog(MultiRefCacheImpl.class);
+ private static Log M_log = LogFactory.getLog(GenericMultiRefCacheImpl.class);
/** Map of reference string -> Collection of cache keys. */
- protected final Map> m_refsStore = new ConcurrentHashMap>();
+ protected final ConcurrentMap> m_refsStore = new ConcurrentHashMap>();
- /** AuthzGroupService used when putting items into the cache. */
- private AuthzGroupService m_authzGroupService;
-
protected class MultiRefCacheEntry extends CacheEntry
{
/** These are the entity reference strings that this entry is sensitive to. */
@@ -78,14 +75,14 @@
* The time (seconds) to keep this cached.
* @param ref
* One entity reference that, if changed, will invalidate this entry.
- * @param azgRefs
- * AuthzGroup refs that, if the changed, will invalidate this entry.
+ * @param dependRefs
+ * References that, if the changed, will invalidate this entry.
*/
- public MultiRefCacheEntry(Object payload, int duration, String ref, Collection azgRefs)
+ public MultiRefCacheEntry(Object payload, int duration, String ref, Collection dependRefs)
{
super(payload, duration);
if (ref != null) m_refs.add(ref);
- if (azgRefs != null) m_refs.addAll(azgRefs);
+ if (dependRefs != null) m_refs.addAll(dependRefs);
}
/**
@@ -99,70 +96,38 @@
/**
* Construct the Cache - checks for expiration periodically.
- * @param authzGroupService TODO
- * @deprecated long sleep no longer used with ehcache
*/
- public MultiRefCacheImpl(BasicMemoryService memoryService,
- EventTrackingService eventTrackingService, AuthzGroupService authzGroupService, long sleep, Ehcache cache)
+ public GenericMultiRefCacheImpl(BasicMemoryService memoryService,
+ EventTrackingService eventTrackingService, Ehcache cache)
{
- super(memoryService, eventTrackingService, sleep, "", cache);
- this.m_authzGroupService = authzGroupService;
- cache.getCacheEventNotificationService().registerListener(this);
-
- }
-
- /**
- * Construct the Cache - checks for expiration periodically.
- * @param authzGroupService TODO
- */
- public MultiRefCacheImpl(BasicMemoryService memoryService,
- EventTrackingService eventTrackingService, AuthzGroupService authzGroupService, Ehcache cache)
- {
super(memoryService, eventTrackingService, "", cache);
- this.m_authzGroupService = authzGroupService;
cache.getCacheEventNotificationService().registerListener(this);
}
- /**
- * @inheritDoc
- */
- public void put(Object key, Object payload, int duration, String ref, Collection azgIds)
+
+ public void put(Object key, Object payload, String ref, Collection dependRefs)
{
if(M_log.isDebugEnabled())
{
- M_log.debug("put(Object " + key + ", Object " + payload + ", int "
- + duration + ", String " + ref + ", Collection " + azgIds
- + ")");
+ M_log.debug("put(Object " + key + ", Object " + payload + ", Reference "+ ref
+ +", Dependent Refs " + dependRefs + ")");
}
if (disabled()) return;
-
- // make refs for any azg ids
- Collection azgRefs = null;
- if (azgIds != null)
- {
- azgRefs = new Vector(azgIds.size());
- for (Iterator i = azgIds.iterator(); i.hasNext();)
- {
- String azgId = (String) i.next();
- azgRefs.add(m_authzGroupService.authzGroupReference(azgId));
- }
- }
-
- // create our extended cache entry for the cache map - the reference strings are recorded
- super.put(key, new MultiRefCacheEntry(payload, duration, ref, azgRefs));
-
+ // Durations don't work any more (hence 0 duration).
+ super.put(key, new MultiRefCacheEntry(payload, 0, ref, dependRefs));
+
+ // Why don't we do do this in the notify handler?
if (ref != null)
{
addRefCachedKey(ref, key);
}
-
- if (azgRefs != null)
+ if (dependRefs != null)
{
- for (Iterator i = azgRefs.iterator(); i.hasNext();)
+ for (Iterator i = dependRefs.iterator(); i.hasNext();)
{
- String azgRef = (String) i.next();
- addRefCachedKey(azgRef, key);
+ String dependRef = (String) i.next();
+ addRefCachedKey(dependRef, key);
}
}
}
@@ -172,7 +137,7 @@
*/
public void put(Object key, Object payload, int duration)
{
- put(key, payload, duration, null, null);
+ put(key, payload, null, null);
}
/**
@@ -180,7 +145,7 @@
*/
public void put(Object key, Object payload)
{
- put(key, payload, 0, null, null);
+ put(key, payload, null, null);
}
/**
@@ -193,11 +158,12 @@
*/
protected void addRefCachedKey(String ref, Object key)
{
- Map cachedKeys = m_refsStore.get(ref);
// Isn't this a threading issue. Two thread hit this and both put their own data into m_refsStore.
- if ( cachedKeys == null ) {
- cachedKeys = new ConcurrentHashMap();
- m_refsStore.put(ref, cachedKeys);
+ ConcurrentMap cachedKeys = new ConcurrentHashMap();
+ ConcurrentMap oldCachedKeys = m_refsStore.putIfAbsent(ref, cachedKeys);
+ if (oldCachedKeys != null)
+ {
+ cachedKeys = oldCachedKeys;
}
cachedKeys.put(key, key);
}
@@ -214,29 +180,28 @@
private void cleanEntityReferences(Object key, Object value)
{
if (M_log.isDebugEnabled())
- M_log.debug("maintainEntityReferences(Object " + key
+ M_log.debug("cleanEntityReferences(Object " + key
+ ", Object " + value + ")");
+ if (value == null)
+ return;
- if (value == null) return;
-
final MultiRefCacheEntry cachedEntry = (MultiRefCacheEntry) value;
// remove this key from any of the entity references in m_refs that are dependent on this entry
for (Iterator iRefs = cachedEntry.getRefs().iterator(); iRefs.hasNext();)
{
String ref = (String) iRefs.next();
- Map keys = m_refsStore.get(ref);
- if ((keys != null) && (keys.containsKey(key)))
+ ConcurrentMap keys = m_refsStore.get(ref);
+ if (keys != null && keys.remove(key) != null)
{
- keys.remove(key);
-
// remove the ref entry if it no longer has any cached keys in
// its collection
+ // TODO This isn't thread safe.
if (keys.isEmpty())
{
- m_refsStore.remove(ref);
+ m_refsStore.remove(ref,keys);
}
- }
+ }
}
}
@@ -249,7 +214,7 @@
*/
public String getDescription()
{
- return "MultiRefCache: " + super.getDescription();
+ return "GenericMultiRefCache: " + super.getDescription();
}
/**********************************************************************************************************************************************************************************************************************************************************
@@ -291,17 +256,22 @@
String ref = event.getResource();
if (M_log.isDebugEnabled())
- M_log.debug("update() [" + m_resourcePattern + "] resource: " + ref
+ M_log.debug("continueUpdate() [" + m_resourcePattern + "] resource: " + ref
+ " event: " + event.getEvent());
- // do we have this in our ref list
- if (m_refsStore.containsKey(ref))
+ // get the copy of the Collection of cache keys for this reference (the actual collection will be reduced as the removes occur)
+ ConcurrentMap cachedKeys = m_refsStore.get(ref);
+ if (cachedKeys != null)
{
- // get the copy of the Collection of cache keys for this reference (the actual collection will be reduced as the removes occur)
- Map cachedKeys = m_refsStore.get(ref);
- for (Iterator iKeys = cachedKeys.keySet().iterator(); iKeys.hasNext();)
+ Set keySet = cachedKeys.keySet();
+ for (Iterator iKeys = keySet.iterator(); iKeys.hasNext();)
{
- remove(iKeys.next()); // evict primary authz cache
+ Object key = iKeys.next();
+ remove(key);
+
+ if (M_log.isDebugEnabled()) {
+ M_log.debug("Removed from cache: "+ key);
+ }
}
}
}
@@ -347,18 +317,12 @@
public void notifyElementEvicted(Ehcache cache, Element element)
{
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementEvicted(Ehcache " + cache + ")");
-
cleanEntityReferences(element.getObjectKey(), element
.getObjectValue());
}
public void notifyElementExpired(Ehcache cache, Element element)
{
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementExpired(Ehcache " + cache + ")");
-
cleanEntityReferences(element.getObjectKey(), element
.getObjectValue());
}
@@ -366,9 +330,6 @@
public void notifyElementPut(Ehcache cache, Element element)
throws CacheException
{
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementPut(Ehcache " + cache + ")");
-
// do nothing...
}
@@ -376,9 +337,6 @@
public void notifyElementRemoved(Ehcache cache, Element element)
throws CacheException
{
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementRemoved(Ehcache " + cache + ")");
-
cleanEntityReferences(element.getObjectKey(), element
.getObjectValue());
}
@@ -386,18 +344,12 @@
public void notifyElementUpdated(Ehcache cache, Element element)
throws CacheException
{
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementUpdated(Ehcache " + cache + ")");
-
// do nothing...
}
public void notifyRemoveAll(Ehcache cache)
{
- if (M_log.isDebugEnabled())
- M_log.debug("notifyRemoveAll(Ehcache " + cache + ")");
-
m_refsStore.clear();
}
@@ -414,45 +366,5 @@
throw new CloneNotSupportedException(
"CacheEventListener implementations should throw CloneNotSupportedException if they do not support clone");
}
-
-
-// /**
-// * Check that the cache and the m_refs are consistent.
-// */
-// protected void checkState()
-// {
-// // every cache entry's every ref must have an entry in m_refs, and that entry must include the cache entry's key
-// for (Iterator iEntries = m_map.entrySet().iterator(); iEntries.hasNext();)
-// {
-// Map.Entry entry = (Map.Entry) iEntries.next();
-// MultiRefCacheEntry ce = (MultiRefCacheEntry) entry.getValue();
-// for (Iterator iRefs = ce.getRefs().iterator(); iRefs.hasNext();)
-// {
-// String ref = (String) iRefs.next();
-// Collection keys = (Collection) m_refs.get(ref);
-// if (keys == null)
-// m_logger.warn("** cache entry's ref not found in m_refs: cache key: " + entry.getKey() + " ref: " + ref);
-// if ((keys != null) && (!keys.contains(entry.getKey())))
-// m_logger.warn("** cache entry's ref's m_refs entry does not contain cache key: key: " + entry.getKey()
-// + " ref: " + ref);
-// }
-// }
-//
-// // every reference in m_refs every key must exist in the cache, and must include the ref in the cache entry's refs
-// for (Iterator iRefs = m_refs.entrySet().iterator(); iRefs.hasNext();)
-// {
-// Map.Entry entry = (Map.Entry) iRefs.next();
-// Collection keys = (Collection) entry.getValue();
-// for (Iterator iKeys = keys.iterator(); iKeys.hasNext();)
-// {
-// String key = (String) iKeys.next();
-// if (m_map.get(key) == null)
-// m_logger.warn("** m_ref's entry's key not found in cache: ref: " + entry.getKey() + " cache key: " + key);
-// if ((m_map.get(key) != null) && (!(((MultiRefCacheEntry) m_map.get(key)).getRefs().contains(entry.getKey()))))
-// m_logger.warn("** m_ref's entry's key->cache entry does not have the ref: ref: " + entry.getKey() + " cache key: " + key);
-// }
-// }
-// }
-
}
Property changes on: kernel-impl/src/main/java/org/sakaiproject/memory/impl/GenericMultiRefCacheImpl.java
___________________________________________________________________
Added: svn:keywords
+ Date Revision Author HeadURL Id
Added: svn:eol-style
+ native
Index: kernel-impl/src/main/java/org/sakaiproject/memory/impl/BasicMemoryService.java
===================================================================
--- kernel-impl/src/main/java/org/sakaiproject/memory/impl/BasicMemoryService.java (revision 76793)
+++ kernel-impl/src/main/java/org/sakaiproject/memory/impl/BasicMemoryService.java (working copy)
@@ -45,6 +45,7 @@
import org.sakaiproject.memory.api.Cache;
import org.sakaiproject.memory.api.CacheRefresher;
import org.sakaiproject.memory.api.Cacher;
+import org.sakaiproject.memory.api.GenericMultiRefCache;
import org.sakaiproject.memory.api.MemoryPermissionException;
import org.sakaiproject.memory.api.MemoryService;
import org.sakaiproject.memory.api.MultiRefCache;
@@ -540,6 +541,7 @@
instantiateCache(cacheName));
}
+ @SuppressWarnings("deprecation")
public MultiRefCache newMultiRefCache(String cacheName) {
return new MultiRefCacheImpl(
this,
@@ -547,5 +549,12 @@
authzGroupService(),
instantiateCache(cacheName));
}
+
+ public GenericMultiRefCache newGenericMultiRefCache(String cacheName) {
+ return new GenericMultiRefCacheImpl(
+ this,
+ eventTrackingService(),
+ instantiateCache(cacheName));
+ }
}
Index: kernel-impl/src/main/java/org/sakaiproject/memory/impl/MultiRefCacheImpl.java
===================================================================
--- kernel-impl/src/main/java/org/sakaiproject/memory/impl/MultiRefCacheImpl.java (revision 76793)
+++ kernel-impl/src/main/java/org/sakaiproject/memory/impl/MultiRefCacheImpl.java (working copy)
@@ -23,22 +23,13 @@
import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Observable;
import java.util.Vector;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
-import net.sf.ehcache.Element;
-import net.sf.ehcache.event.CacheEventListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.AuthzGroupService;
-import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.memory.api.MultiRefCache;
@@ -51,77 +42,28 @@
* Manipulation of this map is synchronized. This map is not used for cache access, just when items are added and removed.
* The cache map itself becomes synchronized when it's manipulated (not when reads occur), so this added sync. for the refs fits the existing pattern.
*
+ * @deprecated Use {@link GenericMultiRefCacheImpl} instead.
*/
-public class MultiRefCacheImpl extends MemCache implements MultiRefCache,
- CacheEventListener
+public class MultiRefCacheImpl extends GenericMultiRefCacheImpl implements MultiRefCache
{
+
/** Our logger. */
private static Log M_log = LogFactory.getLog(MultiRefCacheImpl.class);
+
- /** Map of reference string -> Collection of cache keys. */
- protected final Map> m_refsStore = new ConcurrentHashMap>();
-
/** AuthzGroupService used when putting items into the cache. */
private AuthzGroupService m_authzGroupService;
- protected class MultiRefCacheEntry extends CacheEntry
- {
- /** These are the entity reference strings that this entry is sensitive to. */
- protected List m_refs = new CopyOnWriteArrayList();
-
- /**
- * Construct to cache the payload for the duration.
- *
- * @param payload
- * The thing to cache.
- * @param duration
- * The time (seconds) to keep this cached.
- * @param ref
- * One entity reference that, if changed, will invalidate this entry.
- * @param azgRefs
- * AuthzGroup refs that, if the changed, will invalidate this entry.
- */
- public MultiRefCacheEntry(Object payload, int duration, String ref, Collection azgRefs)
- {
- super(payload, duration);
- if (ref != null) m_refs.add(ref);
- if (azgRefs != null) m_refs.addAll(azgRefs);
- }
-
- /**
- * @inheritDoc
- */
- public List getRefs()
- {
- return m_refs;
- }
- }
-
- /**
- * Construct the Cache - checks for expiration periodically.
- * @param authzGroupService TODO
- * @deprecated long sleep no longer used with ehcache
- */
public MultiRefCacheImpl(BasicMemoryService memoryService,
- EventTrackingService eventTrackingService, AuthzGroupService authzGroupService, long sleep, Ehcache cache)
- {
- super(memoryService, eventTrackingService, sleep, "", cache);
+ EventTrackingService eventTrackingService,
+ AuthzGroupService authzGroupService, Ehcache cache) {
+ super(memoryService, eventTrackingService, cache);
this.m_authzGroupService = authzGroupService;
- cache.getCacheEventNotificationService().registerListener(this);
-
}
- /**
- * Construct the Cache - checks for expiration periodically.
- * @param authzGroupService TODO
- */
- public MultiRefCacheImpl(BasicMemoryService memoryService,
- EventTrackingService eventTrackingService, AuthzGroupService authzGroupService, Ehcache cache)
+ public String getDescription()
{
- super(memoryService, eventTrackingService, "", cache);
- this.m_authzGroupService = authzGroupService;
- cache.getCacheEventNotificationService().registerListener(this);
-
+ return "MultiRefCache: " + super.getDescription();
}
/**
@@ -148,311 +90,6 @@
azgRefs.add(m_authzGroupService.authzGroupReference(azgId));
}
}
-
- // create our extended cache entry for the cache map - the reference strings are recorded
- super.put(key, new MultiRefCacheEntry(payload, duration, ref, azgRefs));
-
- if (ref != null)
- {
- addRefCachedKey(ref, key);
- }
-
- if (azgRefs != null)
- {
- for (Iterator i = azgRefs.iterator(); i.hasNext();)
- {
- String azgRef = (String) i.next();
- addRefCachedKey(azgRef, key);
- }
- }
+ put(key, payload, ref, azgRefs);
}
-
- /**
- * @inheritDoc
- */
- public void put(Object key, Object payload, int duration)
- {
- put(key, payload, duration, null, null);
}
-
- /**
- * @inheritDoc
- */
- public void put(Object key, Object payload)
- {
- put(key, payload, 0, null, null);
- }
-
- /**
- * Make sure there's an entry in refs for this ref that includes this key.
- *
- * @param ref
- * The entity reference string.
- * @param key
- * The cache entry key dependent on this entity ref.
- */
- protected void addRefCachedKey(String ref, Object key)
- {
- Map cachedKeys = m_refsStore.get(ref);
- // Isn't this a threading issue. Two thread hit this and both put their own data into m_refsStore.
- if ( cachedKeys == null ) {
- cachedKeys = new ConcurrentHashMap();
- m_refsStore.put(ref, cachedKeys);
- }
- cachedKeys.put(key, key);
- }
-
- /**
- * @inheritDoc
- */
- public void clear()
- {
- super.clear();
- m_refsStore.clear();
- }
-
- private void cleanEntityReferences(Object key, Object value)
- {
- if (M_log.isDebugEnabled())
- M_log.debug("maintainEntityReferences(Object " + key
- + ", Object " + value + ")");
-
- if (value == null) return;
-
- final MultiRefCacheEntry cachedEntry = (MultiRefCacheEntry) value;
-
- // remove this key from any of the entity references in m_refs that are dependent on this entry
- for (Iterator iRefs = cachedEntry.getRefs().iterator(); iRefs.hasNext();)
- {
- String ref = (String) iRefs.next();
- Map keys = m_refsStore.get(ref);
- if ((keys != null) && (keys.containsKey(key)))
- {
- keys.remove(key);
-
- // remove the ref entry if it no longer has any cached keys in
- // its collection
- if (keys.isEmpty())
- {
- m_refsStore.remove(ref);
- }
- }
- }
- }
-
- /**********************************************************************************************************************************************************************************************************************************************************
- * Cacher implementation
- *********************************************************************************************************************************************************************************************************************************************************/
-
- /**
- * @inheritDoc
- */
- public String getDescription()
- {
- return "MultiRefCache: " + super.getDescription();
- }
-
- /**********************************************************************************************************************************************************************************************************************************************************
- * Observer implementation
- *********************************************************************************************************************************************************************************************************************************************************/
-
- /**
- * @inheritDoc
- */
- public void update(Observable o, Object arg)
- {
- if (disabled()) return;
-
- // arg is Event
- if (!(arg instanceof Event)) return;
- Event event = (Event) arg;
-
- // if this is just a read, not a modify event, we can ignore it
- if (!event.getModify()) return;
-
- // if we are holding event processing
- if (m_holdEventProcessing)
- {
- m_heldEvents.add(event);
- return;
- }
-
- continueUpdate(event);
- }
-
- /**
- * Complete the update, given an event that we know we need to act upon.
- *
- * @param event
- * The event to process.
- */
- protected void continueUpdate(Event event)
- {
- String ref = event.getResource();
-
- if (M_log.isDebugEnabled())
- M_log.debug("update() [" + m_resourcePattern + "] resource: " + ref
- + " event: " + event.getEvent());
-
- // do we have this in our ref list
- if (m_refsStore.containsKey(ref))
- {
- // get the copy of the Collection of cache keys for this reference (the actual collection will be reduced as the removes occur)
- Map cachedKeys = m_refsStore.get(ref);
- for (Iterator iKeys = cachedKeys.keySet().iterator(); iKeys.hasNext();)
- {
- remove(iKeys.next()); // evict primary authz cache
- }
- }
- }
-
- /**
- * @inheritDoc
- */
- public boolean isComplete()
- {
- // we do not support being complete
- return false;
- }
-
- /**
- * @inheritDoc
- */
- public boolean isComplete(String path)
- {
- // we do not support being complete
- return false;
- }
-
- /**
- * @inheritDoc
- * @see org.sakaiproject.memory.impl.MemCache#get(java.lang.Object)
- */
- @Override
- public Object get(Object key) {
- MultiRefCacheEntry mrce = (MultiRefCacheEntry) super.get(key);
- return (mrce != null ? mrce.getPayload(key) : null);
- }
-
- //////////////////////////////////////////////////////////////////////
- // CacheEventListener methods. Cleanup HashMap of m_refs on eviction.
- //////////////////////////////////////////////////////////////////////
-
- public void dispose()
- {
- M_log.debug("dispose()");
- // may not be necessary...
- m_refsStore.clear();
- }
-
- public void notifyElementEvicted(Ehcache cache, Element element)
- {
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementEvicted(Ehcache " + cache + ")");
-
- cleanEntityReferences(element.getObjectKey(), element
- .getObjectValue());
- }
-
- public void notifyElementExpired(Ehcache cache, Element element)
- {
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementExpired(Ehcache " + cache + ")");
-
- cleanEntityReferences(element.getObjectKey(), element
- .getObjectValue());
- }
-
- public void notifyElementPut(Ehcache cache, Element element)
- throws CacheException
- {
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementPut(Ehcache " + cache + ")");
-
- // do nothing...
-
- }
-
- public void notifyElementRemoved(Ehcache cache, Element element)
- throws CacheException
- {
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementRemoved(Ehcache " + cache + ")");
-
- cleanEntityReferences(element.getObjectKey(), element
- .getObjectValue());
- }
-
- public void notifyElementUpdated(Ehcache cache, Element element)
- throws CacheException
- {
- if (M_log.isDebugEnabled())
- M_log.debug("notifyElementUpdated(Ehcache " + cache + ")");
-
- // do nothing...
-
- }
-
- public void notifyRemoveAll(Ehcache cache)
- {
- if (M_log.isDebugEnabled())
- M_log.debug("notifyRemoveAll(Ehcache " + cache + ")");
-
- m_refsStore.clear();
- }
-
- /**
- * @see CacheEventListener#clone()
- */
- @Override
- public Object clone() throws CloneNotSupportedException
- {
- M_log.debug("clone()");
-
- // Creates a clone of this listener. This method will only be called by ehcache before a cache is initialized.
- // This may not be possible for listeners after they have been initialized. Implementations should throw CloneNotSupportedException if they do not support clone.
- throw new CloneNotSupportedException(
- "CacheEventListener implementations should throw CloneNotSupportedException if they do not support clone");
- }
-
-
-
-// /**
-// * Check that the cache and the m_refs are consistent.
-// */
-// protected void checkState()
-// {
-// // every cache entry's every ref must have an entry in m_refs, and that entry must include the cache entry's key
-// for (Iterator iEntries = m_map.entrySet().iterator(); iEntries.hasNext();)
-// {
-// Map.Entry entry = (Map.Entry) iEntries.next();
-// MultiRefCacheEntry ce = (MultiRefCacheEntry) entry.getValue();
-// for (Iterator iRefs = ce.getRefs().iterator(); iRefs.hasNext();)
-// {
-// String ref = (String) iRefs.next();
-// Collection keys = (Collection) m_refs.get(ref);
-// if (keys == null)
-// m_logger.warn("** cache entry's ref not found in m_refs: cache key: " + entry.getKey() + " ref: " + ref);
-// if ((keys != null) && (!keys.contains(entry.getKey())))
-// m_logger.warn("** cache entry's ref's m_refs entry does not contain cache key: key: " + entry.getKey()
-// + " ref: " + ref);
-// }
-// }
-//
-// // every reference in m_refs every key must exist in the cache, and must include the ref in the cache entry's refs
-// for (Iterator iRefs = m_refs.entrySet().iterator(); iRefs.hasNext();)
-// {
-// Map.Entry entry = (Map.Entry) iRefs.next();
-// Collection keys = (Collection) entry.getValue();
-// for (Iterator iKeys = keys.iterator(); iKeys.hasNext();)
-// {
-// String key = (String) iKeys.next();
-// if (m_map.get(key) == null)
-// m_logger.warn("** m_ref's entry's key not found in cache: ref: " + entry.getKey() + " cache key: " + key);
-// if ((m_map.get(key) != null) && (!(((MultiRefCacheEntry) m_map.get(key)).getRefs().contains(entry.getKey()))))
-// m_logger.warn("** m_ref's entry's key->cache entry does not have the ref: ref: " + entry.getKey() + " cache key: " + key);
-// }
-// }
-// }
-
-}
Index: pom.xml
===================================================================
--- pom.xml (revision 76176)
+++ pom.xml (working copy)
@@ -665,7 +665,7 @@
net.sf.ehcache
ehcache
- 1.6.1
+ 1.6.2
provided
Index: kernel-util/pom.xml
===================================================================
--- kernel-util/pom.xml (revision 76176)
+++ kernel-util/pom.xml (working copy)
@@ -72,6 +72,12 @@
org.owasp
antisamy
1.4
+
+
+ xml-apis
+ xml-apis
+
+