Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(revision 1348865)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(working copy)
@@ -43,78 +43,51 @@
      * nodeID (key). The map only contains an entry if the corresponding Node
      * is access controlled.
      */
-    private final Map<NodeId, Entries> cache;
-    private final Object monitor = new Object();
+    private final EntryCache cache;
 
     /**
      * Create a new instance.
-     *
+     * 
      * @param systemSession A system session.
      * @param rootID The id of the root node.
      * @throws RepositoryException If an error occurs.
      */
-    @SuppressWarnings("unchecked")    
     CachingEntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
         super(systemSession, rootID);
-
-        int maxsize = 5000;
-        String propname = "org.apache.jackrabbit.core.security.authorization.acl.CachingEntryCollector.maxsize";
-        try {
-            maxsize = Integer.parseInt(System.getProperty(propname,
-                    Integer.toString(maxsize)));
-        } catch (NumberFormatException ex) {
-            log.error("Parsing system property " + propname + " with value: "
-                    + System.getProperty(propname), ex);
-        }
-
-        log.info("Creating cache with max size of: " + maxsize);
-
-        cache = new GrowingLRUMap(1024, maxsize);
+        cache = new EntryCache();
     }
 
     @Override
     protected void close() {
         super.close();
-        synchronized (monitor) {
-            cache.clear();
-        }
+        cache.clear();
     }
 
-    //-----------------------------------------------------< EntryCollector >---
+    // -----------------------------------------------------< EntryCollector >---
     /**
      * @see EntryCollector#getEntries(org.apache.jackrabbit.core.NodeImpl)
      */
