jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r1072154 [2/3] - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorizat...
Date Fri, 18 Feb 2011 21:24:12 GMT
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java Fri Feb 18 21:24:10 2011
@@ -16,199 +16,232 @@
  */
 package org.apache.jackrabbit.core.security.authorization;
 
-import java.util.ArrayList;
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.core.NamespaceRegistryImpl;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.FileSystemException;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
+import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.Privilege;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-import javax.jcr.NamespaceException;
-import javax.jcr.RepositoryException;
-import javax.jcr.security.AccessControlException;
-import javax.jcr.security.Privilege;
-
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.NameFactory;
-import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
-import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
-
 /**
  * The <code>PrivilegeRegistry</code> defines the set of <code>Privilege</code>s
  * known to the repository.
  */
 public final class PrivilegeRegistry {
 
+    private static final Logger log = LoggerFactory.getLogger(PrivilegeRegistry.class);
+
+    private static final NameFactory NAME_FACTORY = NameFactoryImpl.getInstance();
+
     /**
      * Jackrabbit specific write privilege that combines {@link Privilege#JCR_WRITE}
      * and {@link Privilege#JCR_NODE_TYPE_MANAGEMENT}.
      */
     public static final String REP_WRITE = "{" + Name.NS_REP_URI + "}write";
+    public static final Name REP_WRITE_NAME = NAME_FACTORY.create(REP_WRITE);
 
-    private static final Set<InternalPrivilege> REGISTERED_PRIVILEGES = new HashSet<InternalPrivilege>(20);
-    private static final Map<Integer, InternalPrivilege[]> BITS_TO_PRIVILEGES = new HashMap<Integer, InternalPrivilege[]>();
-    private static final NameFactory NAME_FACTORY = NameFactoryImpl.getInstance();
-
-    private static final Privilege[] EMPTY_ARRAY = new Privilege[0];
-
+    /**
+     * No privileges 
+     */
     public static final int NO_PRIVILEGE = 0;
 
     private static final int READ = 1;
-    private static final int MODIFY_PROPERTIES = 2;
-    private static final int ADD_CHILD_NODES = 4;
-    private static final int REMOVE_CHILD_NODES = 8;
-    private static final int REMOVE_NODE = 16;
-    
-    private static final int READ_AC = 32;
-    private static final int MODIFY_AC = 64;
+    private static final int MODIFY_PROPERTIES = READ << 1;
+    private static final int ADD_CHILD_NODES = MODIFY_PROPERTIES << 1;
+    private static final int REMOVE_CHILD_NODES = ADD_CHILD_NODES << 1;
+    private static final int REMOVE_NODE = REMOVE_CHILD_NODES << 1;
+    private static final int READ_AC = REMOVE_NODE << 1;
+    private static final int MODIFY_AC = READ_AC << 1;
+    private static final int NODE_TYPE_MNGMT = MODIFY_AC << 1;
+    private static final int VERSION_MNGMT = NODE_TYPE_MNGMT << 1;
+    private static final int LOCK_MNGMT = VERSION_MNGMT << 1;
+    private static final int LIFECYCLE_MNGMT = LOCK_MNGMT << 1;
+    private static final int RETENTION_MNGMT = LIFECYCLE_MNGMT << 1;
+
+    private static final Map<Name, Integer> PRIVILEGE_NAMES = new HashMap<Name, Integer>();
+    static {
+        PRIVILEGE_NAMES.put(NameConstants.JCR_READ, READ);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_MODIFY_PROPERTIES, MODIFY_PROPERTIES);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_ADD_CHILD_NODES, ADD_CHILD_NODES);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_REMOVE_CHILD_NODES, REMOVE_CHILD_NODES);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_REMOVE_NODE, REMOVE_NODE);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_READ_ACCESS_CONTROL, READ_AC);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_MODIFY_ACCESS_CONTROL, MODIFY_AC);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_NODE_TYPE_MANAGEMENT, NODE_TYPE_MNGMT);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_VERSION_MANAGEMENT, VERSION_MNGMT);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_LOCK_MANAGEMENT, LOCK_MNGMT);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_LIFECYCLE_MANAGEMENT, LIFECYCLE_MNGMT);
+        PRIVILEGE_NAMES.put(NameConstants.JCR_RETENTION_MANAGEMENT, RETENTION_MNGMT);
+    }
 
-    private static final int NODE_TYPE_MNGMT = 128;
-    private static final int VERSION_MNGMT = 256;
-    private static final int LOCK_MNGMT = 512;
-    private static final int LIFECYCLE_MNGMT = 1024;
-    private static final int RETENTION_MNGMT = 2048;
-
-    private static final int WRITE = 30;
-    private static final int JACKRABBIT_WRITE = 158;
-    private static final int ALL = 4095;
-
-    private static final InternalPrivilege READ_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_READ, READ));
-    private static final InternalPrivilege MODIFY_PROPERTIES_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_MODIFY_PROPERTIES, MODIFY_PROPERTIES));
-    private static final InternalPrivilege ADD_CHILD_NODES_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_ADD_CHILD_NODES, ADD_CHILD_NODES));
-    private static final InternalPrivilege REMOVE_CHILD_NODES_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_REMOVE_CHILD_NODES, REMOVE_CHILD_NODES));
-    private static final InternalPrivilege REMOVE_NODE_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_REMOVE_NODE, REMOVE_NODE));
-
-    private static final InternalPrivilege READ_AC_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_READ_ACCESS_CONTROL, READ_AC));
-    private static final InternalPrivilege MODIFY_AC_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_MODIFY_ACCESS_CONTROL, MODIFY_AC));
-
-    private static final InternalPrivilege NODE_TYPE_MANAGEMENT_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_NODE_TYPE_MANAGEMENT, NODE_TYPE_MNGMT));
-    private static final InternalPrivilege VERSION_MANAGEMENT_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_VERSION_MANAGEMENT, VERSION_MNGMT));
-    private static final InternalPrivilege LOCK_MANAGEMENT_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_LOCK_MANAGEMENT, LOCK_MNGMT));
-    private static final InternalPrivilege LIFECYCLE_MANAGEMENT_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_LIFECYCLE_MANAGEMENT, LIFECYCLE_MNGMT));
-    private static final InternalPrivilege RETENTION_MANAGEMENT_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_RETENTION_MANAGEMENT, RETENTION_MNGMT));
-
-    private static final InternalPrivilege WRITE_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_WRITE, new InternalPrivilege[] {
-            MODIFY_PROPERTIES_PRIVILEGE,
-            ADD_CHILD_NODES_PRIVILEGE,
-            REMOVE_CHILD_NODES_PRIVILEGE,
-            REMOVE_NODE_PRIVILEGE,
-    }));
-
-    private static final InternalPrivilege JACKRABBIT_WRITE_PRIVILEGE = registerPrivilege(new InternalPrivilege(REP_WRITE, new InternalPrivilege[] {
-            WRITE_PRIVILEGE,
-            NODE_TYPE_MANAGEMENT_PRIVILEGE
-    }));
-
-    private static final InternalPrivilege ALL_PRIVILEGE = registerPrivilege(new InternalPrivilege(Privilege.JCR_ALL, new InternalPrivilege[] {
-            READ_PRIVILEGE,
-            WRITE_PRIVILEGE,
-            JACKRABBIT_WRITE_PRIVILEGE,
-            READ_AC_PRIVILEGE,
-            MODIFY_AC_PRIVILEGE,
-            VERSION_MANAGEMENT_PRIVILEGE,
-            LOCK_MANAGEMENT_PRIVILEGE,
-            LIFECYCLE_MANAGEMENT_PRIVILEGE,
-            RETENTION_MANAGEMENT_PRIVILEGE
-    }));
-
-    /**
-     * The name resolver used to determine the correct privilege
-     * {@link Privilege#getName() name} depending on the sessions namespace
-     * mappings.
+    /**
+     * Path to the file system resource used to persist custom privileges
+     * registered with this repository.
      */
-    private final NameResolver resolver;
+    private static final String CUSTOM_PRIVILEGES_RESOURCE_NAME = "/privileges/custom_privileges.xml";
+
+    
+    private final Map<Name, PrivilegeDefinition> registeredPrivileges = new HashMap<Name, PrivilegeDefinition>();
+    private final Map<Integer, Set<Name>> bitsToNames = new HashMap<Integer, Set<Name>>();
+
+    @SuppressWarnings("unchecked")    
+    private final Map<Listener, Listener> listeners = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK));
+
+    private final NamespaceRegistry namespaceRegistry;
+    private final CustomPrivilegeStore customPrivilegesStore;
 
     /**
-     * Per instance map containing the instance specific representation of
-     * the registered privileges.
+     * @deprecated For backwards compatibility only.
      */
