jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r638834 [6/14] - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/ jackr...
Date Wed, 19 Mar 2008 13:57:11 GMT
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLCache.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLCache.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLCache.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,366 @@
+/*
+ * 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.LinkedMap;
+import org.apache.jackrabbit.core.ItemId;
+import org.apache.jackrabbit.core.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ACLCache<br>
+ * Caches already resolved ACLs for one workspace.<p>
+ * The cache keeps per item the ACL if locally defined AND a reference to
+ * the next id, which defines an ACL.
+ * Thus if no entry is contained in the Cache a new one has to be build.
+ *
+ * @author tobi
+ */
+class ACLCache {
+
+    /** the default logger */
+    private static final Logger log = LoggerFactory.getLogger(ACLCache.class);
+
+    /** the acl entries stored by the id of their applying item */
+    private final Map entryByItemId = new HashMap();
+
+    /** map of recently used leaf entries */
+    private final LinkedMap lruMap = new LinkedMap();
+
+    /** the acl entries stored by their id */
+    private final Map entryByAclId = new HashMap();
+
+    /** the maximum size of the cache */
+    private final int maxSize;
+
+    /** the name of this cache */
+    private final String name;
+
+    /**
+     * creates a new ACLCache with the given name and a default maximal size.
+     *
+     * @param name
+     */
+    ACLCache(String name) {
+        this(name, 0x10000);
+    }
+
+    /**
+     * creates a new ACLCache with the given name
+     *
+     * @param name
+     * @param maxSize
+     */
+    ACLCache(String name, int maxSize) {
+        this.name = name;
+        this.maxSize = maxSize;
+    }
+
+    /**
+     * Return the effective ACL for the given item id.<br>
+     *
+     * @param id    of the Item the ACL should apply
+     * @param touch if <code>true</code>, the item is pot. added to the lruMap
+     *
+     * @return the ACL or <code>null</code> if none is stored
+     */
+    ACLImpl getAcl(ItemId id, boolean touch) {
+        Entry entry = (Entry) entryByItemId.get(id);
+        if (entry == null) {
+            return null;
+        } else if (touch && !entry.hasChildren()) {
+            // this is the only potential read-only access, so synchronize
+            synchronized (lruMap) {
+                lruMap.remove(id);
+                lruMap.put(id, id);
+            }
+            if (log.isDebugEnabled()) {
+                log.debug("Added entry to lruMap. {}", this);
+            }
+        }
+        return entry.getAcl();
+    }
+
+    /**
+     * Puts an ACL into this cache.<p>
+     *
+     * @param id       the acl applies
+     * @param parentId id of the item the acl inherits from
+     * @param acl
+     */
+    void cache(ItemId id, ItemId parentId, ACLImpl acl) throws RepositoryException {
+        Entry entry = (Entry) entryByItemId.get(id);
+        if (entry == null) {
+            if (entryByItemId.size() > maxSize) {
+                purge();
+            }
+            if (parentId == null) {
+                new Entry(id, null, acl);
+            } else {
+                Entry parent = (Entry) entryByItemId.get(parentId);
+                if (parent == null) {
+                    throw new RepositoryException("Illegal state...parent ACL must be cached.");
+                }
+                new Entry(id, parent, acl);
+            }
+        } else {
+            entry.setAcl(acl);
+        }
+    }
+
+    /**
+     * purges leaf-entries until 10% of max size is reached
+     */
+    private void purge() {
+        // purge 10% of max size
+        int goal = (maxSize * 90) / 100;
+        int size = entryByItemId.size();
+        while (entryByItemId.size() > goal && !lruMap.isEmpty()) {
+            NodeId id = (NodeId) lruMap.remove(0);
+            removeEntry(id);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("Purged {} entries. {}", String.valueOf(size - entryByItemId.size()), this);
+        }
+    }
+
+    /**
+     * Invalidates the acl with the given id
+     *
+     * @param aclId
+     */
+    void invalidateEntry(NodeId aclId) {
+        Entry entry = (Entry) entryByAclId.get(aclId);
+        if (entry != null) {
+            if (entry.parent != null) {
+                entry.parent.invalidate();
+            } else {
+                entry.invalidate();
+            }
+        }
+    }
+
+    /**
+     * Invalidates the acl that applies to the Item with the given id.
+     *
+     * @param itemId
+     */
+    void removeEntry(NodeId itemId) {
+        Entry entry = (Entry) entryByItemId.get(itemId);
+        if (entry != null) {
+            entry.remove();
+        }
+    }
+
+    /**
+     * closes the cache and clears all maps
+     */
+    void close() {
+        entryByAclId.clear();
+        entryByItemId.clear();
+        lruMap.clear();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return "name=" + name + ", entries=" + entryByItemId.size() + ", leaves=" + lruMap.size();
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Entry class for the acl cache. Every entry represents a accessontrollable
+     * item of the workspace. the entry might have an assosiated ACL. the
+     * parent-child relationships of parent-child ACLs are also recorded in the
+     * entry. please note, that this is not the same as the parent-child
+     * relationship of the actual repository items, since not all items must be
+     * access controllable.
+     */
+    private class Entry {
+
+        /**
+         * the id of the access controlled item
+         */
+        private final ItemId id;
+
+        /**
+         * the ACL for the access controlled item
+         */
+        private ACLImpl acl;
+
+        /**
+         * the parent entry or <code>null</code> if root
+         */
+        private final Entry parent;
+
+        /**
+         * the set of child entries or <code>null</code> if no children
+         */
+        private Set children = new HashSet();
+
+        /**
+         * Creates a new ACLEntry at adds it to the cache
+         *
+         * @param id
+         * @param acl
+         */
+        private Entry(ItemId id, Entry parent, ACLImpl acl) {
+            this.id = id;
+            this.acl = acl;
+            this.parent = parent;
+            if (parent != null) {
+                parent.attachChild(this);
+            }
+            entryByItemId.put(id, this);
+            setAcl(acl);
+            if (log.isDebugEnabled()) {
+                log.debug("Added new entry.");
+            }
+        }
+
+        /**
+         * Attaches a child entry to this one
+         *
+         * @param child
+         */
+        private void attachChild(Entry child) {
+            children.add(child);
+            // remove from lruMap
+            if (lruMap.remove(id) != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("attachChild removed item from lru map. {}", ACLCache.this);
+                }
+            }
+
+        }
+
+        /**
+         * Detaches a child entry
+         * @param child
+         */
+        private void detachChild(Entry child) {
+            children.remove(child);
+            if (children.isEmpty()) {
+                lruMap.put(id, id);
+                if (log.isDebugEnabled()) {
+                    log.debug("detachChild added item to lru map. {}", ACLCache.this);
+                }
+            }
+        }
+
+        /**
+         * sets the acl
+         *
+         * @param newAcl
+         */
+        private void setAcl(ACLImpl newAcl) {
+            if (newAcl == acl) {
+                // ignore
+                return;
+            }
+            // test if an acl is already present -> informInvalid.
+            if (acl != null) {
+                entryByAclId.remove(acl.getId());
+            }
+            // set the acl field to the new value
+            acl = newAcl;
+            if (newAcl != null) {
+                entryByAclId.put(newAcl.getId(), this);
+            }
+        }
+
+        /**
+         * checks if this entry has children
+         * @return <code>true</code> if this enrty has children
+         */
+        private boolean hasChildren() {
+            return !children.isEmpty();
+        }
+
+        /**
+         * returns the assigned acl
+         * @return the acl
+         */
+        private ACLImpl getAcl() {
+            return acl;
+        }
+
+        /**
+         * invalidates this entry, i.e. clears the assigned acl and recursivly
+         * invalidates all its children.
+         */
+        private void invalidate() {
+            setAcl(null);
+            Iterator iter = children.iterator();
+            while (iter.hasNext()) {
+                ((Entry) iter.next()).invalidate();
+            }
+        }
+
+        /**
+         * removes this entry from the cache and recursivly all children.
+         */
+        private void remove() {
+            entryByItemId.remove(id);
+            lruMap.remove(id);
+
+            Iterator iter = children.iterator();
+            while (iter.hasNext()) {
+                ((Entry) iter.next()).remove();
+                iter = children.iterator(); // to avoid concurrent mod excp.
+            }
+
+            if (parent != null) {
+                parent.detachChild(this);
+            }
+            setAcl(null);
+            if (log.isDebugEnabled()) {
+                log.debug("Removed entry. {}", ACLCache.this);
+            }
+        }
+
+        //---------------------------------------------------------< Object >---
+        /**
+         * @see Object#hashCode()
+         */
+        public int hashCode() {
+            return id.hashCode();
+        }
+
+        /**
+         * @see Object#equals(Object)
+         */
+        public boolean equals(Object obj) {
+            if (obj==this) {
+                return true;
+            }
+            if (obj instanceof Entry) {
+                return id.equals(((Entry)obj).id);
+            }
+            return false;
+        }
+    }
+}

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLCache.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,327 @@
+/*
+ * 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.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SecurityItemModifier;
+import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
+import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
+import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlException;
+import org.apache.jackrabbit.core.security.jsr283.security.Privilege;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.spi.commons.conversion.NameParser;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.Name;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Session;
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import java.security.Principal;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * <code>ACLEditor</code>...
+ */
+public class ACLEditor extends SecurityItemModifier implements AccessControlEditor, AccessControlConstants {
+
+    /**
+     * the default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(ACLEditor.class);
+    /**
+     * Default name for ace nodes
+     */
+    private static final String DEFAULT_PERMISSION_NAME = "permission";
+
+    private final SessionImpl session;
+    private final PrincipalManager principalManager;
+
+    protected ACLEditor(Session editingSession) throws RepositoryException {
+        if (editingSession instanceof SessionImpl) {
+            session = ((SessionImpl) editingSession);
+            principalManager = ((SessionImpl) editingSession).getPrincipalManager();
+        } else {
+            throw new IllegalArgumentException("org.apache.jackrabbit.core.SessionImpl expected. Found " + editingSession.getClass());
+        }
+    }
+
+    //------------------------------------------------< AccessControlEditor >---
+    /**
+     * @see AccessControlEditor#getPolicyTemplate(NodeId)
+     */
+    public PolicyTemplate getPolicyTemplate(NodeId id) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        checkProtectsNode(id);
+
+        PolicyTemplate tmpl = null;
+        NodeImpl aclNode = getAclNode(id);
+        if (aclNode != null) {
+            tmpl = new ACLTemplate(aclNode, Collections.EMPTY_SET);
+        }
+        return tmpl;
+    }
+
+    /**
+     * @see AccessControlEditor#editPolicyTemplate(NodeId)
+     */
+    public PolicyTemplate editPolicyTemplate(NodeId id) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        checkProtectsNode(id);
+
+        PolicyTemplate tmpl;
+        NodeImpl aclNode = getAclNode(id);
+        if (aclNode == null) {
+            tmpl = new ACLTemplate();
+        } else {
+            tmpl = new ACLTemplate(aclNode, Collections.EMPTY_SET);
+        }
+        return tmpl;
+    }
+
+    /**
+     * @see AccessControlEditor#setPolicyTemplate(NodeId, PolicyTemplate)
+     */
+    public void setPolicyTemplate(NodeId id, PolicyTemplate template) throws RepositoryException {
+        checkProtectsNode(id);
+
+        NodeImpl aclNode = getAclNode(id);
+        /* in order to assert that the parent (ac-controlled node) gets modified
+           an existing ACL node is removed first and the recreated.
+           this also asserts that all ACEs are cleared without having to
+           access and removed the explicitely
+         */
+        if (aclNode != null) {
+            removeSecurityItem(aclNode);
+        }
+        // now (re) create it
+        aclNode = createAclNode(id);
+
+        PolicyEntry[] entries = template.getEntries();
+        for (int i = 0; i < entries.length; i++) {
+            ACEImpl ace = (ACEImpl) entries[i];
+            // TODO: improve
+            Name nodeName = getUniqueNodeName(aclNode, ace.isAllow() ? "allow" : "deny");
+            Name ntName = (ace.isAllow()) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
+            ValueFactory vf = session.getValueFactory();
+
+            NodeImpl aceNode = addSecurityNode(aclNode, nodeName, ntName);
+            // write the rep:principalName property
+            String principalName = ace.getPrincipal().getName();
+            setSecurityProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(principalName));
+            // ... and the rep:privileges property
+            Privilege[] pvlgs = ace.getPrivileges();
+            Value[] names = getPrivilegeNames(pvlgs, vf);
+            setSecurityProperty(aceNode, P_PRIVILEGES, names);
+        }
+    }
+
+    /**
+     * @see AccessControlEditor#removePolicyTemplate(NodeId)
+     */
+    public PolicyTemplate removePolicyTemplate(NodeId id) throws AccessControlException, RepositoryException {
+        checkProtectsNode(id);
+
+        PolicyTemplate tmpl = null;
+        NodeImpl aclNode = getAclNode(id);
+        if (aclNode != null) {
+            // need to build the template in order to have a return value.
+            tmpl = new ACLTemplate(aclNode, Collections.EMPTY_SET);
+            removeSecurityItem(aclNode);
+        }
+        return tmpl;
+    }
+
+    /**
+     * @see AccessControlEditor#getAccessControlEntries(NodeId)
+     */
+    public AccessControlEntry[] getAccessControlEntries(NodeId id) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        PolicyTemplate pt = getPolicyTemplate(id);
+        if (pt == null) {
+            return new AccessControlEntry[0];
+        } else {
+            PolicyEntry[] entries = pt.getEntries();
+            List l = new ArrayList();
+            for (int i = 0; i < entries.length; i++) {
+                if (entries[i].isAllow()) {
+                    l.add(entries[i]);
+                }
+            }
+            return (AccessControlEntry[]) l.toArray(new AccessControlEntry[l.size()]);
+        }
+    }
+
+    /**
+     * @see AccessControlEditor#addAccessControlEntry(NodeId,Principal,Privilege[])
+     */
+    public AccessControlEntry addAccessControlEntry(NodeId id, Principal principal, Privilege[] privileges) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        // JSR 283 requires that the principal is known TODO: check again.
+        if (!principalManager.hasPrincipal(principal.getName())) {
+            throw new AccessControlException("Principal " + principal.getName() + " does not exist.");
+        }
+
+        ACLTemplate pt = (ACLTemplate) editPolicyTemplate(id);
+        // TODO: check again. maybe these 'grant-ACE' should be stored/evaluated separated
+        int privs = PrivilegeRegistry.getBits(privileges);
+        /*
+        since added access control entry may never remove privileges that are
+        granted by the policy -> retrieve existing allow entries and add
+        the new privileges to be granted.
+        Reason: PolicyTemplate#setEntry does in fact overwrite (which is fine
+        when editing the policy itself, but wrong when adding ACEs over the JCR-API.
+        */
+        ACEImpl[] existing = pt.getEntries(principal);
+        for (int i = 0; i < existing.length; i++) {
+            if (existing[i].isAllow()) {
+                privs |= existing[i].getPrivilegeBits();
+            }
+        }
+
+        pt.setEntry(new ACEImpl(principal, privs, true));
+        setPolicyTemplate(id, pt);
+        ACEImpl[] tmpls = pt.getEntries(principal);
+        for (int i = 0; i < tmpls.length; i++) {
+            if (tmpls[i].isAllow()) {
+                return tmpls[i];
+            }
+        }
+        // should never get here
+        throw new AccessControlException("Internal error: No access control entry added.");
+    }
+
+
+    /**
+     * @see AccessControlEditor#removeAccessControlEntry(NodeId,AccessControlEntry)
+     */
+    public boolean removeAccessControlEntry(NodeId id, AccessControlEntry entry) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        if (!(entry instanceof ACEImpl)) {
+            throw new AccessControlException("Unknown AccessControlEntry implementation.");
+        }
+        // TODO: check again. maybe these 'grant-ACE' should be removed separated
+        PolicyTemplate pt = editPolicyTemplate(id);
+        boolean removed = pt.removeEntry((ACEImpl) entry);
+        if (removed) {
+            setPolicyTemplate(id, pt);
+        }
+        return removed;
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Test if the Node identified by <code>id</code> is itself part of ACL
+     * defining content. It this case setting or modifying an AC-policy is
+     * obviously not possible.
+     *
+     * @param id
+     * @throws AccessControlException If the given id identifies a Node that
+     * represents a ACL or ACE item.
+     * @throws RepositoryException
+     */
+    private void checkProtectsNode(NodeId id) throws RepositoryException {
+        NodeImpl node = session.getNodeById(id);
+        if (ACLProvider.protectsNode(node)) {
+            throw new AccessControlException("Node " + id + " defines ACL or ACE itself.");
+        }
+    }
+
+    /**
+     * Returns the rep:Policy node below the Node identified by the given
+     * id or <code>null</code> if the node is not mix:AccessControllable
+     * or if no policy node exists.
+     *
+     * @param id
+     * @return node or <code>null</code>
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    private NodeImpl getAclNode(NodeId id) throws ItemNotFoundException, RepositoryException {
+        NodeImpl aclNode = null;
+        NodeImpl protectedNode = session.getNodeById(id);
+        if (ACLProvider.isAccessControlled(protectedNode)) {
+            aclNode = protectedNode.getNode(N_POLICY);
+        }
+        return aclNode;
+    }
+
+    /**
+     *
+     * @param id
+     * @return
+     * @throws RepositoryException
+     */
+    private NodeImpl createAclNode(NodeId id) throws RepositoryException {
+        NodeImpl protectedNode = session.getNodeById(id);
+        if (!protectedNode.isNodeType(NT_REP_ACCESS_CONTROLLABLE)) {
+            protectedNode.addMixin(NT_REP_ACCESS_CONTROLLABLE);
+        }
+        return addSecurityNode(protectedNode, N_POLICY, NT_REP_ACL);
+    }
+
+    /**
+     * Create a unique valid name for the Permission nodes to be save.
+     *
+     * @param node a name for the child is resolved
+     * @param name if missing the {@link #DEFAULT_PERMISSION_NAME} is taken
+     * @return
+     * @throws RepositoryException
+     */
+    protected static Name getUniqueNodeName(Node node, String name) throws RepositoryException {
+        if (name == null) {
+            name = DEFAULT_PERMISSION_NAME;
+        } else {
+            try {
+                NameParser.checkFormat(name);
+            } catch (NameException e) {
+                name = DEFAULT_PERMISSION_NAME;
+                log.debug("Invalid path name for Permission: " + name + ".");
+            }
+        }
+        int i=0;
+        String check = name;
+        while (node.hasNode(check)) {
+            check = name + i;
+            i++;
+        }
+        return ((SessionImpl) node.getSession()).getQName(check);
+    }
+
+    /**
+     * Build an array of Value from the specified <code>privileges</code> using
+     * the given <code>valueFactory</code>.
+     *
+     * @param privileges
+     * @param valueFactory
+     * @return an array of Value.
+     */
+    private static Value[] getPrivilegeNames(Privilege[] privileges, ValueFactory valueFactory) {
+        Value[] names = new Value[privileges.length];
+        for (int i = 0; i < privileges.length; i++) {
+            names[i] = valueFactory.createValue(privileges[i].getName());
+        }
+        return names;
+    }
+}
\ No newline at end of file

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,299 @@
+/*
+ * 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.jackrabbit.core.ItemId;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlException;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Item;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * ACL-like implementation of the <code>AccessControlPolicy</code> interface.
+ * <br>
+ * The list consists of entries, each representing a set of Privileges
+ * which are either granted or denied to one principal and may or may not
+ * contain additional restrictions (see below).<br>
+ * The entries are evaluated in the following order:
+ * <ul>
+ * <li>local entries</li>
+ * <li>inherited base entries (recursively)</li>
+ * </ul>
+ * In order to calculate the permissions the ACL combines privileges and
+ * additional restrictions and applies them to the passed jcr path. Note the
+ * following additional rules:
+ * <ul>
+ * <li>Permissions not explicitly granted are denied</li>
+ * <li>Permissions granted/denied by a local entry will not be overruled by
+ * an inherited permission.</li>
+ * </ul>
+ *
+ * @see AccessControlPolicy
+ */
+class ACLImpl implements AccessControlPolicy {
+
+    /**
+     * the default logger
+     */
+    private static Logger log = LoggerFactory.getLogger(ACLImpl.class);
+
+    static final String POLICY_NAME = ACLImpl.class.getName();
+
+    /**
+     * the entries of this ACL
+     */
+    private final List localEntries;
+
+    /**
+     * the id of the node this item is stored
+     */
+    private final NodeId id;
+
+    /**
+     * the base ACL, if existent
+     */
+    private final ACLImpl base;
+
+    /**
+     * Flag indicating, if this ACL is used to protect an item that builds this
+     * acl, e.g. a node with type rep:ACL or rep:ACE.
+     */
+    private final boolean protectsACL;
+
+    /**
+     * The compiled privileges of this ACL. -1 indicates that they have not
+     * yet been calculated.
+     */
+    private int privileges = -1;
+
+    /**
+     * Create a new ACL for the given local entries and the entries inherited
+     * from the given base.
+     *
+     * @param id the id of node this ACL has been built for.
+     * @param localEntries A list of {@link ACEImpl local entries}.
+     * @param base The base ACL.
+     * @param protectsACL <code>true</code> if the node identified by the
+     * given id, stores itself the ACL entries.
+     */
+    ACLImpl(NodeId id, List localEntries, ACLImpl base, boolean protectsACL) {
+        this.id = id;
+        this.localEntries = Collections.unmodifiableList(localEntries);
+        this.base = base;
+        this.protectsACL = protectsACL;
+    }
+
+    /**
+     * Creates a new default ACL for an node that is <i>not access controlled</i>.
+     * If the item is part of the ACL itself <code>protectsACL</code> must be
+     * <code>true</code>.
+     * <p/>
+     * Since the actual ACL is the same as the one of the base acl, the access
+     * controll node does not need to be specified.
+     *
+     * @param id the id of node this ACL has been built for.
+     * @param base the list to add the current aces to
+     * @param protectsACL <code>true</code> if the node identified by the
+     * given id, stores itself the ACL entries.
+     */
+    ACLImpl(NodeId id, ACLImpl base, boolean protectsACL) {
+        this(id, Collections.EMPTY_LIST, base, protectsACL);
+    }
+
+    /**
+     * Returns the ID of <code>Node</code> storing this <code>ACL</code>.
+     *
+     * @return the item id
+     */
+    ItemId getId() {
+        return id;
+    }
+
+    /**
+     * Returns all entries of this ACL including the inherited ones.
+     *
+     * @return Iterator over ACEs.
+     */
+    Iterator getEntries() {
+        return new ACEIteratorImpl(this);
+    }
+
+    /**
+     * Retrieve the privileges from all entries (including the
+     * inherited onces).
+     *
+     * @return Privileges or PrivilegeRegistry.NO_PRIVILEGE if there are
+     * not privileges at all.
+     * @throws AccessControlException
+     */
+    int getPrivileges() throws AccessControlException {
+        if (privileges == -1) {
+            Iterator entries = getEntries();
+            int allows = PrivilegeRegistry.NO_PRIVILEGE;
+            int denies = PrivilegeRegistry.NO_PRIVILEGE;
+            // TODO check again.
+            while (entries.hasNext() && allows != PrivilegeRegistry.ALL) {
+                ACEImpl ace = (ACEImpl) entries.next();
+                int entryBits = ace.getPrivilegeBits();
+                if (ace.isAllow()) {
+                    allows |= PrivilegeRegistry.diff(entryBits, denies);
+                } else {
+                    denies |= PrivilegeRegistry.diff(entryBits, allows);
+                }
+            }
+            privileges = allows;
+        }
+        return privileges;
+    }
+
+    /**
+     * 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 item into account.
+     *
+     * @param target
+     * @return
+     * @throws AccessControlException
+     */
+    int getPermissions(Item target) throws AccessControlException {
+        return internalGetPermissions(true);
+    }
+
+    /**
+     * 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 into account.
+     *
+     * @param targetName
+     * @return
+     * @throws AccessControlException
+     */
+    int getPermissions(String targetName) throws AccessControlException {
+        return internalGetPermissions(false);
+    }
+
+    /**
+     * Since except for READ-privileges the permissions must be determined from
+     * privileges defined for the parent we have to respect both: the base-ACL
+     * and the local entries defined on this ACL.
+     *
+     * @return
+     * @throws AccessControlException
+     */
+    private int internalGetPermissions(boolean existingItem) throws AccessControlException {
+        int privs = getPrivileges();
+        int basePrivs;
+        if (existingItem && !localEntries.isEmpty()) {
+            basePrivs = (base == null) ? PrivilegeRegistry.NO_PRIVILEGE : base.getPrivileges();
+        } else {
+            // no privileges defined on the node this ACL has been built for.
+            // therefore all privileges are inherited and 'basePrivileges'
+            // is the same as getPrivileges(), which combines both local and
+            // inherited privileges.
+            basePrivs = privs;
+        }
+        return Permission.calculatePermissions(privs, basePrivs, protectsACL);
+    }
+
+    //------------------------------------------------< AccessControlPolicy >---
+    /**
+     * @return the name of the current ACL,
+     * @see org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy#getName()
+     */
+    public String getName() throws RepositoryException {
+        return POLICY_NAME;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy#getDescription()
+     */
+    public String getDescription() throws RepositoryException {
+        // TODO
+        return null;
+    }
+
+    //--------------------------------------------------------< inner class >---
+    /**
+     * Iterator over entries present in this ACL or in this ACL and all its
+     * base ACLs. If the base ACLs are included in the iterator the order
+     * of ACE entries starts from the bottom of the inheritance chain i.e. most
+     * derived ACL is included in the iterator first. This allows proper evalution
+     * of privileges.
+     */
+    private static class ACEIteratorImpl implements Iterator {
+
+        private final List baseEntries = new ArrayList();
+        private Iterator currentEntries;
+        private Object next;
+
+        /**
+         *
+         * @param acl
+         */
+        private ACEIteratorImpl(ACLImpl acl) {
+            currentEntries = new ArrayList(acl.localEntries).iterator();
+            ACLImpl a = acl.base;
+            while (a != null) {
+                if (!a.localEntries.isEmpty()) {
+                    baseEntries.add(new ArrayList(a.localEntries).iterator());
+                }
+                a = a.base;
+            }
+            next = seekNext();
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        public Object next() {
+            if (next == null) {
+                throw new NoSuchElementException();
+            }
+            Object ret = next;
+            next = seekNext();
+            return ret;
+        }
+
+        private Object seekNext() {
+            while (currentEntries != null && !currentEntries.hasNext()) {
+                if (baseEntries.isEmpty()) {
+                    // reached last 'base' acl
+                    currentEntries = null;
+                } else {
+                    currentEntries = (Iterator) baseEntries.remove(0);
+                }
+            }
+            return (currentEntries == null) ? null : currentEntries.next();
+        }
+    }
+}

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: 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=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,625 @@
+/*
+ * 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.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+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.AccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
+import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.core.security.jsr283.security.Privilege;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.NodeIterator;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * The ACLProvider generates access control policies out of the items stored
+ * in the workspace applying the following rules:
+ * <ul>
+ * <li>A <code>Node</code> is considered <i>access controlled</i> if an ACL has
+ * been explicitely assigned to it by adding the mixin type
+ * <code>rep:AccessControllable</code> and adding child node of type
+ * <code>rep:acl</code> that forms the acl.</li>
+ * <li>a Property is considered 'access controlled' if its parent Node is.</li>
+ * <li>An ACL is never assigned to a <code>Property</code> item.</li>
+ * <li>A <code>Node</code> that is not access controlled may inherit the ACL.
+ * The ACL is inherited from the closest access controlled ancestor.</li>
+ * <li>It may be possible that a given <code>Node</code> has no effective ACL, in
+ * which case some a default policy is returned that grants READ privilege to
+ * any principal and denies all other privileges.</li>
+ * <li>an item is considered an <i>ACL item</i> if it is used to define an ACL.
+ * ACL items inherit the ACL from node they defined the ACL for.</li>
+ * </ul>
+ *
+ * @see AccessControlProvider for additional information.
+ */
+public class ACLProvider extends AbstractAccessControlProvider implements AccessControlConstants {
+
+    /**
+     * the default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(ACLProvider.class);
+
+    /**
+     * the system session that accesses the workspace
+     */
+    private SessionImpl systemSession;
+
+    private AccessControlEditor systemEditor;
+
+    private ObservationManager obsMgr;
+
+    /**
+     * The node id of the root node
+     */
+    private NodeId rootNodeId;
+
+    private String jcrRepPolicy;
+
+    //----------------------------------------------< AccessControlProvider >---
+    /**
+     * @see AccessControlProvider#init(Session, Map)
+     */
+    public void init(Session systemSession, Map options) throws RepositoryException {
+        if (initialized) {
+            throw new IllegalStateException("already initialized");
+        }
+        if (!(systemSession instanceof SessionImpl)) {
+            throw new RepositoryException("SessionImpl (system session) expected.");
+        }
+
+        // make sure the workspace of the given systemSession has a
+        // minimal protection on the root node.
+        SessionImpl sImpl = (SessionImpl) systemSession;
+        NodeImpl root = (NodeImpl) sImpl.getRootNode();
+        rootNodeId = root.getNodeId();
+        jcrRepPolicy = "/" + sImpl.getJCRName(N_POLICY);
+        systemEditor = new ACLEditor(sImpl);
+
+        if (!isAccessControlled(root)) {
+            initRootACL(sImpl, rootNodeId);
+        }
+
+        this.systemSession = sImpl;
+        obsMgr = sImpl.getWorkspace().getObservationManager();
+        initialized = true;
+    }
+
+    /**
+     * @see AccessControlProvider#getPolicy(NodeId)
+     */
+    public AccessControlPolicy getPolicy(NodeId nodeId) throws ItemNotFoundException, RepositoryException {
+        checkInitialized();
+        return getACL(nodeId);
+    }
+
+    /**
+     * @see AccessControlProvider#getAccessControlEntries(NodeId)
+     */
+    public AccessControlEntry[] getAccessControlEntries(NodeId nodeId) throws RepositoryException {
+        checkInitialized();
+        ACLImpl acl = getACL(nodeId);
+
+        // TODO: check again what the expected return value would be.
+        // TODO: check again if correct. call probably expensive.
+        Map allowed = new HashMap();
+        Map denied = new HashMap();
+        for (Iterator it = acl.getEntries(); it.hasNext();) {
+            ACEImpl ace = (ACEImpl) it.next();
+            Principal pc = ace.getPrincipal();
+
+            int pv = ace.getPrivilegeBits();
+
+            int allowPv = (allowed.containsKey(pc)) ? ((Integer) allowed.get(pc)).intValue() : 0;
+            int denyPv = (denied.containsKey(pc)) ? ((Integer) denied.get(pc)).intValue() : 0;
+
+            // shortcut:
+            if (allowPv == PrivilegeRegistry.ALL) {
+                continue;
+            }
+
+            // if the ace is a granting ACE -> make sure the permissions
+            // it grants are not denied by another ACE
+            if (ace.isAllow()) {
+                // determined those allow-priv from the current ace, that have
+                // not been denied by an ace ealier in the evaluation.
+                allowPv |= PrivilegeRegistry.diff(pv, denyPv);
+                allowed.put(pc, new Integer(allowPv));
+            } else {
+                // determined those deny-priv from the current ace, that have
+                // not been granted by an ace ealier in the evaluation.
+                denyPv |= PrivilegeRegistry.diff(pv, allowPv);
+                denied.put(pc, new Integer(denyPv));
+            }
+        }
+
+        Set s = new HashSet();
+        for (Iterator it = allowed.keySet().iterator(); it.hasNext();) {
+            Principal p = (Principal) it.next();
+            s.add(new ACEImpl(p, ((Integer) allowed.get(p)).intValue(), true));
+        }
+        return (AccessControlEntry[]) s.toArray(new AccessControlEntry[s.size()]);
+    }
+
+    /**
+     * @see AccessControlProvider#getEditor(Session)
+     */
+    public AccessControlEditor getEditor(Session session) {
+        checkInitialized();
+        try {
+            return new ACLEditor(session);
+        } catch (RepositoryException e) {
+            log.debug("Unable to create AccessControlEditor.", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * @see AccessControlProvider#compilePermissions(Set)
+     */
+    public CompiledPermissions compilePermissions(Set principals) throws ItemNotFoundException, RepositoryException {
+        checkInitialized();
+        if (isAdminOrSystem(principals)) {
+            return getAdminPermissions();
+        } else {
+            return new AclPermissions(principals);
+        }
+    }
+
+    //------------------------------------------------------------< private >---
+    /**
+     * Build the ACL that is effective on the Node identified by
+     * <code>nodeId</code>. In contrast to {@link #getACL(NodeId, Set)}
+     * the returned ACL contains all entries that apply to that node.
+     *
+     * @param nodeId
+     * @return
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    private ACLImpl getACL(NodeId nodeId) throws ItemNotFoundException, RepositoryException {
+        return getACL(nodeId, Collections.EMPTY_SET);
+    }
+
+    /**
+     * Build the ACL that is effective on the Node identified by
+     * <code>nodeId</code>, but only retrieve those entries that apply to
+     * any of the principals whose name is present in the given
+     * <code>principalNameFilter</code>.
+     *
+     * @param nodeId
+     * @param principalNameFilter
+     * @return
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    private ACLImpl getACL(NodeId nodeId, Set principalNameFilter) throws ItemNotFoundException, RepositoryException {
+        // -> build the acl for the Node identified by 'id'
+        NodeImpl node = systemSession.getNodeById(nodeId);
+        ACLImpl acl;
+        // check for special ACL building item
+        if (protectsNode(node)) {
+            NodeImpl parentNode;
+            if (node.isNodeType(ACLEditor.NT_REP_ACL)) {
+                parentNode = (NodeImpl) node.getParent();
+            } else {
+                parentNode = (NodeImpl) node.getParent().getParent();
+            }
+            ACLImpl baseACL = buildAcl(parentNode, principalNameFilter);
+            acl = new ACLImpl(nodeId, baseACL, true);
+        } else {
+            // build Acl for non-protection node.
+            acl = buildAcl(node, principalNameFilter);
+        }
+        return acl;
+    }
+
+    /**
+     * Constructs the ACLImpl for a regular node, i.e. a node that does not
+     * store itself ACL-related information. The ACL to be returned combines both
+     * the base-ACL containing the inherited access control information
+     * and the access control information provided with the given node itself.
+     *
+     * @param node the Node to build the ACL for, which must NOT be part of the
+     * structure defined by mix:AccessControllable.
+     * @param principalNameFilter
+     * @return acl or <code>DefaultACL</code> if neither the node nor any of it's
+     * parents is access controlled.
+     * @throws RepositoryException
+     */
+    private ACLImpl buildAcl(NodeImpl node, Set principalNameFilter) throws RepositoryException {
+        // preconditions:
+        // - node is not null
+        // - node is never an ACL building item
+        NodeId id = (NodeId) node.getId();
+        // retrieve the base-ACL (i.e. the ACL that belongs to parentNode)
+        // for this find nearest access controlled parent.
+        ACLImpl baseACL = null;
+        NodeImpl parentNode = id.equals(rootNodeId) ? null : (NodeImpl) node.getParent();
+        while (parentNode != null && baseACL == null) {
+            if (isAccessControlled(parentNode)) {
+                baseACL = buildAcl(parentNode, principalNameFilter);
+            } else {
+                parentNode = (rootNodeId.equals(parentNode.getId())) ? null
+                        : (NodeImpl) parentNode.getParent();
+            }
+        }
+        // the build the effective ACL from the specified Node and the base ACL
+        ACLImpl acl;
+        if (isAccessControlled(node)) {
+            // build acl from access controlled node
+            NodeImpl aclNode = node.getNode(ACLEditor.N_POLICY);
+            PolicyTemplate tmpl = new ACLTemplate(aclNode, principalNameFilter);
+            List localEntries = Arrays.asList(tmpl.getEntries());
+
+            acl = new ACLImpl(aclNode.getNodeId(), localEntries, baseACL, false);
+        } else if (baseACL != null) {
+            // build acl for a non-access controlled item that has a base acl
+            acl = new ACLImpl(id, baseACL, false);
+        } else {
+            // no access control information can be retrieved for the specified
+            // node, since neither the node nor any of its parents is access
+            // controlled -> build a default policy.
+            log.warn("No access controlled node present in item hierarchy starting from " + id);
+            acl = new DefaultACL(id);
+        }
+        return acl;
+    }
+
+    /**
+     * Set-up minimal permissions for the workspace:
+     *
+     * <ul>
+     * <li>adminstrators principal -> all privileges</li>
+     * <li>everybody -> read privilege</li>
+     * </ul>
+     *
+     * @param session to the workspace to set-up inital ACL to
+     * @throws RepositoryException
+     */
+    private void initRootACL(SessionImpl session, NodeId rootId) throws RepositoryException {
+        try {
+            log.info("Install initial ACL:...");
+            PolicyTemplate tmpl = systemEditor.editPolicyTemplate(rootId);
+            PrincipalManager pMgr = session.getPrincipalManager();
+
+            log.info("... Privilege.ALL for administrators.");
+            Principal administrators;
+            String pName = SecurityConstants.ADMINISTRATORS_NAME;
+            if (pMgr.hasPrincipal(pName)) {
+                administrators = pMgr.getPrincipal(pName);
+            } else {
+                log.warn("Administrators principal group is missing.");
+                administrators = new PrincipalImpl(pName);
+            }
+            PolicyEntry entr = new ACEImpl(administrators, PrivilegeRegistry.ALL, true);
+            tmpl.setEntry(entr);
+
+            Principal everyone = pMgr.getEveryone();
+            // TODO: to be improved. how to define where everyone has read-access
+            log.info("... Privilege.READ for everyone.");
+            entr = new ACEImpl(everyone, PrivilegeRegistry.READ, true);
+            tmpl.setEntry(entr);
+
+            systemEditor.setPolicyTemplate(rootId, tmpl);
+            session.save();
+            log.info("... done.");
+
+        } catch (RepositoryException e) {
+            log.error("Failed to set-up minimal access control for root node of workspace " + session.getWorkspace().getName());
+            session.getRootNode().refresh(false);
+            throw e;
+        }
+    }
+
+    /**
+     * Test if the given node is access controlled. The node is access
+     * controlled if it is of nodetype
+     * {@link ACLEditor#NT_REP_ACCESS_CONTROLLABLE "rep:AccessControllable"}
+     * and if it has a child node named
+     * {@link ACLEditor#N_POLICY "rep:ACL"}.
+     *
+     * @param node
+     * @return <code>true</code> if the node is access controlled;
+     *         <code>false</code> otherwise.
+     * @throws RepositoryException
+     */
+    static boolean isAccessControlled(NodeImpl node) throws RepositoryException {
+        return node.isNodeType(ACLEditor.NT_REP_ACCESS_CONTROLLABLE) && node.hasNode(ACLEditor.N_POLICY);
+    }
+
+    /**
+     * Test if the given node is itself a rep:ACL or a rep:ACE node.
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    static boolean protectsNode(NodeImpl node) throws RepositoryException {
+        return node.isNodeType(ACLEditor.NT_REP_ACL) || node.isNodeType(ACLEditor.NT_REP_ACE);
+    }
+
+    //------------------------------------------------< CompiledPermissions >---
+    /**
+     *
+     */
+    private class AclPermissions extends AbstractCompiledPermissions implements EventListener {
+
+        private final Set principalNames;
+        private boolean readAllowed;
+
+        private AclPermissions(Set principals) throws RepositoryException {
+            principalNames = new HashSet(principals.size());
+            for (Iterator it = principals.iterator(); it.hasNext();) {
+                principalNames.add(((Principal) it.next()).getName());
+            }
+
+            /*
+             Determine if there is any 'denyRead' entry (since the default
+             is that everyone can READ everywhere -> makes evaluation for
+             the most common check (can-read) easy.
+            */
+            readAllowed = readAllowedEveryWhere(principalNames);
+
+            /*
+             Make sure this AclPermission recalculates the permissions if
+             any ACL concerning it is modified. interesting events are:
+             - new ACE-entry for any of the principals (NODE_ADDED)
+             - changing ACE-entry for any of the principals (PROPERTY_CHANGED)
+               > new permissions granted/denied
+               >
+             - removed ACE-entry for any of the principals (NODE_REMOVED)
+            */
+            int events = Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED;
+            String[] ntNames = new String[] {
+                    systemSession.getJCRName(NT_REP_ACE),
+                    systemSession.getJCRName(NT_REP_ACL)
+            };
+            obsMgr.addEventListener(this, events, systemSession.getRootNode().getPath(), true, null, ntNames, true);
+        }
+
+        /**
+         * Search if there is any ACE that defines permissions for any of the
+         * principals AND denies-READ.
+         *
+         * @param principalnames
+         * @return true if read is allowed on all items.
+         */
+        private boolean readAllowedEveryWhere(Set principalnames) {
+            try {
+                QueryManager qm = systemSession.getWorkspace().getQueryManager();
+                StringBuffer stmt = new StringBuffer("/jcr:root");
+                stmt.append("//element(*,");
+                stmt.append(systemSession.getJCRName(NT_REP_DENY_ACE));
+                stmt.append(")[");
+
+                // where the rep:principalName property exactly matches any of
+                // the given principalsNames
+                int i = 0;
+                Iterator itr = principalnames.iterator();
+                while (itr.hasNext()) {
+                    stmt.append("@");
+                    String pName = systemSession.getJCRName(P_PRINCIPAL_NAME);
+                    stmt.append(ISO9075.encode(pName));
+                    stmt.append("='").append(itr.next().toString()).append("'");
+                    if (++i < principalnames.size()) {
+                        stmt.append(" or ");
+                    }
+                }
+                // AND rep:privileges contains the READ privilege
+                stmt.append(" and jcr:like(@");
+                String pName = systemSession.getJCRName(P_PRIVILEGES);
+                stmt.append(ISO9075.encode(pName));
+                stmt.append(",'%").append(Privilege.READ).append("%')");
+                stmt.append("]");
+                Query q = qm.createQuery(stmt.toString(), Query.XPATH);
+
+                NodeIterator it = q.execute().getNodes();
+                while (it.hasNext()) {
+                    String path = it.nextNode().getPath();
+                    // if there is a node that AND it is not below /accesscontrol
+                    // we cannot use the short-cut within 'grants'
+                    if (!Text.isDescendantOrEqual("/"+ N_ACCESSCONTROL, path)) {
+                        return false;
+                    }
+                }
+                // didn't find any matching ACE that denies READ for any
+                // of the principals.
+                return true;
+            } catch (RepositoryException e) {
+                log.error(e.toString());
+                // unable to determine... -> no shortcut upon grants
+                return false;
+            }
+        }
+
+        //------------------------------------< AbstractCompiledPermissions >---
+        /**
+         * @see AbstractCompiledPermissions#buildResult(Path)
+         */
+        protected Result buildResult(Path absPath) throws RepositoryException {
+            boolean existingNode = false;
+            NodeId nid;
+            String jcrPath = systemSession.getJCRPath(absPath);
+            if (systemSession.nodeExists(jcrPath)) {
+                nid = systemSession.getHierarchyManager().resolveNodePath(absPath);
+                existingNode = true;
+            } else {
+                // path points to existing prop or non-existing item (node or prop).
+                nid = systemSession.getHierarchyManager().resolveNodePath(absPath.getAncestor(1));
+            }
+            if (nid == null) {
+                throw new ItemNotFoundException("No item exists at " + absPath + " nor at its direct ancestor.");
+            }
+
+            // build the ACL for the specified principals at path or at the
+            // direct ancestor of path (that must be definition exist).
+            ACLImpl acl = getACL(nid, principalNames);
+
+            // privileges to expose
+            int privileges = (existingNode) ? acl.getPrivileges() : PrivilegeRegistry.NO_PRIVILEGE;
+
+            // calculate the permissions
+            int permissions;
+            if (existingNode || systemSession.propertyExists(jcrPath)) {
+                permissions = acl.getPermissions(systemSession.getItem(jcrPath));
+            } else {
+                String name = systemSession.getJCRName(absPath.getNameElement().getName());
+                permissions = acl.getPermissions(name);
+            }
+            return new Result(permissions, privileges);
+        }
+
+        //--------------------------------------------< CompiledPermissions >---
+        /**
+         * @see CompiledPermissions#close()
+         */
+        public void close() {
+            try {
+                obsMgr.removeEventListener(this);
+            } catch (RepositoryException e) {
+                log.error("Internal error: ", e.getMessage());
+            }
+            super.close();
+        }
+
+        /**
+         *
+         * @param absPath
+         * @param permissions
+         * @return
+         * @throws RepositoryException
+         */
+        public boolean grants(Path absPath, int permissions) throws RepositoryException {
+            // common check
+            if (permissions == Permission.READ && readAllowed &&
+                    /* easy check if path doesn't point to AC-content */
+                    systemSession.getJCRPath(absPath).indexOf(jcrRepPolicy) == -1) {
+                return true;
+            }
+            return super.grants(absPath, permissions);
+        }
+
+        //--------------------------------------------------< EventListener >---
+        /**
+         * @see EventListener#onEvent(EventIterator)
+         */
+        public void onEvent(EventIterator events) {
+            // only invalidate cache if any of the events affects the
+            // nodes defining permissions for principals compiled here.
+            boolean clearCache = false;
+            while (events.hasNext() && !clearCache) {
+                try {
+                    Event ev = events.nextEvent();
+                    String path = ev.getPath();
+                    if (Text.isDescendantOrEqual("/"+ N_ACCESSCONTROL, path)) {
+                        // access control change applies to the 'combined' acls
+                        // -> ignore
+                        continue;
+                    }
+
+                    switch (ev.getType()) {
+                        case Event.NODE_ADDED:
+                            // test if the new ACE-nodes affects the permission
+                            // of any of the 'principals'.
+                            NodeImpl n = (NodeImpl) systemSession.getNode(path);
+                            String pName = n.getProperty(P_PRINCIPAL_NAME).getString();
+                            if (principalNames.contains(pName)) {
+                                // new ACE entry for the principals -> clear cache
+                                clearCache = true;
+                                // if ace is a new DENY -> check if denies reading
+                                if (readAllowed && n.isNodeType(NT_REP_DENY_ACE)) {
+                                    Value[] vs = n.getProperty(P_PRIVILEGES).getValues();
+                                    for (int i = 0; i < vs.length; i++) {
+                                        if (Privilege.READ.equals(vs[i].getString())) {
+                                            readAllowed = false;
+                                        }
+                                    }
+                                }
+                            }
+                            break;
+                        case Event.NODE_REMOVED:
+                            // can't find out if the removed ACL/ACE node was
+                            // relevant for the principals
+                            clearCache = true;
+                            break;
+                        case Event.PROPERTY_CHANGED:
+                            // test if the changed ACE_prop affects the permission
+                            // of any of the 'principals' (most interesting are
+                            // changed privileges.
+                            PropertyImpl p = (PropertyImpl) systemSession.getProperty(path);
+                            if (P_PRIVILEGES.equals(p.getQName())) {
+                                // test if principal-name sibling-prop matches
+                                pName = ((NodeImpl) p.getParent()).getProperty(P_PRINCIPAL_NAME).toString();
+                                clearCache = principalNames.contains(pName);
+                            } else if (P_PRINCIPAL_NAME.equals(p.getQName())) {
+                                // an ace change its principal-name. that should
+                                // not happen. -> clear cache to be on the safe side.
+                                clearCache = true;
+                            }
+                            break;
+                        default:
+                            // illegal event-type: should never occur. ignore
+                    }
+                } catch (RepositoryException e) {
+                    // should not get here
+                    log.warn("Internal error: ", e.getMessage());
+                }
+            }
+            if (clearCache) {
+                clearCache();
+            }
+        }
+    }
+}

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: 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=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,336 @@
+/*
+ * 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.jackrabbit.core.security.jsr283.security.AccessControlException;
+import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
+import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.commons.collections.map.ListOrderedMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.NodeIterator;
+import javax.jcr.Value;
+import java.security.Principal;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Collections;
+
+/**
+ * {@link PolicyTemplate}-Implementation for the resource-based {@link ACLImpl}.
+ *
+ * @see PolicyTemplate
+ * @see ACLImpl
+ */
+class ACLTemplate implements PolicyTemplate {
+
+    private static final Logger log = LoggerFactory.getLogger(ACLTemplate.class);
+
+    private final String name;
+    private final String description;
+
+    /**
+     * Map containing the entries of this ACL Template using the principal
+     * name as key. The value represents a List containing maximal one grant
+     * and one deny ACE per principal.
+     */
+    private final Map entries = new HashMap();
+
+    /**
+     * Construct a new empty {@link PolicyTemplate}.
+     */
+    ACLTemplate() {
+        name = ACLImpl.POLICY_NAME;
+        description = null;
+    }
+
+    /**
+     * Create a {@link PolicyTemplate} that is used to edit an existing ACL
+     * node.
+     */
+    ACLTemplate(NodeImpl aclNode) throws RepositoryException {
+        this(aclNode, Collections.EMPTY_SET);
+    }
+
+    /**
+     * Create a {@link PolicyTemplate} that is used to edit an existing ACL
+     * policy but only lists those entries that match any of the principal
+     * names present in the given filter. If the set is empty all entry will
+     * be read as local entries. Otherwise only the entries matching any of
+     * the principals in the set will be retrieved.
+     */
+    ACLTemplate(NodeImpl aclNode, Set principalNames) throws RepositoryException {
+        if (aclNode == null || !aclNode.isNodeType(ACLEditor.NT_REP_ACL)) {
+            throw new IllegalArgumentException("Node must be of type: " + ACLEditor.NT_REP_ACL);
+        }
+        name = ACLImpl.POLICY_NAME;
+        description = null;
+        loadEntries(aclNode, principalNames);
+    }
+
+    /**
+     * Returns those {@link PolicyEntry entries} of this
+     * <code>PolicyTemplate</code> that affect the permissions of the given
+     * <code>principal</code>.
+     *
+     * @return the {@link PolicyEntry entries} present in this
+     * <code>PolicyTemplate</code> that affect the permissions of the given
+     * <code>principal</code>.
+     */
+    ACEImpl[] getEntries(Principal principal) {
+        List l = internalGetEntries(principal);
+        return (ACEImpl[]) l.toArray(new ACEImpl[l.size()]);
+    }
+
+    private void checkValidEntry(PolicyEntry entry) throws AccessControlException {
+        if (!(entry instanceof ACEImpl)) {
+            throw new AccessControlException("Invalid PolicyEntry " + entry + ". Expected instanceof ACEImpl.");
+        }
+        ACEImpl ace = (ACEImpl) entry;
+        // TODO: ev. assert that the principal is known to the repository
+        // make sure valid privileges are provided.
+        PrivilegeRegistry.getBits(ace.getPrivileges());
+    }
+
+    private List internalGetEntries(Principal principal) {
+        String principalName = principal.getName();
+        if (entries.containsKey(principalName)) {
+            return (List) entries.get(principalName);
+        } else {
+            return new ArrayList(2);
+        }
+    }
+
+    private synchronized boolean internalAdd(ACEImpl entry) {
+        Principal principal = entry.getPrincipal();
+        List l = internalGetEntries(principal);
+        if (l.isEmpty()) {
+            l.add(entry);
+            entries.put(principal.getName(), l);
+            return true;
+        } else {
+            return adjustEntries(entry, l);
+        }
+    }
+
+    private static boolean adjustEntries(ACEImpl entry, List l) {
+        if (l.contains(entry)) {
+            // the same entry is already contained -> no modification
+            return false;
+        }
+
+        ACEImpl complementEntry = null;
+        ACEImpl[] entries = (ACEImpl[]) l.toArray(new ACEImpl[l.size()]);
+        for (int i = 0; i < entries.length; i++) {
+            ACEImpl t = entries[i];
+            if (entry.isAllow() == entries[i].isAllow()) {
+                // replace the existing entry with the new one at the end.
+                l.remove(i);
+                l.add(entry);
+            } else {
+                complementEntry = t;
+            }
+        }
+
+        // make sure, that the complement entry (if existing) does not
+        // grant/deny the same privileges -> remove privs that are now
+        // denied/granted.
+        if (complementEntry != null) {
+            int complPrivs = complementEntry.getPrivilegeBits();
+            int resultPrivs = PrivilegeRegistry.diff(complPrivs, entry.getPrivilegeBits());
+            if (resultPrivs == PrivilegeRegistry.NO_PRIVILEGE) {
+                l.remove(complementEntry);
+            } else if (resultPrivs != complPrivs) {
+                l.remove(complementEntry);
+                ACEImpl tmpl = new ACEImpl(entry.getPrincipal(), resultPrivs, !entry.isAllow());
+                l.add(tmpl);
+            } /* else: complement entry is null or does not need to be modified.*/
+        }
+        return true;
+    }
+
+    private synchronized boolean internalRemove(ACEImpl entry) {
+        List l = internalGetEntries(entry.getPrincipal());
+        boolean success = l.remove(entry);
+        if (l.isEmpty()) {
+            entries.remove(entry.getPrincipal().getName());
+        }
+        return success;
+    }
+
+    /**
+     * Read the child nodes of the given node and build {@link ACEImpl}
+     * objects. If the filter set is not empty, the entries are
+     * collected separately for each principal.
+     *
+     * @param aclNode
+     * @param filter Set of principal names used to filter the entries present
+     * within this ACL.
+     */
+    private void loadEntries(NodeImpl aclNode, Set filter)
+            throws RepositoryException {
+        PrincipalManager pMgr = ((SessionImpl) aclNode.getSession()).getPrincipalManager();
+        // NOTE: don't simply add the individual matching entries, instead
+        // collect entries separated for the principals first and later add
+        // them in the order the need to be evaluated (order of principals).
+        // therefore use ListOrderedMap in order to preserve the order of the
+        // principalNames passed with the 'filter'.
+        String noFilter = "";
+        Map princToEntries = new ListOrderedMap();
+        if (filter == null || filter.isEmpty()) {
+            princToEntries.put(noFilter, new ArrayList());
+        } else {
+            for (Iterator it = filter.iterator(); it.hasNext();) {
+                princToEntries.put(it.next().toString(), new ArrayList());
+            }
+        }
+
+        NodeIterator itr = aclNode.getNodes();
+        while (itr.hasNext()) {
+            NodeImpl aceNode = (NodeImpl) itr.nextNode();
+            String principalName = aceNode.getProperty(ACLEditor.P_PRINCIPAL_NAME).getString();
+            // only process aceNode if no filter is present of if the filter
+            // contains the principal-name defined with the ace-Node
+            String key = (filter == null || filter.isEmpty()) ? noFilter : principalName;
+            if (princToEntries.containsKey(key)) {
+                Principal princ = pMgr.getPrincipal(principalName);
+                Value[] privValues = aceNode.getProperty(ACLEditor.P_PRIVILEGES).getValues();
+                String[] privNames = new String[privValues.length];
+                for (int i = 0; i < privValues.length; i++) {
+                    privNames[i] = privValues[i].getString();
+                }
+                // create a new ACEImpl
+                ACEImpl ace = new ACEImpl(
+                        princ,
+                        PrivilegeRegistry.getBits(privNames),
+                        aceNode.isNodeType(ACLEditor.NT_REP_GRANT_ACE));
+                // add it to the proper list (e.g. separated by principals)
+                ((List) princToEntries.get(key)).add(ace);
+            }
+        }
+
+        // now retrieve the entries for each principal names and add them
+        // to the single (complete) list of all entries that need to
+        // be evaluated.
+        for (Iterator it = princToEntries.keySet().iterator(); it.hasNext();) {
+            String princName = it.next().toString();
+            for (Iterator entries = ((List) princToEntries.get(princName)).iterator();
+                 entries.hasNext();) {
+                ACEImpl ace = (ACEImpl) entries.next();
+                internalAdd(ace);
+            }
+        }
+    }
+
+    //------------------------------------------------< AccessControlPolicy >---
+    /**
+     * @see org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy#getName()
+     */
+    public String getName() throws RepositoryException {
+        return name;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy#getDescription()
+     */
+    public String getDescription() throws RepositoryException {
+        return description;
+    }
+
+    //-----------------------------------------------------< PolicyTemplate >---
+    /**
+     * @see PolicyTemplate#isEmpty()
+     */
+    public boolean isEmpty() {
+        return entries.isEmpty();
+    }
+
+    /**
+     * @see PolicyTemplate#size()
+     */
+    public int size() {
+        return entries.size();
+    }
+
+    /**
+     * @see PolicyTemplate#getEntries()
+     */
+    public PolicyEntry[] getEntries() {
+        List l = new ArrayList();
+        for (Iterator it = entries.values().iterator(); it.hasNext();) {
+            l.addAll((List) it.next());
+        }
+        return (PolicyEntry[]) l.toArray(new PolicyEntry[l.size()]);
+    }
+
+    /**
+     * @see PolicyTemplate#setEntry(PolicyEntry)
+     */
+    public boolean setEntry(PolicyEntry entry) throws AccessControlException, RepositoryException {
+        checkValidEntry(entry);
+        return internalAdd((ACEImpl) entry);
+    }
+
+    /**
+     * @see PolicyTemplate#removeEntry(PolicyEntry)
+     */
+    public boolean removeEntry(PolicyEntry entry) throws AccessControlException, RepositoryException {
+        checkValidEntry(entry);
+        return internalRemove((ACEImpl) entry);
+    }
+
+    //-------------------------------------------------------------< Object >---
+    /**
+     * Returns zero to satisfy the Object equals/hashCode contract.
+     * This class is mutable and not meant to be used as a hash key.
+     *
+     * @return always zero
+     * @see Object#hashCode()
+     */
+    public int hashCode() {
+        return 0;
+    }
+
+    /**
+     * Returns true if the name and the entries are equal; false otherwise.
+     *
+     * @param obj
+     * @return true if the name and the entries are equal; false otherwise.
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof ACLTemplate) {
+            ACLTemplate tmpl = (ACLTemplate) obj;
+            boolean equalName = (name == null || tmpl.name == null || name.equals(tmpl.name));
+            return equalName && entries.equals(tmpl.entries);
+        }
+        return false;
+    }
+}

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/DefaultACL.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/DefaultACL.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/DefaultACL.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/DefaultACL.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,56 @@
+/*
+ * 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.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+
+import javax.jcr.RepositoryException;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * <code>DefaultACL</code>
+ */
+final class DefaultACL extends ACLImpl {
+
+    DefaultACL(NodeId id) {
+        super(id, null, false);
+    }
+
+    Iterator getEntries() {
+        return Collections.EMPTY_SET.iterator();
+    }
+
+    int getPrivileges() {
+        return PrivilegeRegistry.NO_PRIVILEGE;
+    }
+
+    int getPermissions() {
+        return Permission.NONE;
+    }
+
+    //------------------------------------------------< AccessControlPolicy >---
+    public String getName() throws RepositoryException {
+        return "Default ACL";
+    }
+
+    public String getDescription() throws RepositoryException {
+        return "Default policy not defining any entries and no privileges.";
+    }
+}
\ No newline at end of file

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/DefaultACL.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url



Mime
View raw message