You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2010/10/15 10:28:54 UTC

svn commit: r1022857 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization: ./ acl/ principalbased/

Author: angela
Date: Fri Oct 15 08:28:53 2010
New Revision: 1022857

URL: http://svn.apache.org/viewvc?rev=1022857&view=rev
Log:
minor improvement

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLTemplate.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/EntriesCache.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java Fri Oct 15 08:28:53 2010
@@ -78,7 +78,7 @@ public abstract class AbstractACLTemplat
      * @return the list of entries.
      * @see #orderBefore(AccessControlEntry, AccessControlEntry)
      */
-    protected abstract List<? extends AccessControlEntry> getEntries();
+    protected abstract List<AccessControlEntry> getEntries();
 
     //--------------------------------------< JackrabbitAccessControlPolicy >---
     /**
@@ -120,7 +120,7 @@ public abstract class AbstractACLTemplat
             return;
         }
 
-        List entries = getEntries();
+        List<AccessControlEntry> entries = getEntries();
         int index = (destEntry == null) ? entries.size()-1 : entries.indexOf(destEntry);
         if (index < 0) {
             throw new AccessControlException("destEntry not contained in this AccessControlList");
@@ -151,4 +151,4 @@ public abstract class AbstractACLTemplat
             throws AccessControlException, RepositoryException {
         return addEntry(principal, privileges, true, Collections.<String, Value>emptyMap());
     }
-}
\ No newline at end of file
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java Fri Oct 15 08:28:53 2010
@@ -16,26 +16,17 @@
  */
 package org.apache.jackrabbit.core.security.authorization.acl;
 
-import org.apache.commons.collections.map.LRUMap;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
-import org.apache.jackrabbit.core.ItemImpl;
-import org.apache.jackrabbit.core.ItemManager;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.id.NodeId;
-import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.security.SecurityConstants;
-import org.apache.jackrabbit.core.security.authorization.AccessControlListener;
 import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider;
-import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
 import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
-import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
 import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
 import org.apache.jackrabbit.core.security.authorization.Permission;
-import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
 import org.apache.jackrabbit.core.security.authorization.UnmodifiableAccessControlList;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
@@ -52,7 +43,6 @@ import javax.jcr.Session;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryManager;
 import javax.jcr.query.QueryResult;
-import javax.jcr.security.AccessControlEntry;
 import javax.jcr.security.AccessControlList;
 import javax.jcr.security.AccessControlManager;
 import javax.jcr.security.AccessControlPolicy;
@@ -60,7 +50,6 @@ import javax.jcr.security.Privilege;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -95,11 +84,6 @@ public class ACLProvider extends Abstrac
     private static final Logger log = LoggerFactory.getLogger(ACLProvider.class);
 
     /**
-     * the system acl editor.
-     */
-    private ACLEditor systemEditor;
-
-    /**
      * The node id of the root node
      */
     private NodeId rootNodeId;
@@ -123,7 +107,7 @@ public class ACLProvider extends Abstrac
         // minimal protection on the root node.
         NodeImpl root = (NodeImpl) session.getRootNode();
         rootNodeId = root.getNodeId();
-        systemEditor = new ACLEditor(systemSession, this);
+        ACLEditor systemEditor = new ACLEditor(systemSession, this);
 
         // TODO: replace by configurable default policy (see JCR-2331)
         boolean initializedWithDefaults = !configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS);
@@ -231,7 +215,7 @@ public class ACLProvider extends Abstrac
         } else if (isReadOnly(principals)) {
             return getReadOnlyPermissions();
         } else {
-            return new AclPermissions(principals);
+            return new CompiledPermissionsImpl(principals, session, entryCollector, this, true);
         }
     }
 
@@ -243,8 +227,12 @@ public class ACLProvider extends Abstrac
         if (isAdminOrSystem(principals)) {
             return true;
         } else {
-            CompiledPermissions cp = new AclPermissions(principals, false);
-            return cp.canRead(null, rootNodeId);
+            CompiledPermissions cp = new CompiledPermissionsImpl(principals, session, entryCollector, this, false);
+            try {
+                return cp.canRead(null, rootNodeId);
+            } finally {
+                cp.close();
+            }
         }
     }
 
