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 re...@apache.org on 2015/08/07 12:31:01 UTC

svn commit: r1694646 [1/2] - in /jackrabbit/oak/trunk: oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/ oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/ oak-jcr/src/test/java/org/apache/j...

Author: reschke
Date: Fri Aug  7 10:31:00 2015
New Revision: 1694646

URL: http://svn.apache.org/r1694646
Log:
fix svn:eol-style

Modified:
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugImportAbortTest.java   (props changed)
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugImportBesteffortTest.java   (props changed)
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugImportIgnoreTest.java   (props changed)
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugSecurityProvider.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AbstractAddMembersByIdTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AbstractRemoveMembersByIdTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AddMembersByIdAbortTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AddMembersByIdBestEffortTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AddMembersByIdIgnoreTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdAbortTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java   (props changed)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdIgnoreTest.java   (props changed)
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/HasPermissionTest.java   (props changed)
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/VersionablePathNodeStoreTest.java   (props changed)
    jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/ManyGroupMembersTest.java   (props changed)
    jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/ParseVersionCopyArgumentTest.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/DescendantsIterator.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/CopyVersionHistoryTest.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeUpgradeTest.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/UpgradeFromTwoSourcesTest.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java   (contents, props changed)
    jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/VersionCopyTestUtils.java   (contents, props changed)

