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 an...@apache.org on 2012/10/30 18:36:01 UTC

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

Author: angela
Date: Tue Oct 30 17:36:00 2012
New Revision: 1403796

URL: http://svn.apache.org/viewvc?rev=1403796&view=rev
Log:
OAK-250 : Enforce jcr constraints for 'protected' items 

- modified TypeValidator such that it uses functionality exposed by the nt-manager instead of
   having yet another place where matching property definitions are collected.
  
- added TODO regarding validations of nodes that don't have a primary node type set.

- NodeTypeCreationTest#unregister subsequently failed because nt:base could be unregistered.
   further investigation showed that didn't work properly before... the test succeeded because
   there was an illegalstateexception triggered by invalid node type definition, which looked pretty
   strange to me and might be related to the TODO above.

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/DefinitionProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeTypeProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadWriteNodeTypeManager.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeValidator.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/DefinitionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/DefinitionProvider.java?rev=1403796&r1=1403795&r2=1403796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/DefinitionProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/DefinitionProvider.java Tue Oct 30 17:36:00 2012
@@ -36,11 +36,14 @@ public interface DefinitionProvider {
     NodeDefinition getDefinition(Node parent, Node targetNode) throws RepositoryException;
 
     @Nonnull
+    NodeDefinition getDefinition(Iterable<NodeType> parentNodeTypes, String nodeName, NodeType nodeType) throws RepositoryException;
+
+    @Nonnull
     PropertyDefinition getDefinition(Node parent, Property targetProperty) throws RepositoryException;
 
     @Nonnull
     PropertyDefinition getDefinition(Node parent, String propertyName, boolean isMultiple, int type, boolean exactTypeMatch) throws RepositoryException;
 
     @Nonnull
-    PropertyDefinition getDefinition(NodeType nodeType, String propertyName, boolean isMultiple, int type, boolean exactTypeMatch) throws RepositoryException;
+    PropertyDefinition getDefinition(Iterable<NodeType> nodeTypes, String propertyName, boolean isMultiple, int type, boolean exactTypeMatch) throws RepositoryException;
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeTypeProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeTypeProvider.java?rev=1403796&r1=1403795&r2=1403796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeTypeProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeTypeProvider.java Tue Oct 30 17:36:00 2012
@@ -20,6 +20,8 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.NodeType;
 
+import org.apache.jackrabbit.oak.api.Tree;
+
 /**
  * EffectiveNodeTypeProvider... TODO
  *
@@ -35,4 +37,13 @@ public interface EffectiveNodeTypeProvid
      * @throws RepositoryException if the type information can not be accessed
      */
     Iterable<NodeType> getEffectiveNodeTypes(Node targetNode) throws RepositoryException;
+
+    /**
+     * Calculates and returns all effective node types of the given tree.
+     *
+     * @param tree
+     * @return all node types of the given tree
+     * @throws RepositoryException if the type information can not be accessed
+     */
+    Iterable<NodeType> getEffectiveNodeTypes(Tree tree) throws RepositoryException;
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java?rev=1403796&r1=1403795&r2=1403796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java Tue Oct 30 17:36:00 2012
@@ -21,6 +21,7 @@ import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -270,7 +271,8 @@ class NodeTypeImpl implements NodeType {
         }
 
         try {
-            PropertyDefinition def = manager.getDefinition(this, propertyName, false, value.getType(), false);
+            Iterable<NodeType> nts = Collections.singleton((NodeType) this);
+            PropertyDefinition def = manager.getDefinition(nts, propertyName, false, value.getType(), false);
             return !def.isProtected() &&
                     meetsTypeConstraints(value, def.getRequiredType()) &&
                     meetsValueConstraints(value, def.getValueConstraints());
@@ -287,8 +289,9 @@ class NodeTypeImpl implements NodeType {
         }
 
         try {
+            Iterable<NodeType> nts = Collections.singleton((NodeType) this);
             int type = (values.length == 0) ? PropertyType.STRING : values[0].getType();
-            PropertyDefinition def = manager.getDefinition(this, propertyName, true, type, false);
+            PropertyDefinition def = manager.getDefinition(nts, propertyName, true, type, false);
             return !def.isProtected() &&
                     meetsTypeConstraints(values, def.getRequiredType()) &&
                     meetsValueConstraints(values, def.getValueConstraints());

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java?rev=1403796&r1=1403795&r2=1403796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java Tue Oct 30 17:36:00 2012
@@ -46,12 +46,20 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Queues;
 import org.apache.jackrabbit.commons.iterator.NodeTypeIteratorAdapter;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.namepath.NameMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapperImpl;
 import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static javax.jcr.PropertyType.UNDEFINED;
+import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
 
 /**
  * Base implementation of a {@link NodeTypeManager} with support for reading
@@ -61,6 +69,8 @@ import static javax.jcr.PropertyType.UND
  */
 public abstract class ReadOnlyNodeTypeManager implements NodeTypeManager, EffectiveNodeTypeProvider, DefinitionProvider {
 
+    private static final Logger log = LoggerFactory.getLogger(ReadOnlyNodeTypeManager.class);
+
     /**
      * Returns the internal name for the specified JCR name.
      *
@@ -243,6 +253,32 @@ public abstract class ReadOnlyNodeTypeMa
         return getEffectiveNodeTypes(queue);
     }
 
+    @Override
+    public Iterable<NodeType> getEffectiveNodeTypes(Tree tree) throws RepositoryException {
+        Queue<NodeType> queue = Queues.newArrayDeque();
+
+        NodeType primaryType;
+        PropertyState jcrPrimaryType = tree.getProperty(JCR_PRIMARYTYPE);
+        if (jcrPrimaryType != null) {
+            String ntName = jcrPrimaryType.getValue(STRING);
+            primaryType = getNodeType(ntName);
+        } else {
+            log.warn("Item at {} has no primary type. Assuming nt:unstructured", tree.getPath());
+            primaryType = getNodeType(NT_UNSTRUCTURED);
+        }
+        queue.add(primaryType);
+
+        List<NodeType> mixinTypes = Lists.newArrayList();
+        PropertyState jcrMixinType = tree.getProperty(JCR_MIXINTYPES);
+        if (jcrMixinType != null) {
+            for (String ntName : jcrMixinType.getValue(STRINGS)) {
+                mixinTypes.add(getNodeType(ntName));
+            }
+        }
+        queue.addAll(mixinTypes);
+
+        return getEffectiveNodeTypes(queue);
+    }
 
     //-------------------------------------------------< DefinitionProvider >---
 
@@ -294,6 +330,51 @@ public abstract class ReadOnlyNodeTypeMa
     }
 
     @Override
+    public NodeDefinition getDefinition(Iterable<NodeType> parentNodeTypes, String nodeName, NodeType nodeType) throws RepositoryException {
+        List<NodeDefinition> residualDefs = new ArrayList<NodeDefinition>();
+        // TODO: This may need to be optimized
+        // TODO: cleanup redundancy with getDefinition(Node, Node)
+        for (NodeType nt : parentNodeTypes) {
+            for (NodeDefinition def : nt.getDeclaredChildNodeDefinitions()) {
+                String defName = def.getName();
+                if (nodeName.equals(defName)) {
+                    boolean match = true;
+                    // TODO: check again if passing null nodeType is legal.
+                    if (nodeType != null) {
+                        for (String type : def.getRequiredPrimaryTypeNames()) {
+                            if (!nodeType.isNodeType(type)) {
+                                match = false;
+                            }
+                        }
+                    }
+                    if (match) {
+                        return def;
+                    }
+                } else if ("*".equals(defName)) {
+                    residualDefs.add(def);
+                }
+            }
+        }
+
+        for (NodeDefinition def : residualDefs) {
+            String defName = def.getName();
+            if ("*".equals(defName)) {
+                boolean match = true;
+                for (String type : def.getRequiredPrimaryTypeNames()) {
+                    if (!nodeType.isNodeType(type)) {
+                        match = false;
+                    }
+                }
+                if (match) {
+                    return def;
+                }
+            }
+        }
+
+        throw new RepositoryException("No matching node definition found for " + this);
+    }
+
+    @Override
     public PropertyDefinition getDefinition(Node parent, Property targetProperty) throws RepositoryException {
         String name = targetProperty.getName();
         boolean isMultiple = targetProperty.isMultiple();
@@ -354,9 +435,11 @@ public abstract class ReadOnlyNodeTypeMa
     }
 
     @Override
-    public PropertyDefinition getDefinition(NodeType nodeType, String propertyName, boolean isMultiple, int type, boolean exactTypeMatch) throws RepositoryException {
+    public PropertyDefinition getDefinition(Iterable<NodeType> nodeTypes, String propertyName, boolean isMultiple, int type, boolean exactTypeMatch) throws RepositoryException {
         Queue<NodeType> queue = Queues.newArrayDeque();
-        queue.add(nodeType);
+        for (NodeType nt : nodeTypes) {
+            queue.add(nt);
+        }
         Collection<NodeType> effective = getEffectiveNodeTypes(queue);
         return getPropertyDefinition(effective, propertyName, isMultiple, type, exactTypeMatch);
     }
@@ -364,7 +447,7 @@ public abstract class ReadOnlyNodeTypeMa
     //------------------------------------------------------------< private >---
 
     private Collection<NodeType> getEffectiveNodeTypes(Queue<NodeType> queue) {
-        Map<String, NodeType> types = Maps.<String, NodeType>newHashMap();
+        Map<String, NodeType> types = Maps.newHashMap();
         while (!queue.isEmpty()) {
             NodeType type = queue.remove();
             String name = type.getName();

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadWriteNodeTypeManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadWriteNodeTypeManager.java?rev=1403796&r1=1403795&r2=1403796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadWriteNodeTypeManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadWriteNodeTypeManager.java Tue Oct 30 17:36:00 2012
@@ -354,6 +354,13 @@ public abstract class ReadWriteNodeTypeM
 
     @Override
     public void unregisterNodeType(String name) throws RepositoryException {
+        // TODO: review again. added to make tck happy.
+        // TODO  before refactoring the type-validation removing nt:based fail with
+        // TODO  IllegalStateException: Inconsistent node type: org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeImpl@55ab3cda
+        if (NT_BASE.equals(name)) {
+            throw new RepositoryException("nt:base cannot be removed.");
+        }
+
         Tree type = null;
         Root root = getWriteRoot();
         Tree types = root.getTree(NODE_TYPES_PATH);
@@ -383,6 +390,13 @@ public abstract class ReadWriteNodeTypeM
 
         try {
             for (String name : names) {
+                // TODO: review again. added to make tck happy.
+                // TODO  before refactoring the type-validation removing nt:based fail with
+                // TODO  IllegalStateException: Inconsistent node type: org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeImpl@55ab3cda
+                if (NT_BASE.equals(name)) {
+                    throw new RepositoryException("nt:base cannot be removed.");
+                }
+
                 Tree type = types.getChild(getOakName(name));
                 if (type == null) {
                     throw new NoSuchNodeTypeException("Node type " + name + " can not be unregistered.");

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeValidator.java?rev=1403796&r1=1403795&r2=1403796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeValidator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeValidator.java Tue Oct 30 17:36:00 2012
@@ -16,35 +16,30 @@
  */
 package org.apache.jackrabbit.oak.plugins.nodetype;
 
-import java.util.Collections;
 import java.util.List;
-
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.PropertyDefinition;
 
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.core.ReadOnlyTree;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
 import org.apache.jackrabbit.oak.spi.commit.Validator;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
 
@@ -60,7 +55,7 @@ import static org.apache.jackrabbit.oak.
 class TypeValidator implements Validator {
     private static final Logger log = LoggerFactory.getLogger(TypeValidator.class);
 
-    private final NodeTypeManager ntm;
+    private final ReadOnlyNodeTypeManager ntm;
     private final ReadOnlyTree parent;
     private final NamePathMapper mapper;
 
@@ -74,7 +69,7 @@ class TypeValidator implements Validator
         return parentType;
     }
 
-    public TypeValidator(NodeTypeManager ntm, ReadOnlyTree parent, NamePathMapper mapper) {
+    public TypeValidator(ReadOnlyNodeTypeManager ntm, ReadOnlyTree parent, NamePathMapper mapper) {
         this.ntm = ntm;
         this.parent = parent;
         this.mapper = mapper;
@@ -129,13 +124,7 @@ class TypeValidator implements Validator
     @Override
     public Validator childNodeAdded(String name, NodeState after) throws CommitFailedException {
         try {
-            PropertyState type = after.getProperty(JCR_PRIMARYTYPE);
-            if (type == null || type.count() == 0) {
-                getParentType().canAddChildNode(name);
-            } else {
-                String ntName = type.getValue(STRING, 0);
-                getParentType().checkAddChildNode(name, ntName);
-            }
+            getParentType().checkAddChildNode(name, getNodeType(after));
 
             ReadOnlyTree addedTree = new ReadOnlyTree(parent, name, after);
             EffectiveNodeType addedType = getEffectiveNodeType(addedTree);
@@ -156,7 +145,7 @@ class TypeValidator implements Validator
     @Override
     public Validator childNodeDeleted(String name, NodeState before) throws CommitFailedException {
         try {
-            getParentType().checkRemoveNode(name);
+            getParentType().checkRemoveNode(name, getNodeType(before));
             return null;
         } catch (RepositoryException e) {
             throw new CommitFailedException("Cannot remove node '" + name + "' at " + parent.getPath(), e);
@@ -186,129 +175,95 @@ class TypeValidator implements Validator
         }
     }
 
-    private NodeType getPrimaryType(Tree tree) throws RepositoryException {
-        PropertyState jcrPrimaryType = tree.getProperty(JCR_PRIMARYTYPE);
-        if (jcrPrimaryType != null) {
-            String ntName = jcrPrimaryType.getValue(STRING);
-            return ntm.getNodeType(ntName);
+    @CheckForNull
+    private NodeType getNodeType(NodeState state) throws RepositoryException {
+        PropertyState type = state.getProperty(JCR_PRIMARYTYPE);
+        if (type == null || type.count() == 0) {
+            // TODO: review again
+            return null;
         } else {
-            log.warn("Item at {} has no primary type. Assuming nt:unstructured", tree.getPath());
-            return ntm.getNodeType(NT_UNSTRUCTURED);
+            String ntName = type.getValue(STRING, 0);
+            return ntm.getNodeType(ntName);
         }
     }
 
-    private List<NodeType> getMixinTypes(Tree tree) throws RepositoryException {
-        List<NodeType> types = Lists.newArrayList();
-        PropertyState jcrMixinType = tree.getProperty(JCR_MIXINTYPES);
-        if (jcrMixinType != null) {
-            for (String ntName : jcrMixinType.getValue(STRINGS)) {
-                types.add(ntm.getNodeType(ntName));
-            }
-        }
-        return types;
+    private static boolean isHidden(PropertyState state) {
+        return NodeStateUtils.isHidden(state.getName());
     }
 
     // FIXME: the same is also required on JCR level. probably keeping that in 1 single location would be preferable.
     private EffectiveNodeType getEffectiveNodeType(Tree tree) throws RepositoryException {
-        return new EffectiveNodeType(getPrimaryType(tree), getMixinTypes(tree));
+        return new EffectiveNodeType(ntm.getEffectiveNodeTypes(tree));
     }
 
     private class EffectiveNodeType {
         private final Iterable<NodeType> allTypes;
 
-        public EffectiveNodeType(NodeType primaryType, List<NodeType> mixinTypes) {
-            this.allTypes = Iterables.concat(mixinTypes, Collections.singleton(primaryType));
+        public EffectiveNodeType(Iterable<NodeType> allTypes) {
+            this.allTypes = allTypes;
         }
 
-        public void checkSetProperty(PropertyState property) throws ConstraintViolationException {
-            if (isProtectedProperty(property.getName())) {
+        public void checkSetProperty(PropertyState property) throws RepositoryException {
+            PropertyDefinition definition = getDefinition(property);
+            if (definition.isProtected()) {
                 return;
             }
-            if (property.isArray()) {
+
+            NodeType nt = definition.getDeclaringNodeType();
+            if (definition.isMultiple()) {
                 List<Value> values = ValueFactoryImpl.createValues(property, mapper);
-                checkSetProperty(property.getName(), values);
+                if (!nt.canSetProperty(property.getName(), values.toArray(new Value[values.size()]))) {
+                    throw new ConstraintViolationException("Cannot set property '" + property.getName() + "' to '" + values + '\'');
+                }
             } else {
-                Value value = ValueFactoryImpl.createValue(property, mapper);
-                checkSetProperty(property.getName(), value);
-            }
-        }
-
-        private void checkSetProperty(final String propertyName, List<Value> values)
-                throws ConstraintViolationException {
-            if (isProtectedProperty(propertyName)) {
-                return;
-            }
-            Value[] valueArray = values.toArray(new Value[values.size()]);
-            for (NodeType nodeType : allTypes) {
-                if (nodeType.canSetProperty(propertyName, valueArray)) {
-                    return;
+                Value v = ValueFactoryImpl.createValue(property, mapper);
+                if (!nt.canSetProperty(property.getName(), v)) {
+                    throw new ConstraintViolationException("Cannot set property '" + property.getName() + "' to '" + v + '\'');
                 }
             }
-            throw new ConstraintViolationException("Cannot set property '" + propertyName + "' to '" + values + '\'');
         }
 
-        private void checkSetProperty(final String propertyName, Value value) throws ConstraintViolationException {
-            if (isProtectedProperty(propertyName)) {
+        public void checkRemoveProperty(PropertyState property) throws RepositoryException {
+            PropertyDefinition definition = getDefinition(property);
+            if (definition.isProtected()) {
                 return;
             }
-            for (NodeType nodeType : allTypes) {
-                if (nodeType.canSetProperty(propertyName, value)) {
-                    return;
-                }
-            }
-            throw new ConstraintViolationException("Cannot set property '" + propertyName + "' to '" + value + '\'');
-        }
 
-        public void checkRemoveProperty(PropertyState property) throws ConstraintViolationException {
-            if (isProtectedProperty(property.getName())) {
-                return;
+            if (!definition.getDeclaringNodeType().canRemoveProperty(property.getName())) {
+                throw new ConstraintViolationException("Cannot remove property '" + property.getName() + '\'');
             }
-            final String name = property.getName();
-            for (NodeType nodeType : allTypes) {
-                if (nodeType.canRemoveProperty(name)) {
-                    return;
-                }
-            }
-            throw new ConstraintViolationException("Cannot remove property '" + property.getName() + '\'');
         }
 
-        public void checkRemoveNode(final String name) throws ConstraintViolationException {
-            if (isProtectedNode(name)) {
+        public void checkRemoveNode(String name, NodeType nodeType) throws RepositoryException {
+            NodeDefinition definition = getDefinition(name, nodeType);
+            if (definition.isProtected()) {
                 return;
             }
-            for (NodeType nodeType : allTypes) {
-                if (nodeType.canRemoveNode(name)) {
-                    return;
-                }
-            }
-            throw new ConstraintViolationException("Cannot remove node '" + name + '\'');
-        }
 
-        public void canAddChildNode(final String name) throws ConstraintViolationException {
-            if (isProtectedNode(name)) {
-                return;
+            if (!definition.getDeclaringNodeType().canRemoveNode(name)) {
+                throw new ConstraintViolationException("Cannot remove node '" + name + '\'');
             }
-            for (NodeType nodeType : allTypes) {
-                if (nodeType.canAddChildNode(name)) {
-                    return;
-                }
-            }
-            throw new ConstraintViolationException("Cannot add node '" + name + '\'');
         }
 
-        public void checkAddChildNode(final String name, final String ntName) throws ConstraintViolationException {
-            if (isProtectedNode(name)) {
+        public void checkAddChildNode(String name, NodeType nodeType) throws RepositoryException {
+            NodeDefinition definition = getDefinition(name, nodeType);
+            if (definition.isProtected()) {
                 return;
             }
-            for (NodeType nodeType : allTypes) {
-                if (nodeType.canAddChildNode(name, ntName)) {
-                    return;
+
+            if (nodeType == null) {
+                if (!definition.getDeclaringNodeType().canAddChildNode(name)) {
+                    throw new ConstraintViolationException("Cannot add node '" + name + '\'');
+                }
+            } else {
+                if (!definition.getDeclaringNodeType().canAddChildNode(name, nodeType.getName())) {
+                    throw new ConstraintViolationException("Cannot add node '" + name + "' of type '" + nodeType.getName() + '\'');
                 }
             }
-            throw new ConstraintViolationException("Cannot add node '" + name + "' of type '" + ntName + '\'');
+
         }
 
-        public void checkMandatoryItems(final ReadOnlyTree tree) throws ConstraintViolationException {
+        public void checkMandatoryItems(ReadOnlyTree tree) throws ConstraintViolationException {
             for (NodeType nodeType : allTypes) {
                 for (PropertyDefinition pd : nodeType.getPropertyDefinitions()) {
                     String name = pd.getName();
@@ -327,26 +282,15 @@ class TypeValidator implements Validator
             }
         }
 
-        private boolean isProtectedProperty(String propertyName) {
-            // FIXME: duplicated code. we should use one common way to determine a matching definition (DefinitionProvider)
-            for (NodeType nodeType : allTypes) {
-                for (PropertyDefinition pd : nodeType.getPropertyDefinitions()) {
-                    if (propertyName.equals(pd.getName()) && pd.isProtected()) {
-                        return true;
-                    }
-                }
-            }
-            for (NodeType nodeType : allTypes) {
-                for (PropertyDefinition pd : nodeType.getPropertyDefinitions()) {
-                    if ("*".equals(pd.getName()) && pd.isProtected()) {
-                        return true;
-                    }
-                }
-            }
-            return false;
+        private PropertyDefinition getDefinition(PropertyState property) throws RepositoryException {
+            String propertyName = property.getName();
+            int propertyType = property.getType().tag();
+            boolean isMultiple = property.isArray();
+
+            return ntm.getDefinition(allTypes, propertyName, isMultiple, propertyType, true);
         }
 
-        private boolean isProtectedNode(String nodeName) {
+        private NodeDefinition getDefinition(String nodeName, NodeType nodeType) throws RepositoryException {
             // FIXME: ugly hack to workaround sns-hack that was used to map sns-item definitions with node types.
             String nameToCheck = nodeName;
             if (nodeName.startsWith("jcr:childNodeDefinition") && !nodeName.equals("jcr:childNodeDefinition")) {
@@ -355,27 +299,9 @@ class TypeValidator implements Validator
             if (nodeName.startsWith("jcr:propertyDefinition") && !nodeName.equals("jcr:propertyDefinition")) {
                 nameToCheck = nodeName.substring(0, "jcr:propertyDefinition".length());
             }
-            // FIXME: duplicated code. we should use one common way to determine a matching definition (DefinitionProvider)
-            for (NodeType nodeType : allTypes) {
-                for (NodeDefinition nd : nodeType.getChildNodeDefinitions()) {
-                    if (nameToCheck.equals(nd.getName()) && nd.isProtected()) {
-                        return true;
-                    }
-                }
-            }
-            for (NodeType nodeType : allTypes) {
-                for (NodeDefinition nd : nodeType.getChildNodeDefinitions()) {
-                    if ("*".equals(nd.getName()) && nd.isProtected()) {
-                        return true;
-                    }
-                }
-            }
-            return false;
+            return ntm.getDefinition(allTypes, nameToCheck, nodeType);
         }
 
-    }
 
-    private static boolean isHidden(PropertyState state) {
-        return NodeStateUtils.isHidden(state.getName());
     }
 }