@@ -257,55 +245,13 @@ public class ACLProvider extends Abstrac
      * @param systemSession The system session to create the entry collector for.
      * @return A new instance of <code>CachingEntryCollector</code>.
      * @throws RepositoryException If an error occurs.
-     * @see #retrieveResultEntries(NodeImpl, EntryFilter)
      */
     protected EntryCollector createEntryCollector(SessionImpl systemSession) throws RepositoryException {
-        return new CachingEntryCollector(systemSession, systemEditor, rootNodeId);
-    }
-
-    /**
-     * Retrieve an iterator of <code>AccessControlEntry</code> to be evaluated
-     * upon {@link AbstractCompiledPermissions#buildResult}.
-     *
-     * @param node Target node.
-     * @param filter The entry filter used to collect the access control entries.
-     * @return an iterator of <code>AccessControlEntry</code>.
-     * @throws RepositoryException If an error occurs.
-     */
-    protected Iterator<AccessControlEntry> retrieveResultEntries(NodeImpl node, EntryFilter filter) throws RepositoryException {
-        Iterator<AccessControlEntry> itr = entryCollector.collectEntries(node, filter).iterator();
-        return itr;
+        return new CachingEntryCollector(systemSession, rootNodeId);
     }
 
     //------------------------------------------------------------< private >---
     /**
-     * Returns the given <code>targetNode</code> unless the node itself stores
-     * access control information in which case it's nearest non-ac-parent is
-     * searched and returned.
-     *
-     * @param targetNode The node for which AC information needs to be retrieved.
-     * @param isAcItem true if the specified target node defines access control
-     * content; false otherwise.
-     * @return the given <code>targetNode</code> or the nearest non-ac-parent
-     * in case the <code>targetNode</code> itself defines access control content.
-     * @throws RepositoryException if an error occurs
-     */
-    private NodeImpl getNode(NodeImpl targetNode, boolean isAcItem) throws RepositoryException {
-        NodeImpl node;
-        if (isAcItem) {
-            Name ntName = ((NodeTypeImpl) targetNode.getPrimaryNodeType()).getQName();
-            if (ntName.equals(NT_REP_ACL)) {
-                node = (NodeImpl) targetNode.getParent();
-            } else {
-                node = (NodeImpl) targetNode.getParent().getParent();
-            }
-        } else {
-            node = targetNode;
-        }
-        return node;
-    }
-
-    /**
      * Recursively collects all ACLs that are effective on the specified node.
      *
      * @param node the Node to collect the ACLs for, which must NOT be part of the
@@ -397,189 +343,30 @@ public class ACLProvider extends Abstrac
         return node.hasNode(N_POLICY) && node.isNodeType(NT_REP_ACCESS_CONTROLLABLE);
     }
 
-    //------------------------------------------------< CompiledPermissions >---
     /**
+     * Returns the given <code>targetNode</code> unless the node itself stores
+     * access control information in which case it's nearest non-ac-parent is
+     * searched and returned.
      *
+     * @param targetNode The node for which AC information needs to be retrieved.
+     * @param isAcItem true if the specified target node defines access control
+     * content; false otherwise.
+     * @return the given <code>targetNode</code> or the nearest non-ac-parent
+     * in case the <code>targetNode</code> itself defines access control content.
+     * @throws RepositoryException if an error occurs
      */
