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 2017/05/09 13:57:42 UTC

svn commit: r1794585 - in /jackrabbit/oak/trunk/oak-upgrade/src: main/java/org/apache/jackrabbit/oak/upgrade/ main/java/org/apache/jackrabbit/oak/upgrade/cli/ main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/ main/java/org/apache/jackrabbit/oak/u...

Author: tomekr
Date: Tue May  9 13:57:41 2017
New Revision: 1794585

URL: http://svn.apache.org/viewvc?rev=1794585&view=rev
Log:
OAK-6188: Allow to exclude nodes containing name fragment during the migration

-added the fragment-paths parameter

Modified:
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopier.java
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeUpgradeTest.java
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java Tue May  9 13:57:41 2017
@@ -66,6 +66,7 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants.REP_PERMISSION_STORE;
 import static org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_EXCLUDE_FRAGMENTS;
 import static org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_EXCLUDE_PATHS;
+import static org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_FRAGMENT_PATHS;
 import static org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_INCLUDE_PATHS;
 import static org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_MERGE_PATHS;
 import static org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.calculateEffectiveIncludePaths;
@@ -101,6 +102,11 @@ public class RepositorySidegrade {
     private Set<String> excludePaths = DEFAULT_EXCLUDE_PATHS;
 
     /**
+     * Paths supporting fragments during the copy process. Empty by default.
+     */
+    private Set<String> fragmentPaths = DEFAULT_FRAGMENT_PATHS;
+
+    /**
      * Fragments to exclude during the copy process. Empty by default.
      */
     private Set<String> excludeFragments = DEFAULT_EXCLUDE_FRAGMENTS;
@@ -215,6 +221,15 @@ public class RepositorySidegrade {
     }
 
     /**
+     * Sets the paths that should support the fragments.
+     *
+     * @param fragmentPaths Paths that should support fragments.
+     */
+    public void setFragmentPaths(@Nonnull String... fragmentPaths) {
+        this.fragmentPaths = copyOf(checkNotNull(fragmentPaths));
+    }
+
+    /**
      * Sets the name fragments that should be excluded when the source repository
      * is copied to the target repository.
      *
@@ -361,7 +376,7 @@ public class RepositorySidegrade {
         for (CheckpointRetriever.Checkpoint checkpoint : checkpoints) {
             NodeState checkpointRoot = source.retrieve(checkpoint.getName());
             if (!isCompleteMigration()) {
-                checkpointRoot = FilteringNodeState.wrap("/", checkpointRoot, includePaths, excludePaths, excludeFragments);
+                checkpointRoot = FilteringNodeState.wrap("/", checkpointRoot, includePaths, excludePaths, fragmentPaths, excludeFragments);
             }
             if (previousRoot == EmptyNodeState.EMPTY_NODE) {
                 LOG.info("Migrating first checkpoint: {}", checkpoint.getName());
@@ -383,7 +398,7 @@ public class RepositorySidegrade {
 
         NodeState sourceRoot = source.getRoot();
         if (!isCompleteMigration()) {
-            sourceRoot = FilteringNodeState.wrap("/", sourceRoot, includePaths, excludePaths, excludeFragments);
+            sourceRoot = FilteringNodeState.wrap("/", sourceRoot, includePaths, excludePaths, fragmentPaths, excludeFragments);
         }
         if (previousRoot == EmptyNodeState.EMPTY_NODE) {
             LOG.info("No checkpoints found; migrating head");
@@ -416,7 +431,7 @@ public class RepositorySidegrade {
     }
 
     private boolean isCompleteMigration() {
-        return includePaths.equals(DEFAULT_INCLUDE_PATHS) && excludePaths.equals(DEFAULT_EXCLUDE_PATHS) && excludeFragments.equals(DEFAULT_EXCLUDE_FRAGMENTS) && mergePaths.equals(DEFAULT_MERGE_PATHS);
+        return includePaths.equals(DEFAULT_INCLUDE_PATHS) && excludePaths.equals(DEFAULT_EXCLUDE_PATHS) && excludeFragments.equals(DEFAULT_EXCLUDE_FRAGMENTS) && mergePaths.equals(DEFAULT_MERGE_PATHS) && fragmentPaths.equals(DEFAULT_FRAGMENT_PATHS);
     }
 
     private void copyWorkspace(NodeState sourceRoot, NodeBuilder targetRoot) {
@@ -432,6 +447,7 @@ public class RepositorySidegrade {
         NodeStateCopier.builder()
             .include(includes)
             .exclude(excludes)
+            .supportFragment(fragmentPaths)
             .excludeFragments(excludeFragments)
             .merge(merges)
             .copy(sourceRoot, targetRoot);

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java Tue May  9 13:57:41 2017
@@ -154,6 +154,8 @@ public class RepositoryUpgrade {
 
     public static final Set<String> DEFAULT_EXCLUDE_PATHS = NONE;
 
+    public static final Set<String> DEFAULT_FRAGMENT_PATHS = NONE;
+
     public static final Set<String> DEFAULT_EXCLUDE_FRAGMENTS = NONE;
 
     public static final Set<String> DEFAULT_MERGE_PATHS = NONE;
@@ -179,6 +181,11 @@ public class RepositoryUpgrade {
     private Set<String> excludePaths = DEFAULT_EXCLUDE_PATHS;
 
     /**
+     * Paths supporting fragments during the copy process. Empty by default.
+     */
+    private Set<String> fragmentPaths = DEFAULT_FRAGMENT_PATHS;
+
+    /**
      * Fragments to exclude during the copy process. Empty by default.
      */
     private Set<String> excludeFragments = DEFAULT_EXCLUDE_FRAGMENTS;
@@ -340,6 +347,15 @@ public class RepositoryUpgrade {
     }
 
     /**
+     * Sets the paths that should support the fragments.
+     *
+     * @param fragmentPaths Paths that should support fragments.
+     */
+    public void setFragmentPaths(@Nonnull String... fragmentPaths) {
+        this.fragmentPaths = copyOf(checkNotNull(fragmentPaths));
+    }
+
+    /**
      * Sets the name fragments that should be excluded when the source repository
      * is copied to the target repository.
      *
@@ -948,6 +964,7 @@ public class RepositoryUpgrade {
         NodeStateCopier.builder()
                 .include(includes)
                 .exclude(excludes)
+                .supportFragment(fragmentPaths)
                 .excludeFragments(excludeFragments)
                 .merge(merges)
                 .copy(sourceRoot, targetRoot);

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java Tue May  9 13:57:41 2017
@@ -85,6 +85,9 @@ public class MigrationFactory {
         if (options.getExcludePaths() != null) {
             upgrade.setExcludes(options.getExcludePaths());
         }
+        if (options.getFragmentPaths() != null) {
+            upgrade.setFragmentPaths(options.getFragmentPaths());
+        }
         if (options.getExcludeFragments() != null) {
             upgrade.setExcludeFragments(options.getExcludeFragments());
         }
@@ -116,6 +119,9 @@ public class MigrationFactory {
         if (options.getExcludeFragments() != null) {
             sidegrade.setExcludeFragments(options.getExcludeFragments());
         }
+        if (options.getFragmentPaths() != null) {
+            sidegrade.setFragmentPaths(options.getFragmentPaths());
+        }
         if (options.getMergePaths() != null) {
             sidegrade.setMerges(options.getMergePaths());
         }

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java Tue May  9 13:57:41 2017
@@ -46,6 +46,8 @@ public class MigrationOptions {
 
     private final String[] excludePaths;
 
+    private final String[] fragmentPaths;
+
     private final String[] excludeFragments;
 
     private final String[] mergePaths;
@@ -119,6 +121,7 @@ public class MigrationOptions {
         }
         this.includePaths = checkPaths(args.getOptionList(OptionParserFactory.INCLUDE_PATHS));
         this.excludePaths = checkPaths(args.getOptionList(OptionParserFactory.EXCLUDE_PATHS));
+        this.fragmentPaths = checkPaths(args.getOptionList(OptionParserFactory.FRAGMENT_PATHS));
         this.excludeFragments = args.getOptionList(OptionParserFactory.EXCLUDE_FRAGMENTS);
         this.mergePaths = checkPaths(args.getOptionList(OptionParserFactory.MERGE_PATHS));
         this.includeIndex = args.hasOption(OptionParserFactory.INCLUDE_INDEX);
@@ -183,6 +186,10 @@ public class MigrationOptions {
         return excludePaths;
     }
 
+    public String[] getFragmentPaths() {
+        return fragmentPaths;
+    }
+
     public String[] getExcludeFragments() {
         return excludeFragments;
     }
@@ -336,6 +343,10 @@ public class MigrationOptions {
             log.info("paths to exclude: {}", (Object) excludePaths);
         }
 
+        if (fragmentPaths != null) {
+            log.info("paths supporting fragments: {}", (Object) fragmentPaths);
+        }
+
         if (excludeFragments != null) {
             log.info("fragments to exclude: {}", (Object) excludeFragments);
         }

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java Tue May  9 13:57:41 2017
@@ -70,6 +70,8 @@ public class OptionParserFactory {
 
     public static final String EXCLUDE_PATHS = "exclude-paths";
 
+    public static final String FRAGMENT_PATHS = "fragment-paths";
+
     public static final String EXCLUDE_FRAGMENTS = "exclude-fragments";
 
     public static final String MERGE_PATHS = "merge-paths";
@@ -135,6 +137,8 @@ public class OptionParserFactory {
                 .ofType(String.class);
         op.accepts(EXCLUDE_PATHS, "Comma-separated list of paths to exclude during copy.").withRequiredArg()
                 .ofType(String.class);
+        op.accepts(FRAGMENT_PATHS, "Comma-separated list of paths supporting fragments.").withRequiredArg()
+                .ofType(String.class);
         op.accepts(EXCLUDE_FRAGMENTS, "Comma-separated list of fragments to exclude during copy.").withRequiredArg()
                 .ofType(String.class);
         op.accepts(MERGE_PATHS, "Comma-separated list of paths to merge during copy.").withRequiredArg()

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java Tue May  9 13:57:41 2017
@@ -67,6 +67,8 @@ public class FilteringNodeState extends
 
     private final Set<String> excludedPaths;
 
+    private final Set<String> fragmentPaths;
+
     private final Set<String> excludedFragments;
 
     /**
@@ -77,6 +79,7 @@ public class FilteringNodeState extends
      * @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 fragmentPaths A Set of paths that should support the fragments (see below). Empty if {@code null}.
      * @param excludedFragments A Set of name fragments that should be hidden. Empty if {@code null}.
      * @return The decorated node-state if required, the original node-state if decoration is unnecessary.
      */
@@ -86,13 +89,15 @@ public class FilteringNodeState extends
             @Nonnull final NodeState delegate,
             @Nullable final Set<String> includePaths,
             @Nullable final Set<String> excludePaths,
+            @Nullable final Set<String> fragmentPaths,
             @Nullable final Set<String> excludedFragments
     ) {
         final Set<String> includes = defaultIfEmpty(includePaths, ALL);
         final Set<String> excludes = defaultIfEmpty(excludePaths, NONE);
+        final Set<String> safeFragmentPaths = defaultIfEmpty(fragmentPaths, NONE);
         final Set<String> safeExcludedFragments = defaultIfEmpty(excludedFragments, NONE);
-        if (hasHiddenDescendants(path, includes, excludes, safeExcludedFragments)) {
-            return new FilteringNodeState(path, delegate, includes, excludes, safeExcludedFragments);
+        if (hasHiddenDescendants(path, includes, excludes, safeFragmentPaths, safeExcludedFragments)) {
+            return new FilteringNodeState(path, delegate, includes, excludes, fragmentPaths, safeExcludedFragments);
         }
         return delegate;
     }
@@ -102,12 +107,14 @@ public class FilteringNodeState extends
             @Nonnull final NodeState delegate,
             @Nonnull final Set<String> includedPaths,
             @Nonnull final Set<String> excludedPaths,
+            @Nonnull final Set<String> fragmentPaths,
             @Nonnull final Set<String> excludedFragments
     ) {
         super(delegate);
         this.path = path;
         this.includedPaths = includedPaths;
         this.excludedPaths = excludedPaths;
+        this.fragmentPaths = fragmentPaths;
         this.excludedFragments = excludedFragments;
     }
 
