You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2013/03/12 15:57:45 UTC

svn commit: r1455565 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/core/ main/java/org/apache/jackrabbit/oak/plugins/version/ main/java/org/apache/jackrabbit/oak/security/authorization/ main/java/org/apache/jackrabbit/oak...

Author: angela
Date: Tue Mar 12 14:57:44 2013
New Revision: 1455565

URL: http://svn.apache.org/r1455565
Log:
OAK-527: permissions (wip)

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java   (contents, props changed)
      - copied, changed from r1455473, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyRoot.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableTree.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/PostValidationHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableRootTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java
      - copied, changed from r1455473, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ReadOnlyTreeTest.java
Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyRoot.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ReadOnlyTreeTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyTree.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionablePathHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlValidatorProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidatorProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateUtils.java

Copied: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java (from r1455473, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyRoot.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java?p2=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyRoot.java&r1=1455473&r2=1455565&rev=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyRoot.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java Tue Mar 12 14:57:44 2013
@@ -31,31 +31,30 @@ import static com.google.common.base.Pre
 
 /**
  * Simple implementation of the Root interface that only supports simple read
- * operations (excluding query) based on the NodeState (or ReadOnly tree)
+ * operations (excluding query) based on the {@code NodeState} (or {@code ImmutableTree})
  * passed to the constructor.
- * <p/>
- * TODO: proper handle node state lifecycle that has an impact on this root.
  */
-public final class ReadOnlyRoot implements Root {
+public final class ImmutableRoot implements Root {
 
-    private final ReadOnlyTree rootTree;
+    private final ImmutableTree rootTree;
 
-    public ReadOnlyRoot(@Nonnull NodeState rootState) {
-        this(new ReadOnlyTree(rootState));
+    public ImmutableRoot(@Nonnull NodeState rootState) {
+        this(new ImmutableTree(rootState));
     }
 
-    public ReadOnlyRoot(@Nonnull Root root) {
-        this(ReadOnlyTree.createFromRoot(root));
+    public ImmutableRoot(@Nonnull Root root, @Nonnull ImmutableTree.TypeProvider typeProvider) {
+        this(ImmutableTree.createFromRoot(root, typeProvider));
     }
 
-    private ReadOnlyRoot(@Nonnull ReadOnlyTree rootTree) {
+    public ImmutableRoot(@Nonnull ImmutableTree rootTree) {
         checkArgument(rootTree.isRoot());
         this.rootTree = rootTree;
     }
 
+    //---------------------------------------------------------------< Root >---
     @Override
-    public ReadOnlyTree getTree(String path) {
-        return (ReadOnlyTree) getLocation(path).getTree();
+    public ImmutableTree getTree(String path) {
+        return (ImmutableTree) getLocation(path).getTree();
     }
 
     @Nonnull
@@ -65,8 +64,6 @@ public final class ReadOnlyRoot implemen
         return rootTree.getLocation().getChild(path.substring(1));
     }
 
-    //---------------------< unsupported methods >------------------------------
-
     @Override
     public boolean move(String sourcePath, String destPath) {
         throw new UnsupportedOperationException();
@@ -94,7 +91,7 @@ public final class ReadOnlyRoot implemen
 
     @Override
     public boolean hasPendingChanges() {
-        throw new UnsupportedOperationException();
+        return false;
     }
 
     @Nonnull

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableTree.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableTree.java?rev=1455565&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableTree.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableTree.java Tue Mar 12 14:57:44 2013
@@ -0,0 +1,274 @@
+/*
+ * 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.oak.core;
+
+import java.util.Iterator;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
+import org.apache.jackrabbit.oak.spi.security.Context;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+
+/**
+ * ImmutableTree...
+ * FIXME: merge with ReadOnlyTree
+ */
+public final class ImmutableTree extends ReadOnlyTree {
+
+    private final ParentProvider parentProvider;
+    private final TypeProvider typeProvider;
+
+    public ImmutableTree(@Nonnull NodeState rootState) {
+        this(ParentProvider.ROOTPROVIDER, "", rootState, TypeProvider.EMPTY);
+    }
+
+    public ImmutableTree(@Nonnull NodeState rootState, @Nonnull TypeProvider typeProvider) {
+        this(ParentProvider.ROOTPROVIDER, "", rootState, typeProvider);
+    }
+
+    public ImmutableTree(@Nonnull ImmutableTree parent, @Nonnull String name, @Nonnull NodeState state) {
+        this(new DefaultParentProvider(parent), name, state, parent.typeProvider);
+    }
+
+    public ImmutableTree(@Nonnull ParentProvider parentProvider, @Nonnull String name, @Nonnull NodeState state) {
+        this(parentProvider, name, state, TypeProvider.EMPTY);
+    }
+
+    public ImmutableTree(@Nonnull ParentProvider parentProvider, @Nonnull String name,
+                         @Nonnull NodeState state, @Nonnull TypeProvider typeProvider) {
+        super(null, name, state);
+        this.parentProvider = checkNotNull(parentProvider);
+        this.typeProvider = typeProvider;
+    }
+
+    public static ImmutableTree createFromRoot(@Nonnull Root root, @Nonnull TypeProvider typeProvider) {
+        if (root instanceof RootImpl) {
+            return new ImmutableTree(((RootImpl) root).getBaseState(), typeProvider);
+        } else if (root instanceof ImmutableRoot) {
+            return ((ImmutableRoot) root).getTree("/");
+        } else {
+            throw new IllegalArgumentException("Unsupported Root implementation.");
+        }
+    }
+
+    //---------------------------------------------------------------< Tree >---
+    @Override
+    public boolean isRoot() {
+        return "".equals(getName());
+    }
+
+    @Override
+    public String getPath() {
+        if (isRoot()) {
+            // shortcut
+            return "/";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        buildPath(sb);
+        return sb.toString();
+    }
+
+    private void buildPath(StringBuilder sb) {
+        if (!isRoot()) {
+            getParent().buildPath(sb);
+            sb.append('/').append(getName());
+        }
+    }
+
+    @Override
+    public ImmutableTree getParent() {
+        return parentProvider.getParent();
+    }
+
+    @Override
+    public ImmutableTree getChild(@Nonnull String name) {
+        NodeState child = getNodeState().getChildNode(name);
+        if (child != null) {
+            return new ImmutableTree(this, name, child);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * This implementation does not respect ordered child nodes, but always
+     * returns them in some implementation specific order.
+     * <p/>
+     * TODO: respect orderable children (needed?)
+     *
+     * @return the children.
+     */
+    @Override
+    public Iterable<Tree> getChildren() {
+        return new Iterable<Tree>() {
+            @Override
+            public Iterator<Tree> iterator() {
+                final Iterator<? extends ChildNodeEntry> iterator =
+                        getNodeState().getChildNodeEntries().iterator();
+                return new Iterator<Tree>() {
+                    @Override
+                    public boolean hasNext() {
+                        return iterator.hasNext();
+                    }
+
+                    @Override
+                    public Tree next() {
+                        ChildNodeEntry entry = iterator.next();
+                        return new ImmutableTree(
+                                ImmutableTree.this,
+                                entry.getName(), entry.getNodeState());
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+
+    //--------------------------------------------------------------------------
+    public NodeState getNodeState() {
+        return state;
+    }
+
+    public int getType() {
+        return typeProvider.getType(this);
+    }
+
+    public static int getType(Tree tree) {
+        checkArgument(tree instanceof ImmutableTree);
+        return ((ImmutableTree) tree).getType();
+    }
+
+    @Nonnull
+    String getIdentifier() {
+        PropertyState property = state.getProperty(JcrConstants.JCR_UUID);
+        if (property != null) {
+            return property.getValue(STRING);
+        } else if (getParent().isRoot()) {
+            return "/";
+        } else {
+            return PathUtils.concat(getParent().getIdentifier(), getName());
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // TODO
+    public interface TypeProvider {
+
+        int TYPE_DEFAULT = 1;
+        int TYPE_VERSION = 2;
+        int TYPE_AC = 4;
+
+        TypeProvider EMPTY = new TypeProvider() {
+            @Override
+            public int getType(@Nullable ImmutableTree tree) {
+                return TYPE_DEFAULT;
+            }
+        };
+
+        int getType(ImmutableTree tree);
+    }
+
+    public static final class DefaultTypeProvider implements TypeProvider {
+
+        private final Context contextInfo;
+
+        public DefaultTypeProvider(@Nonnull Context contextInfo) {
+            this.contextInfo = contextInfo;
+        }
+
+        @Override
+        public int getType(ImmutableTree tree) {
+            ImmutableTree parent = tree.getParent();
+            if (parent == null) {
+                return TYPE_DEFAULT;
+            }
+
+            int type;
+            switch (parent.getType()) {
+                case TYPE_VERSION:
+                    type = parent.getType();
+                    break;
+                case TYPE_AC:
+                    type = parent.getType();
+                    break;
+                default:
+                    if (VersionConstants.VERSION_NODE_NAMES.contains(tree.getName()) ||
+                            VersionConstants.VERSION_NODE_TYPE_NAMES.contains(NodeStateUtils.getPrimaryTypeName(tree.getNodeState()))) {
+                        type = TYPE_VERSION;
+                    } else if (contextInfo.definesTree(tree)) {
+                        type = TYPE_AC;
+                    } else {
+                        type = TYPE_DEFAULT;
+                    }
+            }
+            return type;
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    public interface ParentProvider {
+
+        ParentProvider UNSUPPORTED = new ParentProvider() {
+            @Override
+            public ImmutableTree getParent() {
+                throw new UnsupportedOperationException("not supported.");
+            }
+        };
+
+        ParentProvider ROOTPROVIDER = new ParentProvider() {
+            @Override
+            public ImmutableTree getParent() {
+                return null;
+            }
+        };
+
+        @CheckForNull
+        ImmutableTree getParent();
+    }
+
+    public static final class DefaultParentProvider implements ParentProvider {
+
+        private ImmutableTree parent;
+
+        DefaultParentProvider(ImmutableTree parent) {
+            this.parent = checkNotNull(parent);
+        }
+
+        @Override
+        public ImmutableTree getParent() {
+            return parent;
+        }
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyTree.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyTree.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyTree.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ReadOnlyTree.java Tue Mar 12 14:57:44 2013
@@ -25,7 +25,6 @@ import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.TreeLocation;
 import org.apache.jackrabbit.oak.api.Type;
@@ -53,7 +52,7 @@ public class ReadOnlyTree implements Tre
     /**
      * Underlying node state
      */
-    private final NodeState state;
+    final NodeState state;
 
     public ReadOnlyTree(@Nonnull NodeState rootState) {
         this(null, "", rootState);
@@ -66,16 +65,6 @@ public class ReadOnlyTree implements Tre
         checkArgument(!name.isEmpty() || parent == null);
     }
 
-    public static ReadOnlyTree createFromRoot(Root root) {
-        if (root instanceof RootImpl) {
-            return new ReadOnlyTree(((RootImpl) root).getBaseState());
-        } else if (root instanceof ReadOnlyRoot) {
-            return ((ReadOnlyRoot) root).getTree("/");
-        } else {
-            throw new IllegalArgumentException("Unsupported Root implementation.");
-        }
-    }
-
     @Override
     public String getName() {
         return name;
@@ -252,7 +241,7 @@ public class ReadOnlyTree implements Tre
         return toStringHelper(this).add("path", getPath()).toString();
     }
 
-    //------------------------------------------------------------< internal >---
+    //-----------------------------------------------------------< internal >---
 
     @Nonnull
     String getIdentifier() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java Tue Mar 12 14:57:44 2013
@@ -46,6 +46,7 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.commit.PostValidationHook;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.observation.ChangeExtractor;
 import org.apache.jackrabbit.oak.spi.query.CompositeQueryIndexProvider;
@@ -293,19 +294,21 @@ public class RootImpl implements Root {
     private CommitHook getCommitHook() {
         List<CommitHook> commitHooks = new ArrayList<CommitHook>();
         commitHooks.add(hook);
-        List<CommitHook> securityHooks = new ArrayList<CommitHook>();
+        List<CommitHook> postValidationHooks = new ArrayList<CommitHook>();
         for (SecurityConfiguration sc : securityProvider.getSecurityConfigurations()) {
+            CommitHook ch = sc.getSecurityHooks().getCommitHook(workspaceName);
+            if (ch instanceof PostValidationHook) {
+                postValidationHooks.add(ch);
+            } else if (ch != EmptyHook.INSTANCE) {
+                commitHooks.add(ch);
+            }
             List<? extends ValidatorProvider> validators = sc.getValidators(workspaceName);
             if (!validators.isEmpty()) {
                 commitHooks.add(new EditorHook(
                         CompositeEditorProvider.compose(validators)));
             }
-            CommitHook ch = sc.getSecurityHooks().getCommitHook(workspaceName);
-            if (ch != EmptyHook.INSTANCE) {
-                securityHooks.add(ch);
-            }
         }
-        commitHooks.addAll(securityHooks);
+        commitHooks.addAll(postValidationHooks);
         return CompositeHook.compose(commitHooks);
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java Tue Mar 12 14:57:44 2013
@@ -21,7 +21,6 @@ package org.apache.jackrabbit.oak.plugin
 import java.util.Collections;
 import java.util.GregorianCalendar;
 import java.util.Iterator;
-
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -29,10 +28,10 @@ import org.apache.jackrabbit.oak.api.Roo
 import org.apache.jackrabbit.oak.api.TreeLocation;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.ReadOnlyRoot;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
-import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.core.IdentifierManager;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.plugins.value.Conversions;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -78,13 +77,13 @@ class ReadWriteVersionManager extends Re
     @Nonnull
     @Override
     protected TreeLocation getVersionStorageLocation() {
-        return new ReadOnlyTree(versionStorageNode.getNodeState()).getLocation();
+        return new ImmutableTree(versionStorageNode.getNodeState()).getLocation();
     }
 
     @Nonnull
     @Override
     protected Root getWorkspaceRoot() {
-        return new ReadOnlyRoot(workspaceRoot.getNodeState());
+        return new ImmutableRoot(workspaceRoot.getNodeState());
     }
 
     @Nonnull

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionablePathHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionablePathHook.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionablePathHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionablePathHook.java Tue Mar 12 14:57:44 2013
@@ -24,7 +24,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
@@ -114,8 +114,7 @@ public class VersionablePathHook impleme
         }
 
         private boolean isVersionable(ReadWriteVersionManager versionManager) {
-            // FIXME: this readonlytree is not properly connect to it's parent
-            Tree tree = new ReadOnlyTree(null, PathUtils.getName(path), builder.getNodeState());
+            Tree tree = new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, PathUtils.getName(path), builder.getNodeState());
             return versionManager.isVersionable(tree);
         }
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlValidatorProvider.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlValidatorProvider.java Tue Mar 12 14:57:44 2013
@@ -25,8 +25,8 @@ import com.google.common.collect.Immutab
 import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.core.ReadOnlyRoot;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.spi.commit.Validator;
@@ -59,8 +59,8 @@ class AccessControlValidatorProvider ext
     @Nonnull
     @Override
     public Validator getRootValidator(NodeState before, NodeState after) {
-        Tree rootBefore = new ReadOnlyTree(before);
-        Tree rootAfter = new ReadOnlyTree(after);
+        Tree rootBefore = new ImmutableTree(before);
+        Tree rootAfter = new ImmutableTree(after);
 
         AccessControlConfiguration acConfig = securityProvider.getAccessControlConfiguration();
         RestrictionProvider restrictionProvider = acConfig.getRestrictionProvider(NamePathMapper.DEFAULT);
@@ -72,7 +72,7 @@ class AccessControlValidatorProvider ext
     }
 
     private static Map<String, Privilege> getPrivileges(NodeState beforeRoot, PrivilegeConfiguration config) {
-        Root root = new ReadOnlyRoot(beforeRoot);
+        Root root = new ImmutableRoot(beforeRoot);
         PrivilegeManager pMgr = config.getPrivilegeManager(root, NamePathMapper.DEFAULT);
         ImmutableMap.Builder privileges = ImmutableMap.builder();
         try {
@@ -80,7 +80,7 @@ class AccessControlValidatorProvider ext
                 privileges.put(privilege.getName(), privilege);
             }
         } catch (RepositoryException e) {
-            log.error("Unexpected error: failed to read privileges.");
+            log.error("Unexpected error: failed to read privileges.", e);
         }
         return privileges.build();
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java Tue Mar 12 14:57:44 2013
@@ -26,47 +26,53 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.Iterables;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeBitsProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.Permissions;
-import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.util.TreeUtil;
 import org.apache.jackrabbit.util.Text;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * TODO
+ * TODO: WIP
  */
 class CompiledPermissionImpl implements CompiledPermissions, PermissionConstants {
 
     private final Set<Principal> principals;
     private final RestrictionProvider restrictionProvider;
-    private final Map<String, ReadOnlyTree> trees;
+    private final Map<String, ImmutableTree> trees;
 
     private PrivilegeBitsProvider bitsProvider;
+    private Map<Key, PermissionEntry> repoEntries;
     private Map<Key, PermissionEntry> userEntries;
     private Map<Key, PermissionEntry> groupEntries;
 
     CompiledPermissionImpl(@Nonnull Set<Principal> principals,
-                           @Nonnull ReadOnlyTree permissionsTree,
+                           @Nonnull ImmutableTree permissionsTree,
                            @Nonnull PrivilegeBitsProvider bitsProvider,
                            @Nonnull RestrictionProvider restrictionProvider) {
         checkArgument(!principals.isEmpty());
         this.principals = principals;
         this.restrictionProvider = restrictionProvider;
-        this.trees = new HashMap<String, ReadOnlyTree>(principals.size());
-        refresh(permissionsTree, bitsProvider);
+        this.trees = new HashMap<String, ImmutableTree>(principals.size());
+        buildEntries(permissionsTree);
     }
 
-    void refresh(@Nonnull ReadOnlyTree permissionsTree,
+    void refresh(@Nonnull ImmutableTree permissionsTree,
                  @Nonnull PrivilegeBitsProvider bitsProvider) {
         this.bitsProvider = bitsProvider;
         boolean refresh = false;
@@ -81,11 +87,10 @@ class CompiledPermissionImpl implements 
         }
         // test if any of the trees has been modified in the mean time
         if (!refresh) {
-            for (Map.Entry<String, ReadOnlyTree> entry : trees.entrySet()) {
-                ReadOnlyTree t = entry.getValue();
-                ReadOnlyTree t2 = permissionsTree.getChild(t.getName());
-                // TODO: OAK-660 or equivalent comparision
-                if (!t.equals(t2)) {
+            for (Map.Entry<String, ImmutableTree> entry : trees.entrySet()) {
+                ImmutableTree t = entry.getValue();
+                ImmutableTree t2 = permissionsTree.getChild(t.getName());
+                if (t2 != null && !t.getNodeState().equals(t2.getNodeState())) {
                     refresh = true;
                     break;
                 }
@@ -100,28 +105,29 @@ class CompiledPermissionImpl implements 
     //------------------------------------------------< CompiledPermissions >---
     @Override
     public boolean canRead(Tree tree) {
+        // TODO
         return isGranted(tree, Permissions.READ_NODE);
     }
 
     @Override
     public boolean canRead(Tree tree, PropertyState property) {
+        // TODO
         return isGranted(tree, property, Permissions.READ_PROPERTY);
     }
 
     @Override
     public boolean isGranted(long permissions) {
-        // TODO: only evaluate entries that are defined for the "" path.
-        return false;
+        return hasPermissions(null, permissions, repoEntries.values());
     }
 
     @Override
     public boolean isGranted(Tree tree, long permissions) {
-        return hasPermissions(tree, null, permissions);
+        return hasPermissions(tree, permissions, filterEntries(tree, null));
     }
 
     @Override
     public boolean isGranted(Tree parent, PropertyState property, long permissions) {
-        return hasPermissions(parent, property, permissions);
+        return hasPermissions(parent, permissions, filterEntries(parent, property));
     }
 
     @Override
@@ -141,32 +147,45 @@ class CompiledPermissionImpl implements 
     }
 
     //------------------------------------------------------------< private >---
+    @CheckForNull
+    private static ImmutableTree getPrincipalRoot(ImmutableTree permissionsTree, Principal principal) {
+        return permissionsTree.getChild(Text.escapeIllegalJcrChars(principal.getName()));
+    }
 
-    private void buildEntries(@Nullable ReadOnlyTree permissionsTree) {
+    private void buildEntries(@Nullable ImmutableTree permissionsTree) {
         if (permissionsTree == null) {
+            repoEntries = Collections.emptyMap();
             userEntries = Collections.emptyMap();
             groupEntries = Collections.emptyMap();
         } else {
             EntriesBuilder builder = new EntriesBuilder();
             for (Principal principal : principals) {
-                ReadOnlyTree t = getPrincipalRoot(permissionsTree, principal);
+                ImmutableTree t = getPrincipalRoot(permissionsTree, principal);
                 if (t != null) {
                     trees.put(principal.getName(), t);
-                    builder.addEntry(principal, t, restrictionProvider);
+                    builder.addEntries(principal, t, restrictionProvider);
                 }
             }
+            repoEntries = builder.repoEntries.build();
             userEntries = builder.userEntries.build();
             groupEntries = builder.groupEntries.build();
         }
     }
 
-    @CheckForNull
-    private static ReadOnlyTree getPrincipalRoot(ReadOnlyTree permissionsTree, Principal principal) {
-        return permissionsTree.getChild(Text.escapeIllegalJcrChars(principal.getName()));
+    private Iterable<PermissionEntry> filterEntries(final @Nonnull Tree tree, final @Nullable PropertyState property) {
+        return Iterables.filter(
+                Iterables.concat(userEntries.values(), groupEntries.values()),
+                new Predicate<PermissionEntry>() {
+                    @Override
+                    public boolean apply(@Nullable PermissionEntry entry) {
+                        return entry != null && entry.matches(tree, property);
+                    }
+                });
     }
 
-    private boolean hasPermissions(@Nonnull Tree tree, @Nullable PropertyState property,
-                                   long permissions) {
+    private boolean hasPermissions(@Nullable Tree tree,
+                                   long permissions,
+                                   Iterable<PermissionEntry> entries) {
         // TODO
         return false;
     }
@@ -179,18 +198,51 @@ class CompiledPermissionImpl implements 
 
     private static final class Key implements Comparable<Key> {
 
-        private String path;
-        private long index;
+        private final String path;
+        private final int depth;
+        private final long index;
 
         private Key(Tree tree) {
             path = Strings.emptyToNull(TreeUtil.getString(tree, REP_ACCESS_CONTROLLED_PATH));
-            index = tree.getProperty(REP_INDEX).getValue(Type.LONG);
+            depth = (path == null) ? 0 : PathUtils.getDepth(path);
+            index = checkNotNull(tree.getProperty(REP_INDEX).getValue(Type.LONG)).longValue();
         }
 
         @Override
         public int compareTo(Key key) {
-            // TODO
-            return 0;
+            checkNotNull(key);
+            if (Objects.equal(path, key.path)) {
+                if (index == key.index) {
+                    return 0;
+                } else if (index < key.index) {
+                    return -1;
+                } else {
+                    return 1;
+                }
+            } else {
+                if (depth == key.depth) {
+                    return path.compareTo(key.path);
+                } else {
+                    return (depth < key.depth) ? -1 : 1;
+                }
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(path, index);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (o instanceof Key) {
+                Key other = (Key) o;
+                return index == other.index && Objects.equal(path, other.path);
+            }
+            return false;
         }
     }
 
@@ -198,12 +250,23 @@ class CompiledPermissionImpl implements 
 
         private final boolean isAllow;
         private final PrivilegeBits privilegeBits;
-        private final Set<Restriction> restrictions;
+        private final String path;
+        private final RestrictionPattern restriction;
 
         private PermissionEntry(String accessControlledPath, Tree entryTree, RestrictionProvider restrictionsProvider) {
             isAllow = (PREFIX_ALLOW == entryTree.getName().charAt(0));
             privilegeBits = PrivilegeBits.getInstance(entryTree.getProperty(REP_PRIVILEGE_BITS));
-            restrictions = restrictionsProvider.readRestrictions(accessControlledPath, entryTree);
+            this.path = accessControlledPath;
+            restriction = restrictionsProvider.getPattern(accessControlledPath, entryTree);
+        }
+
+        private boolean matches(@Nonnull Tree tree, @Nullable PropertyState property) {
+            String treePath = tree.getPath();
+            if (Text.isDescendantOrEqual(path, treePath)) {
+                return restriction.matches(tree, property);
+            } else {
+                return false;
+            }
         }
     }
 
@@ -213,19 +276,26 @@ class CompiledPermissionImpl implements 
      */
     private static final class EntriesBuilder {
 
+        private ImmutableSortedMap.Builder<Key, PermissionEntry> repoEntries = ImmutableSortedMap.naturalOrder();
         private ImmutableSortedMap.Builder<Key, PermissionEntry> userEntries = ImmutableSortedMap.naturalOrder();
         private ImmutableSortedMap.Builder<Key, PermissionEntry> groupEntries = ImmutableSortedMap.naturalOrder();
 
-        private void addEntry(@Nonnull Principal principal,
-                              @Nonnull Tree entryTree,
+        private void addEntries(@Nonnull Principal principal,
+                              @Nonnull Tree principalRoot,
                               @Nonnull RestrictionProvider restrictionProvider) {
-            Key key = new Key(entryTree);
-            PermissionEntry entry = new PermissionEntry(key.path, entryTree, restrictionProvider);
-            if (!entry.privilegeBits.isEmpty()) {
-                if (principal instanceof Group) {
-                    groupEntries.put(key, entry);
-                } else {
-                    userEntries.put(key, entry);
+            for (Tree entryTree : principalRoot.getChildren()) {
+                Key key = new Key(entryTree);
+                PermissionEntry entry = new PermissionEntry(key.path, entryTree, restrictionProvider);
+                if (!entry.privilegeBits.isEmpty()) {
+                    if (key.path == null) {
+                        repoEntries.put(key, entry);
+                    } else {
+                        if (principal instanceof Group) {
+                            groupEntries.put(key, entry);
+                        } else {
+                            userEntries.put(key, entry);
+                        }
+                    }
                 }
             }
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java Tue Mar 12 14:57:44 2013
@@ -28,8 +28,8 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.ReadOnlyRoot;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.core.TreeImpl;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
@@ -37,7 +37,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeBitsProvider;
-import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.PostValidationHook;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -56,7 +56,7 @@ import static org.apache.jackrabbit.JcrC
  * access control content and updates persisted permission caches associated
  * with access control related data stored in the repository.
  */
-public class PermissionHook implements CommitHook, AccessControlConstants, PermissionConstants {
+public class PermissionHook implements PostValidationHook, AccessControlConstants, PermissionConstants {
 
     private static final Logger log = LoggerFactory.getLogger(PermissionHook.class);
 
@@ -79,7 +79,7 @@ public class PermissionHook implements C
 
         permissionRoot = getPermissionRoot(rootAfter, workspaceName);
         ntMgr = ReadOnlyNodeTypeManager.getInstance(before);
-        bitsProvider = new PrivilegeBitsProvider(new ReadOnlyRoot(before));
+        bitsProvider = new PrivilegeBitsProvider(new ImmutableRoot(before));
 
         after.compareAgainstBaseState(before, new Diff(new BeforeNode(before), new Node(rootAfter)));
         return rootAfter.getNodeState();
@@ -102,8 +102,7 @@ public class PermissionHook implements C
     }
 
     private static Tree getTree(String name, NodeState nodeState) {
-        // FIXME: this readonlytree is not properly connect to it's parent
-        return new ReadOnlyTree(null, name, nodeState);
+        return new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, name, nodeState, ImmutableTree.TypeProvider.EMPTY);
     }
 
     private static String getAccessControlledPath(BaseNode aclNode) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java Tue Mar 12 14:57:44 2013
@@ -30,13 +30,12 @@ import org.apache.jackrabbit.oak.api.Tre
 import org.apache.jackrabbit.oak.api.TreeLocation;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.ReadOnlyRoot;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
 import org.apache.jackrabbit.oak.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeBitsProvider;
-import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.PermissionProvider;
@@ -44,7 +43,6 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.principal.AdminPrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.SystemPrincipal;
 import org.apache.jackrabbit.oak.util.TreeUtil;
-import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,21 +60,20 @@ public class PermissionProviderImpl impl
 
     private final Root root;
 
-    private final Context acContext;
-
     private final String workspaceName = "default"; // FIXME: use proper workspace as associated with the root
 
+    private final AccessControlConfiguration acConfig;
+
     private final CompiledPermissions compiledPermissions;
 
     public PermissionProviderImpl(@Nonnull Root root, @Nonnull Set<Principal> principals,
                                   @Nonnull SecurityProvider securityProvider) {
         this.root = root;
-        AccessControlConfiguration acConfig = securityProvider.getAccessControlConfiguration();
-        this.acContext = acConfig.getContext();
+        acConfig = securityProvider.getAccessControlConfiguration();
         if (principals.contains(SystemPrincipal.INSTANCE) || isAdmin(principals)) {
             compiledPermissions = AllPermissions.getInstance();
         } else {
-            ReadOnlyTree permissionsTree = getPermissionsRoot();
+            ImmutableTree permissionsTree = getPermissionsRoot();
             if (permissionsTree == null || principals.isEmpty()) {
                 compiledPermissions = NoPermissions.getInstance();
             } else {
@@ -152,7 +149,7 @@ public class PermissionProviderImpl impl
 
     @Override
     public boolean hasPermission(@Nonnull String oakPath, @Nonnull String jcrActions) {
-        TreeLocation location = getReadOnlyRoot().getLocation(oakPath);
+        TreeLocation location = getImmutableRoot().getLocation(oakPath);
         long permissions = Permissions.getPermissions(jcrActions, location);
         if (!location.exists()) {
             // TODO: deal with version content
@@ -180,29 +177,29 @@ public class PermissionProviderImpl impl
         return false;
     }
 
-    private ReadOnlyRoot getReadOnlyRoot() {
-        if (root instanceof ReadOnlyRoot) {
-            return (ReadOnlyRoot) root;
+    private ImmutableRoot getImmutableRoot() {
+        if (root instanceof ImmutableRoot) {
+            return (ImmutableRoot) root;
         } else {
-            return new ReadOnlyRoot(root);
+            return new ImmutableRoot(root, new ImmutableTree.DefaultTypeProvider(acConfig.getContext()));
         }
     }
 
     @CheckForNull
-    private ReadOnlyTree getPermissionsRoot() {
+    private ImmutableTree getPermissionsRoot() {
         String relativePath = PERMISSIONS_STORE_PATH + '/' + workspaceName;
-        ReadOnlyTree rootTree = checkNotNull(getReadOnlyRoot().getTree("/"));
+        ImmutableTree rootTree = checkNotNull(getImmutableRoot().getTree("/"));
         Tree tree = rootTree.getLocation().getChild(relativePath).getTree();
-        return (tree == null) ? null : (ReadOnlyTree) tree;
+        return (tree == null) ? null : (ImmutableTree) tree;
     }
 
     @Nonnull
     private PrivilegeBitsProvider getBitsProvider() {
-        return new PrivilegeBitsProvider(getReadOnlyRoot());
+        return new PrivilegeBitsProvider(getImmutableRoot());
     }
 
     private boolean isAccessControlContent(@Nonnull Tree tree) {
-        return acContext.definesTree(tree);
+        return ImmutableTree.TypeProvider.TYPE_AC == ImmutableTree.getType(tree);
     }
 
     private boolean canReadAccessControlContent(@Nonnull Tree acTree, @Nullable PropertyState acProperty) {
@@ -214,20 +211,7 @@ public class PermissionProviderImpl impl
     }
 
     private static boolean isVersionContent(@Nonnull Tree tree) {
-        if (tree.isRoot()) {
-            return false;
-        }
-        if (VersionConstants.VERSION_NODE_NAMES.contains(tree.getName())) {
-            return true;
-        } else if (VersionConstants.VERSION_NODE_TYPE_NAMES.contains(TreeUtil.getPrimaryTypeName(tree))) {
-            return true;
-        } else {
-            return isVersionContent(tree.getPath());
-        }
-    }
-
-    private static boolean isVersionContent(@Nonnull String path) {
-        return VersionConstants.SYSTEM_PATHS.contains(Text.getAbsoluteParent(path, 1));
+        return ImmutableTree.TypeProvider.TYPE_VERSION == ImmutableTree.getType(tree);
     }
 
     private boolean canReadVersionContent(@Nonnull Tree versionStoreTree, @Nullable PropertyState property) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java Tue Mar 12 14:57:44 2013
@@ -23,13 +23,15 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.security.auth.Subject;
 
-import org.apache.jackrabbit.oak.core.ReadOnlyRoot;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.spi.commit.Validator;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.PermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
@@ -52,13 +54,8 @@ public class PermissionValidatorProvider
     @Nonnull
     @Override
     public Validator getRootValidator(NodeState before, NodeState after) {
-        Subject subject = Subject.getSubject(AccessController.getContext());
-        Set<Principal> principals = (subject != null) ? subject.getPrincipals() : Collections.<Principal>emptySet();
-
-        ReadOnlyRoot root = new ReadOnlyRoot(before);
-        PermissionProvider pp = securityProvider.getAccessControlConfiguration().getPermissionProvider(root, principals);
-
-        return new PermissionValidator(new ReadOnlyTree(before), new ReadOnlyTree(after), pp, this);
+        PermissionProvider pp = getPermissionProvider(before);
+        return new PermissionValidator(createTree(before), createTree(after), pp, this);
     }
 
     //--------------------------------------------------------------------------
@@ -76,4 +73,19 @@ public class PermissionValidatorProvider
         }
         return userCtx;
     }
+
+    private ImmutableTree createTree(NodeState root) {
+        return new ImmutableTree(root, new ImmutableTree.DefaultTypeProvider(getAccessControlContext()));
+    }
+
+    private PermissionProvider getPermissionProvider(NodeState before) {
+        Subject subject = Subject.getSubject(AccessController.getContext());
+        if (subject == null || subject.getPublicCredentials(PrincipalProvider.class).isEmpty()) {
+            Set<Principal> principals = (subject != null) ? subject.getPrincipals() : Collections.<Principal>emptySet();
+            AccessControlConfiguration acConfig = securityProvider.getAccessControlConfiguration();
+            return acConfig.getPermissionProvider(new ImmutableRoot(createTree(before)), principals);
+        } else {
+            return subject.getPublicCredentials(PermissionProvider.class).iterator().next();
+        }
+    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java Tue Mar 12 14:57:44 2013
@@ -21,7 +21,7 @@ import javax.annotation.Nonnull;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.PostValidationHook;
 import org.apache.jackrabbit.oak.spi.state.EmptyNodeStateDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -33,7 +33,7 @@ import org.apache.jackrabbit.util.Text;
  * JcrAllCommitHook is responsible for updating the jcr:all privilege definition
  * upon successful registration of a new privilege.
  */
-public class JcrAllCommitHook implements CommitHook, PrivilegeConstants {
+public class JcrAllCommitHook implements PostValidationHook, PrivilegeConstants {
 
     @Nonnull
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java Tue Mar 12 14:57:44 2013
@@ -22,18 +22,17 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.jcr.RepositoryException;
 
-import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.core.ReadOnlyRoot;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants;
 import org.apache.jackrabbit.oak.spi.commit.Validator;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.TreeUtil;
 import org.apache.jackrabbit.util.Text;
 
 /**
@@ -47,8 +46,8 @@ class PrivilegeValidator implements Priv
     private final PrivilegeBitsProvider bitsProvider;
 
     PrivilegeValidator(NodeState before, NodeState after) {
-        rootBefore = new ReadOnlyRoot(before);
-        rootAfter = new ReadOnlyRoot(after);
+        rootBefore = new ImmutableRoot(before);
+        rootAfter = new ImmutableRoot(after);
         bitsProvider = new PrivilegeBitsProvider(rootBefore);
     }
 
@@ -89,9 +88,8 @@ class PrivilegeValidator implements Priv
         }
 
         // primary node type name must be rep:privilege
-        Tree tree = new ReadOnlyTree(null, name, after);
-        PropertyState primaryType = tree.getProperty(JcrConstants.JCR_PRIMARYTYPE);
-        if (primaryType == null || !NT_REP_PRIVILEGE.equals(primaryType.getValue(Type.STRING))) {
+        Tree tree = new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, name, after);
+        if (!NT_REP_PRIVILEGE.equals(TreeUtil.getPrimaryTypeName(tree))) {
             throw new CommitFailedException("Privilege definition must have primary node type set to rep:privilege");
         }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidatorProvider.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidatorProvider.java Tue Mar 12 14:57:44 2013
@@ -18,7 +18,7 @@ package org.apache.jackrabbit.oak.securi
 
 import javax.annotation.Nonnull;
 
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.spi.commit.Validator;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
@@ -41,7 +41,7 @@ class UserValidatorProvider extends Vali
     @Nonnull
     @Override
     public Validator getRootValidator(NodeState before, NodeState after) {
-        return new UserValidator(new ReadOnlyTree(before), new ReadOnlyTree(after), this);
+        return new UserValidator(new ImmutableTree(before), new ImmutableTree(after), this);
     }
 
     //-----------------------------------------------------------< internal >---

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/PostValidationHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/PostValidationHook.java?rev=1455565&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/PostValidationHook.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/PostValidationHook.java Tue Mar 12 14:57:44 2013
@@ -0,0 +1,25 @@
+/*
+ * 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.oak.spi.commit;
+
+/**
+ * Extension to the {@code CommitHook} interface that indicates that this
+ * commit hook implementation must be executed <strong>after</strong> the
+ * validation hooks.
+ */
+public interface PostValidationHook extends CommitHook {
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateUtils.java?rev=1455565&r1=1455564&r2=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateUtils.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateUtils.java Tue Mar 12 14:57:44 2013
@@ -16,6 +16,12 @@
  */
 package org.apache.jackrabbit.oak.spi.state;
 
+import javax.annotation.CheckForNull;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+
 /**
  * Utility method for code that deals with node states.
  */
@@ -35,4 +41,9 @@ public final class NodeStateUtils {
         return name.startsWith(":");
     }
 
+    @CheckForNull
+    public static String getPrimaryTypeName(NodeState nodeState) {
+        PropertyState ps = nodeState.getProperty(JcrConstants.JCR_PRIMARYTYPE);
+        return (ps == null) ? null : ps.getValue(Type.STRING);
+    }
 }

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableRootTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableRootTest.java?rev=1455565&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableRootTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableRootTest.java Tue Mar 12 14:57:44 2013
@@ -0,0 +1,109 @@
+/*
+ * 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.oak.core;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+public class ImmutableRootTest {
+
+    private ImmutableRoot root;
+
+    @Before
+    public void setUp() throws CommitFailedException {
+        ContentSession session = new Oak().createContentSession();
+
+        // Add test content
+        Root root = session.getLatestRoot();
+        Tree tree = root.getTree("/");
+        Tree x = tree.addChild("x");
+        Tree y = x.addChild("y");
+        Tree z = y.addChild("z");
+        root.commit();
+
+        // Acquire a fresh new root to avoid problems from lingering state
+        this.root = new ImmutableRoot(session.getLatestRoot(), ImmutableTree.TypeProvider.EMPTY);
+    }
+
+    // TODO: add more tests
+
+    @Test
+    public void testHasPendingChanges() {
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testImmutable() {
+
+        try {
+            root.commit();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+
+        try {
+            root.rebase();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+
+        try {
+            root.refresh();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+
+        try {
+            root.getBlobFactory();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+
+        try {
+            root.getQueryEngine();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+
+        try {
+            root.move("/x", "/b");
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+
+        try {
+            root.copy("/x", "/b");
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+    }
+}
\ No newline at end of file

Copied: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java (from r1455473, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ReadOnlyTreeTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java?p2=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java&p1=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ReadOnlyTreeTest.java&r1=1455473&r2=1455565&rev=1455565&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ReadOnlyTreeTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java Tue Mar 12 14:57:44 2013
@@ -28,8 +28,11 @@ import org.junit.Before;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
-public class ReadOnlyTreeTest {
+public class ImmutableTreeTest {
 
     private Root root;
 
@@ -58,16 +61,53 @@ public class ReadOnlyTreeTest {
     public void testGetPath() {
         TreeImpl tree = (TreeImpl) root.getTree("/");
 
-        ReadOnlyTree readOnly = new ReadOnlyTree(tree.getNodeState());
-        assertEquals("/", readOnly.getPath());
+        ImmutableTree immutable = new ImmutableTree(tree.getNodeState());
+        assertEquals("/", immutable.getPath());
 
-        readOnly = readOnly.getChild("x");
-        assertEquals("/x", readOnly.getPath());
+        immutable = immutable.getChild("x");
+        assertEquals("/x", immutable.getPath());
 
-        readOnly = readOnly.getChild("y");
-        assertEquals("/x/y", readOnly.getPath());
+        immutable = immutable.getChild("y");
+        assertEquals("/x/y", immutable.getPath());
 
-        readOnly = readOnly.getChild("z");
-        assertEquals("/x/y/z", readOnly.getPath());
+        immutable = immutable.getChild("z");
+        assertEquals("/x/y/z", immutable.getPath());
+    }
+
+    @Test
+    public void testGetNodeState() {
+        ImmutableTree tree = ImmutableTree.createFromRoot(root, ImmutableTree.TypeProvider.EMPTY);
+        assertNotNull(tree.getNodeState());
+
+        for (Tree child : tree.getChildren()) {
+            assertTrue(child instanceof ImmutableTree);
+            assertNotNull(((ImmutableTree) child).getNodeState());
+        }
+    }
+
+    @Test
+    public void testRoot() {
+        ImmutableTree tree = ImmutableTree.createFromRoot(root, ImmutableTree.TypeProvider.EMPTY);
+        assertTrue(tree.isRoot());
+        assertNull(tree.getParent());
+        assertEquals("", tree.getName());
+        assertEquals(ImmutableTree.TypeProvider.TYPE_DEFAULT, tree.getType());
+    }
+
+    @Test
+    public void testGetParent() {
+        ImmutableTree tree = ImmutableTree.createFromRoot(root, ImmutableTree.TypeProvider.EMPTY);
+        assertNull(tree.getParent());
+
+        ImmutableTree child = tree.getChild("x");
+        assertNotNull(child.getParent());
+        assertEquals("/", child.getParent().getPath());
+
+        ImmutableTree disconnected = new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, child.getName(), child.getNodeState(), ImmutableTree.TypeProvider.EMPTY);
+        try {
+            disconnected.getParent();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
     }
 }