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 to...@apache.org on 2016/12/16 11:12:54 UTC

svn commit: r1774571 [2/3] - in /jackrabbit/oak/branches/1.4/oak-upgrade/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/oak/upgrade/ main/java/org/apache/jackrabbit/oak/upgrade/blob/ main/java/org/apache/jackrabbit/oak/upgra...

Added: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/DatastoreArguments.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/DatastoreArguments.java?rev=1774571&view=auto
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/DatastoreArguments.java (added)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/DatastoreArguments.java Fri Dec 16 11:12:53 2016
@@ -0,0 +1,238 @@
+/*
+ * 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.upgrade.cli.parser;
+
+import org.apache.commons.lang.text.StrSubstitutor;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.BlobStoreFactory;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.ConstantBlobStoreFactory;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.DummyBlobStoreFactory;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.FileBlobStoreFactory;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.FileDataStoreFactory;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.MissingBlobStoreFactory;
+import org.apache.jackrabbit.oak.upgrade.cli.blob.S3DataStoreFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.jackrabbit.oak.upgrade.cli.parser.StoreType.JCR2_DIR_XML;
+
+/**
+ * This class parses the input provided by the user and analyses the given node stores
+ * in order to find out which datastore combination should be used for the migration.
+ *
+ * The desired outcome for the combinations of user input can be found in the table below.
+ * The table is a kind of heuristics that tries to match the user intentions.
+ * <pre>
+ * For sidegrade:
+ || src blobstore defined || src blobs embedded || dst blobstore defined || --copy-binaries || outcome src blobstore || outcome action
+ |   -                    |   -                 |  -                     |  -               |  missing               |  copy references¹
+ |   -                    |   -                 |  -                     |  +               |  missing               |  (x) not supported
+ |   -                    |   -                 |  +                     |  *               |  missing               |  (x) not supported
+ |   -                    |   +                 |  -                     |  *               |  embedded              |  copy to embedded
+ |   -                    |   +                 |  +                     |  *               |  embedded              |  copy to defined blobstore
+ |   +                    |   *                 |  -                     |  -               |  as in src             |  copy references
+ |   +                    |   *                 |  -                     |  +               |  as in src             |  copy to embedded
+ |   +                    |   *                 |  +                     |  *               |  as in src             |  copy to defined blobstore
+
+ ¹ - (x) not supported for SegmentMK -> MongoMK migration
+
+ For upgrade:
+
+ || dst blobstore defined || --copy-binaries || outcome src blobstore || outcome action
+ |  -                     |  -               |  defined by JCR2       |  copy references
+ |  -                     |  +               |  defined by JCR2       |  copy to embedded
+ |  +                     |  *               |  defined by JCR2       |  copy to defined blobstore
+ * </pre>
+ */
+public class DatastoreArguments {
+
+    private static final Logger log = LoggerFactory.getLogger(DatastoreArguments.class);
+
+    private final BlobStoreFactory definedSrcBlob;
+
+    private final BlobStoreFactory definedDstBlob;
+
+    private final StoreArguments storeArguments;
+
+    private final BlobMigrationCase blobMigrationCase;
+
+    private final MigrationOptions options;
+
+    private final boolean srcEmbedded;
+
+    public DatastoreArguments(MigrationOptions options, StoreArguments storeArguments, boolean srcEmbedded) throws CliArgumentException {
+        this.storeArguments = storeArguments;
+        this.options = options;
+        this.srcEmbedded = srcEmbedded;
+
+        try {
+            blobMigrationCase = discoverBlobMigrationCase();
+        } catch (IOException e) {
+            log.error("Can't figure out the right blob migration path", e);
+            throw new CliArgumentException(1);
+        }
+
+        if (blobMigrationCase == BlobMigrationCase.UNSUPPORTED) {
+            throw new CliArgumentException("This combination of data- and node-stores is not supported", 1);
+        }
+
+        try {
+            definedSrcBlob = options.isSrcBlobStoreDefined() ? getDefinedSrcBlobStore() : null;
+            definedDstBlob = options.isDstBlobStoreDefined() ? getDefinedDstBlobStore() : null;
+        } catch(IOException e) {
+            log.error("Can't read the blob configuration", e);
+            throw new CliArgumentException(1);
+        }
+
+        log.info(blobMigrationCase.getDescription(this));
+    }
+
+    public BlobStoreFactory getSrcBlobStore() throws IOException {
+        BlobStoreFactory result;
+        if (options.isSrcBlobStoreDefined()) {
+            result = definedSrcBlob;
+        } else if (blobMigrationCase == BlobMigrationCase.COPY_REFERENCES) {
+            result = new MissingBlobStoreFactory();
+        } else {
+            result = new DummyBlobStoreFactory(); // embedded
+        }
+        log.info("Source blob store: {}", result);
+        return result;
+    }
+
+    public BlobStoreFactory getDstBlobStore(BlobStore srcBlobStore) throws IOException {
+        BlobStoreFactory result;
+        if (options.isDstBlobStoreDefined()) {
+            result = definedDstBlob;
+        } else if (blobMigrationCase == BlobMigrationCase.COPY_REFERENCES && (options.isSrcBlobStoreDefined() || storeArguments.getSrcType() == JCR2_DIR_XML)) {
+            result = new ConstantBlobStoreFactory(srcBlobStore);
+        } else if (blobMigrationCase == BlobMigrationCase.COPY_REFERENCES) {
+            result = new MissingBlobStoreFactory();
+        } else {
+            result = new DummyBlobStoreFactory(); // embedded
+        }
+
+        log.info("Destination blob store: {}", result);
+        return result;
+    }
+
+    private BlobStoreFactory getDefinedSrcBlobStore() throws IOException {
+        boolean ignoreMissingBinaries = options.isIgnoreMissingBinaries();
+        if (options.isSrcFbs()) {
+            return new FileBlobStoreFactory(options.getSrcFbs());
+        } else if (options.isSrcS3()) {
+            return new S3DataStoreFactory(options.getSrcS3Config(), options.getSrcS3(), ignoreMissingBinaries);
+        } else if (options.isSrcFds()) {
+            return new FileDataStoreFactory(options.getSrcFds(), ignoreMissingBinaries);
+        } else {
+            return null;
+        }
+    }
+
+    private BlobStoreFactory getDefinedDstBlobStore() throws IOException {
+        if (options.isDstFbs()) {
+            return new FileBlobStoreFactory(options.getDstFbs());
+        } else if (options.isDstS3()) {
+            return new S3DataStoreFactory(options.getDstS3Config(), options.getDstS3(), false);
+        } else if (options.isDstFds()) {
+            return new FileDataStoreFactory(options.getDstFds(), false);
+        } else {
+            return null;
+        }
+    }
+
+    public enum BlobMigrationCase {
+        COPY_REFERENCES("Only blob references will be copied"),
+        EMBEDDED_TO_EMBEDDED("Blobs embedded in ${srcnode} will be embedded in ${dstnode}"),
+        EMBEDDED_TO_EXTERNAL("Blobs embedded in ${srcnode} will be copied to ${dstblob}"),
+        EXTERNAL_TO_EMBEDDED("Blobs stored in ${srcblob} will be embedded in ${dstnode}"),
+        EXTERNAL_TO_EXTERNAL("Blobs stored in ${srcblob} will be copied to ${dstblob}"),
+        UNSUPPORTED("Unsupported case");
+
+        private final String description;
+
+        BlobMigrationCase(String description) {
+            this.description = description;
+        }
+
+        private String getDescription(DatastoreArguments datastoreArguments) {
+            Map<String, String> map = newHashMap();
+            map.put("srcnode", datastoreArguments.storeArguments.getSrcDescriptor());
+            map.put("dstnode", datastoreArguments.storeArguments.getDstDescriptor());
+
+            if (datastoreArguments.storeArguments.getSrcType() == JCR2_DIR_XML) {
+                map.put("srcblob", "CRX2 datastore");
+            } else {
+                map.put("srcblob", datastoreArguments.definedSrcBlob == null ? "?" : datastoreArguments.definedSrcBlob.toString());
+            }
+            map.put("dstblob", datastoreArguments.definedDstBlob == null ? "?" : datastoreArguments.definedDstBlob.toString());
+
+            StrSubstitutor subst = new StrSubstitutor(map);
+            return subst.replace(description);
+        }
+
+    }
+
+    public BlobMigrationCase getBlobMigrationCase() {
+        return blobMigrationCase;
+    }
+
+    private BlobMigrationCase discoverBlobMigrationCase() throws IOException {
+        boolean srcDefined = options.isSrcBlobStoreDefined() || storeArguments.getSrcType() == JCR2_DIR_XML;
+        boolean dstDefined = options.isDstBlobStoreDefined();
+        boolean copyBinaries = options.isCopyBinaries();
+
+        boolean srcSegment = storeArguments.getSrcType().isSegment();
+        boolean dstSegment = storeArguments.getDstType().isSegment();
+
+        // default case, no datastore-related arguments given, but blobs are stored externally
+        if (!srcDefined && !dstDefined && !srcEmbedded && !copyBinaries) {
+            if (srcSegment && !dstSegment) { // segment -> document is not supported for this case
+                return BlobMigrationCase.UNSUPPORTED;
+            } else { // we try to copy references using MissingBlobStore
+                return BlobMigrationCase.COPY_REFERENCES;
+            }
+            // can't copy binaries if they are stored externally and we don't know where
+        } else if (!srcDefined && !dstDefined && !srcEmbedded && copyBinaries) {
+            return BlobMigrationCase.UNSUPPORTED;
+            // can't copy binaries if they are stored externally and we don't know where
+            // (even if the destination datastore is defined)
+        } else if (!srcDefined && !srcEmbedded && dstDefined) {
+            return BlobMigrationCase.UNSUPPORTED;
+            // source is embedded and no destination given
+        } else if (!srcDefined && srcEmbedded && !dstDefined) {
+            return BlobMigrationCase.EMBEDDED_TO_EMBEDDED;
+            // source is embedded and the destination is given
+        } else if (!srcDefined && srcEmbedded && dstDefined) {
+            return BlobMigrationCase.EMBEDDED_TO_EXTERNAL;
+            // source is given, no destination, but also no --copy-binaries -> copy references
+        } else if (srcDefined && !dstDefined && !copyBinaries) {
+            return BlobMigrationCase.COPY_REFERENCES;
+            // source is given, no destination, but --copy-binaries -> copy to embedded
+        } else if (srcDefined && !dstDefined && copyBinaries) {
+            return BlobMigrationCase.EXTERNAL_TO_EMBEDDED;
+            // source and destination is given
+        } else if (srcDefined && dstDefined) {
+            return BlobMigrationCase.EXTERNAL_TO_EXTERNAL;
+        }
+        return BlobMigrationCase.UNSUPPORTED;
+    }
+}

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationCliArguments.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationCliArguments.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationCliArguments.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationCliArguments.java Fri Dec 16 11:12:53 2016
@@ -27,15 +27,9 @@ public final class MigrationCliArguments
 
     private final List<String> arguments;
 