-    private final Map<Name, Privilege> localCache;
+    private final NameResolver resolver;
+
+    private int nextBits = RETENTION_MNGMT << 1;
+
+    public PrivilegeRegistry(NamespaceRegistry namespaceRegistry, FileSystem fs)
+            throws RepositoryException {
+
+        this.namespaceRegistry = namespaceRegistry;
+        this.customPrivilegesStore = new CustomPrivilegeStore(new FileSystemResource(fs, CUSTOM_PRIVILEGES_RESOURCE_NAME));
+        registerDefinitions(createBuiltInPrivilegeDefinitions());
+
+        try {
+            Map<Name, DefinitionStub> customDefs = customPrivilegesStore.load();
+            Map<Name, PrivilegeDefinition> definitions = createPrivilegeDefinitions(customDefs);
+            registerDefinitions(definitions);
+        } catch (IOException e) {
+            throw new RepositoryException("Failed to load custom privileges", e);
+        } catch (FileSystemException e) {
+            throw new RepositoryException("Failed to load custom privileges", e);
+        }
+
+        this.resolver = new DefaultNamePathResolver(namespaceRegistry);
+    }
 
     /**
-     * Create a new <code>PrivilegeRegistry</code> instance.
+     * Create a new <code>PrivilegeRegistry</code> instance defining only
+     * built-in privileges.
      *
-     * @param resolver NameResolver used to calculate the JCR name of the
-     * privileges.
+     * @param resolver
+     * @deprecated Use {@link PrivilegeManager} instead.
      */
     public PrivilegeRegistry(NameResolver resolver) {
+        registerDefinitions(createBuiltInPrivilegeDefinitions());
+
+        namespaceRegistry = null;
+        customPrivilegesStore = null;
+
         this.resolver = resolver;
-        localCache = new HashMap<Name, Privilege>(REGISTERED_PRIVILEGES.size());
-        for (InternalPrivilege ip : REGISTERED_PRIVILEGES) {
-            Privilege priv = new PrivilegeImpl(ip, resolver);
-            localCache.put(ip.name, priv);
-        }
     }
 
     /**
-     * Returns all registered privileges.
+     * Throws <code>UnsupportedOperationException</code>.
      *
      * @return all registered privileges.
+     * @deprecated Use {@link org.apache.jackrabbit.core.security.authorization.PrivilegeManager#getRegisteredPrivileges()} instead.
      */
     public Privilege[] getRegisteredPrivileges() {
-        return localCache.values().toArray(new Privilege[localCache.size()]);
+        try {
+            return new PrivilegeManager(this, resolver).getRegisteredPrivileges();
+        } catch (RepositoryException e) {
+            throw new UnsupportedOperationException("No supported any more. Use PrivilegeManager#getRegisteredPrivileges() instead.");
+        }
     }
 
     /**
-     * Returns the privilege with the specified <code>privilegeName</code>.
+     * Creates a new <code>PrivilegeManager</code> from the specified resolver
+     * and calls {@link org.apache.jackrabbit.core.security.authorization.PrivilegeManager#getRegisteredPrivileges()}.
      *
-     * @param privilegeName Name of the principal.
+     * @param privilegeName Name of the privilege.
      * @return the privilege with the specified <code>privilegeName</code>.
      * @throws AccessControlException If no privilege with the given name exists.
      * @throws RepositoryException If another error occurs.
+     * @deprecated Use {@link PrivilegeManager#getPrivilege(String)} instead.
      */
     public Privilege getPrivilege(String privilegeName) throws AccessControlException, RepositoryException {
-        Name name = resolver.getQName(privilegeName);
-        if (localCache.containsKey(name)) {
-            return localCache.get(name);
-        } else {
-            throw new AccessControlException("Unknown privilege " + privilegeName);
-        }
+        return new PrivilegeManager(this, resolver).getPrivilege(privilegeName);
     }
 
     /**
-     * Returns an array of registered <code>Privilege</code>s. If the specified
-     * <code>bits</code> represent a registered privilege the returned array
-     * contains a single element. Otherwise the returned array contains the
-     * individual registered privileges that are combined in the given
-     * <code>bits</code>. If <code>bits</code> is {@link #NO_PRIVILEGE 0} or
-     * does not match to any registered privilege an empty array will be returned.
+     * Creates a new <code>PrivilegeManager</code> from the specified resolver
+     * and calls {@link org.apache.jackrabbit.core.security.authorization.PrivilegeManager#getPrivileges(int)}.
      *
      * @param bits Privilege bits as obtained from {@link #getBits(Privilege[])}.
      * @return Array of <code>Privilege</code>s that are presented by the given it
      * or an empty array if <code>bits</code> is lower than {@link #READ} or
      * cannot be resolved to registered <code>Privilege</code>s.
      * @see #getBits(Privilege[])
+     * @deprecated Use {@link PrivilegeManager#getPrivileges(int)} instead.
      */
     public Privilege[] getPrivileges(int bits) {
-        Privilege[] privs;
-        if (bits > NO_PRIVILEGE) {
-            InternalPrivilege[] internalPrivs = getInteralPrivileges(bits);
-            privs = new Privilege[internalPrivs.length];
-            for (int i = 0; i < internalPrivs.length; i++) {
-                privs[i] = localCache.get(internalPrivs[i].name);
-            }
-        } else {
-            privs = new Privilege[0];
-        }
-        return privs;
+        return new PrivilegeManager(this, resolver).getPrivileges(bits);
     }
 
     /**
+     * Best effort approach to calculate bits for built-in privileges. Throws
+     * <code>UnsupportedOperationException</code> if the workaround fails.
+     * Note, that the bits calculated for jcr:all does not include any
+     * registered custom privileges.
+     *
      * @param privileges An array of privileges.
      * @return The privilege bits.
      * @throws AccessControlException If the specified array is null
      * or if it contains an unregistered privilege.
      * @see #getPrivileges(int)
+     * @deprecated Use {@link PrivilegeManager#getBits(javax.jcr.security.Privilege[])} instead.
      */
     public static int getBits(Privilege[] privileges) throws AccessControlException {
         if (privileges == null || privileges.length == 0) {
             throw new AccessControlException("Privilege array is empty or null.");
         }
-        int bits = NO_PRIVILEGE;
+
+        Map<String, String> lookup = new HashMap<String,String>(2);
+        lookup.put(Name.NS_REP_PREFIX, Name.NS_REP_URI);
+        lookup.put(Name.NS_JCR_PREFIX, Name.NS_JCR_URI);
+
+        int bits = PrivilegeRegistry.NO_PRIVILEGE;
         for (Privilege priv : privileges) {
-            if (priv instanceof PrivilegeImpl) {
-                bits |= ((PrivilegeImpl) priv).internalPrivilege.getBits();
+            String prefix = Text.getNamespacePrefix(priv.getName());
+            if (lookup.containsKey(prefix)) {
+                Name n = NAME_FACTORY.create(lookup.get(prefix), Text.getLocalName(priv.getName()));
+                if (PRIVILEGE_NAMES.containsKey(n)) {
+                    bits |= PRIVILEGE_NAMES.get(n);
+                } else if (NameConstants.JCR_WRITE.equals(n)) {
+                    bits |= createJcrWriteDefinition().bits;
+                } else if (REP_WRITE_NAME.equals(n)) {
+                    PrivilegeDefinition jcrWrite = createJcrWriteDefinition();
+                    bits |= createRepWriteDefinition(jcrWrite.bits).bits;
+                } else if (NameConstants.JCR_ALL.equals(n)) {
+                    for (Name pn : PRIVILEGE_NAMES.keySet()) {
+                        bits |= PRIVILEGE_NAMES.get(pn);
+                    }
+                } else {
+                    throw new AccessControlException("Unknown privilege '" + priv.getName() + "'.");
+                }
             } else {
                 throw new AccessControlException("Unknown privilege '" + priv.getName() + "'.");
             }
@@ -309,144 +342,442 @@ public final class PrivilegeRegistry {
         }
         return perm;
     }
+
+    //-----------------------------------< methods used by PrivilegeManager >---
+    /**
+     * Validates and registers a new custom privilege definition with the
+     * specified characteristics. Upon successful registration the new custom
+     * definition is persisted in the corresponding file system resource.<p/>
+     *
+     * <p>The validation includes the following steps:</p>
+     *
+     * <ul>
+     * <li>assert uniqueness of the specified privilegeName</li>
+     * <li>make sure the name doesn't use a reserved namespace</li>
+     * <li>assert that all names referenced in the specified name set refer
+     * to existing privilege definitions.</li>
+     * </ul>
+     *
+     * @param privilegeName
+     * @param isAbstract
+     * @param declaredAggregateNames
+     * @throws RepositoryException If the privilege could not be registered due
+     * to constraint violations or if persisting the custom privilege fails.
+     */
+    void registerDefinition(Name privilegeName, boolean isAbstract, Set<Name> declaredAggregateNames) throws RepositoryException {
+        if (customPrivilegesStore == null) {
+            throw new UnsupportedOperationException("No privilege store defined.");
+        }
+        synchronized (registeredPrivileges) {
+            Map<Name, DefinitionStub> stubs = Collections.singletonMap(privilegeName, new DefinitionStub(privilegeName, isAbstract, declaredAggregateNames, true));
+            Map<Name, PrivilegeDefinition> definitions = createPrivilegeDefinitions(stubs);
+            try {
+                // write the new custom privilege to the store and upon successful
+                // update of the file system resource add finally it to the map of
+                // registered privileges.
+                customPrivilegesStore.append(definitions);
+                registerDefinitions(definitions);
+
+            } catch (IOException e) {
+                throw new RepositoryException("Failed to register custom privilege " + privilegeName.toString(), e);
+            } catch (FileSystemException e) {
+                throw new RepositoryException("Failed to register custom privilege " + privilegeName.toString(), e);
+            }
+        }
+
+        for (Listener l : listeners.keySet()) {
+            l.privilegeRegistered(privilegeName);
+        }
+    }
     
     /**
+     * Returns all registered internal privileges.
+     *
+     * @return all registered internal privileges
+     */
+    PrivilegeDefinition[] getAll() {
+        return registeredPrivileges.values().toArray(new PrivilegeDefinition[registeredPrivileges.size()]);
+    }
+
+    /**
+     * Returns the internal privilege with the specified name or <code>null</code>.
+     *
+     * @param name Name of the internal privilege.
+     * @return the internal privilege with the specified name or <code>null</code>
+     */
+    PrivilegeDefinition get(Name name) {
+        return registeredPrivileges.get(name);
+    }
+
+    /**
      * @param bits The privilege bits.
-     * @return InternalPrivilege that corresponds to the given bits.
+     * @return Privilege names that corresponds to the given bits.
      */
-    private static InternalPrivilege[] getInteralPrivileges(int bits) {
-        if (BITS_TO_PRIVILEGES.containsKey(bits)) {
-            return BITS_TO_PRIVILEGES.get(bits);
+    Name[] getNames(int bits) {
+        if (bitsToNames.containsKey(bits)) {
+            Set<Name> ips = bitsToNames.get(bits);
+            return ips.toArray(new Name[ips.size()]);
         } else {
-            List<InternalPrivilege> privileges = new ArrayList<InternalPrivilege>();
+            Set<Name> names = new HashSet<Name>();
             if ((bits & READ) == READ) {
-                privileges.add(READ_PRIVILEGE);
+                names.add(NameConstants.JCR_READ);
             }
-            if ((bits & JACKRABBIT_WRITE) == JACKRABBIT_WRITE) {
-                privileges.add(JACKRABBIT_WRITE_PRIVILEGE);
-            } else if ((bits & WRITE) == WRITE) {
-                privileges.add(WRITE_PRIVILEGE);
+            int repWrite = registeredPrivileges.get(REP_WRITE_NAME).bits;
+            int jcrWrite = registeredPrivileges.get(NameConstants.JCR_WRITE).bits;
+            if ((bits & repWrite) == repWrite) {
+                names.add(REP_WRITE_NAME);
+            } else if ((bits & jcrWrite) == jcrWrite) {
+                names.add(NameConstants.JCR_WRITE);
             } else {
                 if ((bits & MODIFY_PROPERTIES) == MODIFY_PROPERTIES) {
-                    privileges.add(MODIFY_PROPERTIES_PRIVILEGE);
+                    names.add(NameConstants.JCR_MODIFY_PROPERTIES);
                 }
                 if ((bits & ADD_CHILD_NODES) == ADD_CHILD_NODES) {
-                    privileges.add(ADD_CHILD_NODES_PRIVILEGE);
+                    names.add(NameConstants.JCR_ADD_CHILD_NODES);
                 }
                 if ((bits & REMOVE_CHILD_NODES) == REMOVE_CHILD_NODES) {
-                    privileges.add(REMOVE_CHILD_NODES_PRIVILEGE);
+                    names.add(NameConstants.JCR_REMOVE_CHILD_NODES);
                 }
                 if ((bits & REMOVE_NODE) == REMOVE_NODE) {
-                    privileges.add(REMOVE_NODE_PRIVILEGE);
+                    names.add(NameConstants.JCR_REMOVE_NODE);
                 }
                 if ((bits & NODE_TYPE_MNGMT) == NODE_TYPE_MNGMT) {
-                    privileges.add(NODE_TYPE_MANAGEMENT_PRIVILEGE);
+                    names.add(NameConstants.JCR_NODE_TYPE_MANAGEMENT);
                 }
             }
             if ((bits & READ_AC) == READ_AC) {
-                privileges.add(READ_AC_PRIVILEGE);
+                names.add(NameConstants.JCR_READ_ACCESS_CONTROL);
             }
             if ((bits & MODIFY_AC) == MODIFY_AC) {
-                privileges.add(MODIFY_AC_PRIVILEGE);
+                names.add(NameConstants.JCR_MODIFY_ACCESS_CONTROL);
             }
             if ((bits & VERSION_MNGMT) == VERSION_MNGMT) {
-                privileges.add(VERSION_MANAGEMENT_PRIVILEGE);
+                names.add(NameConstants.JCR_VERSION_MANAGEMENT);
             }
             if ((bits & LOCK_MNGMT) == LOCK_MNGMT) {
-                privileges.add(LOCK_MANAGEMENT_PRIVILEGE);
+                names.add(NameConstants.JCR_LOCK_MANAGEMENT);
             }
             if ((bits & LIFECYCLE_MNGMT) == LIFECYCLE_MNGMT) {
-                privileges.add(LIFECYCLE_MANAGEMENT_PRIVILEGE);
+                names.add(NameConstants.JCR_LIFECYCLE_MANAGEMENT);
             }
             if ((bits & RETENTION_MNGMT) == RETENTION_MNGMT) {
-                privileges.add(RETENTION_MANAGEMENT_PRIVILEGE);
+                names.add(NameConstants.JCR_RETENTION_MANAGEMENT);
             }
 
-            InternalPrivilege[] privs;
-            if (!privileges.isEmpty()) {
-                privs = privileges.toArray(new InternalPrivilege[privileges.size()]);
-                BITS_TO_PRIVILEGES.put(bits, privs);
-            } else {
-                privs = new InternalPrivilege[0];
+            // include matching custom privilege names 
+            for (PrivilegeDefinition def : registeredPrivileges.values()) {
+                if (def.isCustom && ((bits & def.bits) == def.bits)) {
+                    names.add(def.name);
+                }
             }
-            return privs;
+
+            if (!names.isEmpty()) {
+                bitsToNames.put(bits, names);
+            }
+            return names.toArray(new Name[names.size()]);
         }
     }
 
-    private static InternalPrivilege registerPrivilege(InternalPrivilege privilege) {
-        REGISTERED_PRIVILEGES.add(privilege);
-        BITS_TO_PRIVILEGES.put(privilege.getBits(), new InternalPrivilege[] {privilege});
-        return privilege;
+    void addListener(Listener listener) {
+        listeners.put(listener,listener);
     }
 
-    //--------------------------------------------------------------------------
+    //---------------------------------------------< privilege registration >---
     /**
-     * Internal representation of the registered privileges (without JCR
-     * name).
+     * Adds the specified privilege definitions to the internal map(s) and
+     * recalculates the jcr:all privilege definition.
+     * 
+     * @param definitions
      */
-    private static class InternalPrivilege {
+    private void registerDefinitions(Map<Name, PrivilegeDefinition> definitions) {
+        registeredPrivileges.putAll(definitions);
+        for (PrivilegeDefinition def : definitions.values()) {
+            bitsToNames.put(def.bits, Collections.singleton(def.name));
+        }
 
-        private final Name name;
-        private final boolean isAbstract;
-        private final boolean isAggregate;
-        private final InternalPrivilege[] declaredAggregates;
-        private final Set<InternalPrivilege> aggregates;
+        if (!definitions.containsKey(NameConstants.JCR_ALL)) {
+            // redefine the jcr:all privilege definition
+            PrivilegeDefinition all = registeredPrivileges.get(NameConstants.JCR_ALL);
 
-        private final int bits;
+            Set<Name> allAggrNames = all.declaredAggregateNames;
+            allAggrNames.addAll(definitions.keySet());
 
-        /**
-         * Create a simple (non-aggregate) internal privilege.
-         * @param name The JCR name of the privilege in the extended form.
-         * @param bits The privilege bits.
-         */
-        private InternalPrivilege(String name, int bits) {
-            if (name == null) {
-                throw new IllegalArgumentException("A privilege must have a name.");
+            int allBits = all.bits;
+            for (PrivilegeDefinition def : definitions.values()) {
+                allBits |= def.bits;
             }
-            this.name = NAME_FACTORY.create(name);
-            this.bits = bits;
 
-            isAbstract = false;
-            declaredAggregates = null;
-            aggregates = null;
-            isAggregate = false;
+            all = new PrivilegeDefinition(NameConstants.JCR_ALL, false, allAggrNames, allBits);
+            registeredPrivileges.put(NameConstants.JCR_ALL, all);
+            bitsToNames.put(all.bits, Collections.singleton(NameConstants.JCR_ALL));
         }
+    }
+   
+    /**
+     * Creates <code>PrivilegeDefinition</code>s for all built-in privileges.
+     * 
+     * @return definitions for all built-in privileges.
+     */
+    private Map<Name,PrivilegeDefinition> createBuiltInPrivilegeDefinitions() {
+        Map<Name, PrivilegeDefinition> defs = new HashMap<Name, PrivilegeDefinition>();
+
+        // all non-aggregate privileges
+        int jcrAllBits = NO_PRIVILEGE;
+        for (Name privilegeName : PRIVILEGE_NAMES.keySet()) {
+            int bits = PRIVILEGE_NAMES.get(privilegeName);
+            PrivilegeDefinition def = new PrivilegeDefinition(privilegeName, false, bits);
+            defs.put(privilegeName, def);
+            jcrAllBits |= bits;
+        }
+
+        // jcr:write
+        PrivilegeDefinition jcrWrite = createJcrWriteDefinition();
+        defs.put(jcrWrite.name, jcrWrite);
+
+        // rep:write
+        PrivilegeDefinition repWrite = createRepWriteDefinition(jcrWrite.bits);
+        defs.put(repWrite.name, repWrite);
+
+        // jcr:all
+        Set<Name> jcrAllAggregates = new HashSet<Name>(10);
+        jcrAllAggregates.add(NameConstants.JCR_READ);
+        jcrAllAggregates.add(NameConstants.JCR_READ_ACCESS_CONTROL);
+        jcrAllAggregates.add(NameConstants.JCR_MODIFY_ACCESS_CONTROL);
+        jcrAllAggregates.add(NameConstants.JCR_LOCK_MANAGEMENT);
+        jcrAllAggregates.add(NameConstants.JCR_VERSION_MANAGEMENT);
+        jcrAllAggregates.add(NameConstants.JCR_NODE_TYPE_MANAGEMENT);
+        jcrAllAggregates.add(NameConstants.JCR_RETENTION_MANAGEMENT);
+        jcrAllAggregates.add(NameConstants.JCR_LIFECYCLE_MANAGEMENT);
+        jcrAllAggregates.add(NameConstants.JCR_WRITE);
+        jcrAllAggregates.add(REP_WRITE_NAME);
 
-        /**
-         * Create an aggregate internal privilege
-         * @param name The JCR name of the privilege in its extended form.
-         * @param declaredAggregates The declared aggregated privileges.
-         */
-        private InternalPrivilege(String name, InternalPrivilege[] declaredAggregates) {
+        PrivilegeDefinition jcrAll = new PrivilegeDefinition(NameConstants.JCR_ALL, false, jcrAllAggregates, jcrAllBits);
+        defs.put(jcrAll.name, jcrAll);
+
+        return defs;
+    }
+
+    /**
+     * Validates the specified <code>DefinitionStub</code>s and creates
+     * new <code>PrivilegeDefinition</code>s. The validation includes name
+     * validation and resolution of declared aggregate names. The latter
+     * also includes checks to prevent cyclic aggregation.
+     *  
+     * @param toRegister
+     * @return new privilege definitions.
+     * @throws RepositoryException If any of the specified stubs is invalid.
+     */
+    private Map<Name, PrivilegeDefinition> createPrivilegeDefinitions(Map<Name, DefinitionStub> toRegister) throws RepositoryException {
+        Map<Name, PrivilegeDefinition> definitions = new HashMap<Name, PrivilegeDefinition>(toRegister.size());
+        Set<DefinitionStub> aggregates = new HashSet<DefinitionStub>();
+
+        for (DefinitionStub stub : toRegister.values()) {
+            Name name = stub.name;
             if (name == null) {
-                throw new IllegalArgumentException("A privilege must have a name.");
+                throw new RepositoryException("Name of custom privilege may not be null.");
+            }
+            if (registeredPrivileges.containsKey(name)) {
+                throw new RepositoryException("Registered privilege with name " + name + " already exists.");
             }
-            this.name = NAME_FACTORY.create(name);
-            this.isAbstract = false;
-            this.declaredAggregates = declaredAggregates;
-            Set<InternalPrivilege> aggrgt = new HashSet<InternalPrivilege>();
-            int bts = 0;
-            for (InternalPrivilege priv : declaredAggregates) {
-                bts |= priv.getBits();
-                if (priv.isAggregate) {
-                    aggrgt.addAll(priv.aggregates);
+
+            // namespace validation:
+            // - make sure the specified name defines a registered namespace
+            namespaceRegistry.getPrefix(stub.name.getNamespaceURI());
+            // - and isn't one of the reserved namespaces
+            if (((NamespaceRegistryImpl) namespaceRegistry).isReservedURI(name.getNamespaceURI())) {
+                throw new RepositoryException("Failed to register custom privilege: Reserved namespace URI: " + name.getNamespaceURI());
+            }
+
+            // validate aggregates
+            if (stub.declaredAggregateNames.isEmpty()) {
+                // not an aggregate priv definition.
+                definitions.put(name, new PrivilegeDefinition(stub, nextBits()));
+            } else {
+                for (Name declaredAggregateName : stub.declaredAggregateNames) {
+                    if (name.equals(declaredAggregateName)) {
+                        throw new RepositoryException("Declared aggregate name '"+ declaredAggregateName.toString() +"'refers to the same custom privilege.");
+                    }
+                    if (registeredPrivileges.containsKey(declaredAggregateName)) {
+                        log.debug("Declared aggregate name '"+ declaredAggregateName.toString() +"' referring to registered privilege.");
+                    } else if (toRegister.containsKey(declaredAggregateName)) {
+                        log.debug("Declared aggregate name '"+ declaredAggregateName.toString() +"' referring to un-registered privilege.");
+                        // need to check for circular aggregates
+                        if (isCircularAggregation(stub, declaredAggregateName, toRegister)) {
+                            throw new RepositoryException("Detected circular aggregation within custom privilege caused by " + declaredAggregateName.toString());
+                        }
+                    } else {
+                        throw new RepositoryException("Found unresolvable name of declared aggregate privilege " + declaredAggregateName.toString());
+                    }
+                }
+                // remember for further processing
+                aggregates.add(stub);
+            }
+        }
+
+        // process the aggregate stubs in order to calculate the 'bits'
+        while (aggregates.size() > 0) {
+            // monitor progress of resolution into proper definitions.
+            int cnt = aggregates.size();
+
+            // look for those definitions whose declared aggregates have all been processed.
+            for (Iterator<DefinitionStub> itr = aggregates.iterator(); itr.hasNext();) {
+                DefinitionStub stub = itr.next();
+                int bts = getAggregateBits(stub.declaredAggregateNames, definitions);
+                if (bitsToNames.containsKey(bts) && bitsToNames.get(bts).size() == 1) {
+                    Name existingName = bitsToNames.get(bts).iterator().next();
+                    throw new RepositoryException("Custom aggregate privilege '" + stub.name + "' is already covered by '" + existingName.toString() + "'");
+                }
+                if (bts != NO_PRIVILEGE) {
+                    PrivilegeDefinition def = new PrivilegeDefinition(stub, bts);
+                    definitions.put(def.name, def);
+                    itr.remove();
+                }
+            }
+
+            if (cnt == aggregates.size()) {
+                // none of the remaining aggregate-definitions could be processed
+                throw new RepositoryException("Invalid aggregate privilege definition. Failed to resolve aggregate names.");
+            }
+        }
+
+        return definitions;
+    }
+
+    /**
+     *
+     * @return
+     */
+    private int nextBits() {
+        int b = nextBits;
+        nextBits = nextBits << 1;
+        return b;
+    }
+
+    /**
+     *
+     * @param declaredAggregateNames
+     * @param toRegister
+     * @return
+     */
+    private int getAggregateBits(Set<Name> declaredAggregateNames, Map<Name, PrivilegeDefinition> toRegister) {
+        int bts = NO_PRIVILEGE;
+        for (Name n : declaredAggregateNames) {
+            if (registeredPrivileges.containsKey(n)) {
+                bts |= registeredPrivileges.get(n).bits;
+            } else if (toRegister.containsKey(n)) {
+                PrivilegeDefinition def = toRegister.get(n);
+                if (def.bits == NO_PRIVILEGE) {
+                    // not yet processed dependency -> wait for next iteration.
+                    return NO_PRIVILEGE;
                 } else {
-                    aggrgt.add(priv);
+                    bts |= def.bits;
                 }
+            } else {
+                // unknown dependency (should not get here)
+                return NO_PRIVILEGE;
             }
-            aggregates = Collections.unmodifiableSet(aggrgt);
-            bits = bts;
-            isAggregate = true;
         }
+        return bts;
+    }
 
-        int getBits() {
-            return bits;
+    /**
+     *
+     * @param def
+     * @param declaredAggregateName
+     * @param toRegister
+     * @return
+     */
+    private boolean isCircularAggregation(DefinitionStub def, Name declaredAggregateName, Map<Name, DefinitionStub> toRegister) {
+        DefinitionStub d = toRegister.get(declaredAggregateName);
+        if (d.declaredAggregateNames.isEmpty()) {
+            return false;
+        } else {
+            boolean isCircular = false;
+            for (Name n : d.declaredAggregateNames) {
+                if (def.name.equals(n)) {
+                    return true;
+                }
+                if (toRegister.containsKey(n)) {
+                    isCircular = isCircularAggregation(def, n, toRegister);
+                }
+            }
+            return isCircular;
+        }
+    }
+
+    /**
+     * @return PrivilegeDefinition for the jcr:write privilege
+     */
+    private static PrivilegeDefinition createJcrWriteDefinition() {
+        Set<Name> jcrWriteAggregates = new HashSet<Name>(4);
+        jcrWriteAggregates.add(NameConstants.JCR_MODIFY_PROPERTIES);
+        jcrWriteAggregates.add(NameConstants.JCR_ADD_CHILD_NODES);
+        jcrWriteAggregates.add(NameConstants.JCR_REMOVE_CHILD_NODES);
+        jcrWriteAggregates.add(NameConstants.JCR_REMOVE_NODE);
+
+        int jcrWriteBits = NO_PRIVILEGE;
+        for (Name privilegeName : jcrWriteAggregates) {
+            jcrWriteBits |= PRIVILEGE_NAMES.get(privilegeName);
+        }
+        return new PrivilegeDefinition(NameConstants.JCR_WRITE, false, jcrWriteAggregates, jcrWriteBits);
+    }
+
+    private static PrivilegeDefinition createRepWriteDefinition(int jcrWriteBits) {
+        Set<Name> repWriteAggregates = new HashSet<Name>(2);
+        repWriteAggregates.add(NameConstants.JCR_WRITE);
+        repWriteAggregates.add(NameConstants.JCR_NODE_TYPE_MANAGEMENT);
+
+        int repWriteBits = jcrWriteBits | PRIVILEGE_NAMES.get(NameConstants.JCR_NODE_TYPE_MANAGEMENT);
+        return new PrivilegeDefinition(REP_WRITE_NAME, false, repWriteAggregates, repWriteBits);
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Notification about new registered privileges
+     */
+    interface Listener {
+        /**
+         * @param privilegeName The name of the new privilege
+         */
+        void privilegeRegistered(Name privilegeName);
+    }
+
+
+    /**
+     * Raw, non-validated stub of a PrivilegeDefinition
+     */
+    private static class DefinitionStub {
+        
+        protected final Name name;
+        protected final boolean isAbstract;
+        protected final Set<Name> declaredAggregateNames;
+        protected final boolean isCustom;
+        
+        private int hashCode;
+
+        private DefinitionStub(Name name, boolean isAbstract, Set<Name> declaredAggregateNames, boolean isCustom) {
+            this.name = name;
+            this.isAbstract = isAbstract;
+            this.declaredAggregateNames = (declaredAggregateNames == null) ? Collections.<Name>emptySet() : declaredAggregateNames;
+            this.isCustom = isCustom;
         }
 
         //---------------------------------------------------------< Object >---
         @Override
+        public String toString() {
+            return name.toString();
+        }
+
+        @Override
         public int hashCode() {
-            return bits;
+            if (hashCode == 0) {
+                int h = 17;
+                h = 37 * h + name.hashCode();
+                h = 37 * h + Boolean.valueOf(isAbstract).hashCode();
+                h = 37 * h + declaredAggregateNames.hashCode();
+                hashCode = h;
+            }
+            return hashCode;
         }
 
         @Override
@@ -454,88 +785,162 @@ public final class PrivilegeRegistry {
             if (obj == this) {
                 return true;
             }
-            if (obj instanceof InternalPrivilege) {
-                return bits == ((InternalPrivilege) obj).bits;
+            if (obj instanceof DefinitionStub) {
+                DefinitionStub other = (DefinitionStub) obj;
+                return name.equals(other.name)
+                        && isAbstract==other.isAbstract
+                        && declaredAggregateNames.equals(other.declaredAggregateNames);
             }
             return false;
         }
     }
 
     /**
-     * Simple wrapper used to provide an public representation of the
-     * registered internal privileges properly exposing the JCR name.
+     * Internal definition of a jcr level privilege.
      */
-    private class PrivilegeImpl implements Privilege {
+    static class PrivilegeDefinition extends DefinitionStub {
 
-        private final InternalPrivilege internalPrivilege;
-        private final NameResolver resolver;
+        private final int bits;
 
-        private PrivilegeImpl(InternalPrivilege internalPrivilege,
-                              NameResolver resolver) {
-            this.internalPrivilege = internalPrivilege;
-            this.resolver = resolver;
+        private PrivilegeDefinition(DefinitionStub stub, int bits) {
+            this(stub.name, stub.isAbstract, stub.declaredAggregateNames, bits, stub.isCustom);
         }
 
-        public String getName() {
-            try {
-                return resolver.getJCRName(internalPrivilege.name);
-            } catch (NamespaceException e) {
-                // should not occur -> return internal name representation.
-                return internalPrivilege.name.toString();
+        private PrivilegeDefinition(Name name, boolean isAbstract, int bits) {
+            this(name, isAbstract, Collections.<Name>emptySet(), bits, false);
+        }
+
+        private PrivilegeDefinition(Name name, boolean isAbstract, Set<Name> declaredAggregateNames, int bits) {
+            this(name, isAbstract, declaredAggregateNames, bits, false);
+        }
+
+        private PrivilegeDefinition(Name name, boolean isAbstract, Set<Name> declaredAggregateNames, int bits, boolean isCustom) {
+            super(name, isAbstract, declaredAggregateNames, isCustom);
+            if (bits == NO_PRIVILEGE) {
+                throw new IllegalArgumentException("Failed to build int representation of PrivilegeDefinition.");
+            } else {
+                this.bits = bits;
             }
         }
 
-        public boolean isAbstract() {
-            return internalPrivilege.isAbstract;
+        int getBits() {
+            return bits;
         }
 
-        public boolean isAggregate() {
-            return internalPrivilege.isAggregate;
+        Name getName() {
+            return name;
         }
 
-        public Privilege[] getDeclaredAggregatePrivileges() {
-            if (internalPrivilege.isAggregate) {
-                int len = internalPrivilege.declaredAggregates.length;
-                Privilege[] privs = new Privilege[len];
-                for (int i = 0; i < len; i++) {
-                    InternalPrivilege ip = internalPrivilege.declaredAggregates[i];
-                    privs[i] = localCache.get(ip.name);
-                }
-                return privs;
+        boolean isAbstract() {
+            return isAbstract;
+        }
+
+        Name[] getDeclaredAggregateNames() {
+            if (declaredAggregateNames.isEmpty()) {
+                return Name.EMPTY_ARRAY;
             } else {
-                return EMPTY_ARRAY;
+                return declaredAggregateNames.toArray(new Name[declaredAggregateNames.size()]);
             }
         }
+    }
+
+    /**
+     * CustomPrivilegeStore used to read and write custom privilege definitions
+     * from/to a file system resource.
+     */
+    private class CustomPrivilegeStore {
+
+        /**
+         * File system resource used to persist custom privileges registered with
+         * the repository.
+         */
+        private final FileSystemResource customPrivilegesResource;
 
-        public Privilege[] getAggregatePrivileges() {
-            if (internalPrivilege.isAggregate) {
-                Privilege[] privs = new Privilege[internalPrivilege.aggregates.size()];
-                int i = 0;
-                for (InternalPrivilege ip : internalPrivilege.aggregates) {
-                    privs[i++] = localCache.get(ip.name);
+        private CustomPrivilegeStore(FileSystemResource customPrivilegesResource) throws RepositoryException {
+            this.customPrivilegesResource = customPrivilegesResource;
+            try {
+                // make sure path to resource exists
+                if (!customPrivilegesResource.exists()) {
+                    customPrivilegesResource.makeParentDirs();
                 }
-                return privs;
-            } else {
-                return EMPTY_ARRAY;
+            } catch (FileSystemException e) {
+                String error = "Internal error: Failed to access/create file system resource for custom privileges at " + customPrivilegesResource.getPath();
+                log.debug(error);
+                throw new RepositoryException(error, e);
             }
         }
 
-        //---------------------------------------------------------< Object >---
-        @Override
-        public int hashCode() {
-            return internalPrivilege.hashCode();
+        private Map<Name, DefinitionStub> load() throws IOException, FileSystemException, RepositoryException {
+            Map<Name, DefinitionStub> stubs = new LinkedHashMap<Name, DefinitionStub>();
+
+            if (customPrivilegesResource.exists()) {
+                BufferedReader reader = new BufferedReader(new InputStreamReader(customPrivilegesResource.getInputStream(), "utf-8"));
+                try {
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        String[] params = Text.explode(line, ';', true);
+
+                        if (params.length < 1) {
+                            // empty line
+                            continue;
+                        }
+
+                        Name privName = NAME_FACTORY.create(params[0]);
+                        boolean isAbstract = false;
+                        Set<Name> declaredAggrNames = new HashSet<Name>();
+
+                        if (params.length >= 2) {
+                            isAbstract = "abstract".equals(params[1]);
+                        }
+                        if (params.length >= 3) {
+                            String[] declExpNames = Text.explode(params[2], ',');
+                            for (String declExpName : declExpNames) {
+                                declaredAggrNames.add(NAME_FACTORY.create(declExpName));
+                            }
+                        }
+
+                        if (stubs.containsKey(privName)) {
+                            throw new RepositoryException("Duplicate entry for custom privilege with name " + privName.toString());
+                        }
+                        stubs.put(privName, new DefinitionStub(privName, isAbstract, declaredAggrNames, true));
+
+                    }
+                } finally {
+                    reader.close();
+                }
+            }
+            return stubs;
         }
 
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == this) {
-                return true;
-            }
-            if (obj instanceof PrivilegeImpl) {
-                PrivilegeImpl other = (PrivilegeImpl) obj;
-                return internalPrivilege.equals(other.internalPrivilege);
+        private void append(Map<Name, PrivilegeDefinition> newPrivilegeDefinitions) throws IOException, FileSystemException, RepositoryException {
+            Map<Name, DefinitionStub> defs = load();
+            defs.putAll(newPrivilegeDefinitions);
+
+            Writer writer = new OutputStreamWriter(customPrivilegesResource.getOutputStream(), "utf-8");
+            try {
+                for (DefinitionStub def : defs.values()) {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append(def.name.toString()).append(';');
+                    if (def.isAbstract) {
+                        sb.append("abstract");
+                    }
+                    sb.append(";");
+                    if (!def.declaredAggregateNames.isEmpty()) {
+                        int cnt = 0;
+                        for (Name dan : def.declaredAggregateNames) {
+                            if (cnt > 0) {
+                                sb.append(",");
+                            }
+                            sb.append(dan.toString());
+                            cnt++;
+                        }
+                    }
+                    writer.write(sb.toString());
+                    writer.write("\n");
+                }
+            } finally {
+                writer.close();
             }
-            return false;
         }
     }
 }

Modified: 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=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java Fri Feb 18 21:24:10 2011
@@ -20,12 +20,13 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.ProtectedItemModifier;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
 import org.apache.jackrabbit.core.security.authorization.AccessControlEntryImpl;
 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.core.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.conversion.NameException;
 import org.apache.jackrabbit.spi.commons.conversion.NameParser;
@@ -66,15 +67,12 @@ public class ACLEditor extends Protected
      * the editing session
      */
     private final SessionImpl session;
-    private final PrivilegeRegistry privilegeRegistry;
     private final AccessControlUtils utils;
 
     ACLEditor(Session editingSession, AccessControlUtils utils) {
         super(Permission.MODIFY_AC);
         if (editingSession instanceof SessionImpl) {
             session = ((SessionImpl) editingSession);
-            // TODO: review and find better solution
-            privilegeRegistry = new PrivilegeRegistry(session);
         } else {
             throw new IllegalArgumentException("org.apache.jackrabbit.core.SessionImpl expected. Found " + editingSession.getClass());
         }
@@ -88,7 +86,7 @@ public class ACLEditor extends Protected
      * @throws RepositoryException if an error occurs
      */
     ACLTemplate getACL(NodeImpl aclNode) throws RepositoryException {
-        return new ACLTemplate(aclNode, privilegeRegistry);
+        return new ACLTemplate(aclNode);
     }
 
     //------------------------------------------------< AccessControlEditor >---
@@ -132,9 +130,10 @@ public class ACLEditor extends Protected
             // create an empty acl unless the node is protected or cannot have
             // rep:AccessControllable mixin set (e.g. due to a lock)
             String mixin = session.getJCRName(NT_REP_ACCESS_CONTROLLABLE);
+            PrivilegeManager privMgr = ((WorkspaceImpl) session.getWorkspace()).getPrivilegeManager();
             if (controlledNode.isNodeType(mixin) || controlledNode.canAddMixin(mixin)) {
                 acl = new ACLTemplate(nodePath, session.getPrincipalManager(),
-                        privilegeRegistry, session.getValueFactory(), session);
+                        privMgr, session.getValueFactory(), session);
             }
         } // else: acl already present -> getPolicies must be used.
         return (acl != null) ? new AccessControlPolicy[] {acl} : new AccessControlPolicy[0];

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=1072154&r1=1072153&r2=1072154&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 Feb 18 21:24:10 2011
@@ -37,11 +37,13 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.security.authorization.AbstractACLTemplate;
 import org.apache.jackrabbit.core.security.authorization.AccessControlEntryImpl;
 import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
 import org.apache.jackrabbit.core.security.authorization.GlobPattern;
 import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
@@ -75,9 +77,9 @@ class ACLTemplate extends AbstractACLTem
     private final PrincipalManager principalMgr;
 
     /**
-     * The privilege registry
+     * The privilege mgr
      */
-    private final PrivilegeRegistry privilegeRegistry;
+    private final PrivilegeManager privilegeMgr;
 
     /**
      * The name resolver
@@ -101,18 +103,18 @@ class ACLTemplate extends AbstractACLTem
      * Construct a new empty {@link ACLTemplate}.
      *
      * @param path path
-     * @param privilegeRegistry registry
+     * @param privilegeMgr
      * @param valueFactory value factory
      * @param resolver
      * @param principalMgr manager
      * @throws javax.jcr.NamespaceException
      */
     ACLTemplate(String path, PrincipalManager principalMgr, 
-                PrivilegeRegistry privilegeRegistry, ValueFactory valueFactory,
+                PrivilegeManager privilegeMgr, ValueFactory valueFactory,
                 NamePathResolver resolver) throws NamespaceException {
         super(path, valueFactory);
         this.principalMgr = principalMgr;
-        this.privilegeRegistry = privilegeRegistry;
+        this.privilegeMgr = privilegeMgr;
         this.resolver = resolver;
         this.id = null;
 
@@ -124,18 +126,17 @@ class ACLTemplate extends AbstractACLTem
      * node.
      *
      * @param aclNode node
-     * @param privilegeRegistry registry
      * @throws RepositoryException if an error occurs
      */
-    ACLTemplate(NodeImpl aclNode, PrivilegeRegistry privilegeRegistry) throws RepositoryException {
+    ACLTemplate(NodeImpl aclNode) throws RepositoryException {
         super((aclNode != null) ? aclNode.getParent().getPath() : null, (aclNode != null) ? aclNode.getSession().getValueFactory() : null);
         if (aclNode == null || !NT_REP_ACL.equals(((NodeTypeImpl)aclNode.getPrimaryNodeType()).getQName())) {
             throw new IllegalArgumentException("Node must be of type 'rep:ACL'");
         }
         SessionImpl sImpl = (SessionImpl) aclNode.getSession();
         principalMgr = sImpl.getPrincipalManager();
+        privilegeMgr = ((WorkspaceImpl) sImpl.getWorkspace()).getPrivilegeManager();
 
-        this.privilegeRegistry = privilegeRegistry;
         this.resolver = sImpl;
         this.id = aclNode.getParentId();
         jcrRepGlob = sImpl.getJCRName(P_GLOB);
@@ -239,7 +240,7 @@ class ACLTemplate extends AbstractACLTem
                         // both the new privileges and the existing ones.
                         entries.remove(e);
                         int mergedBits = e.getPrivilegeBits() | entry.getPrivilegeBits();
-                        Privilege[] mergedPrivs = privilegeRegistry.getPrivileges(mergedBits);
+                        Privilege[] mergedPrivs = privilegeMgr.getPrivileges(mergedBits);
                         // omit validation check.
                         entry = createEntry(entry, mergedPrivs, entry.isAllow());
                     } else {
@@ -267,7 +268,7 @@ class ACLTemplate extends AbstractACLTem
                     int index = entries.indexOf(complementEntry);
                     entries.remove(complementEntry);
                     Entry tmpl = createEntry(entry,
-                            privilegeRegistry.getPrivileges(resultPrivs),
+                            privilegeMgr.getPrivileges(resultPrivs),
                             !entry.isAllow());
                     entries.add(index, tmpl);
                 } /* else: does not need to be modified.*/
@@ -455,5 +456,10 @@ class ACLTemplate extends AbstractACLTem
         protected ValueFactory getValueFactory() {
             return valueFactory;
         }
+
+        @Override
+        protected PrivilegeManager getPrivilegeManager() {
+            return privilegeMgr;
+        }
     }
 }

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=1072154&r1=1072153&r2=1072154&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 Feb 18 21:24:10 2011
@@ -22,7 +22,6 @@ 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;
@@ -62,8 +61,6 @@ public class EntryCollector extends Acce
      * The root id.
      */
     protected final NodeId rootID;
-
-    private final PrivilegeRegistry privilegeRegistry;
     
     /**
      * Standard JCR name form of the {@link #N_POLICY} constant.
@@ -80,7 +77,6 @@ public class EntryCollector extends Acce
         this.systemSession = systemSession;
         this.rootID = rootID;
 
-        privilegeRegistry = new PrivilegeRegistry(systemSession);
         repPolicyName = systemSession.getJCRName(N_POLICY);
 
         ObservationManager observationMgr = systemSession.getWorkspace().getObservationManager();
@@ -159,7 +155,7 @@ public class EntryCollector extends Acce
         if (ACLProvider.isAccessControlled(node)) {
             // collect the aces of that node.
             NodeImpl aclNode = node.getNode(N_POLICY);
-            entries = new ACLTemplate(aclNode, privilegeRegistry).getEntries();
+            entries = new ACLTemplate(aclNode).getEntries();
         } else {
             // not access controlled
             entries = Collections.emptyList();

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java Fri Feb 18 21:24:10 2011
@@ -20,6 +20,7 @@ import org.apache.commons.collections.ma
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.security.SecurityConstants;
 import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider;
@@ -99,7 +100,7 @@ public class ACLProvider extends Abstrac
 
         editor = new ACLEditor(session, resolver.getQPath(acRoot.getPath()));
         entriesCache = new EntriesCache(session, editor, acRoot.getPath());
-        readBits = PrivilegeRegistry.getBits(new Privilege[] {session.getAccessControlManager().privilegeFromName(Privilege.JCR_READ)});
+        readBits = ((WorkspaceImpl) session.getWorkspace()).getPrivilegeManager().getBits(new String[] {Privilege.JCR_READ});
 
         // TODO: replace by configurable default policy (see JCR-2331)
         if (!configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS)) {

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=1072154&r1=1072153&r2=1072154&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 Feb 18 21:24:10 2011
@@ -19,9 +19,11 @@ package org.apache.jackrabbit.core.secur
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.security.authorization.AccessControlEntryImpl;
 import org.apache.jackrabbit.core.security.authorization.AbstractACLTemplate;
 import org.apache.jackrabbit.core.security.authorization.GlobPattern;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
@@ -34,6 +36,7 @@ import javax.jcr.NodeIterator;
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.security.AccessControlEntry;
@@ -73,6 +76,7 @@ class ACLTemplate extends AbstractACLTem
     private final String jcrGlobName;
 
     private final NameResolver resolver;
+    private final PrivilegeManager privilegeMgr;
 
     ACLTemplate(Principal principal, String path, NamePathResolver resolver, ValueFactory vf)
             throws RepositoryException {
@@ -95,6 +99,8 @@ class ACLTemplate extends AbstractACLTem
         jcrGlobName = resolver.getJCRName(P_GLOB);
 
         this.resolver = resolver;
+        Session session = (acNode != null) ? acNode.getSession() : (Session) resolver;
+        this.privilegeMgr = ((WorkspaceImpl) session.getWorkspace()).getPrivilegeManager();
 
         if (acNode != null && acNode.hasNode(N_POLICY)) {
             // build the list of policy entries;
@@ -326,10 +332,6 @@ class ACLTemplate extends AbstractACLTem
             return pattern.matches(item);
         }
 
-        boolean matchesNodePath(String jcrPath) {
-            return nodePath.equals(jcrPath);
-        }
-
         @Override
         protected NameResolver getResolver() {
             return resolver;
@@ -339,5 +341,10 @@ class ACLTemplate extends AbstractACLTem
         protected ValueFactory getValueFactory() {
             return valueFactory;
         }
+
+        @Override
+        protected PrivilegeManager getPrivilegeManager() {
+            return privilegeMgr;
+        }
     }
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleAccessManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleAccessManager.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleAccessManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleAccessManager.java Fri Feb 18 21:24:10 2011
@@ -21,6 +21,7 @@ import javax.jcr.security.AccessControlE
 import javax.jcr.security.AccessControlPolicy;
 import javax.jcr.security.Privilege;
 import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.security.AMContext;
 import org.apache.jackrabbit.core.security.AbstractAccessControlManager;
@@ -30,7 +31,7 @@ import org.apache.jackrabbit.core.securi
 import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
 import org.apache.jackrabbit.core.security.authorization.NamedAccessControlPolicyImpl;
 import org.apache.jackrabbit.core.security.authorization.Permission;
-import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
@@ -65,7 +66,7 @@ public class SimpleAccessManager extends
 
     private NamePathResolver resolver;
     private WorkspaceAccessManager wspAccessMgr;
-    private PrivilegeRegistry privilegeRegistry;
+    private PrivilegeManager privilegeManager;
 
     private boolean initialized;
 
@@ -101,7 +102,7 @@ public class SimpleAccessManager extends
         subject = context.getSubject();
         hierMgr = context.getHierarchyManager();
         resolver = context.getNamePathResolver();
-        privilegeRegistry = new PrivilegeRegistry(resolver);
+        privilegeManager = ((WorkspaceImpl) context.getSession().getWorkspace()).getPrivilegeManager();
         wspAccessMgr = wspAccessManager;
         anonymous = !subject.getPrincipals(AnonymousPrincipal.class).isEmpty();
         system = !subject.getPrincipals(SystemPrincipal.class).isEmpty();
@@ -217,7 +218,7 @@ public class SimpleAccessManager extends
                 // system has always all permissions
                 return true;
             } else if (anonymous) {
-                if (privileges.length != 1 || !privileges[0].equals(privilegeRegistry.getPrivilege(Privilege.JCR_READ))) {
+                if (privileges.length != 1 || !privileges[0].equals(privilegeManager.getPrivilege(Privilege.JCR_READ))) {
                     // anonymous is only granted READ permissions
                     return false;
                 }
@@ -237,12 +238,12 @@ public class SimpleAccessManager extends
 
         Privilege priv;
         if (anonymous) {
-            priv = privilegeRegistry.getPrivilege(Privilege.JCR_READ);
+            priv = privilegeManager.getPrivilege(Privilege.JCR_READ);
         } else if (system) {
-            priv = privilegeRegistry.getPrivilege(Privilege.JCR_ALL);
+            priv = privilegeManager.getPrivilege(Privilege.JCR_ALL);
         } else {
             // @todo check permission based on principals
-            priv = privilegeRegistry.getPrivilege(Privilege.JCR_ALL);
+            priv = privilegeManager.getPrivilege(Privilege.JCR_ALL);
         }
         return new Privilege[] {priv};
     }
@@ -280,13 +281,11 @@ public class SimpleAccessManager extends
     }
 
     /**
-     * @see AbstractAccessControlManager#getPrivilegeRegistry()
+     * @see AbstractAccessControlManager#getPrivilegeManager()
      */
     @Override
-    protected PrivilegeRegistry getPrivilegeRegistry()
-            throws RepositoryException {
-        checkInitialized();
-        return privilegeRegistry;
+    protected PrivilegeManager getPrivilegeManager() throws RepositoryException {
+        return privilegeManager;
     }
 
     /**
@@ -331,7 +330,7 @@ public class SimpleAccessManager extends
         if (principals.size() == 1) {
             Principal princ = principals.iterator().next();
             if (princ instanceof AnonymousPrincipal) {
-                return privileges.length == 1 && privileges[0].equals(privilegeRegistry.getPrivilege(Privilege.JCR_READ));
+                return privileges.length == 1 && privileges[0].equals(privilegeManager.getPrivilege(Privilege.JCR_READ));
             }
         }
 
@@ -351,11 +350,11 @@ public class SimpleAccessManager extends
         if (principals.size() == 1) {
             Principal princ = principals.iterator().next();
             if (princ instanceof AnonymousPrincipal) {
-                return new Privilege[] {privilegeRegistry.getPrivilege(Privilege.JCR_READ)};
+                return new Privilege[] {privilegeManager.getPrivilege(Privilege.JCR_READ)};
             }
         }
 
         // @todo check permission based on principals
-        return new Privilege[] {privilegeRegistry.getPrivilege(Privilege.JCR_ALL)};
+        return new Privilege[] {privilegeManager.getPrivilege(Privilege.JCR_ALL)};
     }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java Fri Feb 18 21:24:10 2011
@@ -22,6 +22,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.core.ItemImpl;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
@@ -312,8 +313,7 @@ public class UserAccessControlProvider e
     }
 
     private int getPrivilegeBits(String privName) throws RepositoryException {
-        Privilege[] privs = new Privilege[] {session.getAccessControlManager().privilegeFromName(privName)};
-        return PrivilegeRegistry.getBits(privs);
+        return ((WorkspaceImpl) session.getWorkspace()).getPrivilegeManager().getBits(new String[] {privName});
     }
 
     private static boolean containsGroup(Set<Principal> principals, Principal group) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java Fri Feb 18 21:24:10 2011
@@ -35,6 +35,7 @@ import org.apache.jackrabbit.core.nodety
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
 import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.core.state.SessionItemStateManager;
 import org.apache.jackrabbit.core.value.ValueFactoryImpl;
 import org.apache.jackrabbit.spi.Name;
@@ -80,6 +81,11 @@ public class SessionContext implements N
     private final NodeTypeManagerImpl nodeTypeManager;
 
     /**
+     * Privilege manager of this session.
+     */
+    private final PrivilegeManager privilegeManager;
+
+    /**
      * The workspace of this session
      */
     private final WorkspaceImpl workspace;
@@ -124,6 +130,7 @@ public class SessionContext implements N
             new ValueFactoryImpl(session, repositoryContext.getDataStore());
         this.itemValidator = new ItemValidator(this);
         this.nodeTypeManager = new NodeTypeManagerImpl(this);
+        this.privilegeManager = new PrivilegeManager(repositoryContext.getPrivilegeRegistry(), session);
         this.workspace = new WorkspaceImpl(this, workspaceConfig);
     }
 
@@ -223,6 +230,15 @@ public class SessionContext implements N
     }
 
     /**
+     * Returns the privilege manager of this session.
+     *
+     * @return the privilege manager.
+     */
+    public PrivilegeManager getPrivilegeManager() {
+        return privilegeManager;
+    }
+
+    /**
      * Returns the workspace of this session.
      *
      * @return workspace

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplateTest.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplateTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplateTest.java Fri Feb 18 21:24:10 2011
@@ -30,6 +30,8 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.security.TestPrincipal;
 import org.apache.jackrabbit.test.NotExecutableException;
 import org.apache.jackrabbit.test.api.security.AbstractAccessControlTest;
@@ -40,7 +42,8 @@ import org.apache.jackrabbit.test.api.se
 public abstract class AbstractACLTemplateTest extends AbstractAccessControlTest {
 
     protected Principal testPrincipal;
-    protected PrincipalManager pMgr;
+    protected PrincipalManager principalMgr;
+    protected PrivilegeManager privilegeMgr;
 
     @Override
     protected void setUp() throws Exception {
@@ -50,17 +53,18 @@ public abstract class AbstractACLTemplat
             throw new NotExecutableException();
         }
 
-        pMgr = ((JackrabbitSession) superuser).getPrincipalManager();
-        PrincipalIterator it = pMgr.getPrincipals(PrincipalManager.SEARCH_TYPE_NOT_GROUP);
+        principalMgr = ((JackrabbitSession) superuser).getPrincipalManager();
+        PrincipalIterator it = principalMgr.getPrincipals(PrincipalManager.SEARCH_TYPE_NOT_GROUP);
         if (it.hasNext()) {
             testPrincipal = it.nextPrincipal();
         } else {
             throw new NotExecutableException();
         }
+        privilegeMgr = ((WorkspaceImpl) superuser.getWorkspace()).getPrivilegeManager();
     }
 
-    protected static void assertSamePrivileges(Privilege[] privs1, Privilege[] privs2) throws AccessControlException {
-        assertEquals(PrivilegeRegistry.getBits(privs1), PrivilegeRegistry.getBits(privs2));
+    protected void assertSamePrivileges(Privilege[] privs1, Privilege[] privs2) throws AccessControlException {
+        assertEquals(privilegeMgr.getBits(privs1), privilegeMgr.getBits(privs2));
     }
 
     protected abstract String getTestPath();
@@ -85,7 +89,7 @@ public abstract class AbstractACLTemplat
 
     public void testAddInvalidEntry() throws RepositoryException, NotExecutableException {
         Principal unknownPrincipal;
-        if (!pMgr.hasPrincipal("an unknown principal")) {
+        if (!principalMgr.hasPrincipal("an unknown principal")) {
             unknownPrincipal = new TestPrincipal("an unknown principal");
         } else {
             throw new NotExecutableException();
@@ -117,7 +121,7 @@ public abstract class AbstractACLTemplat
                     return false;
                 }
                 public int getPrivilegeBits() throws RepositoryException, NotExecutableException {
-                    return PrivilegeRegistry.getBits(privilegesFromName(Privilege.JCR_READ));
+                    return privilegeMgr.getBits(new String[] {Privilege.JCR_READ});
                 }
                 public String[] getRestrictionNames() {
                     return new String[0];
@@ -202,7 +206,7 @@ public abstract class AbstractACLTemplat
         AccessControlEntry[] entries = pt.getAccessControlEntries();
         for (AccessControlEntry ace : entries) {
             if (testPrincipal.equals(ace.getPrincipal()) && ace instanceof JackrabbitAccessControlEntry) {
-                int entryBits = PrivilegeRegistry.getBits(ace.getPrivileges());
+                int entryBits = privilegeMgr.getBits(ace.getPrivileges());
                 if (((JackrabbitAccessControlEntry) ace).isAllow()) {
                     allows |= Permission.diff(entryBits, denies);
                 } else {
@@ -210,8 +214,8 @@ public abstract class AbstractACLTemplat
                 }
             }
         }
-        assertEquals(PrivilegeRegistry.getBits(read), allows);
-        assertEquals(PrivilegeRegistry.getBits(modProp), denies);
+        assertEquals(privilegeMgr.getBits(read), allows);
+        assertEquals(privilegeMgr.getBits(modProp), denies);
     }
 
     public void testEffect2() throws RepositoryException, NotExecutableException {
@@ -227,7 +231,7 @@ public abstract class AbstractACLTemplat
         AccessControlEntry[] entries = pt.getAccessControlEntries();
         for (AccessControlEntry ace : entries) {
             if (testPrincipal.equals(ace.getPrincipal()) && ace instanceof JackrabbitAccessControlEntry) {
-                int entryBits = PrivilegeRegistry.getBits(ace.getPrivileges());
+                int entryBits = privilegeMgr.getBits(ace.getPrivileges());
                 if (((JackrabbitAccessControlEntry) ace).isAllow()) {
                     allows |= Permission.diff(entryBits, denies);
                 } else {
@@ -237,7 +241,7 @@ public abstract class AbstractACLTemplat
         }
 
         assertEquals(PrivilegeRegistry.NO_PRIVILEGE, allows);
-        assertEquals(PrivilegeRegistry.getBits(privilegesFromName(Privilege.JCR_READ)), denies);
+        assertEquals(privilegeMgr.getBits(privilegesFromName(Privilege.JCR_READ)), denies);
     }
 
     public void testRemoveEntry() throws RepositoryException,

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractEntryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractEntryTest.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractEntryTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractEntryTest.java Fri Feb 18 21:24:10 2011
@@ -26,6 +26,8 @@ import javax.jcr.Value;
 import javax.jcr.security.AccessControlException;
 import javax.jcr.security.Privilege;
 
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.test.NotExecutableException;
 import org.apache.jackrabbit.test.api.security.AbstractAccessControlTest;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
@@ -74,7 +76,6 @@ public abstract class AbstractEntryTest 
     public void testGetPrivilegeBits() throws RepositoryException, NotExecutableException {
         JackrabbitAccessControlEntry tmpl = createEntry(new String[] {Privilege.JCR_READ}, true);
 
-        int privs = PrivilegeRegistry.getBits(tmpl.getPrivileges());
         assertEquals(1, tmpl.getPrivileges().length);
         assertEquals(getAccessControlManager(superuser).privilegeFromName(Privilege.JCR_READ),
                 tmpl.getPrivileges()[0]);
@@ -85,20 +86,21 @@ public abstract class AbstractEntryTest 
     }
 
     public void testGetPrivileges() throws RepositoryException, NotExecutableException {
+        PrivilegeManager privMgr = ((WorkspaceImpl) superuser.getWorkspace()).getPrivilegeManager();
         JackrabbitAccessControlEntry entry = createEntry(new String[] {Privilege.JCR_READ}, true);
 
         Privilege[] privs = entry.getPrivileges();
         assertNotNull(privs);
         assertEquals(1, privs.length);
         assertEquals(privs[0], acMgr.privilegeFromName(Privilege.JCR_READ));
-        assertTrue(PrivilegeRegistry.getBits(privs) == PrivilegeRegistry.getBits(entry.getPrivileges()));
+        assertTrue(privMgr.getBits(privs) == privMgr.getBits(entry.getPrivileges()));
 
         entry = createEntry(new String[] {PrivilegeRegistry.REP_WRITE}, true);
         privs = entry.getPrivileges();
         assertNotNull(privs);
         assertEquals(1, privs.length);
         assertEquals(privs[0], acMgr.privilegeFromName(PrivilegeRegistry.REP_WRITE));
-        assertTrue(PrivilegeRegistry.getBits(privs) == PrivilegeRegistry.getBits(entry.getPrivileges()));
+        assertTrue(privMgr.getBits(privs) == privMgr.getBits(entry.getPrivileges()));
 
         entry = createEntry(new String[] {Privilege.JCR_ADD_CHILD_NODES,
                 Privilege.JCR_REMOVE_CHILD_NODES}, true);
@@ -111,7 +113,7 @@ public abstract class AbstractEntryTest 
                 Privilege.JCR_REMOVE_CHILD_NODES
         });
         assertEquals(Arrays.asList(param), Arrays.asList(privs));
-        assertEquals(PrivilegeRegistry.getBits(privs), PrivilegeRegistry.getBits(entry.getPrivileges()));
+        assertEquals(privMgr.getBits(privs), privMgr.getBits(entry.getPrivileges()));
     }
 
     public void testEquals() throws RepositoryException, NotExecutableException  {
@@ -169,12 +171,14 @@ public abstract class AbstractEntryTest 
         final Privilege[] privs = new Privilege[] {
                 acMgr.privilegeFromName(Privilege.JCR_ALL)
         };
+
+        final PrivilegeManager privMgr = ((WorkspaceImpl) superuser.getWorkspace()).getPrivilegeManager();
         JackrabbitAccessControlEntry pe = new JackrabbitAccessControlEntry() {
             public boolean isAllow() {
                 return true;
             }
             public int getPrivilegeBits() throws AccessControlException {
-                return PrivilegeRegistry.getBits(privs);
+                return privMgr.getBits(privs);
             }
             public String[] getRestrictionNames() {
                 return new String[0];

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractNodeTypeManagementTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractNodeTypeManagementTest.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractNodeTypeManagementTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractNodeTypeManagementTest.java Fri Feb 18 21:24:10 2011
@@ -35,6 +35,7 @@ public abstract class AbstractNodeTypeMa
     private Node childNode;
     private String mixinName;
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
 

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractWriteTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractWriteTest.java?rev=1072154&r1=1072153&r2=1072154&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractWriteTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractWriteTest.java Fri Feb 18 21:24:10 2011
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.core.secur
 import org.apache.jackrabbit.api.JackrabbitNode;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.test.JUnitTest;
 import org.apache.jackrabbit.test.NotExecutableException;
 import org.apache.jackrabbit.test.api.observation.EventResult;
@@ -821,8 +822,9 @@ public abstract class AbstractWriteTest 
         /* make sure the same privileges/permissions are granted as at path. */
         String childPath = n.getPath();
         Privilege[] privs = testAcMgr.getPrivileges(childPath);
-        assertEquals(PrivilegeRegistry.getBits(privilegesFromName(Privilege.JCR_READ)),
-                PrivilegeRegistry.getBits(privs));
+        PrivilegeManager privilegeMgr = ((WorkspaceImpl) getTestSession().getWorkspace()).getPrivilegeManager();
+        assertEquals(privilegeMgr.getBits(privilegesFromName(Privilege.JCR_READ)),
+                privilegeMgr.getBits(privs));
         getTestSession().checkPermission(childPath, javax.jcr.Session.ACTION_READ);
     }
 



Mime
View raw message