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 ro...@apache.org on 2017/10/16 10:35:38 UTC

svn commit: r1812280 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/nodetype/ test/java/org/apache/jackrabbit/oak/plugins/nodetype/

Author: rombert
Date: Mon Oct 16 10:35:37 2017
New Revision: 1812280

URL: http://svn.apache.org/viewvc?rev=1812280&view=rev
Log:
OAK-6834 - Make TypeEditor publically accessible and allow pluggable constraint violation handling

- make the TypeEditor public and add a factory method for accesing it
- add a ConstraintViolationCallback interface which must be passed in to the TypeEditor

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveType.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorProvider.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveType.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveType.java?rev=1812280&r1=1812279&r2=1812280&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveType.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveType.java Mon Oct 16 10:35:37 2017
@@ -267,16 +267,20 @@ class EffectiveType {
         }
         return names;
     }
+    
+    List<String> getDirectTypeNames() {
+        List<String> names = newArrayListWithCapacity(types.size());
+        for (NodeState type : types) {
+            names.add(type.getName(JCR_NODETYPENAME));
+        }
+        return names;
+    }
 
     //------------------------------------------------------------< Object >--
 
     @Override
     public String toString() {
-        List<String> names = newArrayListWithCapacity(types.size());
-        for (NodeState type : types) {
-            names.add(type.getName(JCR_NODETYPENAME));
-        }
-        return names.toString();
+        return getDirectTypeNames().toString();
     }
 
     //-----------------------------------------------------------< private >--

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java?rev=1812280&r1=1812279&r2=1812280&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java Mon Oct 16 10:35:37 2017
@@ -59,6 +59,7 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.osgi.annotation.versioning.ConsumerType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,16 +72,86 @@ import org.slf4j.LoggerFactory;
  *       cannot and should not check whether the value of the protected jcr:uuid
  *       is unique.
  */
