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 st...@apache.org on 2017/06/14 11:03:55 UTC

svn commit: r1798662 [1/2] - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/ oak-core/src/test/...

Author: stillalex
Date: Wed Jun 14 11:03:54 2017
New Revision: 1798662

URL: http://svn.apache.org/viewvc?rev=1798662&view=rev
Log:
OAK-3381 Provide Common Ancestor To ConflictHandler


Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultThreeWayConflictHandler.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerOursTest.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerTheirsTest.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ThreeWayConflictHandlerTest.java   (with props)
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandlers.java   (with props)
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ThreeWayConflictHandler.java   (with props)
Removed:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultConflictHandlerOursTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultConflictHandlerTheirsTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/JcrConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/AsyncIndexUpdate.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ConcurrentPropertyUpdateTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/HierarchyConflictTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeStoreDiffTest.java
    jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCompactionIT.java
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeConflictHandler.java
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandler.java
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/PartialConflictHandler.java
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/state/ConflictAnnotatingRebaseDiff.java
    jackrabbit/oak/trunk/oak-store-spi/src/test/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiffTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java Wed Jun 14 11:03:54 2017
@@ -85,11 +85,13 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider;
 import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
 import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ConflictHandlers;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
 import org.apache.jackrabbit.oak.spi.commit.Observable;
 import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.lifecycle.CompositeInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
@@ -491,9 +493,16 @@ public class Oak {
      *
      * @param conflictHandler conflict handler
      * @return this builder
+     * @deprecated Use {@link #with(ThreeWayConflictHandler)} instead
      */
+    @Deprecated
     @Nonnull
     public Oak with(@Nonnull ConflictHandler conflictHandler) {
+        return with(ConflictHandlers.wrap(conflictHandler));
+    }
+
+    @Nonnull
+    public Oak with(@Nonnull ThreeWayConflictHandler conflictHandler) {
         checkNotNull(conflictHandler);
         withEditorHook();
         commitHooks.add(new ConflictHook(conflictHandler));

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java Wed Jun 14 11:03:54 2017
@@ -37,14 +37,14 @@ import java.util.List;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
-import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.state.ConflictType;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
- * This {@link ConflictHandler} implementation resolves conflicts to
- * {@link org.apache.jackrabbit.oak.spi.commit.ConflictHandler.Resolution#THEIRS} and in addition marks nodes where a
+ * This {@link ThreeWayConflictHandler} implementation resolves conflicts to
+ * {@link org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler.Resolution#THEIRS} and in addition marks nodes where a
  * conflict occurred with the mixin {@code rep:MergeConflict}:
  *
  * <pre>
@@ -59,7 +59,7 @@ import org.apache.jackrabbit.oak.spi.sta
  *
  * @see ConflictValidator
  */
-public class AnnotatingConflictHandler implements ConflictHandler {
+public class AnnotatingConflictHandler implements ThreeWayConflictHandler {
 
     @Override
     public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
@@ -69,30 +69,31 @@ public class AnnotatingConflictHandler i
     }
 
     @Override
-    public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours) {
+    public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours, PropertyState base) {
         NodeBuilder marker = addConflictMarker(parent);
         createChild(marker, CHANGE_DELETED_PROPERTY).setProperty(ours);
         return Resolution.THEIRS;
     }
 
     @Override
-    public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
+    public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs,
+            PropertyState base) {
         NodeBuilder marker = addConflictMarker(parent);
         createChild(marker, CHANGE_CHANGED_PROPERTY).setProperty(ours);
         return Resolution.THEIRS;
     }
 
     @Override
-    public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs) {
+    public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs, PropertyState base) {
         NodeBuilder marker = addConflictMarker(parent);
         createChild(marker, DELETE_CHANGED_PROPERTY).setProperty(theirs);
         return Resolution.THEIRS;
     }
 
     @Override
-    public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState ours) {
+    public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState base) {
         NodeBuilder marker = addConflictMarker(parent);
-        createChild(marker, DELETE_DELETED_PROPERTY).setProperty(ours);
+        createChild(marker, DELETE_DELETED_PROPERTY).setProperty(base);
         return Resolution.THEIRS;
     }
 
@@ -104,21 +105,21 @@ public class AnnotatingConflictHandler i
     }
 
     @Override
-    public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours) {
+    public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours, NodeState base) {
         NodeBuilder marker = addConflictMarker(parent);
         createChild(marker, CHANGE_DELETED_NODE).setChildNode(name, ours);
         return Resolution.THEIRS;
     }
 
     @Override
-    public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs) {
+    public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs, NodeState base) {
         NodeBuilder marker = addConflictMarker(parent);
         markChild(createChild(marker, DELETE_CHANGED_NODE), name);
         return Resolution.THEIRS;
     }
 
     @Override
