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 ju...@apache.org on 2013/03/22 13:49:19 UTC

svn commit: r1459750 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype: EffectiveNodeType.java EffectiveNodeTypeImpl.java ReadOnlyNodeTypeManager.java

Author: jukka
Date: Fri Mar 22 12:49:18 2013
New Revision: 1459750

URL: http://svn.apache.org/r1459750
Log:
OAK-702: Optimize access to node type information

Merge EffectiveNodeTypeImpl and EffectiveNodeType (no need for an interface when there's just one implementation) to simplify refactoring

Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeTypeImpl.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeType.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeType.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeType.java?rev=1459750&r1=1459749&r2=1459750&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeType.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/EffectiveNodeType.java Fri Mar 22 12:49:18 2013
@@ -16,26 +16,63 @@
  */
 package org.apache.jackrabbit.oak.plugins.nodetype;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
 import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.PropertyDefinition;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 
 /**
  * EffectiveNodeType... TODO
  */
-public interface EffectiveNodeType {
+public class EffectiveNodeType {
 
-    Iterable<NodeType> getAllNodeTypes();
+    private static final Logger log = LoggerFactory.getLogger(EffectiveNodeType.class);
 
-    //Iterable<NodeType> getInheritedNodeTypes();
-    //Iterable<NodeType> getMergedNodeTypes();
+    private final Collection<NodeType> nodeTypes;
+    private final ReadOnlyNodeTypeManager ntMgr;
+
+    private EffectiveNodeType(Collection<NodeType> nodeTypes, ReadOnlyNodeTypeManager ntMgr) {
+        this.nodeTypes = nodeTypes;
+        this.ntMgr = ntMgr;
+    }
+
+    static EffectiveNodeType create(Collection<NodeType> nodeTypes, ReadOnlyNodeTypeManager ntMgr) throws ConstraintViolationException {
+        if (!isValid(nodeTypes)) {
+            throw new ConstraintViolationException("Invalid effective node type");
+        }
+        return new EffectiveNodeType(nodeTypes, ntMgr);
+    }
+
+    private static boolean isValid(Collection<NodeType> nodeTypes) {
+        // FIXME: add validation
+        return true;
+    }
+
+    public Iterable<NodeType> getAllNodeTypes() {
+        return nodeTypes;
+    }
 
     /**
      * Determines whether this effective node type representation includes
@@ -44,7 +81,15 @@ public interface EffectiveNodeType {
      * @param nodeTypeName name of node type
      * @return {@code true} if the given node type is included, otherwise {@code false}.
      */
-    boolean includesNodeType(String nodeTypeName);
+    public boolean includesNodeType(String nodeTypeName) {
+        for (NodeType type : nodeTypes) {
+            if (type.isNodeType(nodeTypeName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 
     /**
      * Determines whether this effective node type representation includes
@@ -54,7 +99,14 @@ public interface EffectiveNodeType {
      * @return {@code true} if all of the given node types are included,
      *         otherwise {@code false}
      */
-    boolean includesNodeTypes(String[] nodeTypeNames);
+    public boolean includesNodeTypes(String[] nodeTypeNames) {
+        for (String ntName : nodeTypeNames) {
+            if (!includesNodeType(ntName)) {
+                return false;
+            }
+        }
+        return true;
+    }
 
     /**
      * Determines whether this effective node type supports adding
@@ -62,19 +114,80 @@ public interface EffectiveNodeType {
      * @param mixin name of mixin type
      * @return {@code true} if the mixin type is supported, otherwise {@code false}
      */
-    boolean supportsMixin(String mixin);
-
-    Iterable<NodeDefinition> getNodeDefinitions();
-
-    Iterable<PropertyDefinition> getPropertyDefinitions();
-
-    Iterable<NodeDefinition> getAutoCreateNodeDefinitions();
-
-    Iterable<PropertyDefinition> getAutoCreatePropertyDefinitions();
-
-    Iterable<NodeDefinition> getMandatoryNodeDefinitions();
-
-    Iterable<PropertyDefinition> getMandatoryPropertyDefinitions();
+    public boolean supportsMixin(String mixin) {
+        if (includesNodeType(mixin)) {
+            return true;
+        }
+
+        NodeType mixinType = null;
+        try {
+            mixinType = ntMgr.internalGetNodeType(mixin);
+            if (!mixinType.isMixin() || mixinType.isAbstract()) {
+                return false;
+            }
+        } catch (NoSuchNodeTypeException e) {
+            log.debug("Unknown mixin type " + mixin);
+        }
+
+        if (mixinType != null) {
+            Set<NodeType> newTypes = new HashSet<NodeType>(nodeTypes);
+            newTypes.add(mixinType);
+            return isValid(newTypes);
+        }
+        return false;
+    }
+
+    public Iterable<NodeDefinition> getNodeDefinitions() {
+        List<NodeDefinition> definitions = new ArrayList<NodeDefinition>();
+        for (NodeType nt : nodeTypes) {
+            definitions.addAll(((NodeTypeImpl) nt).internalGetChildDefinitions());
+        }
+        return definitions;
+    }
+
+    public Iterable<PropertyDefinition> getPropertyDefinitions() {
+        List<PropertyDefinition> definitions = new ArrayList<PropertyDefinition>();
+        for (NodeType nt : nodeTypes) {
+            definitions.addAll(((NodeTypeImpl) nt).internalGetPropertyDefinitions());
+        }
+        return definitions;
+    }
+
+    public Iterable<NodeDefinition> getAutoCreateNodeDefinitions() {
+        return Iterables.filter(getNodeDefinitions(), new Predicate<NodeDefinition>() {
+            @Override
+            public boolean apply(NodeDefinition nodeDefinition) {
+                return nodeDefinition.isAutoCreated();
+            }
+        });
+    }
+
+    public Iterable<PropertyDefinition> getAutoCreatePropertyDefinitions() {
+        return Iterables.filter(getPropertyDefinitions(), new Predicate<PropertyDefinition>() {
+            @Override
+            public boolean apply(PropertyDefinition propertyDefinition) {
+                return propertyDefinition.isAutoCreated();
+            }
+        });
+    }
+
+    public Iterable<NodeDefinition> getMandatoryNodeDefinitions() {
+        return Iterables.filter(getNodeDefinitions(), new Predicate<NodeDefinition>() {
+            @Override
+            public boolean apply(NodeDefinition nodeDefinition) {
+                return nodeDefinition.isMandatory();
+            }
+        });
+    }
+
+    public Iterable<PropertyDefinition> getMandatoryPropertyDefinitions() {
+        return Iterables.filter(getPropertyDefinitions(), new Predicate<PropertyDefinition>() {
+            @Override
+            public boolean apply(PropertyDefinition propertyDefinition) {
+                return propertyDefinition.isMandatory();
+            }
+        });
+    }
 
     /**
      * Return all node definitions that match the specified oak name.
@@ -83,7 +196,9 @@ public interface EffectiveNodeType {
      * @return All node definitions that match the given internal oak name.
      */
     @Nonnull
-    Iterable<NodeDefinition> getNamedNodeDefinitions(String oakName);
+    public Iterable<NodeDefinition> getNamedNodeDefinitions(String oakName) {
+        return Iterables.filter(getNodeDefinitions(), new DefinitionNamePredicate(oakName));
+    }
 
     /**
      * Return all property definitions that match the specified oak name.
@@ -92,7 +207,9 @@ public interface EffectiveNodeType {
      * @return All property definitions that match the given internal oak name.
      */
     @Nonnull
-    Iterable<PropertyDefinition> getNamedPropertyDefinitions(String oakName);
+    public Iterable<PropertyDefinition> getNamedPropertyDefinitions(String oakName) {
+        return Iterables.filter(getPropertyDefinitions(), new DefinitionNamePredicate(oakName));
+    }
 
     /**
      * Return all residual node definitions.
@@ -100,7 +217,14 @@ public interface EffectiveNodeType {
      * @return All residual node definitions.
      */
     @Nonnull
-    Iterable<NodeDefinition> getResidualNodeDefinitions();
+    public Iterable<NodeDefinition> getResidualNodeDefinitions() {
+        return Iterables.filter(getNodeDefinitions(), new Predicate<NodeDefinition>() {
+            @Override
+            public boolean apply(NodeDefinition nodeDefinition) {
+                return NodeTypeConstants.RESIDUAL_NAME.equals(nodeDefinition.getName());
+            }
+        });
+    }
 
     /**
      * Return all residual property definitions.
@@ -108,17 +232,139 @@ public interface EffectiveNodeType {
      * @return All residual property definitions.
      */
     @Nonnull
-    Iterable<PropertyDefinition> getResidualPropertyDefinitions();
-
-    void checkSetProperty(PropertyState property) throws RepositoryException;
-
-    void checkRemoveProperty(PropertyState property) throws RepositoryException;
-
-    void checkAddChildNode(String name, NodeType nodeType) throws RepositoryException;
-
-    void checkRemoveNode(String name, NodeType nodeType) throws RepositoryException;
-
-    void checkMandatoryItems(Tree tree) throws ConstraintViolationException;
+    public Iterable<PropertyDefinition> getResidualPropertyDefinitions() {
+        return Iterables.filter(getPropertyDefinitions(), new Predicate<PropertyDefinition>() {
+            @Override
+            public boolean apply(PropertyDefinition propertyDefinition) {
+                return NodeTypeConstants.RESIDUAL_NAME.equals(propertyDefinition.getName());
+            }
+        });
+    }
+
+    public void checkSetProperty(PropertyState property) throws RepositoryException {
+        PropertyDefinition definition = getDefinition(property);
+        if (definition.isProtected()) {
+            return;
+        }
+
+        NodeType nt = definition.getDeclaringNodeType();
+        if (definition.isMultiple()) {
+            List<Value> values = ValueFactoryImpl.createValues(property, ntMgr.getNamePathMapper());
+            if (!nt.canSetProperty(property.getName(), values.toArray(new Value[values.size()]))) {
+                throw new ConstraintViolationException("Cannot set property '" + property.getName() + "' to '" + values + '\'');
+            }
+        } else {
+            Value v = ValueFactoryImpl.createValue(property, ntMgr.getNamePathMapper());
+            if (!nt.canSetProperty(property.getName(), v)) {
+                throw new ConstraintViolationException("Cannot set property '" + property.getName() + "' to '" + v + '\'');
+            }
+        }
+    }
+
+    public void checkRemoveProperty(PropertyState property) throws RepositoryException {
+        PropertyDefinition definition = getDefinition(property);
+        if (definition.isProtected()) {
+            return;
+        }
+
+        if (!definition.getDeclaringNodeType().canRemoveProperty(property.getName())) {
+            throw new ConstraintViolationException("Cannot remove property '" + property.getName() + '\'');
+        }
+    }
+
+    public void checkAddChildNode(String name, NodeType nodeType) throws RepositoryException {
+        NodeDefinition definition = getDefinition(name, nodeType);
+
+        if (definition.isProtected()) {
+            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() + '\'');
+            }
+        }
+    }
+
+    public void checkRemoveNode(String name, NodeType nodeType) throws RepositoryException {
+        NodeDefinition definition = getDefinition(name, nodeType);
+
+        if (definition.isProtected()) {
+            return;
+        }
+
+        if (!definition.getDeclaringNodeType().canRemoveNode(name)) {
+            throw new ConstraintViolationException("Cannot remove node '" + name + '\'');
+        }
+    }
+
+    public void checkMandatoryItems(Tree tree) throws ConstraintViolationException {
+        for (NodeType nodeType : nodeTypes) {
+            for (PropertyDefinition pd : nodeType.getPropertyDefinitions()) {
+                String name = pd.getName();
+                if (pd.isMandatory() && !pd.isProtected() && tree.getProperty(name) == null) {
+                    throw new ConstraintViolationException(
+                            "Property '" + name + "' in '" + nodeType.getName() + "' is mandatory");
+                }
+            }
+            for (NodeDefinition nd : nodeType.getChildNodeDefinitions()) {
+                String name = nd.getName();
+                if (nd.isMandatory() && !nd.isProtected() && tree.getChild(name) == null) {
+                    throw new ConstraintViolationException(
+                            "Node '" + name + "' in '" + nodeType.getName() + "' is mandatory");
+                }
+            }
+        }
+    }
+
+    public void checkOrderableChildNodes() throws UnsupportedRepositoryOperationException {
+        Iterable<NodeType> nts = getAllNodeTypes();
+        for (NodeType nt : nts) {
+            if (nt.hasOrderableChildNodes()) {
+                return;
+            }
+        }
+
+        throw new UnsupportedRepositoryOperationException("Child node ordering is not supported on this node");
+    }
+
+    //------------------------------------------------------------< private >---
+
+    private PropertyDefinition getDefinition(PropertyState property) throws RepositoryException {
+        String propertyName = property.getName();
+        int propertyType = property.getType().tag();
+        boolean isMultiple = property.isArray();
+
+        return ntMgr.getDefinition(nodeTypes, propertyName, isMultiple, propertyType, true);
+    }
+
+    private NodeDefinition getDefinition(String nodeName, NodeType nodeType) throws ConstraintViolationException {
+        // 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")) {
+            nameToCheck = nodeName.substring(0, "jcr:childNodeDefinition".length());
+        }
+        if (nodeName.startsWith("jcr:propertyDefinition") && !nodeName.equals("jcr:propertyDefinition")) {
+            nameToCheck = nodeName.substring(0, "jcr:propertyDefinition".length());
+        }
+        return ntMgr.getDefinition(nodeTypes, nameToCheck, nodeType);
+    }
+
+    private static class DefinitionNamePredicate implements Predicate<ItemDefinition> {
+
+        private final String oakName;
+
+        DefinitionNamePredicate(String oakName) {
+            this.oakName = oakName;
+        }
+        @Override
+        public boolean apply(@Nullable ItemDefinition definition) {
+            return definition instanceof ItemDefinitionImpl && ((ItemDefinitionImpl) definition).getOakName().equals(oakName);
+        }
+    }
 
-    void checkOrderableChildNodes() throws UnsupportedRepositoryOperationException;
 }

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=1459750&r1=1459749&r2=1459750&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 Fri Mar 22 12:49:18 2013
@@ -490,7 +490,7 @@ public abstract class ReadOnlyNodeTypeMa
                 queue.addAll(Arrays.asList(type.getDeclaredSupertypes()));
             }
         }
-        return EffectiveNodeTypeImpl.create(types.values(), this);
+        return EffectiveNodeType.create(types.values(), this);
     }
 
     /**