jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mdue...@apache.org
Subject svn commit: r1350287 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/ oak-core/src/main/java/org/apache/jackrabbit/oak/core/ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/ oak-jcr/src/main/java/org/apache/jack...
Date Thu, 14 Jun 2012 15:13:51 GMT
Author: mduerig
Date: Thu Jun 14 15:13:50 2012
New Revision: 1350287

URL: http://svn.apache.org/viewvc?rev=1350287&view=rev
Log:
OAK-133: Session.refresh(true) should allow for manual conflict reconciliation
Add Validator which fails the commit on presence of merge conflict markers (mix:mergeConflict)

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/CommitFailedException.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/DefaultConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/CommitFailedException.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/CommitFailedException.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/CommitFailedException.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/CommitFailedException.java
Thu Jun 14 15:13:50 2012
@@ -16,15 +16,11 @@
  */
 package org.apache.jackrabbit.oak.api;
 
+import javax.jcr.RepositoryException;
+
 /**
  * Main exception thrown by methods defined on the {@code ContentSession} interface
  * indicating that committing a given set of changes failed.
- *
- * TODO: define mechanism to inform the oak-jcr level about the specific type of exception
- *       possible ways:
- *       - CommitFailedException contains nested jcr exceptions
- *       - CommitFailedException extends from repository exception
- *       - CommitFailedException transports status code that are then converted to jcr exceptions
  */
 public class CommitFailedException extends Exception {
     public CommitFailedException() {
@@ -41,4 +37,21 @@ public class CommitFailedException exten
     public CommitFailedException(Throwable cause) {
         super(cause);
     }
+
+    /**
+     * Rethrow this exception cast into a {@link RepositoryException}: if the cause
+     * for this exception already is a {@code RepositoryException}, the cause is
+     * thrown. Otherwise a new {@code RepositoryException} instance with this
+     * {@code CommitFailedException} is thrown.
+     * @throws RepositoryException
+     */
+    public void throwRepositoryException() throws RepositoryException {
+        Throwable cause = getCause();
+        if (cause instanceof RepositoryException) {
+            throw (RepositoryException) cause;
+        }
+        else {
+            throw new RepositoryException(cause);
+        }
+    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ConflictHandler.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ConflictHandler.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ConflictHandler.java
Thu Jun 14 15:13:50 2012
@@ -18,6 +18,7 @@
  */
 package org.apache.jackrabbit.oak.api;
 
+import org.apache.jackrabbit.oak.core.TreeImpl;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
@@ -52,7 +53,8 @@ public interface ConflictHandler {
         /**
          * Indicated changes have been merged by this {@code ConflictHandler} instance.
          */
-        MERGED}
+        MERGED
+    }
 
     /**
      * The property {@code ours} has been added to {@code parent} which conflicts
@@ -87,6 +89,16 @@ public interface ConflictHandler {
     Resolution changeChangedProperty(Tree parent, PropertyState ours, PropertyState theirs);
 
     /**
+     * The property {@code ours} has been removed in {@code parent} while it was
+     * also removed in the persistence store.
+     *
+     * @param parent  root of the conflict
+     * @param ours  our version of the property
+     * @return  {@link Resolution} of the conflict
+     */
+    Resolution deleteDeletedProperty(TreeImpl parent, PropertyState ours);
+
+    /**
      * The property {@code theirs} changed in the persistence store while it has been
      * deleted locally.
      *
@@ -130,4 +142,14 @@ public interface ConflictHandler {
      * @return  {@link Resolution} of the conflict
      */
     Resolution deleteChangedNode(Tree parent, String name, NodeState theirs);
+
+    /**
+     * The node {@code name} has been removed in {@code parent} while it was
+     * also removed in the persistence store.
+     *
+     * @param parent  root of the conflict
+     * @param name  name of the node
+     * @return  {@link Resolution} of the conflict
+     */
+    Resolution deleteDeletedNode(Tree parent, String name);
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
Thu Jun 14 15:13:50 2012
@@ -16,11 +16,24 @@
  */
 package org.apache.jackrabbit.oak.core;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.mk.core.MicroKernelImpl;
 import org.apache.jackrabbit.mk.index.Indexer;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.QueryEngine;
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
@@ -32,21 +45,16 @@ import org.apache.jackrabbit.oak.spi.Que
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CompositeCommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CompositeValidatorProvider;
+import org.apache.jackrabbit.oak.spi.commit.DefaultValidator;
 import org.apache.jackrabbit.oak.spi.commit.ValidatingCommitHook;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.security.authentication.LoginContextProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.Nonnull;
-import javax.jcr.Credentials;
-import javax.jcr.NoSuchWorkspaceException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * {@link MicroKernel}-based implementation of
  * the {@link ContentRepository} interface.
@@ -70,7 +78,7 @@ public class ContentRepositoryImpl imple
      * test cases only.
      */
     public ContentRepositoryImpl() {
-        this(new MicroKernelImpl(), null, null);
+        this(new MicroKernelImpl(), null, createDefaultValidatorProvider());
         // this(new IndexWrapper(new MicroKernelImpl()), null, null);
     }
 
@@ -86,11 +94,7 @@ public class ContentRepositoryImpl imple
             ValidatorProvider validatorProvider) {
 
         if (validatorProvider == null) {
-            List<ValidatorProvider> providers = new ArrayList<ValidatorProvider>();
-            providers.add(new NameValidatorProvider());
-            providers.add(new NamespaceValidatorProvider());
-            providers.add(new TypeValidatorProvider());
-            validatorProvider = new CompositeValidatorProvider(providers);
+            validatorProvider = createDefaultValidatorProvider();
         }
 
         List<CommitHook> hooks = new ArrayList<CommitHook>();
@@ -113,6 +117,15 @@ public class ContentRepositoryImpl imple
                 null, null);
     }
 