@@ -115,7 +122,7 @@ public class FilteringNodeState extends
     @Override
     protected NodeState decorateChild(@Nonnull final String name, @Nonnull final NodeState child) {
         final String childPath = PathUtils.concat(path, name);
-        return wrap(childPath, child, includedPaths, excludedPaths, excludedFragments);
+        return wrap(childPath, child, includedPaths, excludedPaths, fragmentPaths, excludedFragments);
     }
 
     @Override
@@ -161,10 +168,13 @@ public class FilteringNodeState extends
             @Nonnull final String path,
             @Nonnull final Set<String> includePaths,
             @Nonnull final Set<String> excludePaths,
+            @Nonnull final Set<String> fragmentPaths,
             @Nonnull final Set<String> excludedFragments
     ) {
-        return !excludedFragments.isEmpty()
-                || isHidden(path, includePaths, excludePaths, excludedFragments)
+        return isHidden(path, includePaths, excludePaths, excludedFragments)
+                || isAncestorOfAnyPath(path, fragmentPaths)
+                || isDescendantOfAnyPath(path, fragmentPaths)
+                || fragmentPaths.contains(path)
                 || isAncestorOfAnyPath(path, excludePaths)
                 || isAncestorOfAnyPath(path, includePaths);
     }

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopier.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopier.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopier.java Tue May  9 13:57:41 2017
@@ -80,13 +80,16 @@ public class NodeStateCopier {
 
     private final Set<String> excludePaths;
 
+    private final Set<String> fragmentPaths;
+
     private final Set<String> excludeFragments;
 
     private final Set<String> mergePaths;
 
-    private NodeStateCopier(Set<String> includePaths, Set<String> excludePaths, Set<String> excludeFragments, Set<String> mergePaths) {
+    private NodeStateCopier(Set<String> includePaths, Set<String> excludePaths, Set<String> fragmentPaths, Set<String> excludeFragments, Set<String> mergePaths) {
         this.includePaths = includePaths;
         this.excludePaths = excludePaths;
+        this.fragmentPaths = fragmentPaths;
         this.excludeFragments = excludeFragments;
         this.mergePaths = mergePaths;
     }
@@ -147,7 +150,7 @@ public class NodeStateCopier {
     }
 
     private boolean copyNodeState(@Nonnull final NodeState sourceRoot, @Nonnull final NodeBuilder targetRoot) {
-        final NodeState wrappedSource = FilteringNodeState.wrap("/", sourceRoot, this.includePaths, this.excludePaths, this.excludeFragments);
+        final NodeState wrappedSource = FilteringNodeState.wrap("/", sourceRoot, this.includePaths, this.excludePaths, this.fragmentPaths, this.excludeFragments);
         boolean hasChanges = false;
         for (String includePath : this.includePaths) {
             hasChanges = copyMissingAncestors(sourceRoot, targetRoot, includePath) || hasChanges;
@@ -300,6 +303,8 @@ public class NodeStateCopier {
 
         private Set<String> excludePaths = emptySet();
 
+        private Set<String> fragmentPaths = emptySet();
+
         private Set<String> excludeFragments = emptySet();
 
         private Set<String> mergePaths = emptySet();
@@ -312,7 +317,7 @@ public class NodeStateCopier {
          *
          * @param paths include paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder include(@Nonnull Set<String> paths) {
@@ -327,7 +332,7 @@ public class NodeStateCopier {
          *
          * @param paths include paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder include(@Nonnull String... paths) {
@@ -339,7 +344,7 @@ public class NodeStateCopier {
          *
          * @param paths exclude paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder exclude(@Nonnull Set<String> paths) {
@@ -354,7 +359,7 @@ public class NodeStateCopier {
          *
          * @param paths exclude paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder exclude(@Nonnull String... paths) {
@@ -362,11 +367,38 @@ public class NodeStateCopier {
         }
 
         /**
+         * Set fragment paths.
+         *
+         * @param paths fragment paths
+         * @return this Builder instance
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         */
+        @Nonnull
+        public Builder supportFragment(@Nonnull Set<String> paths) {
+            if (!checkNotNull(paths).isEmpty()) {
+                this.fragmentPaths = copyOf(paths);
+            }
+            return this;
+        }
+
+        /**
+         * Convenience wrapper for {@link #supportFragment(Set)}.
+         *
+         * @param paths fragment paths
+         * @return this Builder instance
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         */
+        @Nonnull
+        public Builder supportFragment(@Nonnull String... paths) {
+            return supportFragment(copyOf(checkNotNull(paths)));
+        }
+
+        /**
          * Set exclude fragments.
          *
          * @param fragments exclude fragments
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder excludeFragments(@Nonnull Set<String> fragments) {
@@ -381,7 +413,7 @@ public class NodeStateCopier {
          *
          * @param fragments exclude fragments
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder excludeFragments(@Nonnull String... fragments) {
@@ -393,7 +425,7 @@ public class NodeStateCopier {
          *
          * @param paths merge paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder merge(@Nonnull Set<String> paths) {
@@ -408,7 +440,7 @@ public class NodeStateCopier {
          *
          * @param paths merge paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
          */
         @Nonnull
         public Builder merge(@Nonnull String... paths) {
@@ -429,7 +461,7 @@ public class NodeStateCopier {
          *         the same content
          */
         public boolean copy(@Nonnull final NodeState sourceRoot, @Nonnull final NodeBuilder targetRoot) {
-            final NodeStateCopier copier = new NodeStateCopier(includePaths, excludePaths, excludeFragments, mergePaths);
+            final NodeStateCopier copier = new NodeStateCopier(includePaths, excludePaths, fragmentPaths, excludeFragments, mergePaths);
             return copier.copyNodeState(checkNotNull(sourceRoot), checkNotNull(targetRoot));
         }
 

Modified: jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java Tue May  9 13:57:41 2017
@@ -73,7 +73,8 @@ public class IncludeExcludeSidegradeTest
             final RepositorySidegrade sidegrade = new RepositorySidegrade(segmentNodeStore, target);
             sidegrade.setIncludes(
                     "/content/foo/en",
-                    "/content/assets/foo"
+                    "/content/assets/foo",
+                    "/content/other"
             );
             sidegrade.setExcludes(
                     "/content/assets/foo/2013",
@@ -84,6 +85,9 @@ public class IncludeExcludeSidegradeTest
             sidegrade.setExcludeFragments(
                     "oak-mount-libs-xyz"
             );
+            sidegrade.setFragmentPaths(
+                    "/content/other/path"
+            );
             sidegrade.copy();
         } finally {
             fileStore.close();

Modified: jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeUpgradeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeUpgradeTest.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeUpgradeTest.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeUpgradeTest.java Tue May  9 13:57:41 2017
@@ -46,10 +46,10 @@ public class IncludeExcludeUpgradeTest e
         JcrUtils.getOrCreateByPath("/content/assets/foo/2011", "nt:folder", session);
         JcrUtils.getOrCreateByPath("/content/assets/foo/2010", "nt:folder", session);
         JcrUtils.getOrCreateByPath("/content/assets/foo/2010/12", "nt:folder", session);
-        JcrUtils.getOrCreateByPath("/content/assets/foo/oak-mount-libs-xyz/node1", "nt:folder", session);
-        JcrUtils.getOrCreateByPath("/content/assets/foo/oak-mount-libs-xyz/node2", "nt:folder", session);
-        JcrUtils.getOrCreateByPath("/content/assets/foo/oak-mount-apps-abc/node3", "nt:folder", session);
-        JcrUtils.getOrCreateByPath("/content/assets/foo/oak-mount-apps-abc/node4", "nt:folder", session);
+        JcrUtils.getOrCreateByPath("/content/other/path/foo/oak-mount-libs-xyz/node1", "nt:folder", session);
+        JcrUtils.getOrCreateByPath("/content/other/path/foo/oak-mount-libs-xyz/node2", "nt:folder", session);
+        JcrUtils.getOrCreateByPath("/content/other/path/foo/oak-mount-apps-abc/node3", "nt:folder", session);
+        JcrUtils.getOrCreateByPath("/content/other/path/foo/oak-mount-apps-abc/node4", "nt:folder", session);
         session.save();
     }
 
@@ -61,7 +61,8 @@ public class IncludeExcludeUpgradeTest e
             final RepositoryUpgrade upgrade = new RepositoryUpgrade(context, target);
             upgrade.setIncludes(
                     "/content/foo/en",
-                    "/content/assets/foo"
+                    "/content/assets/foo",
+                    "/content/other"
             );
             upgrade.setExcludes(
                     "/content/assets/foo/2013",
@@ -72,6 +73,9 @@ public class IncludeExcludeUpgradeTest e
             upgrade.setExcludeFragments(
                     "oak-mount-libs-xyz"
             );
+            upgrade.setFragmentPaths(
+                    "/content/other/path"
+            );
             upgrade.copy(null);
         } finally {
             context.getRepository().shutdown();
@@ -85,8 +89,8 @@ public class IncludeExcludeUpgradeTest e
                 "/content/assets/foo/2015/02",
                 "/content/assets/foo/2015/01",
                 "/content/assets/foo/2014",
-                "/content/assets/foo/oak-mount-apps-abc/node3",
-                "/content/assets/foo/oak-mount-apps-abc/node4"
+                "/content/other/path/foo/oak-mount-apps-abc/node3",
+                "/content/other/path/foo/oak-mount-apps-abc/node4"
         );
     }
 
@@ -106,8 +110,8 @@ public class IncludeExcludeUpgradeTest e
                 "/content/assets/foo/2012",
                 "/content/assets/foo/2011",
                 "/content/assets/foo/2010",
-                "/content/assets/foo/oak-mount-libs-xyz/node1",
-                "/content/assets/foo/oak-mount-libs-xyz/node2"
+                "/content/other/path/foo/oak-mount-libs-xyz/node1",
+                "/content/other/path/foo/oak-mount-libs-xyz/node2"
         );
     }
 }

Modified: jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java?rev=1794585&r1=1794584&r2=1794585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java Tue May  9 13:57:41 2017
@@ -80,46 +80,46 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldNotDecorateForNullArgs() {
-        final NodeState decorated = wrap("/", rootNodeState, null, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, null, null, null);
         assertSame("root should be identical to decorated", rootNodeState, decorated);
     }
 
     @Test
     public void shouldNotDecorateForDefaultIncludes() {
-        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, null, null, null);
         assertSame("root should be identical to decorated", rootNodeState, decorated);
     }
 
     @Test
     public void shouldNotDecorateForDefaultExcludes() {
-        final NodeState decorated = wrap("/", rootNodeState, null, DEFAULT_EXCLUDES, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, DEFAULT_EXCLUDES, null, null);
         assertSame("root should be identical to decorated", rootNodeState, decorated);
     }
 
     @Test
     public void shouldNotDecorateForDefaultIncludesAndExcludes() {
-        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, DEFAULT_EXCLUDES, null);
+        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, DEFAULT_EXCLUDES, null, null);
         assertSame("root should be identical to decorated", rootNodeState, decorated);
     }
 
     @Test
     public void shouldNotDecorateIncludedPath() {
         final NodeState content = getNodeState(rootNodeState, "/content");
-        final NodeState decorated = wrap("/content", content, of("/content"), null, null);
+        final NodeState decorated = wrap("/content", content, of("/content"), null, null, null);
         assertSame("content should be identical to decorated", content, decorated);
     }
 
     @Test
     public void shouldNotDecorateIncludedDescendants() {
         final NodeState foo = getNodeState(rootNodeState, "/content/foo");
-        final NodeState decorated = wrap("/content/foo", foo, of("/content"), null, null);
+        final NodeState decorated = wrap("/content/foo", foo, of("/content"), null, null, null);
         assertSame("foo should be identical to decorated", foo, decorated);
     }
 
     @Test
     public void shouldDecorateAncestorOfExcludedDescendants() {
         final NodeState foo = getNodeState(rootNodeState, "/content/foo");
-        final NodeState decorated = wrap("/content/foo", foo, of("/content"), of("/content/foo/de"), null);
+        final NodeState decorated = wrap("/content/foo", foo, of("/content"), of("/content/foo/de"), null, null);
         assertNotSame("foo should not be identical to decorated", foo, decorated);
 
         assertMissing(decorated, "de");
@@ -135,7 +135,7 @@ public class FilteringNodeStateTest {
     @Test
     public void shouldHaveCorrectChildOrderProperty() throws CommitFailedException {
         final NodeState content = rootNodeState.getChildNode("content");
-        final NodeState decorated = wrap("/content", content, null, of("/content/foo"), null);
+        final NodeState decorated = wrap("/content", content, null, of("/content/foo"), null, null);
 
         assertTrue(decorated.hasProperty(OAK_CHILD_ORDER));
 
@@ -160,7 +160,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDecorateExcludedNode() {
-        final NodeState decoratedRoot = wrap("/", rootNodeState, of("/content"), of("/content/foo/de"), null);
+        final NodeState decoratedRoot = wrap("/", rootNodeState, of("/content"), of("/content/foo/de"), null, null);
         final NodeState de = getNodeState(rootNodeState, "/content/foo/de");
         final NodeState decorated = getNodeState(decoratedRoot, "/content/foo/de");
         assertFalse("de should not be equal to decorated", de.equals(decorated));
@@ -170,14 +170,14 @@ public class FilteringNodeStateTest {
     @Test
     public void shouldDecorateImplicitlyExcludedNode() {
         final NodeState content = getNodeState(rootNodeState, "/content");
-        final NodeState decorated = wrap("/content", content, of("/apps"), null, null);
+        final NodeState decorated = wrap("/content", content, of("/apps"), null, null, null);
         assertNotSame("content should not be identical to decorated", content, decorated);
     }
 
 
     @Test
     public void shouldHideExcludedPathsViaExists() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", "/libs"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", "/libs"), null, null);
         assertMissing(decorated, "apps");
         assertMissing(decorated, "libs/foo/install");
 
@@ -187,7 +187,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideExcludedPathsViaHasChildNode() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", "/libs"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", "/libs"), null, null);
 
         assertExistingHasChildNode(decorated, "content");
         assertMissingHasChildNode(decorated, "apps");
@@ -196,7 +196,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideExcludedPathsViaGetChildNodeNames() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", "/libs"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", "/libs"), null, null);
 
         assertExistingChildNodeName(decorated, "content");
         assertMissingChildNodeName(decorated, "apps");
@@ -205,7 +205,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideMissingIncludedPathsViaExists() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), null, null, null);
         assertMissing(decorated, "apps");
         assertMissing(decorated, "libs/foo/install");
 
@@ -215,7 +215,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideMissingIncludedPathsViaHasChildNode() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), null, null, null);
 
         assertExistingHasChildNode(decorated, "content");
         assertMissingHasChildNode(decorated, "apps");
@@ -224,7 +224,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideMissingIncludedPathsViaGetChildNodeNames() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), null, null, null);
 
         assertExistingChildNodeName(decorated, "content");
         assertMissingChildNodeName(decorated, "apps");
@@ -233,15 +233,15 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldGivePrecedenceForExcludesOverIncludes() {
-        final NodeState conflictingRules = wrap("/", rootNodeState, of("/content"), of("/content"), null);
+        final NodeState conflictingRules = wrap("/", rootNodeState, of("/content"), of("/content"), null, null);
         assertMissingChildNodeName(conflictingRules, "content");
 
-        final NodeState overlappingRules = wrap("/", rootNodeState, of("/content"), of("/content/foo"), null);
+        final NodeState overlappingRules = wrap("/", rootNodeState, of("/content"), of("/content/foo"), null, null);
         assertExistingChildNodeName(overlappingRules, "content");
         assertMissingChildNodeName(overlappingRules.getChildNode("content"), "foo");
 
 
-        final NodeState overlappingRules2 = wrap("/", rootNodeState, of("/content/foo"), of("/content"), null);
+        final NodeState overlappingRules2 = wrap("/", rootNodeState, of("/content/foo"), of("/content"), null, null);
         assertMissingChildNodeName(overlappingRules2, "content");
         assertMissingChildNodeName(overlappingRules2.getChildNode("content"), "foo");
 
@@ -249,7 +249,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldRespectPathBoundariesForIncludes() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content/foo"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content/foo"), null, null, null);
 
         assertExistingChildNodeName(decorated, "content");
         assertExistingChildNodeName(decorated.getChildNode("content"), "foo");
