Author: baedke
Date: Mon Mar 21 14:50:03 2016
New Revision: 1735983

URL: http://svn.apache.org/viewvc?rev=1735983&view=rev
Log:
OAK-3910: Migrating node inheriting from mix:versionable without version history

Creating empty version histories for certain inconsistent versionable nodes 
during Crx2Oak migration. Patch supplied by Tomek Rekawek (tom...@apache.com).

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java
    
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
    
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java

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=1735983&r1=1735982&r2=1735983&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
 Mon Mar 21 14:50:03 2016
@@ -74,13 +74,13 @@ import static org.apache.jackrabbit.oak.
  * Extends the {@link ReadOnlyVersionManager} with methods to modify the
  * version store.
  */
-class ReadWriteVersionManager extends ReadOnlyVersionManager {
+public class ReadWriteVersionManager extends ReadOnlyVersionManager {
 
     private final NodeBuilder versionStorageNode;
     private final NodeBuilder workspaceRoot;
     private ReadOnlyNodeTypeManager ntMgr;
 
-    ReadWriteVersionManager(NodeBuilder versionStorageNode,
+    public ReadWriteVersionManager(NodeBuilder versionStorageNode,
                             NodeBuilder workspaceRoot) {
         this.versionStorageNode = checkNotNull(versionStorageNode);
         this.workspaceRoot = checkNotNull(workspaceRoot);
@@ -119,7 +119,7 @@ class ReadWriteVersionManager extends Re
      *                                  {@code jcr:uuid} property.
      */
     @Nonnull
-    NodeBuilder getOrCreateVersionHistory(@Nonnull NodeBuilder versionable, 
@Nonnull Map<String, Object> infoMap)
+    public NodeBuilder getOrCreateVersionHistory(@Nonnull NodeBuilder 
versionable, @Nonnull Map<String, Object> infoMap)
             throws CommitFailedException {
         checkNotNull(versionable);
         String vUUID = uuidFromNode(versionable);
@@ -379,7 +379,7 @@ class ReadWriteVersionManager extends Re
 
         // jcr:frozenNode of created version
         VersionableState versionableState = VersionableState.fromVersion(
-                version, vHistory, versionable, this, ntMgr);
+                version, vHistory, versionable, this, getNodeTypeManager());
         if (!isRootVersion) {
             versionableState.create();
         }

Modified: 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java?rev=1735983&r1=1735982&r2=1735983&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
 Mon Mar 21 14:50:03 2016
@@ -19,7 +19,9 @@ package org.apache.jackrabbit.oak.upgrad
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
+import org.apache.jackrabbit.oak.plugins.version.ReadWriteVersionManager;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
@@ -29,6 +31,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
 import java.util.Set;
 
 import static com.google.common.collect.ImmutableSet.of;
@@ -43,6 +46,7 @@ import static org.apache.jackrabbit.JcrC
 import static org.apache.jackrabbit.JcrConstants.MIX_VERSIONABLE;
 import static 
org.apache.jackrabbit.oak.plugins.memory.MultiGenericPropertyState.nameProperty;
 import static 
org.apache.jackrabbit.oak.plugins.version.VersionConstants.MIX_REP_VERSIONABLE_PATHS;
+import static 
org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionHistoryNodeState;
 
 /**
  * The VersionableEditor provides two possible ways to handle
@@ -58,6 +62,8 @@ import static org.apache.jackrabbit.oak.
  */
 public class VersionableEditor extends DefaultEditor {
 
+    private static final Logger logger = 
LoggerFactory.getLogger(VersionableEditor.class);
+
     private static final Set<String> SKIPPED_PATHS = of("/oak:index", 
"/jcr:system/jcr:versionStorage");
 
     private final Provider provider;
@@ -70,6 +76,8 @@ public class VersionableEditor extends D
 
     private final VersionCopier versionCopier;
 
+    private final ReadWriteVersionManager vMgr;
+
     private String path;
 
     private VersionableEditor(Provider provider, NodeBuilder builder) {
@@ -79,6 +87,9 @@ public class VersionableEditor extends D
         this.isReferenceable = new TypePredicate(builder.getNodeState(), 
MIX_REFERENCEABLE);
         this.versionCopier = new VersionCopier(provider.sourceRoot, builder);
         this.path = "/";
+
+        NodeBuilder vsRoot = 
rootBuilder.child(NodeTypeConstants.JCR_SYSTEM).child(NodeTypeConstants.JCR_VERSIONSTORAGE);
+        this.vMgr = new ReadWriteVersionManager(vsRoot, rootBuilder);
     }
 
     public static class Provider implements EditorProvider {
@@ -128,7 +139,12 @@ public class VersionableEditor extends D
             if (isVersionHistoryExists(versionableUuid)) {
                 setVersionablePath(versionableUuid);
             } else {
-                removeVersionProperties(getNodeBuilder(rootBuilder, 
this.path));
+                NodeBuilder versionableBuilder = getNodeBuilder(rootBuilder, 
this.path);
+                removeVersionProperties(versionableBuilder);
+                if (isVersionable.apply(versionableBuilder.getNodeState())) {
+                    logger.warn("Node {} is still versionable. Creating empty 
version history.", path);
+                    createEmptyHistory(versionableBuilder);
+                }
             }
         }
 
@@ -149,7 +165,7 @@ public class VersionableEditor extends D
     }
 
     private boolean isVersionHistoryExists(String versionableUuid) {
-        return 
VersionHistoryUtil.getVersionHistoryNodeState(rootBuilder.getNodeState(), 
versionableUuid).exists();
+        return getVersionHistoryNodeState(rootBuilder.getNodeState(), 
versionableUuid).exists();
     }
 
     private void removeVersionProperties(final NodeBuilder versionableBuilder) 
{
@@ -169,6 +185,10 @@ public class VersionableEditor extends D
         versionableBuilder.removeProperty(JCR_ISCHECKEDOUT);
     }
 
+    private void createEmptyHistory(NodeBuilder versionable) throws 
CommitFailedException {
+        vMgr.getOrCreateVersionHistory(versionable, 
Collections.<String,Object>emptyMap());
+    }
+
     @Override
     public Editor childNodeChanged(String name, NodeState before, NodeState 
after) throws CommitFailedException {
         return childNodeAdded(name, after);

Modified: 
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java?rev=1735983&r1=1735982&r2=1735983&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java
 Mon Mar 21 14:50:03 2016
@@ -16,7 +16,12 @@
  */
 package org.apache.jackrabbit.oak.upgrade;
 
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.commons.cnd.CndImporter;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.jcr.Jcr;
 import org.apache.jackrabbit.oak.jcr.repository.RepositoryImpl;
@@ -35,11 +40,15 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
 import javax.jcr.version.VersionManager;
 
 import static org.apache.jackrabbit.JcrConstants.MIX_VERSIONABLE;
 import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 public class BrokenVersionableTest {
 
@@ -70,17 +79,27 @@ public class BrokenVersionableTest {
         SegmentNodeStore source = new SegmentNodeStore();
         RepositoryImpl repository = (RepositoryImpl) new Jcr(new 
Oak(source)).createRepository();
         Session session = repository.login(CREDENTIALS);
-        String versionHistoryPath;
+        List<String> versionHistoryPaths = new ArrayList<String>();
         try {
+            CndImporter.registerNodeTypes(new StringReader("<test = 
'http://jackrabbit.apache.org/ns/test'>\n"
+                    + "[test:Versionable] > nt:unstructured, 
mix:versionable"), session);
+
             Node root = session.getRootNode();
-            Node versionable = root.addNode("versionable", NT_UNSTRUCTURED);
-            versionable.addMixin(MIX_VERSIONABLE);
-            versionable.addNode("child", NT_UNSTRUCTURED);
+
+            Node versionable1 = root.addNode("versionable1", NT_UNSTRUCTURED);
+            versionable1.addMixin(MIX_VERSIONABLE);
+            versionable1.addNode("child", NT_UNSTRUCTURED);
+
+            Node versionable2 = root.addNode("versionable2", 
"test:Versionable");
+            versionable2.addNode("child", NT_UNSTRUCTURED);
+
             session.save();
 
             VersionManager vMgr = session.getWorkspace().getVersionManager();
-            vMgr.checkin("/versionable");
-            versionHistoryPath = 
vMgr.getVersionHistory("/versionable").getPath();
+            vMgr.checkin("/versionable1");
+            vMgr.checkin("/versionable2");
+            
versionHistoryPaths.add(vMgr.getVersionHistory("/versionable1").getPath());
+            
versionHistoryPaths.add(vMgr.getVersionHistory("/versionable2").getPath());
         } finally {
             session.logout();
             repository.shutdown();
@@ -88,9 +107,10 @@ public class BrokenVersionableTest {
 
         // remove version history to corrupt the JCR repository structure
         NodeBuilder rootBuilder = source.getRoot().builder();
-        NodeStateTestUtils.createOrGetBuilder(rootBuilder, 
versionHistoryPath).remove();
+        for (String versionHistoryPath : versionHistoryPaths) {
+            NodeStateTestUtils.createOrGetBuilder(rootBuilder, 
versionHistoryPath).remove();
+        }
         source.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
         return source;
     }
 
@@ -101,8 +121,16 @@ public class BrokenVersionableTest {
     @Test
     public void verifyNoVersionable() throws RepositoryException {
         Session session = createAdminSession();
+        VersionManager vMgr = session.getWorkspace().getVersionManager();
         try {
-            
assertFalse(session.getNode("/versionable").isNodeType(MIX_VERSIONABLE));
+            
assertFalse(session.getNode("/versionable1").isNodeType(MIX_VERSIONABLE));
+
+            Node versionable2 = session.getNode("/versionable2");
+            assertTrue(versionable2.isNodeType(MIX_VERSIONABLE));
+            VersionHistory history = 
vMgr.getVersionHistory(versionable2.getPath());
+            VersionIterator versions = history.getAllVersions();
+            assertEquals("jcr:rootVersion", versions.nextVersion().getName());
+            assertFalse(versions.hasNext());
         } finally {
             session.logout();
         }


Reply via email to