+    private static ValidatorProvider createDefaultValidatorProvider() {
+        List<ValidatorProvider> providers = new ArrayList<ValidatorProvider>();
+        providers.add(new NameValidatorProvider());
+        providers.add(new NamespaceValidatorProvider());
+        providers.add(new TypeValidatorProvider());
+        providers.add(new ConflictValidatorProvider());
+        return new CompositeValidatorProvider(providers);
+    }
+
     private static QueryIndexProvider getDefaultIndexProvider(MicroKernel mk) {
         return Indexer.getInstance(mk);
     }
@@ -135,4 +148,52 @@ public class ContentRepositoryImpl imple
 
         return new ContentSessionImpl(loginContext, workspaceName, nodeStore, queryEngine);
     }
+
+    //------------------------------------------------------------< ConflictValidator
>---
+
+    private static class ConflictValidatorProvider implements ValidatorProvider {
+        @Override
+        public Validator getRootValidator(NodeState before, NodeState after) {
+            return new DefaultValidator() {
+                @Override
+                public void propertyAdded(PropertyState after) throws CommitFailedException
{
+                    failOnMergeConflict(after);
+                }
+
+                @Override
+                public void propertyChanged(PropertyState before, PropertyState after)
+                        throws CommitFailedException {
+                    failOnMergeConflict(after);
+                }
+
+                @Override
+                public Validator childNodeAdded(String name, NodeState after) {
+                    return this;
+                }
+
+                @Override
+                public Validator childNodeChanged(String name, NodeState before, NodeState
after) {
+                    return this;
+                }
+
+                @Override
+                public Validator childNodeDeleted(String name, NodeState before) {
+                    return this;
+                }
+
+                private void failOnMergeConflict(PropertyState property) throws CommitFailedException
{
+                    if ("jcr:mixinTypes".equals(property.getName())) {
+                        assert property.isArray();
+                        Iterable<CoreValue> mixins = property.getValues();
+                        for (CoreValue v : mixins) {
+                            if ("mix:mergeConflict".equals(v.getString())) {
+                                throw new CommitFailedException(new InvalidItemStateException("Item
has unresolved conflicts"));
+                            }
+                        }
+                    }
+                }
+            };
+        }
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/DefaultConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/DefaultConflictHandler.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/DefaultConflictHandler.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/DefaultConflictHandler.java
Thu Jun 14 15:13:50 2012
@@ -73,6 +73,11 @@ public class DefaultConflictHandler impl
     }
 
     @Override
+    public Resolution deleteDeletedProperty(TreeImpl parent, PropertyState ours) {
+        return resolution;
+    }
+
+    @Override
     public Resolution addExistingNode(Tree parent, String name, NodeState ours, NodeState
theirs) {
         return resolution;
     }
@@ -86,4 +91,9 @@ public class DefaultConflictHandler impl
     public Resolution deleteChangedNode(Tree parent, String name, NodeState theirs) {
         return resolution;
     }
+
+    @Override
+    public Resolution deleteDeletedNode(Tree parent, String name) {
+        return resolution;
+    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
Thu Jun 14 15:13:50 2012
@@ -311,9 +311,6 @@ public class RootImpl implements Root {
                 if (p == null) {
                     resolution = OURS;
                 }
-                else if (after.equals(p)) {
-                    resolution = MERGED;
-                }
                 else {
                     resolution = conflictHandler.addExistingProperty(target, after, p);
                 }
@@ -341,9 +338,6 @@ public class RootImpl implements Root {
                 else if (before.equals(p)) {
                     resolution = OURS;
                 }
-                else if (after.equals(p)) {
-                    resolution = MERGED;
-                }
                 else {
                     resolution = conflictHandler.changeChangedProperty(target, after, p);
                 }
@@ -367,7 +361,7 @@ public class RootImpl implements Root {
                     resolution = OURS;
                 }
                 else if (p == null) {
-                    resolution = MERGED;
+                    resolution = conflictHandler.deleteDeletedProperty(target, before);
                 }
                 else {
                     resolution = conflictHandler.deleteChangedProperty(target, p);
@@ -434,7 +428,7 @@ public class RootImpl implements Root {
                 TreeImpl n = target.getChild(name);
 
                 if (n == null) {
-                    resolution = MERGED;
+                    resolution = conflictHandler.deleteDeletedNode(target, name);
                 }
                 else if (before.equals(n.getNodeState())) {
                     resolution = OURS;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
Thu Jun 14 15:13:50 2012
@@ -122,7 +122,6 @@ class KernelNodeStoreBranch implements N
 
     @Override
     public KernelNodeState merge() throws CommitFailedException {
-        // TODO rebase to current trunk?
         MicroKernel kernel = store.getKernel();
         CommitHook commitHook = store.getCommitHook();
 

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
(original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
Thu Jun 14 15:13:50 2012
@@ -54,6 +54,7 @@ import org.apache.jackrabbit.oak.api.Roo
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.core.DefaultConflictHandler;
+import org.apache.jackrabbit.oak.core.TreeImpl;
 import org.apache.jackrabbit.oak.jcr.value.ValueFactoryImpl;
 import org.apache.jackrabbit.oak.namepath.AbstractNameMapper;
 import org.apache.jackrabbit.oak.namepath.NameMapper;
@@ -185,7 +186,7 @@ public class SessionDelegate {
             root.commit(conflictHandler);
         }
         catch (CommitFailedException e) {
-            throw new RepositoryException(e);
+            e.throwRepositoryException();
         }
     }
 
@@ -472,8 +473,6 @@ public class SessionDelegate {
      *
      * The {@code jcr:ours} sub node contains our version of the node prior to
      * the conflict.
-     *
-     * TODO: add corresponding commit hook which fails the commit on existence of mix:mergeConflict
      */
     private class AnnotatingConflictHandler implements ConflictHandler {
         // TODO: move these constants to some common location for repository internal node
types
@@ -483,6 +482,7 @@ public class SessionDelegate {
         public static final String CHANGE_DELETED = "changeDeleted";
         public static final String CHANGE_CHANGED = "changeChanged";
         public static final String DELETE_CHANGED = "deleteChanged";
+        public static final String DELETE_DELETED = "deleteDeleted";
 
         private final CoreValueFactory valueFactory;
         private final String jcrMixinTypes;
@@ -521,6 +521,13 @@ public class SessionDelegate {
         }
 
         @Override
+        public Resolution deleteDeletedProperty(TreeImpl parent, PropertyState ours) {
+            Tree marker = addConflictMarker(parent);
+            setProperty(getOrCreateNode(marker, DELETE_DELETED), ours);
+            return Resolution.THEIRS;
+        }
+
+        @Override
         public Resolution addExistingNode(Tree parent, String name, NodeState ours, NodeState
theirs) {
             Tree marker = addConflictMarker(parent);
             addChild(getOrCreateNode(marker, ADD_EXISTING), name, ours);
@@ -541,10 +548,18 @@ public class SessionDelegate {
             return Resolution.THEIRS;
         }
 
+        @Override
+        public Resolution deleteDeletedNode(Tree parent, String name) {
+            Tree marker = addConflictMarker(parent);
+            markChild(getOrCreateNode(marker, DELETE_DELETED), name);
+            return Resolution.THEIRS;
+        }
+
         private Tree addConflictMarker(Tree parent) {
             PropertyState jcrMixin = parent.getProperty(jcrMixinTypes);
             List<CoreValue> mixins = new ArrayList<CoreValue>();
             if (jcrMixin != null) {
+                assert jcrMixin.isArray();
                 mixins = Iterators.toList(jcrMixin.getValues(), mixins);
             }
             if (!mixins.contains(MIX_MERGE_CONFLICT)) {

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java?rev=1350287&r1=1350286&r2=1350287&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
(original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
Thu Jun 14 15:13:50 2012
@@ -1199,9 +1199,12 @@ public class RepositoryTest extends Abst
             assertTrue(session1.getRootNode().hasNode("node"));
             assertTrue(session2.getRootNode().hasNode("node"));
 
-            session2.save();
-            assertTrue(session1.getRootNode().hasNode("node"));
-            assertTrue(session2.getRootNode().hasNode("node"));
+            try {
+                session2.save();
+                fail("Expected InvalidItemStateException");
+            }
+            catch (InvalidItemStateException expected) {
+            }
         }
         finally {
             session1.logout();
@@ -1228,9 +1231,12 @@ public class RepositoryTest extends Abst
             assertTrue(session2.getRootNode().hasNode("node"));
             assertTrue(session2.getRootNode().getNode("node").hasNode("2"));
 
-            session2.save();
-            assertFalse(session1.getRootNode().hasNode("node"));
-            assertFalse(session2.getRootNode().hasNode("node"));
+            try {
+                session2.save();
+                fail("Expected InvalidItemStateException");
+            }
+            catch (InvalidItemStateException expected) {
+            }
         }
         finally {
             session1.logout();



Mime
View raw message