-    @Override    
+    @Override
     protected Entries getEntries(NodeImpl node) throws RepositoryException {
-        Entries entries;
         NodeId nodeId = node.getNodeId();
-        synchronized (monitor) {
-            entries = cache.get(nodeId);
-            if (entries == null) {
-                // fetch entries and update the cache
-                entries = updateCache(node);
-            } else {
-                log.debug("Cache hit for nodeId {}", nodeId);
-            }
+        Entries entries = cache.get(nodeId);
+        if (entries == null) {
+            // fetch entries and update the cache
+            entries = updateCache(node);
         }
         return entries;
     }
-    
+
     /**
      * @see EntryCollector#getEntries(org.apache.jackrabbit.core.id.NodeId)
      */
     @Override
     protected Entries getEntries(NodeId nodeId) throws RepositoryException {
-        Entries entries;
-        synchronized (monitor) {
-            entries = cache.get(nodeId);
-            if (entries == null) {
-                // fetch entries and update the cache
-                NodeImpl n = getNodeById(nodeId);
-                entries = updateCache(n);
-            } else {
-                log.debug("Cache hit for nodeId {}", nodeId);
-            }
+        Entries entries = cache.get(nodeId);
+        if (entries == null) {
+            // fetch entries and update the cache
+            NodeImpl n = getNodeById(nodeId);
+            entries = updateCache(n);
         }
         return entries;
     }
@@ -122,7 +95,7 @@
     /**
      * Read the entries defined for the specified node and update the cache
      * accordingly.
-     *
+     * 
      * @param node The target node
      * @return The list of entries present on the specified node or an empty list.
      * @throws RepositoryException If an error occurs.
@@ -133,7 +106,7 @@
             // find the next access control ancestor in the hierarchy
             // 'null' indicates that there is no ac-controlled ancestor.
             NodeId nextId = null;
-            NodeImpl n = node;            
+            NodeImpl n = node;
             while (nextId == null && !rootID.equals(n.getNodeId())) {
                 if (cache.containsKey(n.getNodeId())) {
                     nextId = n.getNodeId();
@@ -172,7 +145,7 @@
             return aclNode.hasNodes();
         }
 
-        // no acl defined here
+        // no ACL defined here
         return false;
     }
 
@@ -190,36 +163,96 @@
             }
             NodeId nodeId = (NodeId) key;
             int type = modifications.getType(nodeId);
-            synchronized (monitor) {
-                if ((type & POLICY_ADDED) == POLICY_ADDED) {
-                    // clear the complete cache since the nextAcNodeId may
-                    // have changed due to the added acl.
-                    log.debug("Policy added, clearing the cache");
-                    cache.clear();
-                    break; // no need for further processing.
-                } else if ((type & POLICY_REMOVED) == POLICY_REMOVED) {
-                    // clear the entry and change the entries having a nextID
-                    // pointing to this node.
-                    Entries ce = cache.remove(nodeId);
-                    if (ce != null) {
-                        NodeId nextId = ce.getNextId();
-                        for (Entries entry : cache.values()) {
-                            if (nodeId.equals(entry.getNextId())) {
-                                entry.setNextId(nextId);
-                            }
+            if ((type & POLICY_ADDED) == POLICY_ADDED) {
+                // clear the complete cache since the nextAcNodeId may
+                // have changed due to the added acl.
+                log.debug("Policy added, clearing the cache");
+                cache.clear();
+                break; // no need for further processing.
+            } else if ((type & POLICY_REMOVED) == POLICY_REMOVED) {
+                // clear the entry and change the entries having a nextID
+                // pointing to this node.
+                cache.remove(nodeId, true);
+            } else if ((type & POLICY_MODIFIED) == POLICY_MODIFIED) {
+                // simply clear the cache entry -> reload upon next access.
+                cache.remove(nodeId, false);
+            } else if ((type & MOVE) == MOVE) {
+                // some sort of move operation that may affect the cache
+                log.debug("Move operation, clearing the cache");
+                cache.clear();
+                break; // no need for further processing.
+            }
+        }
+        super.notifyListeners(modifications);
+    }
+
+    private class EntryCache {
+
+        private final Map<NodeId, Entries> cache;
+
+        @SuppressWarnings("unchecked")
+        public EntryCache() {
+            int maxsize = 5000;
+            String propname = "org.apache.jackrabbit.core.security.authorization.acl.CachingEntryCollector.maxsize";
+            try {
+                maxsize = Integer.parseInt(System.getProperty(propname, Integer.toString(maxsize)));
+            } catch (NumberFormatException ex) {
+                log.error("Parsing system property " + propname + " with value: " + System.getProperty(propname), ex);
+            }
+
+            log.info("Creating cache with max size of: " + maxsize);
+
+            cache = new GrowingLRUMap(1024, maxsize);
+        }
+
+        public boolean containsKey(NodeId nodeId) {
+            synchronized (cache) {
+                return cache.containsKey(nodeId);
+            }
+        }
+
+        public void clear() {
+            synchronized (cache) {
+                cache.clear();
+            }
+        }
+
+        public Entries get(NodeId id) {
+            Entries result;
+
+            synchronized (cache) {
+                result = cache.get(id);
+            }
+
+            if (result != null) {
+                log.debug("Cache hit for nodeId {}", id);
+            }
+
+            return result;
+        }
+
+        public void put(NodeId nodeId, Entries entries) {
+            synchronized (cache) {
+                cache.put(nodeId, entries);
+            }
+        }
+
+        public Entries remove(NodeId nodeId, boolean cleanup) {
+            Entries result;
+
+            synchronized (cache) {
+                result = cache.remove(nodeId);
+                if (cleanup && result != null) {
+                    NodeId nextId = result.getNextId();
+                    for (Entries entry : cache.values()) {
+                        if (nodeId.equals(entry.getNextId())) {
+                            entry.setNextId(nextId);
                         }
                     }
-                } else if ((type & POLICY_MODIFIED) == POLICY_MODIFIED) {
-                    // simply clear the cache entry -> reload upon next access.
-                    cache.remove(nodeId);
-                } else if ((type & MOVE) == MOVE) {
-                    // some sort of move operation that may affect the cache
-                    log.debug("Move operation, clearing the cache");
-                    cache.clear();
-                    break; // no need for further processing.
                 }
             }
+
+            return result;
         }
-        super.notifyListeners(modifications);
     }
 }
\ No newline at end of file