Propchange: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugImportAbortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugImportBesteffortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugImportIgnoreTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugSecurityProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AbstractAddMembersByIdTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AbstractRemoveMembersByIdTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AddMembersByIdAbortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AddMembersByIdBestEffortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AddMembersByIdIgnoreTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdAbortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdIgnoreTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/HasPermissionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/version/VersionablePathNodeStoreTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/ManyGroupMembersTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/ParseVersionCopyArgumentTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/ParseVersionCopyArgumentTest.java?rev=1694646&r1=1694645&r2=1694646&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/ParseVersionCopyArgumentTest.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/ParseVersionCopyArgumentTest.java Fri Aug  7 10:31:00 2015
@@ -1,53 +1,53 @@
-/*
- * 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.run;
-
-import java.text.ParseException;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ParseVersionCopyArgumentTest {
-
-    @Test
-    public void parseTrue() throws ParseException {
-        for (String argument : Arrays.asList("true", "TRUE", "TrUe")) {
-            final Calendar result = Main.parseVersionCopyArgument(argument);
-            Assert.assertEquals(0, result.getTimeInMillis());
-        }
-    }
-
-    @Test
-    public void parseDate() throws ParseException {
-        final Calendar result = Main.parseVersionCopyArgument("2013-01-01");
-        Assert.assertEquals(new GregorianCalendar(2013, 0, 1), result);
-    }
-
-    @Test
-    public void parseFalse() throws ParseException {
-        for (String argument : Arrays.asList("false", "FaLse", "", "xyz", null)) {
-            final Calendar result = Main.parseVersionCopyArgument(argument);
-            Assert.assertNull(result);
-        }
-    }
-}
+/*
+ * 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.run;
+
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ParseVersionCopyArgumentTest {
+
+    @Test
+    public void parseTrue() throws ParseException {
+        for (String argument : Arrays.asList("true", "TRUE", "TrUe")) {
+            final Calendar result = Main.parseVersionCopyArgument(argument);
+            Assert.assertEquals(0, result.getTimeInMillis());
+        }
+    }
+
+    @Test
+    public void parseDate() throws ParseException {
+        final Calendar result = Main.parseVersionCopyArgument("2013-01-01");
+        Assert.assertEquals(new GregorianCalendar(2013, 0, 1), result);
+    }
+
+    @Test
+    public void parseFalse() throws ParseException {
+        for (String argument : Arrays.asList("false", "FaLse", "", "xyz", null)) {
+            final Calendar result = Main.parseVersionCopyArgument(argument);
+            Assert.assertNull(result);
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/ParseVersionCopyArgumentTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/DescendantsIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/DescendantsIterator.java?rev=1694646&r1=1694645&r2=1694646&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/DescendantsIterator.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/DescendantsIterator.java Fri Aug  7 10:31:00 2015
@@ -1,46 +1,46 @@
-package org.apache.jackrabbit.oak.upgrade;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Iterator;
-
-import org.apache.jackrabbit.commons.iterator.AbstractLazyIterator;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
-public class DescendantsIterator extends AbstractLazyIterator<NodeState> {
-
-    private final Deque<Iterator<? extends ChildNodeEntry>> stack = new ArrayDeque<Iterator<? extends ChildNodeEntry>>();
-
-    private final int maxLevel;
-
-    public DescendantsIterator(NodeState root, int maxLevel) {
-        this.maxLevel = maxLevel;
-        stack.push(root.getChildNodeEntries().iterator());
-    }
-
-    @Override
-    protected NodeState getNext() {
-        if (!fillStack()) {
-            return null;
-        }
-        return stack.peekFirst().next().getNodeState();
-    }
-
-    private boolean fillStack() {
-        while (stack.size() < maxLevel || !stack.peekFirst().hasNext()) {
-            Iterator<? extends ChildNodeEntry> topIterator = stack.peekFirst();
-            if (topIterator.hasNext()) {
-                final NodeState nextNode = topIterator.next().getNodeState();
-                stack.push(nextNode.getChildNodeEntries().iterator());
-            } else {
-                stack.pop();
-                if (stack.isEmpty()) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-}
+package org.apache.jackrabbit.oak.upgrade;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+
+import org.apache.jackrabbit.commons.iterator.AbstractLazyIterator;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+public class DescendantsIterator extends AbstractLazyIterator<NodeState> {
+
+    private final Deque<Iterator<? extends ChildNodeEntry>> stack = new ArrayDeque<Iterator<? extends ChildNodeEntry>>();
+
+    private final int maxLevel;
+
+    public DescendantsIterator(NodeState root, int maxLevel) {
+        this.maxLevel = maxLevel;
+        stack.push(root.getChildNodeEntries().iterator());
+    }
+
+    @Override
+    protected NodeState getNext() {
+        if (!fillStack()) {
+            return null;
+        }
+        return stack.peekFirst().next().getNodeState();
+    }
+
+    private boolean fillStack() {
+        while (stack.size() < maxLevel || !stack.peekFirst().hasNext()) {
+            Iterator<? extends ChildNodeEntry> topIterator = stack.peekFirst();
+            if (topIterator.hasNext()) {
+                final NodeState nextNode = topIterator.next().getNodeState();
+                stack.push(nextNode.getChildNodeEntries().iterator());
+            } else {
+                stack.pop();
+                if (stack.isEmpty()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/DescendantsIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1694646&r1=1694645&r2=1694646&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 Fri Aug  7 10:31:00 2015
@@ -1,334 +1,334 @@
-package org.apache.jackrabbit.oak.upgrade.nodestate;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-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.plugins.memory.MemoryChildNodeEntry;
-import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
-import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
-import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import java.util.Set;
-
-import static org.apache.jackrabbit.oak.plugins.tree.impl.TreeConstants.OAK_CHILD_ORDER;
-
-/**
- * NodeState implementation that decorates another node-state instance
- * in order to hide subtrees or partial subtrees from the consumer of
- * the API.
- * <br>
- * The set of visible subtrees is defined by two parameters: include paths
- * and exclude paths, both of which are sets of absolute paths.
- * <br>
- * Any paths that are equal or are descendants of one of the
- * <b>excluded paths</b> are hidden by this implementation.
- * <br>
- * For all <b>included paths</b>, the direct ancestors, the node-state at
- * the path itself and all descendants are visible. Any siblings of the
- * defined path or its ancestors are implicitly hidden (unless made visible
- * by another include path).
- * <br>
- * The implementation delegates to the decorated node-state instance and
- * filters out hidden node-states in the following methods:
- * <ul>
- *     <li>{@link #exists()}</li>
- *     <li>{@link #hasChildNode(String)}</li>
- *     <li>{@link #getChildNodeEntries()}</li>
- * </ul>
- * Additionally, hidden node-state names are removed from the property
- * {@code :childOrder} in the following two methods:
- * <ul>
- *     <li>{@link #getProperties()}</li>
- *     <li>{@link #getProperty(String)}</li>
- * </ul>
- */
-public class FilteringNodeState extends AbstractNodeState {
-
-    public static final Set<String> ALL = ImmutableSet.of("/");
-
-    public static final Set<String> NONE = ImmutableSet.of();
-
-    private final NodeState delegate;
-
-    private final String path;
-
-    private final Set<String> includedPaths;
-
-    private final Set<String> excludedPaths;
-
-    /**
-     * Factory method that conditionally decorates the given node-state
-     * iff the node-state is (a) hidden itself or (b) has hidden descendants.
-     *
-     * @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).
-     * @return The decorated node-state if required, the original node-state if decoration is unnecessary.
-     * @param excludePaths
-     */
-    @Nonnull
-    public static NodeState wrap(
-            @Nonnull final String path,
-            @Nonnull final NodeState delegate,
-            @Nullable final Set<String> includePaths,
-            @Nullable final Set<String> excludePaths
-    ) {
-        final Set<String> includes = defaultIfEmpty(includePaths, ALL);
-        final Set<String> excludes = defaultIfEmpty(excludePaths, NONE);
-        if (hasHiddenDescendants(path, includes, excludes)) {
-            return new FilteringNodeState(path, delegate, includes, excludes);
-        }
-        return delegate;
-    }
-
-    private FilteringNodeState(
-            @Nonnull final String path,
-            @Nonnull final NodeState delegate,
-            @Nonnull final Set<String> includedPaths,
-            @Nonnull final Set<String> excludedPaths
-    ) {
-        this.path = path;
-        this.delegate = delegate;
-        this.includedPaths = includedPaths;
-        this.excludedPaths = excludedPaths;
-    }
-
-    @Override
-    @Nonnull
-    public NodeBuilder builder() {
-        return new MemoryNodeBuilder(this);
-    }
-
-    @Override
-    public boolean exists() {
-        return !isHidden(path, includedPaths, excludedPaths) && delegate.exists();
-    }
-
-    @Override
-    @Nonnull
-    public NodeState getChildNode(@Nonnull final String name) throws IllegalArgumentException {
-        final String childPath = PathUtils.concat(path, name);
-        return wrap(childPath, delegate.getChildNode(name), includedPaths, excludedPaths);
-    }
-
-    @Override
-    public boolean hasChildNode(@Nonnull final String name) {
-        final String childPath = PathUtils.concat(path, name);
-        return !isHidden(childPath, includedPaths, excludedPaths) && delegate.hasChildNode(name);
-    }
-
-    @Override
-    @Nonnull
-    public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
-        final Iterable<ChildNodeEntry> transformed = Iterables.transform(
-                delegate.getChildNodeEntries(),
-                new Function<ChildNodeEntry, ChildNodeEntry>() {
-                    @Nullable
-                    @Override
-                    public ChildNodeEntry apply(@Nullable final ChildNodeEntry childNodeEntry) {
-                        if (childNodeEntry != null) {
-                            final String name = childNodeEntry.getName();
-                            final String childPath = PathUtils.concat(path, name);
-                            if (!isHidden(childPath, includedPaths, excludedPaths)) {
-                                final NodeState nodeState = childNodeEntry.getNodeState();
-                                final NodeState state = wrap(childPath, nodeState, includedPaths, excludedPaths);
-                                return new MemoryChildNodeEntry(name, state);
-                            }
-                        }
-                        return null;
-                    }
-                }
-        );
-        return Iterables.filter(transformed, new Predicate<ChildNodeEntry>() {
-            @Override
-            public boolean apply(@Nullable final ChildNodeEntry childNodeEntry) {
-                return childNodeEntry != null;
-            }
-        });
-    }
-
-    @Override
-    public long getPropertyCount() {
-        return delegate.getPropertyCount();
-    }
-
-    @Override
-    @Nonnull
-    public Iterable<? extends PropertyState> getProperties() {
-        return Iterables.transform(delegate.getProperties(), new Function<PropertyState, PropertyState>() {
-            @Nullable
-            @Override
-            public PropertyState apply(@Nullable final PropertyState propertyState) {
-                return fixChildOrderPropertyState(propertyState);
-            }
-        });
-    }
-
-    @Override
-    public PropertyState getProperty(String name) {
-        return fixChildOrderPropertyState(delegate.getProperty(name));
-    }
-
-    @Override
-    public boolean hasProperty(String name) {
-        return delegate.getProperty(name) != null;
-    }
-
-    /**
-     * Utility method to fix the PropertyState of properties called {@code :childOrder}.
-     *
-     * @param propertyState A property-state.
-     * @return The original property-state or if the property name is {@code :childOrder}, a
-     *         property-state with hidden child names removed from the value.
-     */
-    @CheckForNull
-    private PropertyState fixChildOrderPropertyState(@Nullable final PropertyState propertyState) {
-        if (propertyState != null && OAK_CHILD_ORDER.equals(propertyState.getName())) {
-            final Iterable<String> values = Iterables.filter(propertyState.getValue(Type.NAMES), new Predicate<String>() {
-                @Override
-                public boolean apply(@Nullable final String name) {
-                    if (name == null) {
-                        return false;
-                    }
-                    final String childPath = PathUtils.concat(path, name);
-                    return !isHidden(childPath, includedPaths, excludedPaths);
-                }
-            });
-            return PropertyStates.createProperty(OAK_CHILD_ORDER, values, Type.NAMES);
-        }
-        return propertyState;
-    }
-
-    /**
-     * Utility method to determine whether a given path should is hidden given the
-     * include paths and exclude paths.
-     *
-     * @param path Path to be checked
-     * @param includes Include paths
-     * @param excludes Exclude paths
-     * @return Whether the {@code path} is hidden or not.
-     */
-    public static boolean isHidden(
-            @Nonnull final String path,
-            @Nonnull final Set<String> includes,
-            @Nonnull final Set<String> excludes
-    ) {
-        return isExcluded(path, excludes) || !isIncluded(path, includes);
-    }
-
-    /**
-     * Utility method to determine whether the path itself or any of its descendants should
-     * be hidden given the include paths and exclude paths.
-     *
-     * @param path Path to be checked
-     * @param includePaths Include paths
-     * @param excludePaths Exclude paths
-     * @return Whether the {@code path} or any of its descendants are hidden or not.
-     */
-    private static boolean hasHiddenDescendants(
-            @Nonnull final String path,
-            @Nonnull final Set<String> includePaths,
-            @Nonnull final Set<String> excludePaths
-    ) {
-        return isHidden(path, includePaths, excludePaths)
-                || isAncestorOfAnyPath(path, excludePaths)
-                || isAncestorOfAnyPath(path, includePaths);
-    }
-
-    /**
-     * Utility method to check whether a given set of include paths cover the given
-     * {@code path}. I.e. whether the path is visible or implicitly hidden due to the
-     * lack of a matching include path.
-     * <br>
-     * Note: the ancestors of every include path are considered visible.
-     *
-     * @param path Path to be checked
-     * @param includePaths Include paths
-     * @return Whether the path is covered by the include paths or not.
-     */
-    private static boolean isIncluded(@Nonnull final String path, @Nonnull final Set<String> includePaths) {
-        return isAncestorOfAnyPath(path, includePaths)
-                || includePaths.contains(path)
-                || isDescendantOfAnyPath(path, includePaths);
-    }
-
-    /**
-     * Utility method to check whether a given set of exclude paths cover the given
-     * {@code path}. I.e. whether the path is hidden due to the presence of a
-     * matching exclude path.
-     *
-     * @param path Path to be checked
-     * @param excludePaths Exclude paths
-     * @return Whether the path is covered by the excldue paths or not.
-     */
-    private static boolean isExcluded(@Nonnull final String path, @Nonnull final Set<String> excludePaths) {
-        return excludePaths.contains(path) || isDescendantOfAnyPath(path, excludePaths);
-    }
-
-    /**
-     * Utility method to check whether any of the provided {@code paths} is a descendant
-     * of the given ancestor path.
-     *
-     * @param ancestor Ancestor path
-     * @param paths Paths that may be descendants of {@code ancestor}.
-     * @return true if {@code paths} contains a descendant of {@code ancestor}, false otherwise.
-     */
-    private static boolean isAncestorOfAnyPath(@Nonnull final String ancestor, @Nonnull final Set<String> paths) {
-        for (final String p : paths) {
-            if (PathUtils.isAncestor(ancestor, p)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Utility method to check whether any of the provided {@code paths} is an ancestor
-     * of the given descendant path.
-     *
-     * @param descendant Descendant path
-     * @param paths Paths that may be ancestors of {@code descendant}.
-     * @return true if {@code paths} contains an ancestor of {@code descendant}, false otherwise.
-     */
-    private static boolean isDescendantOfAnyPath(@Nonnull final String descendant, @Nonnull final Set<String> paths) {
-        for (final String p : paths) {
-            if (PathUtils.isAncestor(p, descendant)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Utility method to return the given {@code Set} if it is not empty and a default Set otherwise.
-     *
-     * @param value Value to check for emptiness
-     * @param defaultValue Default value
-     * @return return the given {@code Set} if it is not empty and a default Set otherwise
-     */
-    @Nonnull
-    private static <T> Set<T> defaultIfEmpty(@Nullable Set<T> value, @Nonnull Set<T> defaultValue) {
-        return !isEmpty(value) ? value : defaultValue;
-    }
-
-    /**
-     * Utility method to check whether a Set is empty, i.e. null or of size 0.
-     *
-     * @param set The Set to check.
-     * @return true if empty, false otherwise
-     */
-    private static <T> boolean isEmpty(@Nullable final Set<T> set) {
-        return set == null || set.isEmpty();
-    }
-}
+package org.apache.jackrabbit.oak.upgrade.nodestate;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+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.plugins.memory.MemoryChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Set;
+
+import static org.apache.jackrabbit.oak.plugins.tree.impl.TreeConstants.OAK_CHILD_ORDER;
+
+/**
+ * NodeState implementation that decorates another node-state instance
+ * in order to hide subtrees or partial subtrees from the consumer of
+ * the API.
+ * <br>
+ * The set of visible subtrees is defined by two parameters: include paths
+ * and exclude paths, both of which are sets of absolute paths.
+ * <br>
+ * Any paths that are equal or are descendants of one of the
+ * <b>excluded paths</b> are hidden by this implementation.
+ * <br>
+ * For all <b>included paths</b>, the direct ancestors, the node-state at
+ * the path itself and all descendants are visible. Any siblings of the
+ * defined path or its ancestors are implicitly hidden (unless made visible
+ * by another include path).
+ * <br>
+ * The implementation delegates to the decorated node-state instance and
+ * filters out hidden node-states in the following methods:
+ * <ul>
+ *     <li>{@link #exists()}</li>
+ *     <li>{@link #hasChildNode(String)}</li>
+ *     <li>{@link #getChildNodeEntries()}</li>
+ * </ul>
+ * Additionally, hidden node-state names are removed from the property
+ * {@code :childOrder} in the following two methods:
+ * <ul>
+ *     <li>{@link #getProperties()}</li>
+ *     <li>{@link #getProperty(String)}</li>
+ * </ul>
+ */
+public class FilteringNodeState extends AbstractNodeState {
+
+    public static final Set<String> ALL = ImmutableSet.of("/");
+
+    public static final Set<String> NONE = ImmutableSet.of();
+
+    private final NodeState delegate;
+
+    private final String path;
+
+    private final Set<String> includedPaths;
+
+    private final Set<String> excludedPaths;
+
+    /**
+     * Factory method that conditionally decorates the given node-state
+     * iff the node-state is (a) hidden itself or (b) has hidden descendants.
+     *
+     * @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).
+     * @return The decorated node-state if required, the original node-state if decoration is unnecessary.
+     * @param excludePaths
+     */
+    @Nonnull
+    public static NodeState wrap(
+            @Nonnull final String path,
+            @Nonnull final NodeState delegate,
+            @Nullable final Set<String> includePaths,
+            @Nullable final Set<String> excludePaths
+    ) {
+        final Set<String> includes = defaultIfEmpty(includePaths, ALL);
+        final Set<String> excludes = defaultIfEmpty(excludePaths, NONE);
+        if (hasHiddenDescendants(path, includes, excludes)) {
+            return new FilteringNodeState(path, delegate, includes, excludes);
+        }
+        return delegate;
+    }
+
+    private FilteringNodeState(
+            @Nonnull final String path,
+            @Nonnull final NodeState delegate,
+            @Nonnull final Set<String> includedPaths,
+            @Nonnull final Set<String> excludedPaths
+    ) {
+        this.path = path;
+        this.delegate = delegate;
+        this.includedPaths = includedPaths;
+        this.excludedPaths = excludedPaths;
+    }
+
+    @Override
+    @Nonnull
+    public NodeBuilder builder() {
+        return new MemoryNodeBuilder(this);
+    }
+
+    @Override
+    public boolean exists() {
+        return !isHidden(path, includedPaths, excludedPaths) && delegate.exists();
+    }
+
+    @Override
+    @Nonnull
+    public NodeState getChildNode(@Nonnull final String name) throws IllegalArgumentException {
+        final String childPath = PathUtils.concat(path, name);
+        return wrap(childPath, delegate.getChildNode(name), includedPaths, excludedPaths);
+    }
+
+    @Override
+    public boolean hasChildNode(@Nonnull final String name) {
+        final String childPath = PathUtils.concat(path, name);
+        return !isHidden(childPath, includedPaths, excludedPaths) && delegate.hasChildNode(name);
+    }
+
+    @Override
+    @Nonnull
+    public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
+        final Iterable<ChildNodeEntry> transformed = Iterables.transform(
+                delegate.getChildNodeEntries(),
+                new Function<ChildNodeEntry, ChildNodeEntry>() {
+                    @Nullable
+                    @Override
+                    public ChildNodeEntry apply(@Nullable final ChildNodeEntry childNodeEntry) {
+                        if (childNodeEntry != null) {
+                            final String name = childNodeEntry.getName();
+                            final String childPath = PathUtils.concat(path, name);
+                            if (!isHidden(childPath, includedPaths, excludedPaths)) {
+                                final NodeState nodeState = childNodeEntry.getNodeState();
+                                final NodeState state = wrap(childPath, nodeState, includedPaths, excludedPaths);
+                                return new MemoryChildNodeEntry(name, state);
+                            }
+                        }
+                        return null;
+                    }
+                }
+        );
+        return Iterables.filter(transformed, new Predicate<ChildNodeEntry>() {
+            @Override
+            public boolean apply(@Nullable final ChildNodeEntry childNodeEntry) {
+                return childNodeEntry != null;
+            }
+        });
+    }
+
+    @Override
+    public long getPropertyCount() {
+        return delegate.getPropertyCount();
+    }
+
+    @Override
+    @Nonnull
+    public Iterable<? extends PropertyState> getProperties() {
+        return Iterables.transform(delegate.getProperties(), new Function<PropertyState, PropertyState>() {
+            @Nullable
+            @Override
+            public PropertyState apply(@Nullable final PropertyState propertyState) {
+                return fixChildOrderPropertyState(propertyState);
+            }
+        });
+    }
+
+    @Override
+    public PropertyState getProperty(String name) {
+        return fixChildOrderPropertyState(delegate.getProperty(name));
+    }
+
+    @Override
+    public boolean hasProperty(String name) {
+        return delegate.getProperty(name) != null;
+    }
+
+    /**
+     * Utility method to fix the PropertyState of properties called {@code :childOrder}.
+     *
+     * @param propertyState A property-state.
+     * @return The original property-state or if the property name is {@code :childOrder}, a
+     *         property-state with hidden child names removed from the value.
+     */
+    @CheckForNull
+    private PropertyState fixChildOrderPropertyState(@Nullable final PropertyState propertyState) {
+        if (propertyState != null && OAK_CHILD_ORDER.equals(propertyState.getName())) {
+            final Iterable<String> values = Iterables.filter(propertyState.getValue(Type.NAMES), new Predicate<String>() {
+                @Override
+                public boolean apply(@Nullable final String name) {
+                    if (name == null) {
+                        return false;
+                    }
+                    final String childPath = PathUtils.concat(path, name);
+                    return !isHidden(childPath, includedPaths, excludedPaths);
+                }
+            });
+            return PropertyStates.createProperty(OAK_CHILD_ORDER, values, Type.NAMES);
+        }
+        return propertyState;
+    }
+
+    /**
+     * Utility method to determine whether a given path should is hidden given the
+     * include paths and exclude paths.
+     *
+     * @param path Path to be checked
+     * @param includes Include paths
+     * @param excludes Exclude paths
+     * @return Whether the {@code path} is hidden or not.
+     */
+    public static boolean isHidden(
+            @Nonnull final String path,
+            @Nonnull final Set<String> includes,
+            @Nonnull final Set<String> excludes
+    ) {
+        return isExcluded(path, excludes) || !isIncluded(path, includes);
+    }
+
+    /**
+     * Utility method to determine whether the path itself or any of its descendants should
+     * be hidden given the include paths and exclude paths.
+     *
+     * @param path Path to be checked
+     * @param includePaths Include paths
+     * @param excludePaths Exclude paths
+     * @return Whether the {@code path} or any of its descendants are hidden or not.
+     */
+    private static boolean hasHiddenDescendants(
+            @Nonnull final String path,
+            @Nonnull final Set<String> includePaths,
+            @Nonnull final Set<String> excludePaths
+    ) {
+        return isHidden(path, includePaths, excludePaths)
+                || isAncestorOfAnyPath(path, excludePaths)
+                || isAncestorOfAnyPath(path, includePaths);
+    }
+
+    /**
+     * Utility method to check whether a given set of include paths cover the given
+     * {@code path}. I.e. whether the path is visible or implicitly hidden due to the
+     * lack of a matching include path.
+     * <br>
+     * Note: the ancestors of every include path are considered visible.
+     *
+     * @param path Path to be checked
+     * @param includePaths Include paths
+     * @return Whether the path is covered by the include paths or not.
+     */
+    private static boolean isIncluded(@Nonnull final String path, @Nonnull final Set<String> includePaths) {
+        return isAncestorOfAnyPath(path, includePaths)
+                || includePaths.contains(path)
+                || isDescendantOfAnyPath(path, includePaths);
+    }
+
+    /**
+     * Utility method to check whether a given set of exclude paths cover the given
+     * {@code path}. I.e. whether the path is hidden due to the presence of a
+     * matching exclude path.
+     *
+     * @param path Path to be checked
+     * @param excludePaths Exclude paths
+     * @return Whether the path is covered by the excldue paths or not.
+     */
+    private static boolean isExcluded(@Nonnull final String path, @Nonnull final Set<String> excludePaths) {
+        return excludePaths.contains(path) || isDescendantOfAnyPath(path, excludePaths);
+    }
+
+    /**
+     * Utility method to check whether any of the provided {@code paths} is a descendant
+     * of the given ancestor path.
+     *
+     * @param ancestor Ancestor path
+     * @param paths Paths that may be descendants of {@code ancestor}.
+     * @return true if {@code paths} contains a descendant of {@code ancestor}, false otherwise.
+     */
+    private static boolean isAncestorOfAnyPath(@Nonnull final String ancestor, @Nonnull final Set<String> paths) {
+        for (final String p : paths) {
+            if (PathUtils.isAncestor(ancestor, p)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Utility method to check whether any of the provided {@code paths} is an ancestor
+     * of the given descendant path.
+     *
+     * @param descendant Descendant path
+     * @param paths Paths that may be ancestors of {@code descendant}.
+     * @return true if {@code paths} contains an ancestor of {@code descendant}, false otherwise.
+     */
+    private static boolean isDescendantOfAnyPath(@Nonnull final String descendant, @Nonnull final Set<String> paths) {
+        for (final String p : paths) {
+            if (PathUtils.isAncestor(p, descendant)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Utility method to return the given {@code Set} if it is not empty and a default Set otherwise.
+     *
+     * @param value Value to check for emptiness
+     * @param defaultValue Default value
+     * @return return the given {@code Set} if it is not empty and a default Set otherwise
+     */
+    @Nonnull
+    private static <T> Set<T> defaultIfEmpty(@Nullable Set<T> value, @Nonnull Set<T> defaultValue) {
+        return !isEmpty(value) ? value : defaultValue;
+    }
+
+    /**
+     * Utility method to check whether a Set is empty, i.e. null or of size 0.
+     *
+     * @param set The Set to check.
+     * @return true if empty, false otherwise
+     */
+    private static <T> boolean isEmpty(@Nullable final Set<T> set) {
+        return set == null || set.isEmpty();
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java?rev=1694646&r1=1694645&r2=1694646&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java Fri Aug  7 10:31:00 2015
@@ -1,97 +1,97 @@
-/*
- * 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.version;
-
-import static org.apache.jackrabbit.JcrConstants.JCR_CREATED;
-import static org.apache.jackrabbit.JcrConstants.NT_VERSION;
-
-import java.util.Calendar;
-
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier;
-import org.apache.jackrabbit.util.ISO8601;
-
-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.getVersionHistoryNodeState;
-
-/**
- * This class allows to copy the version history, optionally filtering it with a
- * given date.
- */
-public class VersionCopier {
-
-    private final TypePredicate isVersion;
-
-    private final NodeState sourceRoot;
-
-    private final NodeBuilder rootBuilder;
-
-    public VersionCopier(NodeState sourceRoot, NodeBuilder rootBuilder) {
-        this.isVersion = new TypePredicate(rootBuilder.getNodeState(), NT_VERSION);
-        this.sourceRoot = sourceRoot;
-        this.rootBuilder = rootBuilder;
-    }
-
-    /**
-     * Copy history filtering versions using passed date and returns @{code
-     * true} if at least one version has been copied.
-     * 
-     * @param versionableUuid
-     *            Name of the version history node
-     * @param minDate
-     *            Only versions older than this date will be copied
-     * @return {@code true} if at least one version has been copied
-     */
-    public boolean copyVersionHistory(String versionableUuid, Calendar minDate) {
-        final String versionHistoryPath = getVersionHistoryPath(versionableUuid);
-        final NodeState versionHistory = getVersionHistoryNodeState(sourceRoot, versionableUuid);
-        final Calendar lastModified = getVersionHistoryLastModified(versionHistory);
-
-        if (lastModified.after(minDate) || minDate.getTimeInMillis() == 0) {
-            NodeStateCopier.builder()
-                    .include(versionHistoryPath)
-                    .merge(VERSION_STORE_PATH)
-                    .copy(sourceRoot, rootBuilder);
-            return true;
-        }
-        return false;
-    }
-
-    private Calendar getVersionHistoryLastModified(final NodeState versionHistory) {
-        Calendar youngest = Calendar.getInstance();
-        youngest.setTimeInMillis(0);
-        for (final ChildNodeEntry entry : versionHistory.getChildNodeEntries()) {
-            final NodeState version = entry.getNodeState();
-            if (!isVersion.apply(version)) {
-                continue;
-            }
-            if (version.hasProperty(JCR_CREATED)) {
-                final Calendar created = ISO8601.parse(version.getProperty(JCR_CREATED).getValue(Type.DATE));
-                if (created.after(youngest)) {
-                    youngest = created;
-                }
-            }
-        }
-        return youngest;
-    }
-}
+/*
+ * 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.version;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_CREATED;
+import static org.apache.jackrabbit.JcrConstants.NT_VERSION;
+
+import java.util.Calendar;
+
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier;
+import org.apache.jackrabbit.util.ISO8601;
+
+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.getVersionHistoryNodeState;
+
+/**
+ * This class allows to copy the version history, optionally filtering it with a
+ * given date.
+ */
+public class VersionCopier {
+
+    private final TypePredicate isVersion;
+
+    private final NodeState sourceRoot;
+
+    private final NodeBuilder rootBuilder;
+
+    public VersionCopier(NodeState sourceRoot, NodeBuilder rootBuilder) {
+        this.isVersion = new TypePredicate(rootBuilder.getNodeState(), NT_VERSION);
+        this.sourceRoot = sourceRoot;
+        this.rootBuilder = rootBuilder;
+    }
+
+    /**
+     * Copy history filtering versions using passed date and returns @{code
+     * true} if at least one version has been copied.
+     * 
+     * @param versionableUuid
+     *            Name of the version history node
+     * @param minDate
+     *            Only versions older than this date will be copied
+     * @return {@code true} if at least one version has been copied
+     */
+    public boolean copyVersionHistory(String versionableUuid, Calendar minDate) {
+        final String versionHistoryPath = getVersionHistoryPath(versionableUuid);
+        final NodeState versionHistory = getVersionHistoryNodeState(sourceRoot, versionableUuid);
+        final Calendar lastModified = getVersionHistoryLastModified(versionHistory);
+
+        if (lastModified.after(minDate) || minDate.getTimeInMillis() == 0) {
+            NodeStateCopier.builder()
+                    .include(versionHistoryPath)
+                    .merge(VERSION_STORE_PATH)
+                    .copy(sourceRoot, rootBuilder);
+            return true;
+        }
+        return false;
+    }
+
+    private Calendar getVersionHistoryLastModified(final NodeState versionHistory) {
+        Calendar youngest = Calendar.getInstance();
+        youngest.setTimeInMillis(0);
+        for (final ChildNodeEntry entry : versionHistory.getChildNodeEntries()) {
+            final NodeState version = entry.getNodeState();
+            if (!isVersion.apply(version)) {
+                continue;
+            }
+            if (version.hasProperty(JCR_CREATED)) {
+                final Calendar created = ISO8601.parse(version.getProperty(JCR_CREATED).getValue(Type.DATE));
+                if (created.after(youngest)) {
+                    youngest = created;
+                }
+            }
+        }
+        return youngest;
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java?rev=1694646&r1=1694645&r2=1694646&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java Fri Aug  7 10:31:00 2015
@@ -1,67 +1,67 @@
-/*
- * 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.version;
-
-import java.util.Calendar;
-
-/**
- * This class allows to configure the behaviour of the version copier.
- */
-public class VersionCopyConfiguration {
-
-    private Calendar copyVersions;
-
-    private Calendar copyOrphanedVersions;
-
-    public VersionCopyConfiguration() {
-        final Calendar epoch = Calendar.getInstance();
-        epoch.setTimeInMillis(0);
-        this.copyVersions = epoch;
-        this.copyOrphanedVersions = epoch;
-    }
-
-    public void setCopyVersions(Calendar copyVersions) {
-        this.copyVersions = copyVersions;
-    }
-
-    public void setCopyOrphanedVersions(Calendar copyOrphanedVersions) {
-        this.copyOrphanedVersions = copyOrphanedVersions;
-    }
-
-    public Calendar getVersionsMinDate() {
-        return copyVersions;
-    }
-
-    public Calendar getOrphanedMinDate() {
-        if (copyVersions == null) {
-            return copyVersions;
-        } else if (copyOrphanedVersions != null && copyVersions.after(copyOrphanedVersions)) {
-            return copyVersions;
-        } else {
-            return copyOrphanedVersions;
-        }
-    }
-
-    public boolean isCopyVersions() {
-        return copyVersions != null;
-    }
-
-    public boolean skipOrphanedVersionsCopy() {
-        return copyVersions == null || copyOrphanedVersions == null;
-    }
-
+/*
+ * 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.version;
+
+import java.util.Calendar;
+
+/**
+ * This class allows to configure the behaviour of the version copier.
+ */
+public class VersionCopyConfiguration {
+
+    private Calendar copyVersions;
+
+    private Calendar copyOrphanedVersions;
+
+    public VersionCopyConfiguration() {
+        final Calendar epoch = Calendar.getInstance();
+        epoch.setTimeInMillis(0);
+        this.copyVersions = epoch;
+        this.copyOrphanedVersions = epoch;
+    }
+
+    public void setCopyVersions(Calendar copyVersions) {
+        this.copyVersions = copyVersions;
+    }
+
+    public void setCopyOrphanedVersions(Calendar copyOrphanedVersions) {
+        this.copyOrphanedVersions = copyOrphanedVersions;
+    }
+
+    public Calendar getVersionsMinDate() {
+        return copyVersions;
+    }
+
+    public Calendar getOrphanedMinDate() {
+        if (copyVersions == null) {
+            return copyVersions;
+        } else if (copyOrphanedVersions != null && copyVersions.after(copyOrphanedVersions)) {
+            return copyVersions;
+        } else {
+            return copyOrphanedVersions;
+        }
+    }
+
+    public boolean isCopyVersions() {
+        return copyVersions != null;
+    }
+
+    public boolean skipOrphanedVersionsCopy() {
+        return copyVersions == null || copyOrphanedVersions == null;
+    }
+
 }
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java?rev=1694646&r1=1694645&r2=1694646&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java Fri Aug  7 10:31:00 2015
@@ -1,67 +1,67 @@
-/*
- * 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.version;
-
-import static com.google.common.collect.Iterables.concat;
-import static java.util.Collections.singleton;
-import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
-import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
-import com.google.common.base.Joiner;
-
-public class VersionHistoryUtil {
-
-    public static String getVersionHistoryPath(String versionableUuid) {
-        return Joiner.on('/').join(concat(
-                singleton(""),
-                getVersionHistoryPathSegments(versionableUuid),
-                singleton(versionableUuid)));
-    }
-
-    static NodeState getVersionHistoryNodeState(NodeState root, String versionableUuid) {
-        NodeState historyParent = root;
-        for (String segment : getVersionHistoryPathSegments(versionableUuid)) {
-            historyParent = historyParent.getChildNode(segment);
-        }
-        return historyParent.getChildNode(versionableUuid);
-    }
-
-    static NodeBuilder getVersionHistoryBuilder(NodeBuilder root, String versionableUuid) {
-        NodeBuilder history = root;
-        for (String segment : getVersionHistoryPathSegments(versionableUuid)) {
-            history = history.getChildNode(segment);
-        }
-        return history.getChildNode(versionableUuid);
-    }
-
-    private static List<String> getVersionHistoryPathSegments(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;
-    }
-
-}
+/*
+ * 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.version;
+
+import static com.google.common.collect.Iterables.concat;
+import static java.util.Collections.singleton;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import com.google.common.base.Joiner;
+
+public class VersionHistoryUtil {
+
+    public static String getVersionHistoryPath(String versionableUuid) {
+        return Joiner.on('/').join(concat(
+                singleton(""),
+                getVersionHistoryPathSegments(versionableUuid),
+                singleton(versionableUuid)));
+    }
+
+    static NodeState getVersionHistoryNodeState(NodeState root, String versionableUuid) {
+        NodeState historyParent = root;
+        for (String segment : getVersionHistoryPathSegments(versionableUuid)) {
+            historyParent = historyParent.getChildNode(segment);
+        }
+        return historyParent.getChildNode(versionableUuid);
+    }
+
+    static NodeBuilder getVersionHistoryBuilder(NodeBuilder root, String versionableUuid) {
+        NodeBuilder history = root;
+        for (String segment : getVersionHistoryPathSegments(versionableUuid)) {
+            history = history.getChildNode(segment);
+        }
+        return history.getChildNode(versionableUuid);
+    }
+
+    private static List<String> getVersionHistoryPathSegments(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;
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java?rev=1694646&r1=1694645&r2=1694646&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java Fri Aug  7 10:31:00 2015
@@ -1,226 +1,226 @@
-/*
- * 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.version;
-
-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.TypePredicate;
-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 java.util.Set;
-
-import static com.google.common.collect.ImmutableSet.of;
-import static com.google.common.collect.Sets.newHashSet;
-import static org.apache.jackrabbit.JcrConstants.JCR_BASEVERSION;
-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_UUID;
-import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONHISTORY;
-import static org.apache.jackrabbit.JcrConstants.MIX_REFERENCEABLE;
-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;
-
-/**
- * The VersionableEditor provides two possible ways to handle
- * versionable nodes:
- * <ul>
- *     <li>it can copy the version histories of versionable nodes, or</li>
- *     <li>
- *         it can skip copying version histories and remove the
- *         {@code mix:versionable} mixin together with any related
- *         properties (see {@link #removeVersionProperties(NodeBuilder)}).
- *     </li>
- * </ul>
- */
-public class VersionableEditor extends DefaultEditor {
-
-    private static final Set<String> SKIPPED_PATHS = of("/oak:index", "/jcr:system/jcr:versionStorage");
-
-    private final Provider provider;
-
-    private final NodeBuilder rootBuilder;
-
-    private final TypePredicate isReferenceable;
-
-    private final TypePredicate isVersionable;
-
-    private final VersionCopier versionCopier;
-
-    private String path;
-
-    private VersionableEditor(Provider provider, NodeBuilder builder) {
-        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.path = "/";
-    }
-
-    public static class Provider implements EditorProvider {
-
-        private final NodeState sourceRoot;
-
-        private final String workspaceName;
-
-        private final VersionCopyConfiguration config;
-
-        public Provider(NodeState sourceRoot, String workspaceName, VersionCopyConfiguration config) {
-            this.sourceRoot = sourceRoot;
-            this.workspaceName = workspaceName;
-            this.config = config;
-        }
-
-        @Override
-        public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder builder, CommitInfo info) throws CommitFailedException {
-            return new VersionableEditor(this, builder);
-        }
-    }
-
-    @Override
-    public Editor childNodeAdded(String name, NodeState after) throws CommitFailedException {
-        final String path = PathUtils.concat(this.path, name);
-        // skip deleted nodes and well known paths that may not contain versionable nodes
-        if (after == null || SKIPPED_PATHS.contains(path)) {
-            return null;
-        }
-
-        // assign path field only after checking that we don't skip this subtree
-        this.path = path;
-
-        final VersionCopyConfiguration c = provider.config;
-        if (isVersionable.apply(after)) {
-            final String versionableUuid = getProperty(after, JCR_UUID, Type.STRING);
-            boolean versionHistoryExists = isVersionHistoryExists(versionableUuid);
-            if (c.isCopyVersions() && c.skipOrphanedVersionsCopy()) {
-                versionHistoryExists = copyVersionHistory(after);
-            } else if (c.isCopyVersions() && !c.skipOrphanedVersionsCopy()) {
-                // all version histories have been copied, but maybe the date
-                // range for orphaned entries is narrower
-                if (c.getOrphanedMinDate().after(c.getVersionsMinDate())) {
-                    versionHistoryExists = copyVersionHistory(after);
-                }
-            } else {
-                versionHistoryExists = false;
-            }
-
-            if (versionHistoryExists) {
-                setVersionablePath(versionableUuid);
-            } else {
-                removeVersionProperties(getNodeBuilder(rootBuilder, this.path));
-            }
-        }
-
-        return this;
-    }
-
-    private boolean copyVersionHistory(NodeState versionable) {
-        assert versionable.exists();
-
-        final String versionableUuid = versionable.getProperty(JCR_UUID).getValue(Type.STRING);
-        return versionCopier.copyVersionHistory(versionableUuid, provider.config.getVersionsMinDate());
-    }
-
-    private void setVersionablePath(String versionableUuid) {
-        final NodeBuilder versionHistory = VersionHistoryUtil.getVersionHistoryBuilder(rootBuilder, versionableUuid);
-        versionHistory.setProperty(provider.workspaceName, path, Type.PATH);
-        addMixin(versionHistory, MIX_REP_VERSIONABLE_PATHS);
-    }
-
-    private boolean isVersionHistoryExists(String versionableUuid) {
-        return VersionHistoryUtil.getVersionHistoryNodeState(rootBuilder.getNodeState(), versionableUuid).exists();
-    }
-
-    private void removeVersionProperties(final NodeBuilder versionableBuilder) {
-        assert versionableBuilder.exists();
-
-        removeMixin(versionableBuilder, MIX_VERSIONABLE);
-
-        // we don't know if the UUID is otherwise referenced,
-        // so make sure the node remains referencable
-        if (!isReferenceable.apply(versionableBuilder.getNodeState())) {
-            addMixin(versionableBuilder, MIX_REFERENCEABLE);
-        }
-
-        versionableBuilder.removeProperty(JCR_VERSIONHISTORY);
-        versionableBuilder.removeProperty(JCR_PREDECESSORS);
-        versionableBuilder.removeProperty(JCR_BASEVERSION);
-        versionableBuilder.removeProperty(JCR_ISCHECKEDOUT);
-    }
-
-    @Override
-    public Editor childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
-        return childNodeAdded(name, after);
-    }
-
-    @Override
-    public Editor childNodeDeleted(String name, NodeState before) throws CommitFailedException {
-        return childNodeAdded(name, null);
-    }
-
-    @Override
-    public void leave(NodeState before, NodeState after) throws CommitFailedException {
-        this.path = PathUtils.getParentPath(this.path);
-    }
-
-    private static <T> T getProperty(NodeState state, String name, Type<T> type) {
-        if (state.hasProperty(name)) {
-            return state.getProperty(name).getValue(type);
-        }
-        return null;
-    }
-
-    private static NodeBuilder getNodeBuilder(NodeBuilder root, String path) {
-        NodeBuilder builder = root;
-        for (String name : PathUtils.elements(path)) {
-            builder = builder.getChildNode(name);
-        }
-        return builder;
-    }
-
-    private static void addMixin(NodeBuilder builder, String name) {
-        if (builder.hasProperty(JCR_MIXINTYPES)) {
-            final Set<String> mixins = newHashSet(builder.getProperty(JCR_MIXINTYPES).getValue(Type.NAMES));
-            if (mixins.add(name)) {
-                builder.setProperty(nameProperty(JCR_MIXINTYPES, mixins));
-            }
-        } else {
-            builder.setProperty(nameProperty(JCR_MIXINTYPES, of(name)));
-        }
-    }
-
-    private static void removeMixin(NodeBuilder builder, String name) {
-        if (builder.hasProperty(JCR_MIXINTYPES)) {
-            final Set<String> mixins = newHashSet(builder.getProperty(JCR_MIXINTYPES).getValue(Type.NAMES));
-            if (mixins.remove(name)) {
-                if (mixins.isEmpty()) {
-                    builder.removeProperty(JCR_MIXINTYPES);
-                } else {
-                    builder.setProperty(nameProperty(JCR_MIXINTYPES, mixins));
-                }
-            }
-        }
-    }
-}
+/*
+ * 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.version;
+
+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.TypePredicate;
+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 java.util.Set;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.JcrConstants.JCR_BASEVERSION;
+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_UUID;
+import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONHISTORY;
+import static org.apache.jackrabbit.JcrConstants.MIX_REFERENCEABLE;
+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;
+
+/**
+ * The VersionableEditor provides two possible ways to handle
+ * versionable nodes:
+ * <ul>
+ *     <li>it can copy the version histories of versionable nodes, or</li>
+ *     <li>
+ *         it can skip copying version histories and remove the
+ *         {@code mix:versionable} mixin together with any related
+ *         properties (see {@link #removeVersionProperties(NodeBuilder)}).
+ *     </li>
+ * </ul>
+ */
+public class VersionableEditor extends DefaultEditor {
+
+    private static final Set<String> SKIPPED_PATHS = of("/oak:index", "/jcr:system/jcr:versionStorage");
+
+    private final Provider provider;
+
+    private final NodeBuilder rootBuilder;
+
+    private final TypePredicate isReferenceable;
+
+    private final TypePredicate isVersionable;
+
+    private final VersionCopier versionCopier;
+
+    private String path;
+
+    private VersionableEditor(Provider provider, NodeBuilder builder) {
+        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.path = "/";
+    }
+
+    public static class Provider implements EditorProvider {
+
+        private final NodeState sourceRoot;
+
+        private final String workspaceName;
+
+        private final VersionCopyConfiguration config;
+
+        public Provider(NodeState sourceRoot, String workspaceName, VersionCopyConfiguration config) {
+            this.sourceRoot = sourceRoot;
+            this.workspaceName = workspaceName;
+            this.config = config;
+        }
+
+        @Override
+        public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder builder, CommitInfo info) throws CommitFailedException {
+            return new VersionableEditor(this, builder);
+        }
+    }
+
+    @Override
+    public Editor childNodeAdded(String name, NodeState after) throws CommitFailedException {
+        final String path = PathUtils.concat(this.path, name);
+        // skip deleted nodes and well known paths that may not contain versionable nodes
+        if (after == null || SKIPPED_PATHS.contains(path)) {
+            return null;
+        }
+
+        // assign path field only after checking that we don't skip this subtree
+        this.path = path;
+
+        final VersionCopyConfiguration c = provider.config;
+        if (isVersionable.apply(after)) {
+            final String versionableUuid = getProperty(after, JCR_UUID, Type.STRING);
+            boolean versionHistoryExists = isVersionHistoryExists(versionableUuid);
+            if (c.isCopyVersions() && c.skipOrphanedVersionsCopy()) {
+                versionHistoryExists = copyVersionHistory(after);
+            } else if (c.isCopyVersions() && !c.skipOrphanedVersionsCopy()) {
+                // all version histories have been copied, but maybe the date
+                // range for orphaned entries is narrower
+                if (c.getOrphanedMinDate().after(c.getVersionsMinDate())) {
+                    versionHistoryExists = copyVersionHistory(after);
+                }
+            } else {
+                versionHistoryExists = false;
+            }
+
+            if (versionHistoryExists) {
+                setVersionablePath(versionableUuid);
+            } else {
+                removeVersionProperties(getNodeBuilder(rootBuilder, this.path));
+            }
+        }
+
+        return this;
+    }
+
+    private boolean copyVersionHistory(NodeState versionable) {
+        assert versionable.exists();
+
+        final String versionableUuid = versionable.getProperty(JCR_UUID).getValue(Type.STRING);
+        return versionCopier.copyVersionHistory(versionableUuid, provider.config.getVersionsMinDate());
+    }
+
+    private void setVersionablePath(String versionableUuid) {
+        final NodeBuilder versionHistory = VersionHistoryUtil.getVersionHistoryBuilder(rootBuilder, versionableUuid);
+        versionHistory.setProperty(provider.workspaceName, path, Type.PATH);
+        addMixin(versionHistory, MIX_REP_VERSIONABLE_PATHS);
+    }
+
+    private boolean isVersionHistoryExists(String versionableUuid) {
+        return VersionHistoryUtil.getVersionHistoryNodeState(rootBuilder.getNodeState(), versionableUuid).exists();
+    }
+
+    private void removeVersionProperties(final NodeBuilder versionableBuilder) {
+        assert versionableBuilder.exists();
+
+        removeMixin(versionableBuilder, MIX_VERSIONABLE);
+
+        // we don't know if the UUID is otherwise referenced,
+        // so make sure the node remains referencable
+        if (!isReferenceable.apply(versionableBuilder.getNodeState())) {
+            addMixin(versionableBuilder, MIX_REFERENCEABLE);
+        }
+
+        versionableBuilder.removeProperty(JCR_VERSIONHISTORY);
+        versionableBuilder.removeProperty(JCR_PREDECESSORS);
+        versionableBuilder.removeProperty(JCR_BASEVERSION);
+        versionableBuilder.removeProperty(JCR_ISCHECKEDOUT);
+    }
+
+    @Override
+    public Editor childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
+        return childNodeAdded(name, after);
+    }
+
+    @Override
+    public Editor childNodeDeleted(String name, NodeState before) throws CommitFailedException {
+        return childNodeAdded(name, null);
+    }
+
+    @Override
+    public void leave(NodeState before, NodeState after) throws CommitFailedException {
+        this.path = PathUtils.getParentPath(this.path);
+    }
+
+    private static <T> T getProperty(NodeState state, String name, Type<T> type) {
+        if (state.hasProperty(name)) {
+            return state.getProperty(name).getValue(type);
+        }
+        return null;
+    }
+
+    private static NodeBuilder getNodeBuilder(NodeBuilder root, String path) {
+        NodeBuilder builder = root;
+        for (String name : PathUtils.elements(path)) {
+            builder = builder.getChildNode(name);
+        }
+        return builder;
+    }
+
+    private static void addMixin(NodeBuilder builder, String name) {
+        if (builder.hasProperty(JCR_MIXINTYPES)) {
+            final Set<String> mixins = newHashSet(builder.getProperty(JCR_MIXINTYPES).getValue(Type.NAMES));
+            if (mixins.add(name)) {
+                builder.setProperty(nameProperty(JCR_MIXINTYPES, mixins));
+            }
+        } else {
+            builder.setProperty(nameProperty(JCR_MIXINTYPES, of(name)));
+        }
+    }
+
+    private static void removeMixin(NodeBuilder builder, String name) {
+        if (builder.hasProperty(JCR_MIXINTYPES)) {
+            final Set<String> mixins = newHashSet(builder.getProperty(JCR_MIXINTYPES).getValue(Type.NAMES));
+            if (mixins.remove(name)) {
+                if (mixins.isEmpty()) {
+                    builder.removeProperty(JCR_MIXINTYPES);
+                } else {
+                    builder.setProperty(nameProperty(JCR_MIXINTYPES, mixins));
+                }
+            }
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
------------------------------------------------------------------------------
    svn:eol-style = native