-class TypeEditor extends DefaultEditor {
+public class TypeEditor extends DefaultEditor {
+    
+    /**
+     * Extension point that allows pluggable handling of constraint violations
+     */
+    @ConsumerType
+    public static interface ConstraintViolationCallback {
+        /**
+         * Invoked whenever a constraint violation is detected.
+         * 
+         * <p>Implementors may choose to throw a {@link #CommitFailedException} or to handle the error
+         * internally, for instance by logging.</p>
+         * 
+         * <p>Implementors may <b>not</b> throw other exception types from this method.</p>
+         * 
+         * @param path the path where the constraint violation was detected
+         * @param nodeTypeNames the node type names of the node
+         * @param code the error code
+         * @param message the descriptive error mesage
+         * @throws CommitFailedException thrown when the implementation decides to stop futher processing
+         * 
+         * @see TypeEditor#THROW_ON_CONSTRAINT_VIOLATION
+         * @see TypeEditor#WARN_ON_CONSTRAINT_VIOLATION
+         */
+        void onConstraintViolation(String path, List<String> nodeTypeNames, int code, String message) throws CommitFailedException;
+    }
 
-    private static final Logger log = LoggerFactory.getLogger(TypeEditor.class);
+    public static final ConstraintViolationCallback THROW_ON_CONSTRAINT_VIOLATION = new ConstraintViolationCallback() {
+        
+        @Override
+        public void onConstraintViolation(String path, List<String> nodeTypeNames, int code, String message) throws CommitFailedException {
+            
+            String fullPath =  path + '[' + nodeTypeNames.toString() + ']';
+
+            throw new CommitFailedException(CONSTRAINT, code, fullPath + ": " + message);
+        }
+    };
+    
+    public static final ConstraintViolationCallback WARN_ON_CONSTRAINT_VIOLATION = new ConstraintViolationCallback() {
+        
+        @Override
+        public void onConstraintViolation(String path, List<String> nodeTypeNames, int code, String message ) {
+            
+            String fullPath =  path + '[' + nodeTypeNames.toString() + ']';
+
+            log.warn(new CommitFailedException(CONSTRAINT, code, fullPath + ": " + message).getMessage());
+
+        }
+    };
+    
+    /**
+     * Creates a new <tt>TypeEditor</instance>
+     * 
+     * @param callback the callback to use when a constraint violation is found. The client must
+     *   check the results of the callback invocations if the specified callback does not
+     *   immediately propagate constraint violations as checked exceptions.
+     * @param typesToCheck the types to check for. If <tt>null</tt>, this node is checked. Otherwise
+     *  it is checked if its primary type or one of it's mixin types is containd in this parameters 
+     * @param types the <tt>/jcr:system/jcr:nodeTypes</tt> node
+     * @param primary the node's primary type
+     * @param mixins the node's mixins
+     * @param builder a builder containing the current state of the node to check. May be used to set
+     *  a default primary type if none is set
+     * @return a new TypeEditor instance
+     * @throws CommitFailedException when the primary type of mixin definition is incorrect
+     */
+    public static TypeEditor create(@Nonnull ConstraintViolationCallback callback, Set<String> typesToCheck,
+            @Nonnull NodeState types, String primary, Iterable<String> mixins, 
+            @Nonnull NodeBuilder builder) throws CommitFailedException {
+        return new TypeEditor(callback, typesToCheck, types, primary, mixins, builder);
+    }
 
-    private final boolean strict;
+    private static final Logger log = LoggerFactory.getLogger(TypeEditor.class);
 
     private final Set<String> typesToCheck;
 
     private boolean checkThisNode;
 
+    private final ConstraintViolationCallback callback;
+    
     private final TypeEditor parent;
 
     private final String nodeName;
@@ -92,12 +163,12 @@ class TypeEditor extends DefaultEditor {
     private final NodeBuilder builder;
 
     private final boolean validate;
-
+    
     TypeEditor(
-            boolean strict, Set<String> typesToCheck, NodeState types,
+            ConstraintViolationCallback callback, Set<String> typesToCheck, NodeState types,
             String primary, Iterable<String> mixins, NodeBuilder builder)
             throws CommitFailedException {
-        this.strict = strict;
+        this.callback = checkNotNull(callback);
         this.typesToCheck = typesToCheck;
         this.checkThisNode =
                 typesToCheck == null
@@ -116,7 +187,7 @@ class TypeEditor extends DefaultEditor {
             @CheckForNull String primary, @Nonnull Iterable<String> mixins, @Nonnull NodeBuilder builder,
             boolean validate)
             throws CommitFailedException {
-        this.strict = parent.strict;
+        this.callback= parent.callback;
         this.typesToCheck = parent.typesToCheck;
         this.checkThisNode =
                 typesToCheck == null
@@ -134,7 +205,7 @@ class TypeEditor extends DefaultEditor {
      * Test constructor.
      */
     TypeEditor(EffectiveType effective) {
-        this.strict = true;
+        this.callback = TypeEditor.THROW_ON_CONSTRAINT_VIOLATION;
         this.typesToCheck = null;
         this.checkThisNode = true;
         this.parent = null;
@@ -153,15 +224,9 @@ class TypeEditor extends DefaultEditor {
      * @throws CommitFailedException the constraint violation
      */
     private void constraintViolation(int code, String message) throws CommitFailedException {
-        String path = getPath();
-        path = path + '[' + effective + ']';
-
-        CommitFailedException exception = new CommitFailedException(CONSTRAINT, code, path + ": " + message);
-        if (strict) {
-            throw exception;
-        } else {
-            log.warn(exception.getMessage());
-        }
+        List<String> nodeTypeNames = effective != null ? effective.getDirectTypeNames() : Collections.emptyList();
+        
+        callback.onConstraintViolation(getPath(), nodeTypeNames, code, message);
     }
 
     private String getPath() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorProvider.java?rev=1812280&r1=1812279&r2=1812280&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorProvider.java Mon Oct 16 10:35:37 2017
@@ -30,6 +30,7 @@ import javax.jcr.nodetype.NodeType;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditor.ConstraintViolationCallback;
 import org.apache.jackrabbit.oak.plugins.tree.factories.RootFactory;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
@@ -90,11 +91,14 @@ public class TypeEditorProvider implemen
                     LOG.info("Node type changes: " + modifiedTypes + " appear to be trivial, repository will not be scanned");
                 }
                 else {
+                    
+                    ConstraintViolationCallback callback = strict ? TypeEditor.THROW_ON_CONSTRAINT_VIOLATION : TypeEditor.WARN_ON_CONSTRAINT_VIOLATION;
+                    
                     long start = System.currentTimeMillis();
                     // Some node types were modified, so scan the repository
                     // to make sure that the modified definitions still apply.
                     Editor editor = new VisibleEditor(new TypeEditor(
-                            strict, modifiedTypes, afterTypes,
+                            callback, modifiedTypes, afterTypes,
                             primary, mixins, builder));
                     LOG.info("Node type changes: " + modifiedTypes + " appear not to be trivial, starting repository scan");
                     CommitFailedException exception =
@@ -107,9 +111,11 @@ public class TypeEditorProvider implemen
                 }
             }
         }
+        
+        ConstraintViolationCallback callback = strict ? TypeEditor.THROW_ON_CONSTRAINT_VIOLATION : TypeEditor.WARN_ON_CONSTRAINT_VIOLATION;
 
         return new VisibleEditor(new TypeEditor(
-                strict, null, afterTypes, primary, mixins, builder));
+                callback, null, afterTypes, primary, mixins, builder));
     }
 
     private boolean isTrivialChange(ReadOnlyNodeTypeManager ntBefore, ReadOnlyNodeTypeManager ntAfter, String nodeType) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java?rev=1812280&r1=1812279&r2=1812280&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java Mon Oct 16 10:35:37 2017
@@ -29,6 +29,8 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.Collections;
+
 import com.google.common.collect.ImmutableList;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.Type;
@@ -85,6 +87,7 @@ public class TypeEditorTest {
     public void removeMandatoryProperty() throws CommitFailedException {
         EffectiveType effective = createControl().createMock(EffectiveType.class);
         expect(effective.isMandatoryProperty("mandatory")).andReturn(true);
+        expect(effective.getDirectTypeNames()).andReturn(Collections.emptyList());
 
         replay(effective);
 
@@ -107,6 +110,7 @@ public class TypeEditorTest {
     public void removeMandatoryChildNode() throws CommitFailedException {
         EffectiveType effective = createControl().createMock(EffectiveType.class);
         expect(effective.isMandatoryChildNode("mandatory")).andReturn(true);
+        expect(effective.getDirectTypeNames()).andReturn(Collections.emptyList());
 
         replay(effective);