-    public Resolution deleteDeletedNode(NodeBuilder parent, String name) {
+    public Resolution deleteDeletedNode(NodeBuilder parent, String name, NodeState base) {
         NodeBuilder marker = addConflictMarker(parent);
         markChild(createChild(marker, DELETE_DELETED_NODE), name);
         return Resolution.THEIRS;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHook.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHook.java Wed Jun 14 11:03:54 2017
@@ -22,26 +22,40 @@ import org.apache.jackrabbit.oak.api.Com
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ConflictHandlers;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * This commit hook implementation is responsible for resolving
  * conflicts. It does so by detecting the presence of conflict
  * markers added by the Microkernel and delegating to a
- * {@link org.apache.jackrabbit.oak.spi.commit.ConflictHandler}
+ * {@link org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler}
  * for resolving the conflicts.
  *
  * @see org.apache.jackrabbit.oak.spi.state.NodeStore#rebase(org.apache.jackrabbit.oak.spi.state.NodeBuilder)
  */
 public class ConflictHook implements CommitHook {
-    private final ConflictHandler conflictHandler;
+    private final ThreeWayConflictHandler conflictHandler;
+
+    /**
+     * @deprecated Use {@link #of(ThreeWayConflictHandler)} instead.
+     */
+    @Deprecated
+    public static final ConflictHook of(ConflictHandler handler) {
+        return of(ConflictHandlers.wrap(handler));
+    }
+
+    public static final ConflictHook of(ThreeWayConflictHandler handler) {
+        return new ConflictHook(handler);
+    }
 
     /**
      * Create a new instance of the conflict hook using the
      * passed conflict handler for resolving conflicts.
      * @param conflictHandler  a conflict handler
      */
-    public ConflictHook(ConflictHandler conflictHandler) {
+    public ConflictHook(ThreeWayConflictHandler conflictHandler) {
         this.conflictHandler = conflictHandler;
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultConflictHandler.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultConflictHandler.java Wed Jun 14 11:03:54 2017
@@ -27,7 +27,9 @@ import org.apache.jackrabbit.oak.spi.sta
  * This implementation of a {@link ConflictHandler} always returns the same resolution.
  * It can be used to implement default behaviour or as a base class for more specialised
  * implementations.
+ * @deprecated Use {@link org.apache.jackrabbit.oak.plugins.commit.DefaultThreeWayConflictHandler} instead.
  */
+@Deprecated
 public class DefaultConflictHandler implements ConflictHandler {
 
     /**

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultThreeWayConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultThreeWayConflictHandler.java?rev=1798662&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultThreeWayConflictHandler.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultThreeWayConflictHandler.java Wed Jun 14 11:03:54 2017
@@ -0,0 +1,117 @@
+/*
+ * 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.plugins.commit;
+
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * This implementation of a {@link ThreeWayConflictHandler} always returns the
+ * same resolution. It can be used to implement default behaviour or as a base
+ * class for more specialised implementations.
+ */
+public class DefaultThreeWayConflictHandler implements ThreeWayConflictHandler {
+
+    /**
+     * A {@code ConflictHandler} which always return
+     * {@link org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler.Resolution#OURS}.
+     */
+    public static final ThreeWayConflictHandler OURS = new DefaultThreeWayConflictHandler(Resolution.OURS);
+
+    /**
+     * A {@code ConflictHandler} which always return
+     * {@link org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler.Resolution#THEIRS}.
+     */
+    public static final ThreeWayConflictHandler THEIRS = new DefaultThreeWayConflictHandler(Resolution.THEIRS);
+
+    private final Resolution resolution;
+
+    /**
+     * Create a new {@code ConflictHandler} which always returns
+     * {@code resolution}.
+     *
+     * @param resolution
+     *            the resolution to return from all methods of this
+     *            {@code ConflictHandler} instance.
+     */
+    public DefaultThreeWayConflictHandler(Resolution resolution) {
+        this.resolution = resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours, PropertyState base) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs,
+            PropertyState base) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState base) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs, PropertyState base) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution addExistingNode(NodeBuilder parent, String name, NodeState ours, NodeState theirs) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours, NodeState base) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs, NodeState base) {
+        return resolution;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteDeletedNode(NodeBuilder parent, String name, NodeState base) {
+        return resolution;
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/DefaultThreeWayConflictHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/JcrConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/JcrConflictHandler.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/JcrConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/JcrConflictHandler.java Wed Jun 14 11:03:54 2017
@@ -18,8 +18,10 @@
  */
 package org.apache.jackrabbit.oak.plugins.commit;
 
-import com.google.common.collect.ImmutableList;
 import org.apache.jackrabbit.oak.spi.commit.CompositeConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ConflictHandlers;
+
+import com.google.common.collect.ImmutableList;
 
 /**
  * Utility class providing conflict handlers used for JCR.
@@ -27,15 +29,15 @@ import org.apache.jackrabbit.oak.spi.com
 public final class JcrConflictHandler {
 
     /**
-     * The conflict handler is a composite of {@link ChildOrderConflictHandler}
+     * The conflict handler is a composite of
+     * {@link JcrLastModifiedConflictHandler}, {@link ChildOrderConflictHandler}
      * and {@link AnnotatingConflictHandler}.
      */
     public static CompositeConflictHandler createJcrConflictHandler() {
         return new CompositeConflictHandler(ImmutableList.of(
-                new JcrLastModifiedConflictHandler(),
-                new ChildOrderConflictHandler(),
-                new AnnotatingConflictHandler()
-        ));
+                ConflictHandlers.wrap(new JcrLastModifiedConflictHandler()),
+                ConflictHandlers.wrap(new ChildOrderConflictHandler()),
+                new AnnotatingConflictHandler()));
     }
 
     private JcrConflictHandler() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java Wed Jun 14 11:03:54 2017
@@ -17,7 +17,9 @@
 package org.apache.jackrabbit.oak.plugins.commit;
 
 import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff.BASE;
 import static org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff.CONFLICT;
+import static org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff.OURS;
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.ADD_EXISTING_NODE;
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.ADD_EXISTING_PROPERTY;
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.CHANGE_CHANGED_PROPERTY;
@@ -29,15 +31,19 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.DELETE_DELETED_PROPERTY;
 
 import java.util.Map;
+import java.util.Set;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.json.JsopDiff;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
 import org.apache.jackrabbit.oak.plugins.tree.impl.TreeConstants;
-import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
-import org.apache.jackrabbit.oak.spi.commit.PartialConflictHandler.Resolution;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler.Resolution;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff;
 import org.apache.jackrabbit.oak.spi.state.ConflictType;
 import org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -53,20 +59,20 @@ public final class MergingNodeStateDiff
 
     private final NodeState parent;
     private final NodeBuilder target;
-    private final ConflictHandler conflictHandler;
+    private final ThreeWayConflictHandler conflictHandler;
 
-    private MergingNodeStateDiff(NodeState parent, NodeBuilder target, ConflictHandler conflictHandler) {
+    private MergingNodeStateDiff(NodeState parent, NodeBuilder target, ThreeWayConflictHandler conflictHandler) {
         this.parent = parent;
         this.target = target;
         this.conflictHandler = conflictHandler;
     }
 
-    static NodeState merge(NodeState fromState, NodeState toState, ConflictHandler conflictHandler) {
+    static NodeState merge(NodeState fromState, NodeState toState, ThreeWayConflictHandler conflictHandler) {
         return merge(fromState, toState, toState.builder(), conflictHandler).getNodeState();
     }
 
     private static NodeBuilder merge(NodeState fromState, NodeState toState, NodeBuilder target,
-                                     ConflictHandler conflictHandler) {
+                    ThreeWayConflictHandler conflictHandler) {
         toState.compareAgainstBaseState(fromState,
                 new MergingNodeStateDiff(toState, target, conflictHandler));
 
@@ -98,23 +104,44 @@ public final class MergingNodeStateDiff
     private void resolveConflict(ConflictType conflictType, NodeState conflictInfo) {
         PropertyConflictHandler propertyConflictHandler = propertyConflictHandlers.get(conflictType);
         if (propertyConflictHandler != null) {
-            for (PropertyState ours : conflictInfo.getProperties()) {
-                PropertyState theirs = parent.getProperty(ours.getName());
-                Resolution resolution = propertyConflictHandler.resolve(ours, theirs);
-                applyResolution(resolution, conflictType, ours);
+            NodeState oursNS = conflictInfo.getChildNode(OURS);
+            NodeState baseNS = conflictInfo.getChildNode(BASE);
+
+            Set<String> processed = Sets.newHashSet();
+            for (PropertyState ours : oursNS.getProperties()) {
+                String name = ours.getName();
+                processed.add(name);
+                PropertyState base = baseNS.getProperty(name);
+                PropertyState theirs = parent.getProperty(name);
+                Resolution resolution = propertyConflictHandler.resolve(ours, theirs, base);
+                applyPropertyResolution(resolution, conflictType, name, ours);
+            }
+            for (PropertyState base : baseNS.getProperties()) {
+                String name = base.getName();
+                if (processed.contains(name)) {
+                    continue;
+                }
+                PropertyState theirs = parent.getProperty(name);
+                Resolution resolution = propertyConflictHandler.resolve(null, theirs, base);
+                applyPropertyResolution(resolution, conflictType, name, null);
             }
-        }
-        else {
+        } else {
             NodeConflictHandler nodeConflictHandler = nodeConflictHandlers.get(conflictType);
             if (nodeConflictHandler != null) {
-                for (ChildNodeEntry oursCNE : conflictInfo.getChildNodeEntries()) {
-                    String name = oursCNE.getName();
-                    NodeState ours = oursCNE.getNodeState();
+                NodeState oursNS = conflictInfo.getChildNode(OURS);
+                NodeState baseNS = conflictInfo.getChildNode(BASE);
+
+                Set<String> candidates = Sets.union(Sets.newHashSet(oursNS.getChildNodeNames()),
+                        Sets.newHashSet(baseNS.getChildNodeNames()));
+                for (String name : candidates) {
+                    NodeState ours = oursNS.getChildNode(name);
+                    NodeState base = baseNS.getChildNode(name);
                     NodeState theirs = parent.getChildNode(name);
-                    Resolution resolution = nodeConflictHandler.resolve(name, ours, theirs);
+                    Resolution resolution = nodeConflictHandler.resolve(name, ours, theirs, base);
                     applyResolution(resolution, conflictType, name, ours);
+
                     if (LOG.isDebugEnabled()) {
-                        String diff = JsopDiff.diffToJsop(ours, theirs);
+                        String diff = JsopDiff.diffToJsop(base, theirs);
                         LOG.debug(
                                 "{} resolved conflict of type {} with resolution {} on node {}, conflict trace {}",
                                 nodeConflictHandler, conflictType, resolution,
@@ -129,12 +156,12 @@ public final class MergingNodeStateDiff
 
         NodeBuilder conflictMarker = getConflictMarker(conflictType);
         if (conflictMarker != null) {
-            assert conflictMarker.getChildNodeCount(1) == 0;
+            assert conflictMarker.getChildNode(ConflictAnnotatingRebaseDiff.BASE).getChildNodeCount(1) == 0;
+            assert conflictMarker.getChildNode(ConflictAnnotatingRebaseDiff.OURS).getChildNodeCount(1) == 0;
         }
     }
 
-    private void applyResolution(Resolution resolution, ConflictType conflictType, PropertyState ours) {
-        String name = ours.getName();
+    private void applyPropertyResolution(Resolution resolution, ConflictType conflictType, String name, PropertyState ours) {
         NodeBuilder conflictMarker = getConflictMarker(conflictType);
         if (resolution == Resolution.OURS) {
             if (DELETE_CHANGED_PROPERTY == conflictType) {
@@ -145,7 +172,14 @@ public final class MergingNodeStateDiff
             }
 
         }
-        conflictMarker.removeProperty(name);
+        NodeBuilder baseClean = conflictMarker.getChildNode(ConflictAnnotatingRebaseDiff.BASE);
+        if (baseClean.exists()) {
+            baseClean.removeProperty(name);
+        }
+        NodeBuilder oursClean = conflictMarker.getChildNode(ConflictAnnotatingRebaseDiff.OURS);
+        if (oursClean.exists()) {
+            oursClean.removeProperty(name);
+        }
     }
 
     private void applyResolution(Resolution resolution, ConflictType conflictType, String name, NodeState ours) {
@@ -158,7 +192,17 @@ public final class MergingNodeStateDiff
                 addChild(target, name, ours);
             }
         }
-        conflictMarker.getChildNode(name).remove();
+
+        NodeBuilder baseClean = conflictMarker.getChildNode(ConflictAnnotatingRebaseDiff.BASE);
+        if (baseClean.exists()) {
+            baseClean.getChildNode(name).remove();
+        }
+
+        NodeBuilder oursClean = conflictMarker.getChildNode(ConflictAnnotatingRebaseDiff.OURS);
+        if (oursClean.exists()) {
+            oursClean.getChildNode(name).remove();
+        }
+
     }
 
     private NodeBuilder getConflictMarker(ConflictType conflictType) {
@@ -174,17 +218,17 @@ public final class MergingNodeStateDiff
     }
 
     private interface PropertyConflictHandler {
-        Resolution resolve(PropertyState ours, PropertyState theirs);
+        Resolution resolve(PropertyState ours, PropertyState theirs, PropertyState base);
     }
 
     private interface NodeConflictHandler {
-        Resolution resolve(String name, NodeState ours, NodeState theirs);
+        Resolution resolve(String name, NodeState ours, NodeState theirs, NodeState base);
     }
 
     private final Map<ConflictType, PropertyConflictHandler> propertyConflictHandlers = ImmutableMap.of(
         ADD_EXISTING_PROPERTY, new PropertyConflictHandler() {
             @Override
-            public Resolution resolve(PropertyState ours, PropertyState theirs) {
+            public Resolution resolve(PropertyState ours, PropertyState theirs, PropertyState base) {
                 return conflictHandler.addExistingProperty(target, ours, theirs);
             }
 
@@ -195,8 +239,8 @@ public final class MergingNodeStateDiff
         },
         CHANGE_DELETED_PROPERTY, new PropertyConflictHandler() {
             @Override
-            public Resolution resolve(PropertyState ours, PropertyState theirs) {
-                return conflictHandler.changeDeletedProperty(target, ours);
+            public Resolution resolve(PropertyState ours, PropertyState theirs, PropertyState base) {
+                return conflictHandler.changeDeletedProperty(target, ours, base);
             }
 
             @Override
@@ -206,8 +250,8 @@ public final class MergingNodeStateDiff
         },
         CHANGE_CHANGED_PROPERTY, new PropertyConflictHandler() {
             @Override
-            public Resolution resolve(PropertyState ours, PropertyState theirs) {
-                return conflictHandler.changeChangedProperty(target, ours, theirs);
+            public Resolution resolve(PropertyState ours, PropertyState theirs, PropertyState base) {
+                return conflictHandler.changeChangedProperty(target, ours, theirs, base);
             }
 
             @Override
@@ -217,8 +261,8 @@ public final class MergingNodeStateDiff
         },
         DELETE_DELETED_PROPERTY, new PropertyConflictHandler() {
             @Override
-            public Resolution resolve(PropertyState ours, PropertyState theirs) {
-                return conflictHandler.deleteDeletedProperty(target, ours);
+            public Resolution resolve(PropertyState ours, PropertyState theirs, PropertyState base) {
+                return conflictHandler.deleteDeletedProperty(target, base);
             }
 
             @Override
@@ -228,8 +272,8 @@ public final class MergingNodeStateDiff
         },
         DELETE_CHANGED_PROPERTY, new PropertyConflictHandler() {
             @Override
-            public Resolution resolve(PropertyState ours, PropertyState theirs) {
-                return conflictHandler.deleteChangedProperty(target, theirs);
+            public Resolution resolve(PropertyState ours, PropertyState theirs, PropertyState base) {
+                return conflictHandler.deleteChangedProperty(target, theirs, base);
             }
 
             @Override
@@ -242,7 +286,7 @@ public final class MergingNodeStateDiff
     private final Map<ConflictType, NodeConflictHandler> nodeConflictHandlers = ImmutableMap.of(
         ADD_EXISTING_NODE, new NodeConflictHandler() {
             @Override
-            public Resolution resolve(String name, NodeState ours, NodeState theirs) {
+            public Resolution resolve(String name, NodeState ours, NodeState theirs, NodeState base) {
                 return conflictHandler.addExistingNode(target, name, ours, theirs);
             }
 
@@ -253,8 +297,8 @@ public final class MergingNodeStateDiff
         },
         CHANGE_DELETED_NODE, new NodeConflictHandler() {
             @Override
-            public Resolution resolve(String name, NodeState ours, NodeState theirs) {
-                return conflictHandler.changeDeletedNode(target, name, ours);
+            public Resolution resolve(String name, NodeState ours, NodeState theirs, NodeState base) {
+                return conflictHandler.changeDeletedNode(target, name, ours, base);
             }
 
             @Override
@@ -264,8 +308,8 @@ public final class MergingNodeStateDiff
         },
         DELETE_CHANGED_NODE, new NodeConflictHandler() {
             @Override
-            public Resolution resolve(String name, NodeState ours, NodeState theirs) {
-                return conflictHandler.deleteChangedNode(target, name, theirs);
+            public Resolution resolve(String name, NodeState ours, NodeState theirs, NodeState base) {
+                return conflictHandler.deleteChangedNode(target, name, theirs, base);
             }
 
             @Override
@@ -275,8 +319,8 @@ public final class MergingNodeStateDiff
         },
         DELETE_DELETED_NODE, new NodeConflictHandler() {
             @Override
-            public Resolution resolve(String name, NodeState ours, NodeState theirs) {
-                return conflictHandler.deleteDeletedNode(target, name);
+                public Resolution resolve(String name, NodeState ours, NodeState theirs, NodeState base) {
+                return conflictHandler.deleteDeletedNode(target, name, base);
             }
 
             @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/AsyncIndexUpdate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/AsyncIndexUpdate.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/AsyncIndexUpdate.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/AsyncIndexUpdate.java Wed Jun 14 11:03:54 2017
@@ -850,7 +850,7 @@ public class AsyncIndexUpdate implements
         editorProviders.addAll(validatorProviders);
         CompositeHook hooks = new CompositeHook(
                 ResetCommitAttributeHook.INSTANCE,
-                new ConflictHook(new AnnotatingConflictHandler()),
+                ConflictHook.of(new AnnotatingConflictHandler()),
                 new EditorHook(CompositeEditorProvider.compose(editorProviders)),
                 concurrentUpdateCheck);
         try {

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerOursTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerOursTest.java?rev=1798662&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerOursTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerOursTest.java Wed Jun 14 11:03:54 2017
@@ -0,0 +1,171 @@
+/*
+ * 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.core;
+
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.commit.DefaultThreeWayConflictHandler;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DefaultThreeWayConflictHandlerOursTest {
+
+    private static final String OUR_VALUE = "our value";
+    private static final String THEIR_VALUE = "their value";
+
+    private Root ourRoot;
+    private Root theirRoot;
+
+    @Before
+    public void setUp() throws CommitFailedException {
+        ContentSession session = new Oak()
+                .with(new OpenSecurityProvider())
+                .with(DefaultThreeWayConflictHandler.OURS)
+                .createContentSession();
+
+        // Add test content
+        Root root = session.getLatestRoot();
+        Tree tree = root.getTree("/");
+        tree.setProperty("a", 1);
+        tree.setProperty("b", 2);
+        tree.setProperty("c", 3);
+        tree.addChild("x");
+        tree.addChild("y");
+        tree.addChild("z");
+        root.commit();
+
+        ourRoot = session.getLatestRoot();
+        theirRoot = session.getLatestRoot();
+    }
+
+    @After
+    public void tearDown() {
+        ourRoot = null;
+        theirRoot = null;
+    }
+
+    @Test
+    public void testAddExistingProperties() throws CommitFailedException {
+        theirRoot.getTree("/").setProperty("p", THEIR_VALUE);
+        theirRoot.getTree("/").setProperty("q", THEIR_VALUE);
+        ourRoot.getTree("/").setProperty("p", OUR_VALUE);
+        ourRoot.getTree("/").setProperty("q", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("p");
+        assertNotNull(p);
+        assertEquals(OUR_VALUE, p.getValue(STRING));
+
+        PropertyState q = ourRoot.getTree("/").getProperty("q");
+        assertNotNull(q);
+        assertEquals(OUR_VALUE, p.getValue(STRING));
+    }
+
+    @Test
+    public void testChangeDeletedProperty() throws CommitFailedException {
+        theirRoot.getTree("/").removeProperty("a");
+        ourRoot.getTree("/").setProperty("a", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("a");
+        assertNotNull(p);
+        assertEquals(OUR_VALUE, p.getValue(STRING));
+    }
+
+    @Test
+    public void testChangeChangedProperty() throws CommitFailedException {
+        theirRoot.getTree("/").setProperty("a", THEIR_VALUE);
+        ourRoot.getTree("/").setProperty("a", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("a");
+        assertNotNull(p);
+        assertEquals(OUR_VALUE, p.getValue(STRING));
+    }
+
+    @Test
+    public void testDeleteChangedProperty() throws CommitFailedException {
+        theirRoot.getTree("/").setProperty("a", THEIR_VALUE);
+        ourRoot.getTree("/").removeProperty("a");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("a");
+        assertNull(p);
+    }
+
+    @Test
+    public void testAddExistingNode() throws CommitFailedException {
+        theirRoot.getTree("/").addChild("n").setProperty("p", THEIR_VALUE);
+        ourRoot.getTree("/").addChild("n").setProperty("p", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        Tree n = ourRoot.getTree("/n");
+        assertTrue(n.exists());
+        assertEquals(OUR_VALUE, n.getProperty("p").getValue(STRING));
+    }
+
+    @Test
+    public void testChangeDeletedNode() throws CommitFailedException {
+        theirRoot.getTree("/x").remove();
+        ourRoot.getTree("/x").setProperty("p", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        Tree n = ourRoot.getTree("/x");
+        assertTrue(n.exists());
+        assertEquals(OUR_VALUE, n.getProperty("p").getValue(STRING));
+    }
+
+    @Test
+    public void testDeleteChangedNode() throws CommitFailedException {
+        theirRoot.getTree("/x").setProperty("p", THEIR_VALUE);
+        ourRoot.getTree("/x").remove();
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        Tree n = ourRoot.getTree("/x");
+        assertFalse(n.exists());
+    }
+
+}

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

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerTheirsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerTheirsTest.java?rev=1798662&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerTheirsTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/DefaultThreeWayConflictHandlerTheirsTest.java Wed Jun 14 11:03:54 2017
@@ -0,0 +1,171 @@
+/*
+ * 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.core;
+
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.commit.DefaultThreeWayConflictHandler;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DefaultThreeWayConflictHandlerTheirsTest {
+
+    private static final String OUR_VALUE = "our value";
+    private static final String THEIR_VALUE = "their value";
+
+    private Root ourRoot;
+    private Root theirRoot;
+
+    @Before
+    public void setUp() throws CommitFailedException {
+        ContentSession session = new Oak()
+                .with(new OpenSecurityProvider())
+                .with(DefaultThreeWayConflictHandler.THEIRS)
+                .createContentSession();
+
+        // Add test content
+        Root root = session.getLatestRoot();
+        Tree tree = root.getTree("/");
+        tree.setProperty("a", 1);
+        tree.setProperty("b", 2);
+        tree.setProperty("c", 3);
+        tree.addChild("x");
+        tree.addChild("y");
+        tree.addChild("z");
+        root.commit();
+
+        ourRoot = session.getLatestRoot();
+        theirRoot = session.getLatestRoot();
+    }
+
+    @After
+    public void tearDown() {
+        ourRoot = null;
+        theirRoot = null;
+    }
+
+    @Test
+    public void testAddExistingProperties() throws CommitFailedException {
+        theirRoot.getTree("/").setProperty("p", THEIR_VALUE);
+        theirRoot.getTree("/").setProperty("q", THEIR_VALUE);
+        ourRoot.getTree("/").setProperty("p", OUR_VALUE);
+        ourRoot.getTree("/").setProperty("q", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("p");
+        assertNotNull(p);
+        assertEquals(THEIR_VALUE, p.getValue(STRING));
+
+        PropertyState q = ourRoot.getTree("/").getProperty("q");
+        assertNotNull(q);
+        assertEquals(THEIR_VALUE, p.getValue(STRING));
+    }
+
+    @Test
+    public void testChangeDeletedProperty() throws CommitFailedException {
+        theirRoot.getTree("/").removeProperty("a");
+        ourRoot.getTree("/").setProperty("a", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("a");
+        assertNull(p);
+    }
+
+    @Test
+    public void testChangeChangedProperty() throws CommitFailedException {
+        theirRoot.getTree("/").setProperty("a", THEIR_VALUE);
+        ourRoot.getTree("/").setProperty("a", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("a");
+        assertNotNull(p);
+        assertEquals(THEIR_VALUE, p.getValue(STRING));
+    }
+
+    @Test
+    public void testDeleteChangedProperty() throws CommitFailedException {
+        theirRoot.getTree("/").setProperty("a", THEIR_VALUE);
+        ourRoot.getTree("/").removeProperty("a");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        PropertyState p = ourRoot.getTree("/").getProperty("a");
+        assertNotNull(p);
+        assertEquals(THEIR_VALUE, p.getValue(STRING));
+    }
+
+    @Test
+    public void testAddExistingNode() throws CommitFailedException {
+        theirRoot.getTree("/").addChild("n").setProperty("p", THEIR_VALUE);
+        ourRoot.getTree("/").addChild("n").setProperty("p", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        Tree n = ourRoot.getTree("/n");
+        assertNotNull(n);
+        assertEquals(THEIR_VALUE, n.getProperty("p").getValue(STRING));
+    }
+
+    @Test
+    public void testChangeDeletedNode() throws CommitFailedException {
+        theirRoot.getTree("/x").remove();
+        ourRoot.getTree("/x").setProperty("p", OUR_VALUE);
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        Tree n = ourRoot.getTree("/x");
+        assertFalse(n.exists());
+    }
+
+    @Test
+    public void testDeleteChangedNode() throws CommitFailedException {
+        theirRoot.getTree("/x").setProperty("p", THEIR_VALUE);
+        ourRoot.getTree("/x").remove();
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        Tree n = ourRoot.getTree("/x");
+        assertTrue(n.exists());
+        assertEquals(THEIR_VALUE, n.getProperty("p").getValue(STRING));
+    }
+
+}

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

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ThreeWayConflictHandlerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ThreeWayConflictHandlerTest.java?rev=1798662&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ThreeWayConflictHandlerTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/ThreeWayConflictHandlerTest.java Wed Jun 14 11:03:54 2017
@@ -0,0 +1,357 @@
+/*
+ * 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.core;
+
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ThreeWayConflictHandlerTest {
+
+    @Test
+    public void addExistingProperty() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
+                called.set(true);
+                assertEquals("ours", ours.getValue(STRING));
+                assertEquals("theirs", theirs.getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").setProperty("p0", "theirs");
+        ourRoot.getTree("/c").setProperty("p0", "ours");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void changeDeletedProperty() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours, PropertyState base) {
+                called.set(true);
+                assertEquals("ours", ours.getValue(STRING));
+                assertEquals("base", base.getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").removeProperty("p");
+        ourRoot.getTree("/c").setProperty("p", "ours");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void changeChangedProperty() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs,
+                    PropertyState base) {
+                called.set(true);
+                assertEquals("ours", ours.getValue(STRING));
+                assertEquals("theirs", theirs.getValue(STRING));
+                assertEquals("base", base.getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").setProperty("p", "theirs");
+        ourRoot.getTree("/c").setProperty("p", "ours");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void deleteDeletedProperty() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState base) {
+                called.set(true);
+                assertEquals("base", base.getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").removeProperty("p");
+        ourRoot.getTree("/c").removeProperty("p");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void deleteChangedProperty() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs, PropertyState base) {
+                called.set(true);
+                assertEquals("theirs", theirs.getValue(STRING));
+                assertEquals("base", base.getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").setProperty("p", "theirs");
+        ourRoot.getTree("/c").removeProperty("p");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void changeDeletedNode() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours, NodeState base) {
+                called.set(true);
+                assertTrue(ours.hasProperty("p"));
+                assertTrue(base.hasProperty("p"));
+                assertEquals("ours", ours.getProperty("p").getValue(STRING));
+                assertEquals("base", base.getProperty("p").getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").remove();
+        ourRoot.getTree("/c").setProperty("p", "ours");
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void deleteChangedNode() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs, NodeState base) {
+                called.set(true);
+                assertTrue(theirs.hasProperty("p"));
+                assertTrue(base.hasProperty("p"));
+                assertEquals("theirs", theirs.getProperty("p").getValue(STRING));
+                assertEquals("base", base.getProperty("p").getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").setProperty("p", "theirs");
+        ourRoot.getTree("/c").remove();
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    @Test
+    public void deleteDeletedNode() throws Exception {
+        AtomicBoolean called = new AtomicBoolean(false);
+        ThreeWayConflictHandler handler = new ErrorThreeWayConflictHandler() {
+
+            @Override
+            public Resolution deleteDeletedNode(NodeBuilder parent, String name, NodeState base) {
+                called.set(true);
+                assertTrue(base.hasProperty("p"));
+                assertEquals("base", base.getProperty("p").getValue(STRING));
+                return Resolution.IGNORED;
+            }
+        };
+
+        ContentRepository repo = newRepo(handler);
+        Root root = login(repo);
+        setup(root);
+
+        Root ourRoot = login(repo);
+        Root theirRoot = login(repo);
+
+        theirRoot.getTree("/c").remove();
+        ourRoot.getTree("/c").remove();
+
+        theirRoot.commit();
+        ourRoot.commit();
+
+        assertTrue(called.get());
+    }
+
+    private static ContentRepository newRepo(ThreeWayConflictHandler handler) {
+        return new Oak().with(new OpenSecurityProvider()).with(handler).createContentRepository();
+    }
+
+    private static Root login(ContentRepository repo) throws Exception {
+        return repo.login(null, null).getLatestRoot();
+    }
+
+    private static void setup(Root root) throws Exception {
+        Tree tree = root.getTree("/");
+        tree.addChild("c").setProperty("p", "base");
+        root.commit();
+    }
+
+    private static class ErrorThreeWayConflictHandler implements ThreeWayConflictHandler {
+
+        @Override
+        public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours, PropertyState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs,
+                PropertyState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs, PropertyState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution addExistingNode(NodeBuilder parent, String name, NodeState ours, NodeState theirs) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours, NodeState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs, NodeState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+
+        @Override
+        public Resolution deleteDeletedNode(NodeBuilder parent, String name, NodeState base) {
+            Assert.fail("method should not be called");
+            return Resolution.IGNORED;
+        }
+    }
+}

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

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ConcurrentPropertyUpdateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ConcurrentPropertyUpdateTest.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ConcurrentPropertyUpdateTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ConcurrentPropertyUpdateTest.java Wed Jun 14 11:03:54 2017
@@ -46,7 +46,7 @@ public class ConcurrentPropertyUpdateTes
     private static final int NUM_THREADS = 2;
 
     private static final CommitHook HOOK = new CompositeHook(
-            new ConflictHook(new AnnotatingConflictHandler()),
+            ConflictHook.of(new AnnotatingConflictHandler()),
             new EditorHook(new ConflictValidatorProvider()));
 
     private ExecutorService service = Executors.newFixedThreadPool(NUM_THREADS);

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java Wed Jun 14 11:03:54 2017
@@ -1930,7 +1930,7 @@ public class DocumentNodeStoreTest {
                             hookList.add(hook);
                         }
                         hookList.add(blockingHook);
-                        hookList.add(new ConflictHook(new AnnotatingConflictHandler()));
+                        hookList.add(ConflictHook.of(new AnnotatingConflictHandler()));
                         hookList.add(new EditorHook(new ConflictValidatorProvider()));
                         store.merge(builder, CompositeHook.compose(hookList), CommitInfo.EMPTY);
                     } catch (CommitFailedException cfe) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/HierarchyConflictTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/HierarchyConflictTest.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/HierarchyConflictTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/HierarchyConflictTest.java Wed Jun 14 11:03:54 2017
@@ -208,7 +208,7 @@ public class HierarchyConflictTest {
                         return null;
                     }
                 }),
-                new ConflictHook(new AnnotatingConflictHandler()),
+                ConflictHook.of(new AnnotatingConflictHandler()),
                 new EditorHook(new ConflictValidatorProvider()));
         store.merge(root, hooks, CommitInfo.EMPTY);
     }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeStoreDiffTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeStoreDiffTest.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeStoreDiffTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeStoreDiffTest.java Wed Jun 14 11:03:54 2017
@@ -98,7 +98,7 @@ public class NodeStoreDiffTest {
         //For now exception would be thrown
         ns.merge(b1,
                 new CompositeHook(
-                        new ConflictHook(new AnnotatingConflictHandler()),
+                        ConflictHook.of(new AnnotatingConflictHandler()),
                         new EditorHook(new ConflictValidatorProvider())
                 ),
                 CommitInfo.EMPTY);

Modified: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java (original)
+++ jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java Wed Jun 14 11:03:54 2017
@@ -37,6 +37,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.commit.ChildOrderConflictHandler;
 import org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider;
 import org.apache.jackrabbit.oak.spi.commit.CompositeConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ConflictHandlers;
 import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -60,7 +61,7 @@ public class TreeTest extends OakBaseTes
         repository = new Oak(store)
             .with(new OpenSecurityProvider())
             .with(new CompositeConflictHandler(ImmutableList.of(
-                    new ChildOrderConflictHandler() {
+                    ConflictHandlers.wrap(new ChildOrderConflictHandler() {
                         /**
                          * Allow deleting changed node.
                          * See {@link TreeTest#removeWithConcurrentOrderBefore()}
@@ -71,7 +72,7 @@ public class TreeTest extends OakBaseTes
                                 NodeState theirs) {
                             return Resolution.OURS;
                         }
-                    },
+                    }),
                     new AnnotatingConflictHandler()
             )))
             .with(new ConflictValidatorProvider())

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java Wed Jun 14 11:03:54 2017
@@ -52,10 +52,12 @@ import org.apache.jackrabbit.oak.securit
 import org.apache.jackrabbit.oak.spi.commit.BackgroundObserver;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CompositeConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ConflictHandlers;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
 import org.apache.jackrabbit.oak.spi.commit.Observer;
 import org.apache.jackrabbit.oak.spi.commit.PartialConflictHandler;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
 import org.apache.jackrabbit.oak.spi.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
@@ -216,8 +218,17 @@ public class Jcr {
         return this;
     }
 
+    /**
+     * @deprecated Use {@link #with(ThreeWayConflictHandler)} instead
+     */
+    @Deprecated
     @Nonnull
     public final Jcr with(@Nonnull PartialConflictHandler conflictHandler) {
+        return with(ConflictHandlers.wrap(conflictHandler));
+    }
+
+    @Nonnull
+    public final Jcr with(@Nonnull ThreeWayConflictHandler conflictHandler) {
         ensureRepositoryIsNotCreated();
         this.conflictHandler.addHandler(checkNotNull(conflictHandler));
         return this;

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCompactionIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCompactionIT.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCompactionIT.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCompactionIT.java Wed Jun 14 11:03:54 2017
@@ -77,7 +77,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
 import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean;
 import org.apache.jackrabbit.oak.plugins.commit.ConflictHook;
-import org.apache.jackrabbit.oak.plugins.commit.DefaultConflictHandler;
+import org.apache.jackrabbit.oak.plugins.commit.DefaultThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.plugins.metric.MetricStatisticsProvider;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentRevisionGC;
@@ -471,8 +471,8 @@ public class SegmentCompactionIT {
                     if (!cancelled) {
                         try {
                             CommitHook commitHook = rnd.nextBoolean()
-                                    ? new CompositeHook(new ConflictHook(DefaultConflictHandler.OURS))
-                                    : new CompositeHook(new ConflictHook(DefaultConflictHandler.THEIRS));
+                                    ? new CompositeHook(ConflictHook.of(DefaultThreeWayConflictHandler.OURS))
+                                    : new CompositeHook(ConflictHook.of(DefaultThreeWayConflictHandler.THEIRS));
                             nodeStore.merge(root, commitHook, CommitInfo.EMPTY);
                             segmentCompactionMBean.committed();
                         } catch (CommitFailedException e) {

Modified: jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeConflictHandler.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeConflictHandler.java Wed Jun 14 11:03:54 2017
@@ -21,6 +21,7 @@ package org.apache.jackrabbit.oak.spi.co
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Lists.newLinkedList;
+import static org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler.Resolution.IGNORED;
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.ADD_EXISTING_NODE;
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.ADD_EXISTING_PROPERTY;
 import static org.apache.jackrabbit.oak.spi.state.ConflictType.CHANGE_CHANGED_PROPERTY;
@@ -43,12 +44,12 @@ import org.apache.jackrabbit.oak.spi.sta
  * A {@code CompositeConflictHandler} delegates conflict handling
  * to multiple backing handlers. The backing handlers are invoked in
  * the inverse order they have been installed until a handler returning
- * a valid resolution (i.e. not {@code null)} is found. If for a certain
+ * a valid resolution (i.e. not {@code IGNORED)} is found. If for a certain
  * conflict none of the backing handlers returns a valid resolution
  * this implementation throws an {@code IllegalStateException}.
  */
-public class CompositeConflictHandler implements ConflictHandler {
-    private final LinkedList<PartialConflictHandler> handlers;
+public class CompositeConflictHandler implements ThreeWayConflictHandler {
+    private final LinkedList<ThreeWayConflictHandler> handlers;
 
     /**
      * Create a new {@code CompositeConflictHandler} with an initial set of
@@ -56,7 +57,7 @@ public class CompositeConflictHandler im
      * handlers.
      * @param handlers  the backing handlers
      */
-    public CompositeConflictHandler(@Nonnull Iterable<PartialConflictHandler> handlers) {
+    public CompositeConflictHandler(@Nonnull Iterable<ThreeWayConflictHandler> handlers) {
         this.handlers = newLinkedList(checkNotNull(handlers));
     }
 
@@ -74,16 +75,16 @@ public class CompositeConflictHandler im
      * @param handler
      * @return this
      */
-    public CompositeConflictHandler addHandler(PartialConflictHandler handler) {
+    public CompositeConflictHandler addHandler(ThreeWayConflictHandler handler) {
         handlers.addFirst(handler);
         return this;
     }
 
     @Override
     public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
-        for (PartialConflictHandler handler : handlers) {
+        for (ThreeWayConflictHandler handler : handlers) {
             Resolution resolution = handler.addExistingProperty(parent, ours, theirs);
-            if (resolution != null) {
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -92,10 +93,10 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.changeDeletedProperty(parent, ours);
-            if (resolution != null) {
+    public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours, PropertyState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.changeDeletedProperty(parent, ours, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -104,10 +105,11 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.changeChangedProperty(parent, ours, theirs);
-            if (resolution != null) {
+    public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs,
+            PropertyState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.changeChangedProperty(parent, ours, theirs, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -116,10 +118,10 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState ours) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.deleteDeletedProperty(parent, ours);
-            if (resolution != null) {
+    public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.deleteDeletedProperty(parent, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -128,10 +130,10 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.deleteChangedProperty(parent, theirs);
-            if (resolution != null) {
+    public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs, PropertyState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.deleteChangedProperty(parent, theirs, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -141,9 +143,9 @@ public class CompositeConflictHandler im
 
     @Override
     public Resolution addExistingNode(NodeBuilder parent, String name, NodeState ours, NodeState theirs) {
-        for (PartialConflictHandler handler : handlers) {
+        for (ThreeWayConflictHandler handler : handlers) {
             Resolution resolution = handler.addExistingNode(parent, name, ours, theirs);
-            if (resolution != null) {
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -152,10 +154,10 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.changeDeletedNode(parent, name, ours);
-            if (resolution != null) {
+    public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours, NodeState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.changeDeletedNode(parent, name, ours, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -164,10 +166,10 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.deleteChangedNode(parent, name, theirs);
-            if (resolution != null) {
+    public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs, NodeState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.deleteChangedNode(parent, name, theirs, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }
@@ -176,10 +178,10 @@ public class CompositeConflictHandler im
     }
 
     @Override
-    public Resolution deleteDeletedNode(NodeBuilder parent, String name) {
-        for (PartialConflictHandler handler : handlers) {
-            Resolution resolution = handler.deleteDeletedNode(parent, name);
-            if (resolution != null) {
+    public Resolution deleteDeletedNode(NodeBuilder parent, String name, NodeState base) {
+        for (ThreeWayConflictHandler handler : handlers) {
+            Resolution resolution = handler.deleteDeletedNode(parent, name, base);
+            if (resolution != IGNORED) {
                 return resolution;
             }
         }

Modified: jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandler.java?rev=1798662&r1=1798661&r2=1798662&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandler.java Wed Jun 14 11:03:54 2017
@@ -37,8 +37,9 @@ import org.apache.jackrabbit.oak.spi.sta
  * that the changes have been successfully merged by this {@code ConflictHandler}
  * instance ({@link Resolution#MERGED}).
  *
- * @see ConflictHandler
+ * @deprecated Use {@link org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler} instead.
  */
+@Deprecated
 public interface ConflictHandler extends PartialConflictHandler {
 
     /**

Added: jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandlers.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandlers.java?rev=1798662&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandlers.java (added)
+++ jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandlers.java Wed Jun 14 11:03:54 2017
@@ -0,0 +1,104 @@
+/*
+ * 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.commit;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler.Resolution;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+public class ConflictHandlers {
+
+    private ConflictHandlers() {
+    }
+
+    @SuppressWarnings("deprecation")
+    public static ThreeWayConflictHandler wrap(PartialConflictHandler handler) {
+        return new ThreeWayConflictHandlerWrapper(handler);
+    }
+
+    @SuppressWarnings("deprecation")
+    private static Resolution wrap(org.apache.jackrabbit.oak.spi.commit.PartialConflictHandler.Resolution r) {
+        if (r == null) {
+            return Resolution.IGNORED;
+        }
+        switch (r) {
+        case OURS:
+            return Resolution.OURS;
+        case THEIRS:
+            return Resolution.THEIRS;
+        case MERGED:
+            return Resolution.MERGED;
+        }
+        return Resolution.IGNORED;
+    }
+
+    @SuppressWarnings("deprecation")
+    private static class ThreeWayConflictHandlerWrapper implements ThreeWayConflictHandler {
+        private final PartialConflictHandler handler;
+
+        public ThreeWayConflictHandlerWrapper(PartialConflictHandler handler) {
+            this.handler = handler;
+        }
+
+        @Override
+        public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) {
+            return wrap(handler.addExistingProperty(parent, ours, theirs));
+        }
+
+        @Override
+        public Resolution changeDeletedProperty(NodeBuilder parent, PropertyState ours, PropertyState base) {
+            return wrap(handler.changeDeletedProperty(parent, ours));
+        }
+
+        @Override
+        public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs,
+                PropertyState base) {
+            return wrap(handler.changeChangedProperty(parent, ours, theirs));
+        }
+
+        @Override
+        public Resolution deleteDeletedProperty(NodeBuilder parent, PropertyState base) {
+            return wrap(handler.deleteDeletedProperty(parent, base));
+        }
+
+        @Override
+        public Resolution deleteChangedProperty(NodeBuilder parent, PropertyState theirs, PropertyState base) {
+            return wrap(handler.deleteChangedProperty(parent, theirs));
+        }
+
+        @Override
+        public Resolution addExistingNode(NodeBuilder parent, String name, NodeState ours, NodeState theirs) {
+            return wrap(handler.addExistingNode(parent, name, ours, theirs));
+        }
+
+        @Override
+        public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours, NodeState base) {
+            return wrap(handler.changeDeletedNode(parent, name, ours));
+        }
+
+        @Override
+        public Resolution deleteChangedNode(NodeBuilder parent, String name, NodeState theirs, NodeState base) {
+            return wrap(handler.deleteChangedNode(parent, name, theirs));
+        }
+
+        @Override
+        public Resolution deleteDeletedNode(NodeBuilder parent, String name, NodeState base) {
+            return wrap(handler.deleteDeletedNode(parent, name));
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/spi/commit/ConflictHandlers.java
------------------------------------------------------------------------------
    svn:eol-style = native