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 {
