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(); }