Index: BindableRepositoryFactory.java
===================================================================
--- BindableRepositoryFactory.java (revision 900832)
+++ BindableRepositoryFactory.java (working copy)
@@ -16,6 +16,7 @@
*/
package org.apache.jackrabbit.core.jndi;
+import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.map.ReferenceMap;
import javax.jcr.RepositoryException;
@@ -24,35 +25,77 @@
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
/**
- * BindableRepositoryFactory is an object factory that when given
- * a reference for a BindableRepository object, will create an
- * instance of the corresponding BindableRepository.
+ * BindableRepositoryFactory is an object factory that when given a reference for a
+ * BindableRepository object, will create an instance of the corresponding BindableRepository.
*/
public class BindableRepositoryFactory implements ObjectFactory {
/**
- * cache using java.naming.Reference objects as keys and
- * storing soft references to BindableRepository instances
+ * cache using java.naming.Reference objects as keys and storing soft references to
+ * BindableRepository instances
*/
- private static final Map cache = new ReferenceMap();
+ static final Map cache = new ReferenceMap();
/**
* {@inheritDoc}
*/
- public synchronized Object getObjectInstance(
- Object obj, Name name, Context nameCtx, Hashtable environment)
+ public synchronized Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment)
throws RepositoryException {
synchronized (cache) {
Object instance = cache.get(obj);
if (instance == null && obj instanceof Reference) {
- instance = new BindableRepository((Reference) obj);
+ instance = new BindableRepository((Reference) obj) {
+ private static final long serialVersionUID = -8609106126568988192L;
+
+ public void shutdown() {
+ super.shutdown();
+ /*
+ * If the repository gets shutdown, it must be removed from cache, because it can not be used
+ * anymore. Therefore we override this method to invalidate the cache. Maybe a
+ * RepositoryStateListener should be introduced to allow other components to react on repository
+ * state changes.
+ */
+ invalidateCacheObject(this);
+ }
+ };
cache.put(obj, instance);
}
return instance;
}
}
+ /**
+ * Invalidates the given object in this factory's cache. If this factory's cache does not contain the given object
+ * it returns false, true if the object has been successfully invalidated.
+ *
+ * @param cachedObject
+ * the object that should be invalidated.
+ * @return true, if the cachedObject has been invalidated successfully, false otherwise.
+ */
+ private boolean invalidateCacheObject(Object cachedObject) {
+ synchronized (cache) {
+ Map invertedCacheMap = MapUtils.invertMap(cache);
+ Object cachedObjectKey = invertedCacheMap.get(cachedObject);
+ try {
+ return cache.remove(cachedObjectKey) != null;
+ } catch (NullPointerException e) {
+ /**
+ * As told by the java.util.Map#remove(Object) API documentation it is implementation-specific if null
+ * keys are allowed or not. Therefore a NullPointerException may occur if the cache implementation does
+ * not support null values and the give cachedObject is null. Nevertheless we must be prepared that a
+ * cacheObject is mapped under a null value.
+ *
+ * The cachedObjectKey can be null under two circumstances:
+ * 1. the cache does not contain the given cachedObject, therefore the cachedObjectKey is null.
+ * 2. the cache implementation allows null keys and the cachedObject is mapped via a null key.
+ */
+ return false;
+ }
+ }
+ }
}