-    private final MigrationOptions migrationOptions;
-
-    private final StoreArguments storeArguments;
-
     public MigrationCliArguments(OptionSet options) throws CliArgumentException {
         this.options = options;
-        arguments = getNonOptionArguments();
-        migrationOptions = new MigrationOptions(this);
-        storeArguments = new StoreArguments(this);
+        this.arguments = getNonOptionArguments();
     }
 
     private List<String> getNonOptionArguments() {
@@ -67,15 +61,7 @@ public final class MigrationCliArguments
         }
     }
 
-    public MigrationOptions getOptions() {
-        return migrationOptions;
-    }
-
-    public StoreArguments getStoreArguments() {
-        return storeArguments;
-    }
-
-    List<String> getArguments() {
+    public List<String> getArguments() {
         return arguments;
     }
 }

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java Fri Dec 16 11:12:53 2016
@@ -21,6 +21,7 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -30,9 +31,9 @@ public class MigrationOptions {
 
     private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
 
-    private final boolean copyBinariesByReference;
+    private final boolean copyBinaries;
 
-    private final boolean mmap;
+    private final boolean disableMmap;
 
     private final int cacheSizeInMB;
 
@@ -52,11 +53,43 @@ public class MigrationOptions {
 
     private final boolean skipInitialization;
 
+    private final boolean skipNameCheck;
+
     private final boolean ignoreMissingBinaries;
 
+    private final boolean verify;
+
+    private final boolean onlyVerify;
+
+    private final String srcUser;
+
+    private final String srcPassword;
+
+    private final String dstUser;
+
+    private final String dstPassword;
+
+    private final String srcFbs;
+
+    private final String srcFds;
+
+    private final String srcS3Config;
+
+    private final String srcS3;
+
+    private final String dstFbs;
+
+    private final String dstFds;
+
+    private final String dstS3Config;
+
+    private final String dstS3;
+
+    private final Boolean srcExternalBlobs;
+
     public MigrationOptions(MigrationCliArguments args) {
-        this.copyBinariesByReference = !args.hasOption(OptionParserFactory.COPY_BINARIES);
-        this.mmap = args.hasOption(OptionParserFactory.MMAP);
+        this.disableMmap = args.hasOption(OptionParserFactory.DISABLE_MMAP);
+        this.copyBinaries = args.hasOption(OptionParserFactory.COPY_BINARIES);
         if (args.hasOption(OptionParserFactory.CACHE_SIZE)) {
             this.cacheSizeInMB = args.getIntOption(OptionParserFactory.CACHE_SIZE);
         } else {
@@ -75,22 +108,46 @@ public class MigrationOptions {
         } else {
             this.copyOrphanedVersions = epoch;
         }
-        this.includePaths = split(args.getOption(OptionParserFactory.INCLUDE_PATHS));
-        this.excludePaths = split(args.getOption(OptionParserFactory.EXCLUDE_PATHS));
-        this.mergePaths = split(args.getOption(OptionParserFactory.MERGE_PATHS));
+        this.includePaths = args.getOptionList(OptionParserFactory.INCLUDE_PATHS);
+        this.excludePaths = args.getOptionList(OptionParserFactory.EXCLUDE_PATHS);
+        this.mergePaths = args.getOptionList(OptionParserFactory.MERGE_PATHS);
         this.failOnError = args.hasOption(OptionParserFactory.FAIL_ON_ERROR);
         this.earlyShutdown = args.hasOption(OptionParserFactory.EARLY_SHUTDOWN);
         this.skipInitialization = args.hasOption(OptionParserFactory.SKIP_INIT);
+        this.skipNameCheck = args.hasOption(OptionParserFactory.SKIP_NAME_CHECK);
         this.ignoreMissingBinaries = args.hasOption(OptionParserFactory.IGNORE_MISSING_BINARIES);
-        logOptions();
+        this.verify = args.hasOption(OptionParserFactory.VERIFY);
+        this.onlyVerify = args.hasOption(OptionParserFactory.ONLY_VERIFY);
+
+        this.srcUser = args.getOption(OptionParserFactory.SRC_USER);
+        this.srcPassword = args.getOption(OptionParserFactory.SRC_USER);
+        this.dstUser = args.getOption(OptionParserFactory.DST_USER);
+        this.dstPassword = args.getOption(OptionParserFactory.DST_PASSWORD);
+
+        this.srcFbs = args.getOption(OptionParserFactory.SRC_FBS);
+        this.srcFds = args.getOption(OptionParserFactory.SRC_FDS);
+        this.srcS3 = args.getOption(OptionParserFactory.SRC_S3);
+        this.srcS3Config = args.getOption(OptionParserFactory.SRC_S3_CONFIG);
+
+        this.dstFbs = args.getOption(OptionParserFactory.DST_FBS);
+        this.dstFds = args.getOption(OptionParserFactory.DST_FDS);
+        this.dstS3 = args.getOption(OptionParserFactory.DST_S3);
+        this.dstS3Config = args.getOption(OptionParserFactory.DST_S3_CONFIG);
+
+        if (args.hasOption(OptionParserFactory.SRC_EXTERNAL_BLOBS)) {
+            this.srcExternalBlobs = Boolean
+                    .valueOf(OptionParserFactory.SRC_EXTERNAL_BLOBS);
+        } else {
+            this.srcExternalBlobs = null;
+        }
     }
 
-    public boolean isCopyBinariesByReference() {
-        return copyBinariesByReference;
+    public boolean isCopyBinaries() {
+        return copyBinaries;
     }
 
-    public boolean isMmap() {
-        return mmap;
+    public boolean isDisableMmap() {
+        return disableMmap;
     }
 
     public int getCacheSizeInMB() {
@@ -129,19 +186,105 @@ public class MigrationOptions {
         return skipInitialization;
     }
 
+    public boolean isSkipNameCheck() {
+        return skipNameCheck;
+    }
+
     public boolean isIgnoreMissingBinaries() {
         return ignoreMissingBinaries;
     }
 
-    private void logOptions() {
-        if (copyBinariesByReference) {
-            log.info("DataStore needs to be shared with new repository");
-        } else {
-            log.info("Binary content would be copied to the NodeStore.");
-        }
+    public boolean isVerify() {
+        return verify;
+    }
+
+    public boolean isOnlyVerify() {
+        return onlyVerify;
+    }
+
+    public String getSrcUser() {
+        return srcUser;
+    }
+
+    public String getSrcPassword() {
+        return srcPassword;
+    }
+
+    public String getDstUser() {
+        return dstUser;
+    }
+
+    public String getDstPassword() {
+        return dstPassword;
+    }
+
+    public String getSrcFbs() {
+        return srcFbs;
+    }
+
+    public String getSrcFds() {
+        return srcFds;
+    }
 
-        if (mmap) {
-            log.info("Enabling memory mapped file access for Segment Store");
+    public String getSrcS3Config() {
+        return srcS3Config;
+    }
+
+    public String getSrcS3() {
+        return srcS3;
+    }
+
+    public String getDstFbs() {
+        return dstFbs;
+    }
+
+    public String getDstFds() {
+        return dstFds;
+    }
+
+    public String getDstS3Config() {
+        return dstS3Config;
+    }
+
+    public String getDstS3() {
+        return dstS3;
+    }
+
+    public boolean isSrcFds() {
+        return StringUtils.isNotBlank(srcFds);
+    }
+
+    public boolean isSrcFbs() {
+        return StringUtils.isNotBlank(srcFbs);
+    }
+
+    public boolean isSrcS3() {
+        return StringUtils.isNotBlank(srcS3) && StringUtils.isNotBlank(srcS3Config);
+    }
+
+    public boolean isDstFds() {
+        return StringUtils.isNotBlank(dstFds);
+    }
+
+    public boolean isDstFbs() {
+        return StringUtils.isNotBlank(dstFbs);
+    }
+
+    public boolean isDstS3() {
+        return StringUtils.isNotBlank(dstS3) && StringUtils.isNotBlank(dstS3Config);
+    }
+
+    public boolean isSrcBlobStoreDefined() {
+        return isSrcFbs() || isSrcFds() || isSrcS3();
+    }
+
+    public boolean isDstBlobStoreDefined() {
+        return isDstFbs() || isDstFds() || isDstS3();
+    }
+
+    public void logOptions() {
+        if (disableMmap) {
+            log.info("Disabling memory mapped file access for Segment Store");
         }
 
         if (copyVersions == null) {
@@ -176,22 +319,22 @@ public class MigrationOptions {
             log.info("The repository initialization will be skipped");
         }
 
+        if (skipNameCheck) {
+            log.info("Test for long-named nodes will be disabled");
+        }
+
         if (ignoreMissingBinaries) {
             log.info("Missing binaries won't break the migration");
         }
 
+        if (srcExternalBlobs != null) {
+            log.info("Source DataStore external blobs: {}", srcExternalBlobs);
+        }
+
         log.info("Cache size: {} MB", cacheSizeInMB);
 
     }
 
-    private static String[] split(String list) {
-        if (list == null) {
-            return null;
-        } else {
-            return list.split(",");
-        }
-    }
-
     private static Calendar parseVersionCopyArgument(String string) {
         final Calendar calendar;
 
@@ -211,4 +354,8 @@ public class MigrationOptions {
         return calendar;
     }
 
+    public Boolean getSrcExternalBlobs() {
+        return srcExternalBlobs;
+    }
+
 }

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java Fri Dec 16 11:12:53 2016
@@ -24,7 +24,7 @@ public class OptionParserFactory {
 
     public static final String COPY_BINARIES = "copy-binaries";
 
-    public static final String MMAP = "mmap";
+    public static final String DISABLE_MMAP = "disable-mmap";
 
     public static final String FAIL_ON_ERROR = "fail-on-error";
 
@@ -52,6 +52,8 @@ public class OptionParserFactory {
 
     public static final String SRC_S3_CONFIG = "src-s3config";
 
+    public static final String SRC_EXTERNAL_BLOBS = "src-external-ds";
+
     public static final String DST_FDS = "datastore";
 
     public static final String DST_FBS = "fileblobstore";
@@ -72,6 +74,12 @@ public class OptionParserFactory {
 
     public static final String SKIP_INIT = "skip-init";
 
+    public static final String SKIP_NAME_CHECK = "skip-name-check";
+
+    public static final String VERIFY = "verify";
+
+    public static final String ONLY_VERIFY = "only-verify";
+
     public static OptionParser create() {
         OptionParser op = new OptionParser();
         addUsageOptions(op);
@@ -104,6 +112,7 @@ public class OptionParserFactory {
         op.accepts(DST_S3_CONFIG, "Configuration file for the target S3DataStore").withRequiredArg()
                 .ofType(String.class);
         op.accepts(IGNORE_MISSING_BINARIES, "Don't break the migration if some binaries are missing");
+        op.accepts(SRC_EXTERNAL_BLOBS, "Flag specifying if the source Store has external references or not");
     }
 
     private static void addRdbOptions(OptionParser op) {
@@ -132,11 +141,14 @@ public class OptionParserFactory {
     }
 
     private static void addMiscOptions(OptionParser op) {
-        op.accepts(MMAP, "Enable memory mapped file access for Segment Store");
+        op.accepts(DISABLE_MMAP, "Disable memory mapped file access for Segment Store");
         op.accepts(FAIL_ON_ERROR, "Fail completely if nodes can't be read from the source repo");
         op.accepts(EARLY_SHUTDOWN,
                 "Shutdown the source repository after nodes are copied and before the commit hooks are applied");
         op.accepts(CACHE_SIZE, "Cache size in MB").withRequiredArg().ofType(Integer.class).defaultsTo(256);
         op.accepts(SKIP_INIT, "Skip the repository initialization; only copy data");
+        op.accepts(SKIP_NAME_CHECK, "Skip the initial phase of testing node name lengths");
+        op.accepts(VERIFY, "After the sidegrade check whether the source repository is exactly the same as destination");
+        op.accepts(ONLY_VERIFY, "Performs only --" + VERIFY + ", without copying content");
     }
 }

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreArguments.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreArguments.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreArguments.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreArguments.java Fri Dec 16 11:12:53 2016
@@ -23,25 +23,10 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.jackrabbit.oak.plugins.segment.SegmentVersion;
-import org.apache.jackrabbit.oak.upgrade.cli.blob.BlobStoreFactory;
-import org.apache.jackrabbit.oak.upgrade.cli.blob.DummyBlobStoreFactory;
-import org.apache.jackrabbit.oak.upgrade.cli.blob.FileBlobStoreFactory;
-import org.apache.jackrabbit.oak.upgrade.cli.blob.FileDataStoreFactory;
-import org.apache.jackrabbit.oak.upgrade.cli.blob.S3DataStoreFactory;
 import org.apache.jackrabbit.oak.upgrade.cli.node.StoreFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.IGNORE_MISSING_BINARIES;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.SRC_FBS;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.SRC_FDS;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.SRC_S3;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.SRC_S3_CONFIG;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.DST_FBS;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.DST_FDS;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.DST_S3;
-import static org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.DST_S3_CONFIG;
-
 import static org.apache.jackrabbit.oak.upgrade.cli.parser.StoreType.JCR2_DIR;
 import static org.apache.jackrabbit.oak.upgrade.cli.parser.StoreType.JCR2_DIR_XML;
 import static org.apache.jackrabbit.oak.upgrade.cli.parser.StoreType.JCR2_XML;
@@ -56,20 +41,27 @@ public class StoreArguments {
 
     private static final Logger log = LoggerFactory.getLogger(StoreArguments.class);
 
-    private final MigrationCliArguments parser;
+    private final MigrationOptions options;
 
     private final StoreDescriptor src;
 
     private final StoreDescriptor dst;
 
-    public StoreArguments(MigrationCliArguments parser) throws CliArgumentException {
-        this.parser = parser;
+    private Boolean srcHasExternalBlobRefs;
 
-        List<StoreDescriptor> descriptors = createStoreDescriptors(parser.getArguments());
+    public StoreArguments(MigrationOptions options, List<String> arguments) throws CliArgumentException {
+        this.options = options;
+        List<StoreDescriptor> descriptors = createStoreDescriptors(arguments, options);
 
         src = descriptors.get(0);
         dst = descriptors.get(1);
 
+        if (options.getSrcExternalBlobs() != null) {
+            srcHasExternalBlobRefs = options.getSrcExternalBlobs();
+        }
+    }
+
+    public void logOptions() {
         log.info("Source: {}", src);
         log.info("Destination: {}", dst);
 
@@ -79,42 +71,27 @@ public class StoreArguments {
     }
 
     public StoreFactory getSrcStore() {
-        return src.getFactory(MigrationDirection.SRC, parser);
+        return src.getFactory(MigrationDirection.SRC, options);
     }
 
     public StoreFactory getDstStore() {
-        return dst.getFactory(MigrationDirection.DST, parser);
+        return dst.getFactory(MigrationDirection.DST, options);
     }
 
-    public BlobStoreFactory getSrcBlobStore() throws IOException {
-        BlobStoreFactory factory;
-        boolean ignoreMissingBinaries = parser.hasOption(IGNORE_MISSING_BINARIES);
-        if (parser.hasOption(SRC_FBS)) {
-            factory = new FileBlobStoreFactory(parser.getOption(SRC_FBS));
-        } else if (parser.hasOption(SRC_S3_CONFIG) && parser.hasOption(SRC_S3)) {
-            factory = new S3DataStoreFactory(parser.getOption(SRC_S3_CONFIG), parser.getOption(SRC_S3), ignoreMissingBinaries);
-        } else if (parser.hasOption(SRC_FDS)) {
-            factory = new FileDataStoreFactory(parser.getOption(SRC_FDS), ignoreMissingBinaries);
-        } else {
-            factory = new DummyBlobStoreFactory();
-        }
-        log.info("Source blob store: {}", factory);
-        return factory;
-    }
-
-    public BlobStoreFactory getDstBlobStore() throws IOException {
-        BlobStoreFactory factory;
-        if (parser.hasOption(DST_FBS)) {
-            factory = new FileBlobStoreFactory(parser.getOption(DST_FBS));
-        } else if (parser.hasOption(DST_S3_CONFIG) && parser.hasOption(DST_S3)) {
-            factory = new S3DataStoreFactory(parser.getOption(DST_S3_CONFIG), parser.getOption(DST_S3), false);
-        } else if (parser.hasOption(DST_FDS)) {
-            factory = new FileDataStoreFactory(parser.getOption(DST_FDS), false);
-        } else {
-            factory = new DummyBlobStoreFactory();
-        }
-        log.info("Destination blob store: {}", factory);
-        return factory;
+    public StoreType getSrcType() {
+        return src.getType();
+    }
+
+    public StoreType getDstType() {
+        return dst.getType();
+    }
+
+    String getSrcDescriptor() {
+        return src.toString();
+    }
+
+    String getDstDescriptor() {
+        return dst.toString();
     }
 
     public boolean isInPlaceUpgrade() {
@@ -124,19 +101,22 @@ public class StoreArguments {
         return false;
     }
 
-    public boolean isSkipLongNames() {
-        return dst.getType() != SEGMENT;
-    }
-
     public String[] getSrcPaths() {
         return src.getPaths();
     }
 
-    private static List<StoreDescriptor> createStoreDescriptors(List<String> arguments) throws CliArgumentException {
+    public boolean srcUsesEmbeddedDatastore() throws IOException {
+        if (srcHasExternalBlobRefs == null) {
+            srcHasExternalBlobRefs = src.getFactory(StoreArguments.MigrationDirection.SRC, options).hasExternalBlobReferences();
+        }
+        return !srcHasExternalBlobRefs;
+    }
+
+    private static List<StoreDescriptor> createStoreDescriptors(List<String> arguments, MigrationOptions options) throws CliArgumentException {
         List<StoreDescriptor> descriptors = mapToStoreDescriptors(arguments);
         mergeCrx2Descriptors(descriptors);
         addSegmentAsDestination(descriptors);
-        validateDescriptors(descriptors);
+        validateDescriptors(descriptors, options);
         return descriptors;
     }
 
@@ -212,7 +192,7 @@ public class StoreArguments {
         }
     }
 
-    private static void validateDescriptors(List<StoreDescriptor> descriptors) throws CliArgumentException {
+    private static void validateDescriptors(List<StoreDescriptor> descriptors, MigrationOptions options) throws CliArgumentException {
         if (descriptors.size() < 2) {
             throw new CliArgumentException("Not enough node store arguments: " + descriptors.toString(), 1);
         } else if (descriptors.size() > 2) {
@@ -220,6 +200,14 @@ public class StoreArguments {
         } else if (descriptors.get(1).getType() == JCR2_DIR_XML) {
             throw new CliArgumentException("Can't use CRX2 as a destination", 1);
         }
+        StoreDescriptor src = descriptors.get(0);
+        StoreDescriptor dst = descriptors.get(1);
+        if (src.getType() == dst.getType() && src.getPath().equals(dst.getPath())) {
+            throw new CliArgumentException("The source and the destination is the same repository.", 1);
+        }
+        if (src.getType() == StoreType.JCR2_DIR_XML && options.isSrcBlobStoreDefined()) {
+            throw new CliArgumentException("The --src-datastore can't be used for the repository upgrade. Source datastore configuration is placed in the repository.xml file.", 1);
+        }
     }
 
     private static void logSegmentVersion() {
@@ -259,8 +247,8 @@ public class StoreArguments {
             return type;
         }
 
-        public StoreFactory getFactory(MigrationDirection direction, MigrationCliArguments arguments) {
-            return type.createFactory(paths, direction, arguments);
+        public StoreFactory getFactory(MigrationDirection direction, MigrationOptions options) {
+            return type.createFactory(paths, direction, options);
         }
 
         @Override
@@ -271,5 +259,6 @@ public class StoreArguments {
                 return String.format("%s%s", type, Arrays.toString(getPaths()));
             }
         }
+
     }
 }

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreType.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreType.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreType.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreType.java Fri Dec 16 11:12:53 2016
@@ -26,7 +26,7 @@ import org.apache.jackrabbit.oak.upgrade
 import org.apache.jackrabbit.oak.upgrade.cli.node.StoreFactory;
 import org.apache.jackrabbit.oak.upgrade.cli.parser.StoreArguments.MigrationDirection;
 
-enum StoreType {
+public enum StoreType {
     JCR2_XML {
         @Override
         public boolean matches(String argument) {
@@ -34,9 +34,14 @@ enum StoreType {
         }
 
         @Override
-        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments) {
+        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions) {
             throw new UnsupportedOperationException();
         }
+
+        @Override
+        public boolean isSupportLongNames() {
+            return true;
+        }
     },
     JCR2_DIR {
         @Override
@@ -45,9 +50,14 @@ enum StoreType {
         }
 
         @Override
-        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments) {
+        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions) {
             throw new UnsupportedOperationException();
         }
+
+        @Override
+        public boolean isSupportLongNames() {
+            return true;
+        }
     },
     JCR2_DIR_XML {
         @Override
@@ -56,9 +66,14 @@ enum StoreType {
         }
 
         @Override
-        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments) {
+        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions) {
             return new StoreFactory(new Jackrabbit2Factory(paths[0], paths[1]));
         }
+
+        @Override
+        public boolean isSupportLongNames() {
+            return true;
+        }
     },
     JDBC {
         @Override
@@ -67,17 +82,22 @@ enum StoreType {
         }
 
         @Override
-        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments) {
+        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions) {
             String username, password;
             if (direction == MigrationDirection.SRC) {
-                username = arguments.getOption(OptionParserFactory.SRC_USER);
-                password = arguments.getOption(OptionParserFactory.SRC_PASSWORD);
+                username = migrationOptions.getSrcUser();
+                password = migrationOptions.getSrcPassword();
             } else {
-                username = arguments.getOption(OptionParserFactory.DST_USER);
-                password = arguments.getOption(OptionParserFactory.DST_PASSWORD);
+                username = migrationOptions.getDstUser();
+                password = migrationOptions.getDstPassword();
             }
             return new StoreFactory(
-                    new JdbcFactory(paths[0], arguments.getOptions().getCacheSizeInMB(), username, password));
+                    new JdbcFactory(paths[0], migrationOptions.getCacheSizeInMB(), username, password, direction == MigrationDirection.SRC));
+        }
+
+        @Override
+        public boolean isSupportLongNames() {
+            return false;
         }
     },
     MONGO {
@@ -87,8 +107,13 @@ enum StoreType {
         }
 
         @Override
-        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments) {
-            return new StoreFactory(new MongoFactory(paths[0], arguments.getOptions().getCacheSizeInMB()));
+        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions) {
+            return new StoreFactory(new MongoFactory(paths[0], migrationOptions.getCacheSizeInMB(), direction == MigrationDirection.SRC));
+        }
+
+        @Override
+        public boolean isSupportLongNames() {
+            return false;
         }
     },
     SEGMENT {
@@ -98,8 +123,13 @@ enum StoreType {
         }
 
         @Override
-        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments) {
-            return new StoreFactory(new SegmentFactory(paths[0], arguments.getOptions().isMmap()));
+        public StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions) {
+            return new StoreFactory(new SegmentFactory(paths[0], migrationOptions.isDisableMmap(), direction == MigrationDirection.SRC));
+        }
+
+        @Override
+        public boolean isSupportLongNames() {
+            return true;
         }
     };
 
@@ -114,5 +144,11 @@ enum StoreType {
 
     public abstract boolean matches(String argument);
 
-    public abstract StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationCliArguments arguments);
+    public abstract StoreFactory createFactory(String[] paths, MigrationDirection direction, MigrationOptions migrationOptions);
+
+    public abstract boolean isSupportLongNames();
+
+    public boolean isSegment() {
+        return this == SEGMENT;
+    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java Fri Dec 16 11:12:53 2016
@@ -73,8 +73,8 @@ public class FilteringNodeState extends
      *
      * @param path The path where the node-state should be assumed to be located.
      * @param delegate The node-state to decorate.
-     * @param includePaths A Set of paths that should be visible. Defaults to ["/"] if {@code null).
-     * @param excludePaths A Set of paths that should be hidden. Empty if {@code null).
+     * @param includePaths A Set of paths that should be visible. Defaults to ["/"] if {@code null}.
+     * @param excludePaths A Set of paths that should be hidden. Empty if {@code null}.
      * @return The decorated node-state if required, the original node-state if decoration is unnecessary.
      * @param excludePaths
      */

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NameFilteringNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NameFilteringNodeState.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NameFilteringNodeState.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NameFilteringNodeState.java Fri Dec 16 11:12:53 2016
@@ -72,7 +72,7 @@ public class NameFilteringNodeState exte
      *            to check
      * @return true if the name is longer than {@link Utils#NODE_NAME_LIMIT}
      */
-    private static boolean isNameTooLong(@Nonnull String name) {
+    public static boolean isNameTooLong(@Nonnull String name) {
         // OAK-1589: maximum supported length of name for DocumentNodeStore
         // is 150 bytes. Skip the sub tree if the the name is too long
         return name.length() > SAFE_NODE_NAME_LENGTH && name.getBytes(Charsets.UTF_8).length > NODE_NAME_LIMIT;

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeState.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeState.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeState.java Fri Dec 16 11:12:53 2016
@@ -44,7 +44,9 @@ import javax.annotation.Nullable;
  * reported. Therefore if exactly counting unique accesses is a
  * requirement, the reporter needs to take care of de-duplication.
  *
- * @see Reporter, PeriodicReporter, LoggingReporter
+ * @see Reporter
+ * @see PeriodicReporter
+ * @see LoggingReporter
  */
 public class ReportingNodeState extends AbstractDecoratedNodeState {
 

Added: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/AuthorizableFolderEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/AuthorizableFolderEditor.java?rev=1774571&view=auto
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/AuthorizableFolderEditor.java (added)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/AuthorizableFolderEditor.java Fri Dec 16 11:12:53 2016
@@ -0,0 +1,113 @@
+/*
+ * 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.upgrade.security;
+
+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.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.spi.security.user.UserConstants.NT_REP_AUTHORIZABLE_FOLDER;
+
+/**
+ * There are occasions where in old JR2 repositories not all ancestors on
+ * the users path are of type {@code rep:AuthorizableFolder}, thus leading
+ * to exceptions after repository upgrade.
+ * <br/>
+ * In order to avoid such situations, this hook verifies that all nodes on
+ * the users and groups paths are of type {@code rep:AuthorizableFolder} and
+ * fixes the node-type if it is incorrect.
+ */
+public class AuthorizableFolderEditor extends DefaultEditor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AuthorizableFolderEditor.class);
+
+    private final NodeBuilder currentBuilder;
+
+    private final String groupsPath;
+
+    private final String usersPath;
+
+    private final String path;
+
+    public AuthorizableFolderEditor(final NodeBuilder builder, final String path, final String groupsPath, final String usersPath) {
+        this.currentBuilder = builder;
+        this.groupsPath = groupsPath;
+        this.usersPath = usersPath;
+        this.path = path;
+    }
+
+    public static EditorProvider provider(final String groupsPath, final String usersPath) {
+        return new EditorProvider() {
+            @Override
+            public Editor getRootEditor(final NodeState before,
+                                        final NodeState after,
+                                        final NodeBuilder builder,
+                                        final CommitInfo info) throws CommitFailedException {
+                return new AuthorizableFolderEditor(builder, "/", groupsPath, usersPath);
+            }
+        };
+    }
+
+    @Override
+    public void propertyAdded(final PropertyState after) throws CommitFailedException {
+         propertyChanged(null, after);
+    }
+
+    @Override
+    public void propertyChanged(final PropertyState before, final PropertyState after) throws CommitFailedException {
+        if (JCR_PRIMARYTYPE.equals(after.getName())) {
+            String nodeType = after.getValue(Type.STRING);
+            LOG.debug("Found {}/jcr:primaryType = {}", path, nodeType);
+            if (!nodeType.equals(NT_REP_AUTHORIZABLE_FOLDER) && expectAuthorizableFolder(path)) {
+                LOG.info("Changed {}/jcr:primaryType from {} to {}", path, nodeType, NT_REP_AUTHORIZABLE_FOLDER);
+                currentBuilder.setProperty(JCR_PRIMARYTYPE, NT_REP_AUTHORIZABLE_FOLDER, Type.NAME);
+            }
+        }
+    }
+
+    private boolean expectAuthorizableFolder(final String path) {
+        return !PathUtils.denotesRoot(path)
+                && (PathUtils.isAncestor(path, groupsPath) || path.equals(groupsPath)
+                || PathUtils.isAncestor(path, usersPath) || path.equals(usersPath));
+    }
+
+    @Override
+    public Editor childNodeAdded(final String name, final NodeState after) throws CommitFailedException {
+        return childNodeChanged(name, null, after);
+    }
+
+    @Override
+    public Editor childNodeChanged(final String name, final NodeState before, final NodeState after) throws CommitFailedException {
+        final String childPath = PathUtils.concat(path, name);
+        if (expectAuthorizableFolder(childPath)) {
+            LOG.debug("Found {} - descending", childPath);
+            return new AuthorizableFolderEditor(currentBuilder.child(name), childPath, groupsPath, usersPath);
+        } else {
+            return null;
+        }
+    }
+}

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java Fri Dec 16 11:12:53 2016
@@ -17,16 +17,12 @@
 package org.apache.jackrabbit.oak.upgrade.version;
 
 import static org.apache.jackrabbit.JcrConstants.JCR_CREATED;
-import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
-import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
 import static org.apache.jackrabbit.JcrConstants.NT_VERSION;
 
 import java.util.Calendar;
 import java.util.Iterator;
 
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
 import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -35,10 +31,9 @@ import org.apache.jackrabbit.oak.upgrade
 import org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier;
 import org.apache.jackrabbit.util.ISO8601;
 
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
 import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.VERSION_STORE_PATH;
 
-import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionHistoryPath;
+import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getRelativeVersionHistoryPath;
 import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionHistoryNodeState;
 
 /**
@@ -49,32 +44,29 @@ public class VersionCopier {
 
     private final TypePredicate isVersion;
 
-    private final NodeState sourceRoot;
+    private final NodeState sourceVersionStorage;
+
+    private final NodeBuilder targetVersionStorage;
 
     private final NodeBuilder targetRoot;
 
-    public VersionCopier(NodeState sourceRoot, NodeBuilder targetRoot) {
+    public VersionCopier(NodeBuilder targetRoot, NodeState sourceVersionStorage, NodeBuilder targetVersionStorage) {
         this.isVersion = new TypePredicate(targetRoot.getNodeState(), NT_VERSION);
-        this.sourceRoot = sourceRoot;
+        this.sourceVersionStorage = sourceVersionStorage;
+        this.targetVersionStorage = targetVersionStorage;
         this.targetRoot = targetRoot;
     }
 
-    public static void copyVersionStorage(NodeState sourceRoot, NodeBuilder targetRoot, VersionCopyConfiguration config) {
-        final NodeState versionStorage = sourceRoot.getChildNode(JCR_SYSTEM).getChildNode(JCR_VERSIONSTORAGE);
-        final Iterator<NodeState> versionStorageIterator = new DescendantsIterator(versionStorage, 3);
-        final VersionCopier versionCopier = new VersionCopier(sourceRoot, targetRoot);
+    public static void copyVersionStorage(NodeBuilder targetRoot, NodeState sourceVersionStorage, NodeBuilder targetVersionStorage, VersionCopyConfiguration config) {
+        final Iterator<NodeState> versionStorageIterator = new DescendantsIterator(sourceVersionStorage, 3);
+        final VersionCopier versionCopier = new VersionCopier(targetRoot, sourceVersionStorage, targetVersionStorage);
 
-        boolean versionsCopied = false;
         while (versionStorageIterator.hasNext()) {
             final NodeState versionHistoryBucket = versionStorageIterator.next();
             for (String versionHistory : versionHistoryBucket.getChildNodeNames()) {
-                versionsCopied |= versionCopier.doCopyVersionHistory(versionHistory, config.getOrphanedMinDate());
+                versionCopier.copyVersionHistory(versionHistory, config.getOrphanedMinDate());
             }
         }
-
-        if (versionsCopied) {
-            versionCopier.markUuidToReindex();
-        }
     }
 
     /**
@@ -88,23 +80,15 @@ public class VersionCopier {
      * @return {@code true} if at least one version has been copied
      */
     public boolean copyVersionHistory(String versionableUuid, Calendar minDate) {
-        boolean copied = doCopyVersionHistory(versionableUuid, minDate);
-        if (copied) {
-            markUuidToReindex();
-        }
-        return copied;
-    }
-
-    private boolean doCopyVersionHistory(String versionableUuid, Calendar minDate) {
-        final String versionHistoryPath = getVersionHistoryPath(versionableUuid);
-        final NodeState sourceVersionHistory = getVersionHistoryNodeState(sourceRoot, versionableUuid);
+        final String versionHistoryPath = getRelativeVersionHistoryPath(versionableUuid);
+        final NodeState sourceVersionHistory = getVersionHistoryNodeState(sourceVersionStorage, versionableUuid);
         final Calendar lastModified = getVersionHistoryLastModified(sourceVersionHistory);
 
         if (sourceVersionHistory.exists() && (lastModified.after(minDate) || minDate.getTimeInMillis() == 0)) {
             NodeStateCopier.builder()
                     .include(versionHistoryPath)
                     .merge(VERSION_STORE_PATH)
-                    .copy(sourceRoot, targetRoot);
+                    .copy(sourceVersionStorage, targetVersionStorage);
             return true;
         }
         return false;
@@ -127,12 +111,4 @@ public class VersionCopier {
         }
         return youngest;
     }
-
-    private void markUuidToReindex() {
-        final NodeBuilder uuidIndexDefinition = IndexUtils.getOrCreateOakIndex(targetRoot).getChildNode("uuid");
-        final PropertyState reindex = uuidIndexDefinition.getProperty(REINDEX_PROPERTY_NAME);
-        if (reindex == null || !reindex.getValue(Type.BOOLEAN)) {
-            uuidIndexDefinition.setProperty(REINDEX_PROPERTY_NAME, true);
-        }
-    }
 }

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java Fri Dec 16 11:12:53 2016
@@ -64,4 +64,8 @@ public class VersionCopyConfiguration {
         return copyVersions == null || copyOrphanedVersions == null;
     }
 
+    public boolean isCopyAll() {
+        return copyVersions != null && copyVersions.getTimeInMillis() == 0 && copyOrphanedVersions != null && copyOrphanedVersions.getTimeInMillis() == 0;
+    }
+
 }
\ No newline at end of file

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java Fri Dec 16 11:12:53 2016
@@ -18,12 +18,15 @@ package org.apache.jackrabbit.oak.upgrad
 
 import static com.google.common.collect.Iterables.concat;
 import static java.util.Collections.singleton;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
 import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
+import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.REP_VERSIONSTORAGE;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
@@ -31,10 +34,10 @@ import com.google.common.base.Joiner;
 
 public class VersionHistoryUtil {
 
-    public static String getVersionHistoryPath(String versionableUuid) {
+    public static String getRelativeVersionHistoryPath(String versionableUuid) {
         return Joiner.on('/').join(concat(
                 singleton(""),
-                getVersionHistoryPathSegments(versionableUuid),
+                getRelativeVersionHistoryPathSegments(versionableUuid),
                 singleton(versionableUuid)));
     }
 
@@ -46,30 +49,44 @@ public class VersionHistoryUtil {
      * @return The NodeState corresponding to the version history, or {@code null}
      *         if it does not exist.
      */
-    static NodeState getVersionHistoryNodeState(NodeState root, String versionableUuid) {
-        NodeState historyParent = root;
-        for (String segment : getVersionHistoryPathSegments(versionableUuid)) {
+    static NodeState getVersionHistoryNodeState(NodeState versionStorage, String versionableUuid) {
+        NodeState historyParent = versionStorage;
+        for (String segment : getRelativeVersionHistoryPathSegments(versionableUuid)) {
             historyParent = historyParent.getChildNode(segment);
         }
         return historyParent.getChildNode(versionableUuid);
     }
 
-    static NodeBuilder getVersionHistoryBuilder(NodeBuilder root, String versionableUuid) {
-        NodeBuilder history = root;
-        for (String segment : getVersionHistoryPathSegments(versionableUuid)) {
+    static NodeBuilder getVersionHistoryBuilder(NodeBuilder versionStorage, String versionableUuid) {
+        NodeBuilder history = versionStorage;
+        for (String segment : getRelativeVersionHistoryPathSegments(versionableUuid)) {
             history = history.getChildNode(segment);
         }
         return history.getChildNode(versionableUuid);
     }
 
-    private static List<String> getVersionHistoryPathSegments(String versionableUuid) {
+    private static List<String> getRelativeVersionHistoryPathSegments(String versionableUuid) {
         final List<String> segments = new ArrayList<String>();
-        segments.add(JCR_SYSTEM);
-        segments.add(JCR_VERSIONSTORAGE);
         for (int i = 0; i < 3; i++) {
             segments.add(versionableUuid.substring(i * 2, i * 2 + 2));
         }
         return segments;
     }
 
+    public static NodeState getVersionStorage(NodeState root) {
+        return root.getChildNode(JCR_SYSTEM).getChildNode(JCR_VERSIONSTORAGE);
+    }
+
+    public static NodeBuilder getVersionStorage(NodeBuilder root) {
+        return root.getChildNode(JCR_SYSTEM).getChildNode(JCR_VERSIONSTORAGE);
+    }
+
+    public static NodeBuilder createVersionStorage(NodeBuilder root) {
+        NodeBuilder vs = root.child(JCR_SYSTEM).child(JCR_VERSIONSTORAGE);
+        if (!vs.hasProperty(JCR_PRIMARYTYPE)) {
+            vs.setProperty(JCR_PRIMARYTYPE, REP_VERSIONSTORAGE, Type.NAME);
+        }
+        return vs;
+    }
+
 }

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java Fri Dec 16 11:12:53 2016
@@ -19,7 +19,6 @@ 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;
@@ -46,7 +45,9 @@ 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.getVersionHistoryBuilder;
 import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionHistoryNodeState;
+import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionStorage;
 
 /**
  * The VersionableEditor provides two possible ways to handle
@@ -70,6 +71,8 @@ public class VersionableEditor extends D
 
     private final NodeBuilder rootBuilder;
 
+    private final NodeBuilder versionStorage;
+
     private final TypePredicate isReferenceable;
 
     private final TypePredicate isVersionable;
@@ -80,16 +83,17 @@ public class VersionableEditor extends D
 
     private String path;
 
-    private VersionableEditor(Provider provider, NodeBuilder builder) {
+    private VersionableEditor(Provider provider, NodeBuilder rootBuilder) {
+        this.rootBuilder = rootBuilder;
+        this.versionStorage = getVersionStorage(rootBuilder);
+        this.vMgr = new ReadWriteVersionManager(versionStorage, rootBuilder);
+
         this.provider = provider;
-        this.rootBuilder = builder;
-        this.isVersionable = new TypePredicate(builder.getNodeState(), MIX_VERSIONABLE);
-        this.isReferenceable = new TypePredicate(builder.getNodeState(), MIX_REFERENCEABLE);
-        this.versionCopier = new VersionCopier(provider.sourceRoot, builder);
+        this.isVersionable = new TypePredicate(rootBuilder.getNodeState(), MIX_VERSIONABLE);
+        this.isReferenceable = new TypePredicate(rootBuilder.getNodeState(), MIX_REFERENCEABLE);
+        this.versionCopier = new VersionCopier(rootBuilder, getVersionStorage(provider.sourceRoot), versionStorage);
         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 {
@@ -107,8 +111,8 @@ public class VersionableEditor extends D
         }
 
         @Override
-        public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder builder, CommitInfo info) throws CommitFailedException {
-            return new VersionableEditor(this, builder);
+        public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder rootBuilder, CommitInfo info) throws CommitFailedException {
+            return new VersionableEditor(this, rootBuilder);
         }
     }
 
@@ -159,13 +163,15 @@ public class VersionableEditor extends D
     }
 
     private void setVersionablePath(String versionableUuid) {
-        final NodeBuilder versionHistory = VersionHistoryUtil.getVersionHistoryBuilder(rootBuilder, versionableUuid);
-        versionHistory.setProperty(provider.workspaceName, path, Type.PATH);
+        final NodeBuilder versionHistory = VersionHistoryUtil.getVersionHistoryBuilder(versionStorage, versionableUuid);
+        if (!versionHistory.hasProperty(provider.workspaceName)) {
+            versionHistory.setProperty(provider.workspaceName, path, Type.PATH);
+        }
         addMixin(versionHistory, MIX_REP_VERSIONABLE_PATHS);
     }
 
     private boolean isVersionHistoryExists(String versionableUuid) {
-        return getVersionHistoryNodeState(rootBuilder.getNodeState(), versionableUuid).exists();
+        return getVersionHistoryBuilder(versionStorage, versionableUuid).exists();
     }
 
     private void removeVersionProperties(final NodeBuilder versionableBuilder) {

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionablePropertiesEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionablePropertiesEditor.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionablePropertiesEditor.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionablePropertiesEditor.java Fri Dec 16 11:12:53 2016
@@ -37,7 +37,6 @@ import static com.google.common.collect.
 import static org.apache.jackrabbit.JcrConstants.JCR_BASEVERSION;
 import static org.apache.jackrabbit.JcrConstants.JCR_FROZENMIXINTYPES;
 import static org.apache.jackrabbit.JcrConstants.JCR_ISCHECKEDOUT;
-import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
 import static org.apache.jackrabbit.JcrConstants.JCR_PREDECESSORS;
 import static org.apache.jackrabbit.JcrConstants.JCR_ROOTVERSION;
 import static org.apache.jackrabbit.JcrConstants.JCR_SUCCESSORS;
@@ -51,6 +50,7 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.api.Type.REFERENCES;
 import static org.apache.jackrabbit.oak.plugins.memory.MultiGenericPropertyState.nameProperty;
 import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionHistoryNodeState;
+import static org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionStorage;
 
 /**
  * The VersionablePropertiesEditor adds missing versionable properties.
@@ -63,6 +63,8 @@ public final class VersionableProperties
 
     private final NodeBuilder rootBuilder;
 
+    private final NodeBuilder versionStorage;
+
     private final NodeBuilder builder;
 
     private final TypePredicate isVersionable;
@@ -76,6 +78,7 @@ public final class VersionableProperties
     private VersionablePropertiesEditor(NodeBuilder rootBuilder) {
         this.builder = rootBuilder;
         this.rootBuilder = rootBuilder;
+        this.versionStorage = getVersionStorage(rootBuilder);
         this.isVersionable = new TypePredicate(rootBuilder.getNodeState(), MIX_VERSIONABLE);
         this.isSimpleVersionable = new TypePredicate(rootBuilder.getNodeState(), MIX_SIMPLE_VERSIONABLE);
         this.isNtVersion = new TypePredicate(rootBuilder.getNodeState(), NT_VERSION);
@@ -85,6 +88,7 @@ public final class VersionableProperties
     private VersionablePropertiesEditor(VersionablePropertiesEditor parent, NodeBuilder builder) {
         this.builder = builder;
         this.rootBuilder = parent.rootBuilder;
+        this.versionStorage = parent.versionStorage;
         this.isVersionable = parent.isVersionable;
         this.isSimpleVersionable = parent.isSimpleVersionable;
         this.isNtVersion = parent.isNtVersion;
@@ -133,7 +137,7 @@ public final class VersionableProperties
     }
 
     private void fixProperties(NodeBuilder node) {
-        NodeState versionHistory = getVersionHistoryNodeState(rootBuilder.getNodeState(), node.getString(JCR_UUID));
+        NodeState versionHistory = getVersionHistoryNodeState(versionStorage.getNodeState(), node.getString(JCR_UUID));
         if (!versionHistory.exists()) {
             log.warn("No version history for {}", node);
             return;

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/main/resources/upgrade_usage.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/resources/upgrade_usage.txt?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/main/resources/upgrade_usage.txt (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/main/resources/upgrade_usage.txt Fri Dec 16 11:12:53 2016
@@ -34,14 +34,15 @@ in-place. Old files will be moved to the
 
 An descriptor of the Oak node store. Possible options:
 
-  * path to the segment store
+  * path to the segment-tar store
+  * segment-old:/path/to/classic/segment
   * jdbc:... (requires passing username and password as separate parameters)
   * mongodb://host:port/database
 
 # node store options
 
 --cache <int>             Cache size in MB (default: 256)
---mmap                    Enable memory mapped file access for Segment Store
+--disable-mmap            Disable memory mapped file access for Segment Store
 
 --src-password            Source rdb password
 --src-user                Source rdb user
@@ -92,4 +93,7 @@ An descriptor of the Oak node store. Pos
 
 # other options
 
--?, -h, --help            show help
\ No newline at end of file
+-?, -h, --help            Show help
+--skip-init               Don't initialize the destination repository
+--skip-name-check         Don't look for long-named nodes at the beginning of
+                          the migration
\ No newline at end of file

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AbstractRepositoryUpgradeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AbstractRepositoryUpgradeTest.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AbstractRepositoryUpgradeTest.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AbstractRepositoryUpgradeTest.java Fri Dec 16 11:12:53 2016
@@ -159,24 +159,30 @@ public abstract class AbstractRepository
     protected void assertExisting(final String... paths) throws RepositoryException {
         final Session session = createAdminSession();
         try {
-            for (final String path : paths) {
-                final String relPath = path.substring(1);
-                assertTrue("node " + path + " should exist", session.getRootNode().hasNode(relPath));
-            }
+            assertExisting(session, paths);
         } finally {
             session.logout();
         }
     }
 
+    protected void assertExisting(final Session session, final String... paths) throws RepositoryException {
+        for (final String path : paths) {
+            assertTrue("node " + path + " should exist", session.nodeExists(path));
+        }
+    }
+
     protected void assertMissing(final String... paths) throws RepositoryException {
         final Session session = createAdminSession();
         try {
-            for (final String path : paths) {
-                final String relPath = path.substring(1);
-                assertFalse("node " + path + " should not exist", session.getRootNode().hasNode(relPath));
-            }
+            assertMissing(session, paths);
         } finally {
             session.logout();
         }
     }
+
+    protected void assertMissing(final Session session, final String... paths) throws RepositoryException {
+        for (final String path : paths) {
+            assertFalse("node " + path + " should not exist", session.nodeExists(path));
+        }
+    }
 }

Added: jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AuthorizableFolderEditorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AuthorizableFolderEditorTest.java?rev=1774571&view=auto
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AuthorizableFolderEditorTest.java (added)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AuthorizableFolderEditorTest.java Fri Dec 16 11:12:53 2016
@@ -0,0 +1,127 @@
+/*
+ * 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.upgrade;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Test;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import java.io.InputStream;
+
+import static org.junit.Assert.assertThat;
+
+public class AuthorizableFolderEditorTest extends AbstractRepositoryUpgradeTest {
+
+    // this repository config sets the groupsPath and usersPath to match
+    // this tests expectations
+    private static final String REPOSITORY_XML_FILE = "repository-groupmember.xml";
+
+    private static final String TEST_GROUP = "AuthorizableFolderEditorTest-Group";
+
+    private static final String TEST_USER = "AuthorizableFolderEditorTest-User";
+
+    private static final String HOME_PATH = "/home";
+
+    private static final String GROUPS_PATH = HOME_PATH + "/groups";
+
+    private static final String USERS_PATH = HOME_PATH + "/users";
+
+    private static final String CONTROL_PATH = HOME_PATH + "/control";
+
+    @Override
+    protected void createSourceContent(final Session session) throws Exception {
+        UserManager userMgr = ((JackrabbitSession) session).getUserManager();
+        userMgr.autoSave(false);
+        Group group = userMgr.createGroup(TEST_GROUP);
+        User user = userMgr.createUser(TEST_USER, "secret");
+        group.addMember(user);
+        session.save();
+
+        // simulate the error, set node types to incorrect values
+        Node home = session.getNode("/home");
+        home.setPrimaryType(JcrConstants.NT_UNSTRUCTURED);
+        home.getNode("users").setPrimaryType(JcrConstants.NT_UNSTRUCTURED);
+        home.getNode("groups").setPrimaryType(JcrConstants.NT_UNSTRUCTURED);
+        home.addNode("control", JcrConstants.NT_UNSTRUCTURED);
+        session.save();
+    }
+
+    @Override
+    public InputStream getRepositoryConfig() {
+        return getClass().getClassLoader().getResourceAsStream(REPOSITORY_XML_FILE);
+    }
+
+    @Test
+    public void verifyCorrectedNodeTypes() throws RepositoryException {
+        final Session session = createAdminSession();
+        assertExisting(session, HOME_PATH, USERS_PATH, GROUPS_PATH, CONTROL_PATH);
+
+        assertThat(session.getNode(HOME_PATH), hasNodeType(UserConstants.NT_REP_AUTHORIZABLE_FOLDER));
+        assertThat(session.getNode(USERS_PATH), hasNodeType(UserConstants.NT_REP_AUTHORIZABLE_FOLDER));
+        assertThat(session.getNode(GROUPS_PATH), hasNodeType(UserConstants.NT_REP_AUTHORIZABLE_FOLDER));
+        assertThat(session.getNode(CONTROL_PATH), hasNodeType(JcrConstants.NT_UNSTRUCTURED));
+    }
+
+    private static Matcher<? super Node> hasNodeType(final String expectedNodeType) {
+        return new TypeSafeMatcher<Node>() {
+
+            private String path;
+
+            @Override
+            protected boolean matchesSafely(final Node node) {
+                path = getPath(node);
+                return getNodeTypeName(node).equals(expectedNodeType);
+            }
+
+            @Override
+            public void describeTo(final Description description) {
+                description.appendText("the node " + path + " to be of type ").appendValue(expectedNodeType);
+            }
+
+            @Override
+            protected void describeMismatchSafely(final Node node, final Description mismatchDescription) {
+                mismatchDescription.appendText(" was ").appendValue(getNodeTypeName(node));
+            }
+
+            private String getNodeTypeName(final Node node) {
+                try {
+                    return node.getPrimaryNodeType().getName();
+                } catch (RepositoryException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            private String getPath(final Node node) {
+                try {
+                    return node.getPath();
+                } catch (RepositoryException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        };
+    }
+}

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java Fri Dec 16 11:12:53 2016
@@ -16,10 +16,25 @@
  */
 package org.apache.jackrabbit.oak.upgrade;
 
+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;
+
 import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.jcr.Credentials;
+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 org.apache.jackrabbit.api.JackrabbitSession;
 import org.apache.jackrabbit.commons.cnd.CndImporter;
 import org.apache.jackrabbit.oak.Oak;
@@ -35,21 +50,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import javax.jcr.Credentials;
-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 {
 
     private static final Credentials CREDENTIALS = new SimpleCredentials("admin", "admin".toCharArray());

Modified: jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/CopyVersionHistoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/CopyVersionHistoryTest.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/CopyVersionHistoryTest.java (original)
+++ jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/CopyVersionHistoryTest.java Fri Dec 16 11:12:53 2016
@@ -16,8 +16,37 @@
  */
 package org.apache.jackrabbit.oak.upgrade;
 
+import static org.apache.jackrabbit.JcrConstants.JCR_PREDECESSORS;
+import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONHISTORY;
+import static org.apache.jackrabbit.JcrConstants.MIX_VERSIONABLE;
+import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.MIX_REP_VERSIONABLE_PATHS;
+import static org.apache.jackrabbit.oak.upgrade.util.VersionCopyTestUtils.createLabeledVersions;
+import static org.apache.jackrabbit.oak.upgrade.util.VersionCopyTestUtils.getOrAddNodeWithMixins;
+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;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionManager;
+
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.core.RepositoryContext;
 import org.apache.jackrabbit.core.config.RepositoryConfig;
 import org.apache.jackrabbit.oak.Oak;
@@ -32,37 +61,6 @@ import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Test;
 
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyType;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-import javax.jcr.version.VersionManager;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Map;
-
-import com.google.common.collect.Lists;
-
-import static org.apache.jackrabbit.JcrConstants.JCR_PREDECESSORS;
-import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONHISTORY;
-import static org.apache.jackrabbit.JcrConstants.MIX_VERSIONABLE;
-import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.MIX_REP_VERSIONABLE_PATHS;
-import static org.apache.jackrabbit.oak.upgrade.util.VersionCopyTestUtils.getOrAddNodeWithMixins;
-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;
-import static org.apache.jackrabbit.oak.upgrade.util.VersionCopyTestUtils.createLabeledVersions;
-
 public class CopyVersionHistoryTest extends AbstractRepositoryUpgradeTest {
 
     private static final String VERSIONABLES_PATH_PREFIX = "/versionables/";
@@ -253,6 +251,8 @@ public class CopyVersionHistoryTest exte
 
         assertMissingHistories(session,
                 VERSIONABLES_OLD, VERSIONABLES_OLD_ORPHANED, VERSIONABLES_YOUNG, VERSIONABLES_YOUNG_ORPHANED);
+        assertNotNull(session.getNode("/jcr:system/jcr:versionStorage")
+                .getPrimaryNodeType());
     }
 
     protected Session performCopy(VersionCopySetup setup) throws RepositoryException, IOException {