@@ -258,7 +258,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldRespectPathBoundariesForExcludes() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo"), null, null);
 
         assertExistingChildNodeName(decorated, "content");
         assertMissingChildNodeName(decorated.getChildNode("content"), "foo");
@@ -267,7 +267,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDelegatePropertyCount() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo/de"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo/de"), null, null);
 
         assertEquals(1, getNodeState(decorated, "/content").getPropertyCount());
         assertEquals(0, getNodeState(decorated, "/content/foo").getPropertyCount());
@@ -276,7 +276,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDelegateGetProperty() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo"), null, null);
         final NodeState content = getNodeState(decorated, "/content");
 
         assertNotNull(content.getProperty(OAK_CHILD_ORDER));
@@ -286,7 +286,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDelegateHasProperty() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo/de"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo/de"), null, null);
 
         assertTrue(getNodeState(decorated, "/content").hasProperty(OAK_CHILD_ORDER));
         assertFalse(getNodeState(decorated, "/content").hasProperty("foo"));
@@ -295,7 +295,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void exists() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo"), null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/content/foo"), null, null);
         assertTrue("/content should exist and be visible", getNodeState(decorated, "/content").exists());
         assertFalse("/content/foo should be hidden", getNodeState(decorated, "/content/foo").exists());
         assertFalse("/nonexisting should not exist", getNodeState(decorated, "/nonexisting").exists());