Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStateDiff.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.jackrabbit.oak.spi.state; +import javax.annotation.CheckForNull; + import org.apache.jackrabbit.oak.api.PropertyState; /** @@ -38,9 +40,11 @@ * Note that the * {@link NodeState#compareAgainstBaseState(NodeState, NodeStateDiff)} * method only compares the given states without recursing to the subtrees - * below. An implementation of this interface should recursively call that - * method for the relevant child node entries to find out all the changes - * across the entire subtree below the given node. + * below. To find out all the changes across the entire subtree below the + * given node, an implementation should either recursively call that method + * in {@link #childNodeChanged(String, NodeState, NodeState)} or return + * a {@code NodeStateDiff} instance in {@link #createChildDiff(String, NodeState, NodeState)}. + * That {@code NodeStateDiff} is then used to continue comparison of the subtrees. */ public interface NodeStateDiff { @@ -93,6 +97,19 @@ boolean childNodeChanged(String name, NodeState before, NodeState after); /** + * Create a {@code NodeStateDiff} for diffing the passed {@code before} and + * {@code after} states. Returning {@code null} skips comparison for the sub + * trees rooted at the passed states. + * + * @param name name of the child node + * @param before before state of the child node + * @param after after state of the child node + * @return {@code NodeStateDiff} for the child node + */ + @CheckForNull + NodeStateDiff createChildDiff(String name, NodeState before, NodeState after); + + /** * Called for all deleted child nodes. * * @param name name of the deleted child node @@ -100,5 +117,4 @@ * @return {@code true} to continue the comparison, {@code false} to stop */ boolean childNodeDeleted(String name, NodeState before); - } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/EditorDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/EditorDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/EditorDiff.java (revision ) @@ -135,6 +135,11 @@ } @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + + @Override public boolean childNodeDeleted(String name, NodeState before) { try { Editor e = editor.childNodeDeleted(name, before); \ No newline at end of file Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/VisibleDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/VisibleDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/VisibleDiff.java (revision ) @@ -32,11 +32,11 @@ * * @since Oak 0.9 */ -public class VisibleDiff extends RecursingNodeStateDiff { +public class VisibleDiff implements NodeStateDiff { private final NodeStateDiff diff; @Nonnull - public static RecursingNodeStateDiff wrap(@Nonnull NodeStateDiff diff) { + public static NodeStateDiff wrap(@Nonnull NodeStateDiff diff) { return new VisibleDiff(checkNotNull(diff)); } @@ -98,17 +98,15 @@ } } - @Nonnull @Override - public RecursingNodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { - if (diff instanceof RecursingNodeStateDiff) { + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { - if (isHidden(name)) { + if (isHidden(name)) { - return RecursingNodeStateDiff.EMPTY; + return null; - } else { + } else { - return ((RecursingNodeStateDiff) diff).createChildDiff(name, before, after); - } - } else { - return super.createChildDiff(name, before, after); + NodeStateDiff childDiff = diff.createChildDiff(name, before, after); + return childDiff == null + ? null + : wrap(childDiff); } } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java (revision ) @@ -119,6 +119,10 @@ if (!diff.childNodeChanged(name, beforeChild, afterChild)) { return false; } + NodeStateDiff childDiff = diff.createChildDiff(name, beforeChild, afterChild); + if (childDiff != null && !afterChild.compareAgainstBaseState(beforeChild, childDiff)) { + return false; + } } } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/SecurableNodeStateDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/SecurableNodeStateDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/SecurableNodeStateDiff.java (revision ) @@ -26,7 +26,6 @@ import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; -import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff; /** * Base class for {@code NodeStateDiff} implementations that can be secured. @@ -62,7 +61,7 @@ * Unsecured diff this secured diff delegates to after it has determined * that the items pertaining to a call back are accessible. */ - private RecursingNodeStateDiff diff; + private NodeStateDiff diff; /** * Deferred {@link #childNodeChanged(String, NodeState, NodeState)} calls. @@ -72,7 +71,7 @@ */ private Deferred deferred = Deferred.EMPTY; - private SecurableNodeStateDiff(SecurableNodeStateDiff parent, Tree beforeTree, Tree afterTree, RecursingNodeStateDiff diff) { + private SecurableNodeStateDiff(SecurableNodeStateDiff parent, Tree beforeTree, Tree afterTree, NodeStateDiff diff) { this.parent = parent; this.beforeTree = beforeTree; this.afterTree = afterTree; @@ -87,7 +86,7 @@ * @param name name of the child node */ protected SecurableNodeStateDiff(SecurableNodeStateDiff parent, Tree beforeParent, Tree afterParent, String name) { - this(parent, beforeParent.getChild(name), afterParent.getChild(name), RecursingNodeStateDiff.EMPTY); + this(parent, beforeParent.getChild(name), afterParent.getChild(name), (NodeStateDiff) null); } /** @@ -96,7 +95,7 @@ * @param beforeTree parent tree before the changes * @param afterTree parent tree after the changes */ - protected SecurableNodeStateDiff(RecursingNodeStateDiff diff, Tree beforeTree, Tree afterTree) { + protected SecurableNodeStateDiff(NodeStateDiff diff, Tree beforeTree, Tree afterTree) { this(null, beforeTree, afterTree, diff); } @@ -213,13 +212,18 @@ boolean call() { if (applyDeferred() && diff.childNodeChanged(name, secureBefore(name, before), secureAfter(name, after))) { childDiff.diff = diff.createChildDiff(name, secureBefore(name, before), secureAfter(name, after)); - return true; + return childDiff.diff != null; } else { return false; } } }; return after.compareAgainstBaseState(before, childDiff); + } + + @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() } @Override Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java (revision ) @@ -34,7 +34,6 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import javax.annotation.Nonnull; import javax.jcr.observation.Event; import javax.jcr.observation.EventListener; @@ -54,7 +53,7 @@ import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.ChangeSet; import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher.Listener; import org.apache.jackrabbit.oak.spi.state.NodeState; -import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff; +import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; import org.apache.jackrabbit.oak.spi.state.VisibleDiff; import org.apache.jackrabbit.oak.spi.whiteboard.Registration; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; @@ -220,7 +219,7 @@ //------------------------------------------------------------< private >--- - private class EventGeneratingNodeStateDiff extends RecursingNodeStateDiff { + private class EventGeneratingNodeStateDiff implements NodeStateDiff { public static final int EVENT_LIMIT = 8192; private final ChangeSet changes; @@ -314,15 +313,13 @@ return !stopping; } - @Nonnull @Override - public RecursingNodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { if (filterRef.get().includeChildren(afterTree.getPath())) { - EventGeneratingNodeStateDiff diff = new EventGeneratingNodeStateDiff( + return new EventGeneratingNodeStateDiff( changes, beforeTree.getChild(name), afterTree.getChild(name), events); - return VisibleDiff.wrap(diff); } else { - return RecursingNodeStateDiff.EMPTY; + return null; } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeState.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeState.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeState.java (revision ) @@ -161,6 +161,10 @@ if (!diff.childNodeChanged(name, before, after)) { return false; } + NodeStateDiff childDiff = diff.createChildDiff(name, before, after); + if (childDiff != null && !after.compareAgainstBaseState(before, childDiff)) { + return false; + } } } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java (revision ) @@ -133,6 +133,8 @@ expect(diff.childNodeChanged( "baz", before.getChildNode("baz"), after.getChildNode("baz"))).andReturn(true); + expect(diff.createChildDiff( + "baz", before.getChildNode("baz"), after.getChildNode("baz"))).andReturn(null); replay(diff); after.compareAgainstBaseState(before, diff); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (revision ) @@ -660,8 +660,15 @@ if (t.matches('{')) { t.read('}'); String name = PathUtils.getName(path); - continueComparison = diff.childNodeChanged(name, - base.getChildNode(name), getChildNode(name)); + NodeState beforeChild = base.getChildNode(name); + NodeState afterChild = getChildNode(name); + continueComparison = diff.childNodeChanged(name, beforeChild, afterChild); + if (continueComparison) { + NodeStateDiff childDiff = diff.createChildDiff(name, beforeChild, afterChild); + if (childDiff != null && !afterChild.compareAgainstBaseState(beforeChild, childDiff)) { + return false; + } + } } else if (t.matches('[')) { // ignore multi valued property while (t.read() != ']') { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java (revision ) @@ -226,6 +226,11 @@ } @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + + @Override public boolean childNodeDeleted(String name, NodeState before) { if (!builder.hasChildNode(name)) { deleteDeletedNode(builder, name, before); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/SecureNodeStateDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/SecureNodeStateDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/SecureNodeStateDiff.java (revision ) @@ -25,10 +25,10 @@ import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.core.ImmutableTree; import org.apache.jackrabbit.oak.spi.state.NodeState; -import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff; +import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; public class SecureNodeStateDiff extends SecurableNodeStateDiff { - private SecureNodeStateDiff(RecursingNodeStateDiff diff, Tree before, Tree after) { + private SecureNodeStateDiff(NodeStateDiff diff, Tree before, Tree after) { super(diff, before, after); } @@ -36,7 +36,7 @@ super(parent, beforeParent, afterParent, name); } - public static void compare(RecursingNodeStateDiff diff, ImmutableTree before, ImmutableTree after) { + public static void compare(NodeStateDiff diff, ImmutableTree before, ImmutableTree after) { SecureNodeStateDiff secureDiff = new SecureNodeStateDiff(diff, before, after); after.getNodeState().compareAgainstBaseState(before.getNodeState(), secureDiff); } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/SecureNodeStateDiffTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/SecureNodeStateDiffTest.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/SecureNodeStateDiffTest.java (revision ) @@ -29,7 +29,6 @@ import org.apache.jackrabbit.oak.spi.state.NodeBuilder; import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; -import org.apache.jackrabbit.oak.spi.state.RecursingNodeStateDiff; import org.junit.Before; import org.junit.Test; @@ -119,11 +118,11 @@ super(parent, beforeParent, afterParent, name); } - public static NodeStateDiff wrap(RecursingNodeStateDiff diff, Tree before, Tree after) { + public static NodeStateDiff wrap(NodeStateDiff diff, Tree before, Tree after) { return new SecureNodeStateDiff(diff, before, after); } - private SecureNodeStateDiff(RecursingNodeStateDiff diff, Tree before, Tree after) { + private SecureNodeStateDiff(NodeStateDiff diff, Tree before, Tree after) { super(diff, before, after); } @@ -152,7 +151,7 @@ } } - private static class AssertingNodeStateDiff extends RecursingNodeStateDiff { + private static class AssertingNodeStateDiff implements NodeStateDiff { private final StringBuilder actual = new StringBuilder(); private final NodeState before; private final NodeState after; @@ -196,6 +195,11 @@ public boolean childNodeChanged(String name, NodeState before, NodeState after) { actual.append('^').append(name); return true; + } + + @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return this; } @Override Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/DefaultNodeStateDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/DefaultNodeStateDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/DefaultNodeStateDiff.java (revision ) @@ -53,6 +53,11 @@ } @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + + @Override public boolean childNodeDeleted(String name, NodeState before) { return true; } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java (revision ) @@ -74,6 +74,11 @@ } @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + + @Override public boolean childNodeDeleted(String name, NodeState before) { if (builder.hasChildNode(name) && before.equals(builder.child(name).getNodeState())) { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java (revision ) @@ -384,11 +384,16 @@ if (!diff.childNodeAdded(name, after)) { return false; } - } else if (before != after // TODO: fastEquals? - && !diff.childNodeChanged(name, before, after)) { + } else if (before != after) { // TODO: fastEquals? + if (!diff.childNodeChanged(name, before, after)) { - return false; - } + return false; + } + NodeStateDiff childDiff = diff.createChildDiff(name, before, after); + if (childDiff != null && !after.compareAgainstBaseState(before, childDiff)) { + return false; - } + } + } + } return this.base.compareAgainstBaseState(base, new NodeStateDiff() { @Override @@ -414,9 +419,21 @@ } @Override public boolean childNodeChanged(String name, NodeState before, NodeState after) { - return nodes.containsKey(name) - || diff.childNodeChanged(name, before, after); + if (nodes.containsKey(name)) { + return true; - } + } + if (!diff.childNodeChanged(name, before, after)) { + return false; + } + NodeStateDiff childDiff = diff.createChildDiff(name, before, after); + return childDiff == null || after.compareAgainstBaseState(before, childDiff); + } + + @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + @Override public boolean childNodeDeleted(String name, NodeState before) { return nodes.containsKey(name) Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ApplyDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ApplyDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ApplyDiff.java (revision ) @@ -89,6 +89,11 @@ } @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + + @Override public boolean childNodeDeleted(String name, NodeState before) { builder.getChildNode(name).remove(); return true; Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java (revision ) @@ -136,6 +136,11 @@ return true; } + @Override + public NodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { + return null; // michid consider using this method instead of recursing in childNodeChanged() + } + //------------------------------------------------------------< Object >-- @Override \ No newline at end of file Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java (revision ) @@ -346,7 +346,11 @@ if (!diff.childNodeChanged(childName, beforeNode, afterNode)) { return false; } + NodeStateDiff childDiff = diff.createChildDiff(childName, beforeNode, afterNode); + if (childDiff != null && !afterNode.compareAgainstBaseState(beforeNode, childDiff)) { + return false; - } + } + } if (beforeTemplate.childName == MANY_CHILD_NODES || (beforeTemplate.childName != ZERO_CHILD_NODES && !beforeNode.exists())) { @@ -376,11 +380,15 @@ NodeState beforeChild = beforeTemplate.getChildNode(name, beforeSegment, beforeId); if (beforeChild.exists()) { - if (!fastEquals(afterChild, beforeChild) - && !diff.childNodeChanged( - childName, beforeChild, afterChild)) { + if (!fastEquals(afterChild, beforeChild)) { + if (!diff.childNodeChanged(childName, beforeChild, afterChild)) { - return false; - } + return false; + } + NodeStateDiff childDiff = diff.createChildDiff(name, beforeChild, afterChild); + if (childDiff != null && !afterChild.compareAgainstBaseState(beforeChild, childDiff)) { + return false; + } + } } else { if (!diff.childNodeAdded(childName, afterChild)) { return false; @@ -404,8 +412,14 @@ public boolean entryChanged(MapEntry before, MapEntry after) { SegmentNodeState b = before.getNodeState(); SegmentNodeState a = after.getNodeState(); - return fastEquals(a, b) - || diff.childNodeChanged(before.getName(), b, a); + if (fastEquals(a, b)) { + return true; + } + if (!diff.childNodeChanged(before.getName(), b, a)) { + return false; + } + NodeStateDiff childDiff = diff.createChildDiff(before.getName(), b, a); + return childDiff == null || a.compareAgainstBaseState(b, childDiff); } @Override public boolean entryDeleted(MapEntry before) { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/RecursingNodeStateDiff.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/RecursingNodeStateDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/RecursingNodeStateDiff.java (revision 2d1bb5859775d494432a83ed038e7f4669db7e76) @@ -1,46 +0,0 @@ -/* - * 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.spi.state; - -import javax.annotation.Nonnull; - -/** - * A {@code RecursingNodeStateDiff} extends {@link DefaultNodeStateDiff} - * with a factory method for diffing child nodes. - * In contrast to {@code DefaultNodeStateDiff}, {@link #childNodeChanged(String, NodeState, NodeState)} - * should not recurse into child nodes but rather only be concerned about whether to continue - * diffing or not. The {@link #createChildDiff(String, NodeState, NodeState)} will be called instead - * for diffing child nodes. - */ -public class RecursingNodeStateDiff extends DefaultNodeStateDiff { - public static final RecursingNodeStateDiff EMPTY = new RecursingNodeStateDiff(); - - /** - * Create a {@code RecursingNodeStateDiff} for a child node - * @param name name of the child node - * @param before before state of the child node - * @param after after state of the child node - * @return {@code RecursingNodeStateDiff} for the child node - */ - @Nonnull - public RecursingNodeStateDiff createChildDiff(String name, NodeState before, NodeState after) { - return this; - } -}