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 2015/10/23 11:37:39 UTC

svn commit: r1710159 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/version/ test/java/org/apache/jackrabbit/oak/ test/java/org/apache/jackrabbit/oak/plugins/version/ test/java/org/apache/jackrabbit/oak/security/au...

Author: angela
Date: Fri Oct 23 09:37:38 2015
New Revision: 1710159

URL: http://svn.apache.org/viewvc?rev=1710159&view=rev
Log:
OAK-3543 : Add ReadOnlyVersionManager.getVersionable

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/package-info.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java?rev=1710159&r1=1710158&r2=1710159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java Fri Oct 23 09:37:38 2015
@@ -23,14 +23,18 @@ import javax.annotation.Nonnull;
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
 
+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.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -40,6 +44,8 @@ import static com.google.common.base.Pre
  */
 public abstract class ReadOnlyVersionManager {
 
+    private static final Logger log = LoggerFactory.getLogger(ReadOnlyVersionManager.class);
+
     /**
      * @return the read-only {@link Tree} for the jcr:versionStorage node. The
      *         returned {@code Tree} instance must be up-to-date with the
@@ -49,7 +55,7 @@ public abstract class ReadOnlyVersionMan
     protected abstract Tree getVersionStorage();
 
     /**
-    /**
+     /**
      * @return the {@code Root} of the workspace.
      */
     @Nonnull
@@ -61,6 +67,40 @@ public abstract class ReadOnlyVersionMan
     @Nonnull
     protected abstract ReadOnlyNodeTypeManager getNodeTypeManager();
 
+    //--------------------------------------------------------------------------
+
+    /**
+     * Return a new instance of {@code ReadOnlyVersionManager} that reads version
+     * information from the tree at {@link VersionConstants#VERSION_STORE_PATH}.
+     *
+     * @param root The root to read version information from.
+     * @param namePathMapper The {@code NamePathMapper} to use.
+     * @return a new instance of {@code ReadOnlyVersionManager}.
+     */
+    @Nonnull
+    public static ReadOnlyVersionManager getInstance(final Root root,
+                                                     final NamePathMapper namePathMapper) {
+        return new ReadOnlyVersionManager() {
+            @Nonnull
+            @Override
+            protected Tree getVersionStorage() {
+                return root.getTree(VersionConstants.VERSION_STORE_PATH);
+            }
+
+            @Nonnull
+            @Override
+            protected Root getWorkspaceRoot() {
+                return root;
+            }
+
+            @Nonnull
+            @Override
+            protected ReadOnlyNodeTypeManager getNodeTypeManager() {
+                return ReadOnlyNodeTypeManager.getInstance(root, namePathMapper);
+            }
+        };
+    }
+
     /**
      * Returns {@code true} if the tree is checked out; otherwise
      * {@code false}. The root node is always considered checked out.
@@ -166,6 +206,80 @@ public abstract class ReadOnlyVersionMan
         return getIdentifierManager().getTree(p.getValue(Type.STRING));
     }
 
+    /**
+     * Returns {@code true} if the specified tree has {@link VersionConstants#REP_VERSIONSTORAGE}
+     * defines as primary node type i.e. is part of the intermediate version storage
+     * structure that contains the version histories and the versions.
+     *
+     * @param tree The tree to be tested.
+     * @return {@code true} if the target node has {@link VersionConstants#REP_VERSIONSTORAGE}
+     * defines as primary node type; {@code false} otherwise.
+     */
+    public static boolean isVersionStoreTree(@Nonnull Tree tree) {
+        return VersionConstants.REP_VERSIONSTORAGE.equals(TreeUtil.getPrimaryTypeName(tree));
+    }
+
+    /**
+     * Tries to retrieve the tree corresponding to specified {@code versionTree}
+     * outside of the version storage based on versionable path information
+     * stored with the version history. The following cases are distinguished:
+     *
+     * <ul>
+     *     <li>Version History: If the given tree is a version history the
+     *     associated versionable tree in the specified workspace is being returned
+     *     based on the information stored in the versionable path property. If
+     *     no versionable path property is present {@code null} is returned.</li>
+     *     <li>Version: Same as for version history.</li>
+     *     <li>Version Labels: Same as for version history.</li>
+     *     <li>Frozen Node: If the given tree forms part of a frozen node the
+     *     path of the target node is computed from the versionable path and
+     *     the relative path of the frozen node.</li>
+     *     <li>Other Nodes: If the specified tree is not part of the tree structure
+     *     defined by a version history, {@code null} will be returned.</li>
+     * </ul>
+     *
+     * Please note that this method will not verify if the tree at the versionable
+     * path or the computed subtree actually exists. This must be asserted by
+     * the caller before operating on the tree.
+     *
+     * @param versionTree The tree from within the version storage for which
+     *                    that versionable correspondent should be retrieved.
+     * @param workspaceName The name of the workspace for which the target should be retrieved.
+     * @return A existing or non-existing tree pointing to the location of the
+     * correspondent tree outside of the version storage or {@code null} if the
+     * versionable path property for the specified workspace is missing or if
+     * the given tree is not located within the tree structure defined by a version history.
+     *
+     * @see {@link VersionablePathHook}
+     * @see {@link VersionConstants#MIX_REP_VERSIONABLE_PATHS}
+     */
+    @CheckForNull
+    public Tree getVersionable(@Nonnull Tree versionTree, @Nonnull String workspaceName) {
+        Root root = getWorkspaceRoot();
+        String relPath = "";
+        Tree t = versionTree;
+        while (t.exists() && !isVersionStoreTree(t) && !t.isRoot()) {
+            String ntName = TreeUtil.getPrimaryTypeName(t);
+            if (VersionConstants.NT_FROZENNODE.equals(ntName)) {
+                relPath = PathUtils.relativize(t.getPath(), versionTree.getPath());
+            } else if (JcrConstants.NT_VERSIONHISTORY.equals(ntName)) {
+                PropertyState prop = t.getProperty(workspaceName);
+                if (prop != null) {
+                    return root.getTree(PathUtils.concat(prop.getValue(Type.PATH), relPath));
+                } else {
+                    // version history is missing the versionable path property for the given workspace name
+                    log.warn("Missing versionable path property for {} at {}", workspaceName, t.getPath());
+                    break;
+                }
+            }
+            t = t.getParent();
+        }
+
+        // intermediate node in the version storage that matches none of the special
+        // conditions checked above and cannot be resolve to a versionable tree.
+        return null;
+    }
+
     //----------------------------< internal >----------------------------------
     /**
      * @return an identifier manager that is able to resolve identifiers of

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/package-info.java?rev=1710159&r1=1710158&r2=1710159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/package-info.java Fri Oct 23 09:37:38 2015
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("1.1.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.plugins.version;
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1710159&r1=1710158&r2=1710159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java Fri Oct 23 09:37:38 2015
@@ -52,7 +52,9 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
 import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
 import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+import org.apache.jackrabbit.oak.plugins.version.VersionEditorProvider;
 import org.apache.jackrabbit.oak.security.SecurityProviderImpl;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 import org.apache.jackrabbit.oak.spi.security.authentication.ConfigurationUtil;
@@ -82,6 +84,7 @@ public abstract class AbstractSecurityTe
     public void before() throws Exception {
         Oak oak = new Oak()
                 .with(new InitialContent())
+                .with(new EditorHook(new VersionEditorProvider()))
                 .with(JcrConflictHandler.createJcrConflictHandler())
                 .with(new NamespaceEditorProvider())
                 .with(new ReferenceEditorProvider())

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java?rev=1710159&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java Fri Oct 23 09:37:38 2015
@@ -0,0 +1,169 @@
+/*
+ * 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.plugins.version;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_ISCHECKEDOUT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class ReadOnlyVersionManagerTest extends AbstractSecurityTest {
+
+    private Tree versionable;
+    private String workspaceName;
+
+    private ReadOnlyVersionManager versionManager;
+
+    @Override
+    @Before
+    public void before() throws Exception {
+        super.before();
+
+        NodeUtil node = new NodeUtil(root.getTree("/"));
+        NodeUtil a = node.addChild("a", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        a.addChild("b", NodeTypeConstants.NT_OAK_UNSTRUCTURED).addChild("c", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
+
+        TreeUtil.addMixin(a.getTree(), JcrConstants.MIX_VERSIONABLE, root.getTree(NodeTypeConstants.NODE_TYPES_PATH), null);
+        root.commit();
+
+        versionable = root.getTree("/a");
+
+        // force the creation of a version that has a frozen node
+        versionable.setProperty(JCR_ISCHECKEDOUT, Boolean.FALSE, Type.BOOLEAN);
+        root.commit();
+        versionable.setProperty(JCR_ISCHECKEDOUT, Boolean.TRUE, Type.BOOLEAN);
+        root.commit();
+
+        versionManager = ReadOnlyVersionManager.getInstance(root, NamePathMapper.DEFAULT);
+        workspaceName = root.getContentSession().getWorkspaceName();
+    }
+
+    @Override
+    @After
+    public void after() throws Exception {
+        try {
+            root.refresh();
+
+            Tree a = root.getTree("/a");
+            if (a.exists()) {
+                a.remove();
+                root.commit();
+            }
+        } finally {
+            super.after();
+        }
+    }
+
+    @Test
+    public void testIsVersionStoreTree() throws Exception {
+        assertFalse(ReadOnlyVersionManager.isVersionStoreTree(root.getTree("/")));
+        assertFalse(ReadOnlyVersionManager.isVersionStoreTree(root.getTree("/a")));
+        assertFalse(ReadOnlyVersionManager.isVersionStoreTree(root.getTree("/a/b/c")));
+
+        assertTrue(ReadOnlyVersionManager.isVersionStoreTree(root.getTree(VersionConstants.VERSION_STORE_PATH)));
+
+        Tree versionHistory = versionManager.getVersionHistory(root.getTree("/a"));
+        assertNotNull(versionHistory);
+        assertFalse(ReadOnlyVersionManager.isVersionStoreTree(versionHistory));
+        assertTrue(ReadOnlyVersionManager.isVersionStoreTree(versionHistory.getParent()));
+    }
+
+    @Test
+    public void testGetVersionable() throws Exception {
+        Tree versionHistory = checkNotNull(versionManager.getVersionHistory(root.getTree("/a")));
+        assertVersionable("/a", versionHistory);
+
+        Tree rootVersion = versionHistory.getChild(JcrConstants.JCR_ROOTVERSION);
+        assertVersionable("/a", rootVersion);
+
+        Tree baseVersion = checkNotNull(versionManager.getBaseVersion(versionable));
+        assertVersionable("/a", baseVersion);
+
+        Tree frozen = baseVersion.getChild(VersionConstants.JCR_FROZENNODE);
+        assertVersionable("/a", frozen);
+
+        Tree frozenB = frozen.getChild("b");
+        assertVersionable("/a/b", frozenB);
+
+        Tree frozenC = frozenB.getChild("c");
+        assertVersionable("/a/b/c", frozenC);
+    }
+
+
+    private void assertVersionable(@Nonnull String expectedPath, @Nonnull Tree versionTree) {
+        String p = versionTree.getPath();
+        assertTrue(p, versionTree.exists());
+
+        Tree versionable = versionManager.getVersionable(versionTree, workspaceName);
+        assertNotNull(p, versionable);
+        assertEquals(p, expectedPath, versionable.getPath());
+    }
+
+    @Test
+    public void testGetVersionableForNonVersionTree() throws Exception {
+        assertNull(versionManager.getVersionable(versionManager.getVersionStorage(), workspaceName));
+        assertNull(versionManager.getVersionable(versionable, workspaceName));
+        assertNull(versionManager.getVersionable(root.getTree("/"), workspaceName));
+    }
+
+    @Test
+    public void testGetVersionableMissingPathProperty() throws Exception {
+        Tree versionHistory = checkNotNull(versionManager.getVersionHistory(root.getTree("/a")));
+        versionHistory.removeProperty(workspaceName);
+
+        assertNull(versionManager.getVersionable(versionHistory, workspaceName));
+        assertNull(versionManager.getVersionable(versionHistory.getChild(JcrConstants.JCR_ROOTVERSION), workspaceName));
+    }
+
+    @Test
+    public void testGetVersionableNonExistingWorkspace() throws Exception {
+        Tree versionHistory = checkNotNull(versionManager.getVersionHistory(root.getTree("/a")));
+
+        assertNull(versionManager.getVersionable(versionHistory, "nonExistingWorkspaceName"));
+        assertNull(versionManager.getVersionable(versionHistory.getChild(JcrConstants.JCR_ROOTVERSION), "nonExistingWorkspaceName"));
+    }
+
+    @Test
+    public void testGetVersionableTargetRemoved() throws Exception {
+        Tree baseVersion = checkNotNull(versionManager.getBaseVersion(versionable));
+
+        versionable.remove();
+        root.commit();
+
+        Tree t = versionManager.getVersionable(baseVersion, workspaceName);
+        assertNotNull(t);
+        assertFalse(t.exists());
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java?rev=1710159&r1=1710158&r2=1710159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java Fri Oct 23 09:37:38 2015
@@ -100,11 +100,6 @@ public class VersionStorageTest extends
         root.commit();
     }
 
-    @Override
-    protected Oak withEditors(Oak oak) {
-        return oak.with(new VersionEditorProvider());
-    }
-
     @Test
     public void testGetVersionStorage() throws Exception {
         Tree vs = getTestRoot().getTree(VersionConstants.VERSION_STORE_PATH);