-    private class AclPermissions extends AbstractCompiledPermissions implements AccessControlListener {
-
-        private final List<String> principalNames;
-        // TODO find optimal cache size and ev. make it configurable (see also JCR-2573).
-        private final Map<ItemId, Boolean> readCache = new LRUMap(5000);
-        private final Object monitor = new Object();
-
-        private AclPermissions(Set<Principal> principals) throws RepositoryException {
-            this(principals, true);
-        }
-
-        private AclPermissions(Set<Principal> principals, boolean listenToEvents) throws RepositoryException {
-            principalNames = new ArrayList<String>(principals.size());
-            for (Principal princ : principals) {
-                principalNames.add(princ.getName());
-            }
-
-            if (listenToEvents) {
-                /*
-                 Make sure this AclPermission recalculates the permissions if
-                 any ACL concerning it is modified.
-                 */
-                 entryCollector.addListener(this);
-            }
-        }
-
-        private Result buildResult(NodeImpl node, boolean isExistingNode, boolean isAcItem, EntryFilterImpl filter) throws RepositoryException {
-            // retrieve all ACEs at path or at the direct ancestor of path that
-            // apply for the principal names.
-            Iterator<AccessControlEntry> entries = retrieveResultEntries(getNode(node, isAcItem), filter);
-
-            /*
-             Calculate privileges and permissions:
-             Since the ACEs only define privileges on a node and do not allow
-             to add additional restrictions, the permissions can be determined
-             without taking the given target name or target item into account.
-             */
-            int allows = Permission.NONE;
-            int denies = Permission.NONE;
-
-            int allowPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
-            int denyPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
-            int parentAllows = PrivilegeRegistry.NO_PRIVILEGE;
-            int parentDenies = PrivilegeRegistry.NO_PRIVILEGE;
-
-            String parentPath = Text.getRelativeParent(filter.getPath(), 1);
-
-            while (entries.hasNext()) {
-                ACLTemplate.Entry ace = (ACLTemplate.Entry) entries.next();
-                /*
-                 Determine if the ACE also takes effect on the parent:
-                 Some permissions (e.g. add-node or removal) must be determined
-                 from privileges defined for the parent.
-                 A 'local' entry defined on the target node never effects the
-                 parent. For inherited ACEs determine if the ACE matches the
-                 parent path.
-                 */
-                int entryBits = ace.getPrivilegeBits();
-                boolean isLocal = isExistingNode && ace.isLocal(node.getNodeId());
-                boolean matchesParent = (!isLocal && ace.matches(parentPath));
-                if (matchesParent) {
-                    if (ace.isAllow()) {
-                        parentAllows |= Permission.diff(entryBits, parentDenies);
-                    } else {
-                        parentDenies |= Permission.diff(entryBits, parentAllows);
-                    }
-                }
-                if (ace.isAllow()) {
-                    allowPrivileges |= Permission.diff(entryBits, denyPrivileges);
-                    int permissions = PrivilegeRegistry.calculatePermissions(allowPrivileges, parentAllows, true, isAcItem);
-                    allows |= Permission.diff(permissions, denies);
-                } else {
-                    denyPrivileges |= Permission.diff(entryBits, allowPrivileges);
-                    int permissions = PrivilegeRegistry.calculatePermissions(denyPrivileges, parentDenies, false, isAcItem);
-                    denies |= Permission.diff(permissions, allows);
-                }
-            }
-            return new Result(allows, denies, allowPrivileges, denyPrivileges);
-        }
-
-        //------------------------------------< AbstractCompiledPermissions >---
-        /**
-         * @see AbstractCompiledPermissions#buildResult(Path)
-         */
-        @Override
-        protected Result buildResult(Path absPath) throws RepositoryException {
-            boolean existingNode = false;
-            NodeImpl node;
-
-            ItemManager itemMgr = session.getItemManager();
-            try {
-                ItemImpl item = itemMgr.getItem(absPath);
-                if (item.isNode()) {
-                    node = (NodeImpl) item;
-                    existingNode = true;
-                } else {
-                    node = (NodeImpl) item.getParent();
-                }
-            } catch (RepositoryException e) {
-                // path points to a non-persisted item.
-                // -> find the nearest persisted node starting from the root.
-                Path.Element[] elems = absPath.getElements();
-                NodeImpl parent = (NodeImpl) session.getRootNode();
-                for (int i = 1; i < elems.length - 1; i++) {
-                    Name name = elems[i].getName();
-                    int index = elems[i].getIndex();
-                    if (!parent.hasNode(name, index)) {
-                        // last persisted node reached
-                        break;
-                    }
-                    parent = parent.getNode(name, index);
-
-                }
-                node = parent;
-            }
-
-            if (node == null) {
-                // should never get here
-                throw new ItemNotFoundException("Item out of hierarchy.");
-            }
-
-            boolean isAcItem = isAcItem(absPath);
-            return buildResult(node, existingNode, isAcItem, new EntryFilterImpl(principalNames, absPath, session));
-        }
-
-        /**
-         * @see AbstractCompiledPermissions#clearCache()
-         */
-        @Override
-        protected void clearCache() {
-            synchronized (monitor) {
-                readCache.clear();
-            }
-            super.clearCache();
-        }
-
-        //--------------------------------------------< CompiledPermissions >---
-        /**
-         * @see CompiledPermissions#close()
-         */
-        @Override
-        public void close() {
-            entryCollector.removeListener(this);
-            super.close();
-        }
-
-        /**
-         * @see CompiledPermissions#canRead(Path, ItemId)
-         */
-        public boolean canRead(Path path, ItemId itemId) throws RepositoryException {
-            ItemId id = (itemId == null) ? session.getHierarchyManager().resolvePath(path) : itemId;
-            // no extra check for existence as method may only be called for existing items.
-            boolean isExistingNode = id.denotesNode();
-            boolean canRead;
-            synchronized (monitor) {
-                if (readCache.containsKey(id)) {
-                    canRead = readCache.get(id);
-                } else {
-                    ItemManager itemMgr = session.getItemManager();
-                    NodeId nodeId = (isExistingNode) ? (NodeId) id : ((PropertyId) id).getParentId();
-                    NodeImpl node = (NodeImpl) itemMgr.getItem(nodeId);
-                    // TODO: check again if retrieving the path can be avoided
-                    Path absPath = (path == null) ? session.getHierarchyManager().getPath(id) : path;
-                    Result result = buildResult(node, isExistingNode, isAcItem(node), new EntryFilterImpl(principalNames, absPath, session));
-
-                    canRead = result.grants(Permission.READ);
-                    readCache.put(id, canRead);
-                }
+    static NodeImpl getNode(NodeImpl targetNode, boolean isAcItem) throws RepositoryException {
+        NodeImpl node;
+        if (isAcItem) {
+            Name ntName = ((NodeTypeImpl) targetNode.getPrimaryNodeType()).getQName();
+            if (ntName.equals(NT_REP_ACL)) {
+                node = (NodeImpl) targetNode.getParent();
+            } else {
+                node = (NodeImpl) targetNode.getParent().getParent();
             }
-            return canRead;
-        }
-
-        //----------------------------------------< ACLModificationListener >---
-        /**
-         * @see org.apache.jackrabbit.core.security.authorization.AccessControlListener#acModified(AccessControlModifications)
-         */
-        public void acModified(AccessControlModifications modifications) {
-            // ignore the details of the modifications and clear all caches.
-            clearCache();
+        } else {
+            node = targetNode;
         }
+        return node;
     }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java Fri Oct 15 08:28:53 2010
@@ -67,7 +67,7 @@ class ACLTemplate extends AbstractACLTem
     /**
      * List containing the entries of this ACL Template.
      */
-    private final List<Entry> entries = new ArrayList<Entry>();
+    private final List<AccessControlEntry> entries = new ArrayList<AccessControlEntry>();
 
     /**
      * The principal manager used for validation checks
@@ -197,9 +197,9 @@ class ACLTemplate extends AbstractACLTem
     private List<Entry> internalGetEntries(Principal principal) {
         String principalName = principal.getName();
         List<Entry> entriesPerPrincipal = new ArrayList<Entry>(2);
-        for (Entry entry : entries) {
+        for (AccessControlEntry entry : entries) {
             if (principalName.equals(entry.getPrincipal().getName())) {
-                entriesPerPrincipal.add(entry);
+                entriesPerPrincipal.add((Entry) entry);
             }
         }
         return entriesPerPrincipal;
@@ -311,7 +311,7 @@ class ACLTemplate extends AbstractACLTem
      * @see org.apache.jackrabbit.core.security.authorization.AbstractACLTemplate#getEntries()
      */
     @Override
-    protected List<? extends AccessControlEntry> getEntries() {
+    protected List<AccessControlEntry> getEntries() {
         return entries;
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java Fri Oct 15 08:28:53 2010
@@ -52,13 +52,12 @@ class CachingEntryCollector extends Entr
     /**
      * 
      * @param systemSession
-     * @param systemEditor
      * @param rootID
      * @throws RepositoryException
      */
     @SuppressWarnings("unchecked")    
-    CachingEntryCollector(SessionImpl systemSession, ACLEditor systemEditor, NodeId rootID) throws RepositoryException {
-        super(systemSession, systemEditor, rootID);
+    CachingEntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
+        super(systemSession, rootID);
         
         cache = new LRUMap(1000);
     }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java?rev=1022857&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java Fri Oct 15 08:28:53 2010
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authorization.acl;
+
+import org.apache.commons.collections.map.LRUMap;
+import org.apache.jackrabbit.core.ItemImpl;
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.AccessControlListener;
+import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
+import org.apache.jackrabbit.core.security.authorization.AccessControlUtils;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.util.Text;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlEntry;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <code>CompiledPermissionsImpl</code>...
+ */
+class CompiledPermissionsImpl extends AbstractCompiledPermissions implements AccessControlListener {
+
+    private final List<String> principalNames;
+    private final SessionImpl session;
+    private final EntryCollector entryCollector;
+    private final AccessControlUtils util;
+    
+    private final Map<ItemId, Boolean> readCache = new LRUMap(5000);
+    private final Object monitor = new Object();
+
+    CompiledPermissionsImpl(Set<Principal> principals, SessionImpl session,
+                            EntryCollector entryCollector, AccessControlUtils util,
+                            boolean listenToEvents) throws RepositoryException {
+        this.session = session;
+        this.entryCollector = entryCollector;
+        this.util = util;
+
+        principalNames = new ArrayList<String>(principals.size());
+        for (Principal princ : principals) {
+            principalNames.add(princ.getName());
+        }
+
+        if (listenToEvents) {
+            /*
+            Make sure this AclPermission recalculates the permissions if
+            any ACL concerning it is modified.
+            */
+            entryCollector.addListener(this);
+        }
+    }
+
+    private Result buildResult(NodeImpl node, boolean isExistingNode, boolean isAcItem, EntryFilterImpl filter) throws RepositoryException {
+        // retrieve all ACEs at path or at the direct ancestor of path that
+        // apply for the principal names.
+        NodeImpl n = ACLProvider.getNode(node, isAcItem);
+        Iterator<AccessControlEntry> entries = entryCollector.collectEntries(n, filter).iterator();
+
+        /*
+        Calculate privileges and permissions:
+        Since the ACEs only define privileges on a node and do not allow
+        to add additional restrictions, the permissions can be determined
+        without taking the given target name or target item into account.
+        */
+        int allows = Permission.NONE;
+        int denies = Permission.NONE;
+
+        int allowPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
+        int denyPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
+        int parentAllows = PrivilegeRegistry.NO_PRIVILEGE;
+        int parentDenies = PrivilegeRegistry.NO_PRIVILEGE;
+
+        String parentPath = Text.getRelativeParent(filter.getPath(), 1);
+
+        while (entries.hasNext()) {
+            ACLTemplate.Entry ace = (ACLTemplate.Entry) entries.next();
+            /*
+            Determine if the ACE also takes effect on the parent:
+            Some permissions (e.g. add-node or removal) must be determined
+            from privileges defined for the parent.
+            A 'local' entry defined on the target node never effects the
+            parent. For inherited ACEs determine if the ACE matches the
+            parent path.
+            */
+            int entryBits = ace.getPrivilegeBits();
+            boolean isLocal = isExistingNode && ace.isLocal(node.getNodeId());
+            boolean matchesParent = (!isLocal && ace.matches(parentPath));
+            if (matchesParent) {
+                if (ace.isAllow()) {
+                    parentAllows |= Permission.diff(entryBits, parentDenies);
+                } else {
+                    parentDenies |= Permission.diff(entryBits, parentAllows);
+                }
+            }
+            if (ace.isAllow()) {
+                allowPrivileges |= Permission.diff(entryBits, denyPrivileges);
+                int permissions = PrivilegeRegistry.calculatePermissions(allowPrivileges, parentAllows, true, isAcItem);
+                allows |= Permission.diff(permissions, denies);
+            } else {
+                denyPrivileges |= Permission.diff(entryBits, allowPrivileges);
+                int permissions = PrivilegeRegistry.calculatePermissions(denyPrivileges, parentDenies, false, isAcItem);
+                denies |= Permission.diff(permissions, allows);
+            }
+        }
+        return new Result(allows, denies, allowPrivileges, denyPrivileges);
+    }
+
+    //------------------------------------< AbstractCompiledPermissions >---
+    /**
+     * @see AbstractCompiledPermissions#buildResult(org.apache.jackrabbit.spi.Path)
+     */
+    @Override
+    protected Result buildResult(Path absPath) throws RepositoryException {
+        boolean existingNode = false;
+        NodeImpl node;
+
+        ItemManager itemMgr = session.getItemManager();
+        try {
+            ItemImpl item = itemMgr.getItem(absPath);
+            if (item.isNode()) {
+                node = (NodeImpl) item;
+                existingNode = true;
+            } else {
+                node = (NodeImpl) item.getParent();
+            }
+        } catch (RepositoryException e) {
+            // path points to a non-persisted item.
+            // -> find the nearest persisted node starting from the root.
+            Path.Element[] elems = absPath.getElements();
+            NodeImpl parent = (NodeImpl) session.getRootNode();
+            for (int i = 1; i < elems.length - 1; i++) {
+                Name name = elems[i].getName();
+                int index = elems[i].getIndex();
+                if (!parent.hasNode(name, index)) {
+                    // last persisted node reached
+                    break;
+                }
+                parent = parent.getNode(name, index);
+
+            }
+            node = parent;
+        }
+
+        if (node == null) {
+            // should never get here
+            throw new ItemNotFoundException("Item out of hierarchy.");
+        }
+
+        boolean isAcItem = util.isAcItem(absPath);
+        return buildResult(node, existingNode, isAcItem, new EntryFilterImpl(principalNames, absPath, session));
+    }
+
+    /**
+     * @see AbstractCompiledPermissions#clearCache()
+     */
+    @Override
+    protected void clearCache() {
+        synchronized (monitor) {
+            readCache.clear();
+        }
+        super.clearCache();
+    }
+
+    //--------------------------------------------< CompiledPermissions >---
+    /**
+     * @see org.apache.jackrabbit.core.security.authorization.CompiledPermissions#close()
+     */
+    @Override
+    public void close() {
+        entryCollector.removeListener(this);
+        // NOTE: do not logout shared session.
+        super.close();
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.security.authorization.CompiledPermissions#canRead(Path, ItemId)
+     */
+    public boolean canRead(Path path, ItemId itemId) throws RepositoryException {
+        ItemId id = (itemId == null) ? session.getHierarchyManager().resolvePath(path) : itemId;
+        // no extra check for existence as method may only be called for existing items.
+        boolean isExistingNode = id.denotesNode();
+        boolean canRead;
+        synchronized (monitor) {
+            if (readCache.containsKey(id)) {
+                canRead = readCache.get(id);
+            } else {
+                ItemManager itemMgr = session.getItemManager();
+                NodeId nodeId = (isExistingNode) ? (NodeId) id : ((PropertyId) id).getParentId();
+                NodeImpl node = (NodeImpl) itemMgr.getItem(nodeId);
+                // TODO: check again if retrieving the path can be avoided
+                Path absPath = (path == null) ? session.getHierarchyManager().getPath(id) : path;
+                Result result = buildResult(node, isExistingNode, util.isAcItem(node), new EntryFilterImpl(principalNames, absPath, session));
+
+                canRead = result.grants(Permission.READ);
+                readCache.put(id, canRead);
+            }
+        }
+        return canRead;
+    }
+
+    //----------------------------------------< ACLModificationListener >---
+    /**
+     * @see org.apache.jackrabbit.core.security.authorization.AccessControlListener#acModified(org.apache.jackrabbit.core.security.authorization.AccessControlModifications)
+     */
+    public void acModified(AccessControlModifications modifications) {
+        // ignore the details of the modifications and clear all caches.
+        clearCache();
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java Fri Oct 15 08:28:53 2010
@@ -22,6 +22,7 @@ import org.apache.jackrabbit.core.id.Nod
 import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
 import org.apache.jackrabbit.core.security.authorization.AccessControlObserver;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +34,6 @@ import javax.jcr.observation.EventIterat
 import javax.jcr.observation.ObservationManager;
 import javax.jcr.security.AccessControlEntry;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -51,25 +51,36 @@ public class EntryCollector extends Acce
      * logger instance
      */
     private static final Logger log = LoggerFactory.getLogger(EntryCollector.class);
-        
+
+    /**
+     * The system session used to register an event listener and process the
+     * events as well as collect AC entries.
+     */
     protected final SessionImpl systemSession;
+
+    /**
+     * The root id.
+     */
     protected final NodeId rootID;
+
+    private final PrivilegeRegistry privilegeRegistry;
     
-    private final ACLEditor systemEditor;
-       
+    /**
+     * Standard JCR name form of the {@link #N_POLICY} constant.
+     */
     private final String repPolicyName;
 
     /**
      *
      * @param systemSession
-     * @param systemEditor
      * @param rootID
      * @throws RepositoryException
      */
-    protected EntryCollector(SessionImpl systemSession, ACLEditor systemEditor, NodeId rootID) throws RepositoryException {
+    protected EntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
         this.systemSession = systemSession;
-        this.systemEditor = systemEditor;
         this.rootID = rootID;
+
+        privilegeRegistry = new PrivilegeRegistry(systemSession);
         repPolicyName = systemSession.getJCRName(N_POLICY);
 
         ObservationManager observationMgr = systemSession.getWorkspace().getObservationManager();
@@ -95,6 +106,7 @@ public class EntryCollector extends Acce
      * Release all resources contained by this instance. It will no longer be
      * used. This implementation only stops listening to ac modification events.
      */
+    @Override
     protected void close() {
         super.close();
         try {
@@ -126,7 +138,7 @@ public class EntryCollector extends Acce
             next = getParentId(next);
         }
         
-        List<AccessControlEntry> entries = new ArrayList(userAces.size() + groupAces.size());
+        List<AccessControlEntry> entries = new ArrayList<AccessControlEntry>(userAces.size() + groupAces.size());
         entries.addAll(userAces);
         entries.addAll(groupAces);
 
@@ -147,7 +159,7 @@ public class EntryCollector extends Acce
         if (ACLProvider.isAccessControlled(node)) {
             // collect the aces of that node.
             NodeImpl aclNode = node.getNode(N_POLICY);
-            entries = Arrays.asList(systemEditor.getACL(aclNode).getAccessControlEntries());
+            entries = new ACLTemplate(aclNode, privilegeRegistry).getEntries();
         } else {
             // not access controlled
             entries = Collections.emptyList();
@@ -288,7 +300,7 @@ public class EntryCollector extends Acce
 
         if (!modMap.isEmpty()) {
             // notify listeners and eventually clean up internal caches.
-            notifyListeners(new AccessControlModifications(modMap));
+            notifyListeners(new AccessControlModifications<NodeId>(modMap));
         }
     }
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLTemplate.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLTemplate.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLTemplate.java Fri Oct 15 08:28:53 2010
@@ -185,7 +185,7 @@ class ACLTemplate extends AbstractACLTem
      * @see org.apache.jackrabbit.core.security.authorization.AbstractACLTemplate#getEntries() 
      */
     @Override
-    protected List<? extends AccessControlEntry> getEntries() {
+    protected List<AccessControlEntry> getEntries() {
         return entries;
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/EntriesCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/EntriesCache.java?rev=1022857&r1=1022856&r2=1022857&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/EntriesCache.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/EntriesCache.java Fri Oct 15 08:28:53 2010
@@ -100,6 +100,7 @@ class EntriesCache extends AccessControl
      * Release all resources contained by this instance. It will no longer be
      * used. This implementation only stops listening to ac modification events.
      */
+    @Override
     protected void close() {
         super.close();
         try {
@@ -110,7 +111,7 @@ class EntriesCache extends AccessControl
     }
 
     List<AccessControlEntry> getEntries(Collection<Principal> principals) throws RepositoryException {
-        Object key = getCacheKey(principals);
+        String key = getCacheKey(principals);
         List<AccessControlEntry> entries;
         synchronized (monitor) {
             entries = cache.get(key);
@@ -134,7 +135,7 @@ class EntriesCache extends AccessControl
         return entries;
     }
 
-    private static Object getCacheKey(Collection<Principal> principals) {
+    private static String getCacheKey(Collection<Principal> principals) {
         StringBuilder sb = new StringBuilder();
         for (Principal p : principals) {
             sb.append(p.getName()).append('/');
@@ -219,7 +220,7 @@ class EntriesCache extends AccessControl
             synchronized (monitor) {
                 cache.clear();
             }
-            notifyListeners(new AccessControlModifications(modMap));
+            notifyListeners(new AccessControlModifications<String>(modMap));
         }
     }
 }