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/04/12 12:47:45 UTC
svn commit: r1467235 - in /jackrabbit/oak/trunk/oak-core/src/main:
java/org/apache/jackrabbit/oak/plugins/nodetype/
resources/org/apache/jackrabbit/oak/plugins/nodetype/write/
Author: jukka
Date: Fri Apr 12 10:47:44 2013
New Revision: 1467235
URL: http://svn.apache.org/r1467235
Log:
OAK-411: Validator for node type management
Improve the set of pre-compiled type information
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/NodeTypeConstants.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/RegistrationEditor.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java
jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
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=1467235&r1=1467234&r2=1467235&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 Fri Apr 12 10:47:44 2013
@@ -17,11 +17,13 @@
package org.apache.jackrabbit.oak.plugins.nodetype;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.jackrabbit.JcrConstants.JCR_MANDATORY;
+import static com.google.common.collect.Sets.newHashSet;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_NODETYPENAME;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
-import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
import java.util.List;
import java.util.Set;
@@ -31,10 +33,10 @@ import javax.annotation.Nonnull;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
class EffectiveType {
@@ -49,29 +51,18 @@ class EffectiveType {
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
for (NodeState type : types) {
- NodeState properties =
- type.getChildNode("oak:namedPropertyDefinitions");
- for (ChildNodeEntry entry : properties.getChildNodeEntries()) {
- String name = entry.getName();
- if ("oak:primaryType".equals(name)) {
- name = JCR_PRIMARYTYPE;
- } else if ("oak:mixinTypes".equals(name)) {
- name = JCR_MIXINTYPES;
- } else if ("oak:uuid".equals(name)) {
- name = JCR_UUID;
- }
- if (node.getProperty(name) == null
- && isMandatory(name, entry.getNodeState())) {
+ PropertyState properties =
+ type.getProperty("oak:mandatoryProperties");
+ for (String name : properties.getValue(NAMES)) {
+ if (node.getProperty(name) == null) {
builder.add(name);
}
}
- NodeState childNodes =
- type.getChildNode("oak:namedChildNodeDefinitions");
- for (ChildNodeEntry entry : childNodes.getChildNodeEntries()) {
- String name = entry.getName();
- if (!node.hasChildNode(name)
- && isMandatory(name, entry.getNodeState())) {
+ PropertyState childNodes =
+ type.getProperty("oak:mandatoryChildNodes");
+ for (String name : childNodes.getValue(NAMES)) {
+ if (!node.hasChildNode(name)) {
builder.add(name);
}
}
@@ -200,24 +191,16 @@ class EffectiveType {
return null;
}
- //-----------------------------------------------------------< private >--
-
- private boolean isMandatory(String name, NodeState definitions) {
- for (ChildNodeEntry entry : definitions.getChildNodeEntries()) {
- NodeState definition = entry.getNodeState();
- if (getBoolean(definition, JCR_MANDATORY)) {
- return true;
- }
+ Set<String> getTypeNames() {
+ Set<String> names = newHashSet();
+ for (NodeState type : types) {
+ names.add(type.getProperty(JCR_NODETYPENAME).getValue(NAME));
+ Iterables.addAll(names, type.getProperty("oak:supertypes").getValue(NAMES));
}
- return false;
+ return names;
}
- private boolean getBoolean(NodeState node, String name) {
- PropertyState property = node.getProperty(name);
- return property != null
- && property.getType() == BOOLEAN
- && property.getValue(BOOLEAN);
- }
+ //-----------------------------------------------------------< private >--
private String getTypeKey(Type<?> type) {
if (type == Type.BINARIES) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java?rev=1467235&r1=1467234&r2=1467235&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java Fri Apr 12 10:47:44 2013
@@ -58,4 +58,22 @@ public interface NodeTypeConstants exten
String DELETE_DELETED = "deleteDeleted";
String RESIDUAL_NAME = "*";
-}
\ No newline at end of file
+
+ // Precompiled Oak type information fields
+ String OAK_SUPERTYPES = "oak:supertypes";
+ String OAK_SUBTYPES = "oak:subtypes";
+ String OAK_NAMED_PROPERTIES = "oak:namedProperties";
+ String OAK_MANDATORY_PROPERTIES = "oak:mandatoryProperties";
+ String OAK_MANDATORY_CHILD_NODES = "oak:mandatoryChildNodes";
+ String OAK_RESIDUAL_CHILD_NODE_DEFINITIONS =
+ "oak:residualChildNodeDefinitions";
+ String OAK_NAMED_CHILD_NODE_DEFINITIONS =
+ "oak:namedChildNodeDefinitions";
+ String OAK_RESIDUAL_PROPERTY_DEFINITIONS =
+ "oak:residualPropertyDefinitions";
+ String OAK_NAMED_PROPERTY_DEFINITIONS =
+ "oak:namedPropertyDefinitions";
+ String OAK_PROPERTY_DEFINITIONS = "oak:propertyDefinitions";
+ String OAK_CHILD_NODE_DEFINITIONS = "oak:childNodeDefinitions";
+
+}
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=1467235&r1=1467234&r2=1467235&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 Apr 12 10:47:44 2013
@@ -17,14 +17,14 @@
package org.apache.jackrabbit.oak.plugins.nodetype;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.contains;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.oak.api.Type.STRING;
import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NODE_TYPES_PATH;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUPERTYPES;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -44,7 +44,6 @@ import javax.jcr.nodetype.PropertyDefini
import javax.jcr.nodetype.PropertyDefinitionTemplate;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.commons.iterator.NodeTypeIteratorAdapter;
import org.apache.jackrabbit.oak.api.PropertyState;
@@ -282,49 +281,41 @@ public abstract class ReadOnlyNodeTypeMa
return false;
}
- Set<String> typeNames = Sets.newHashSet();
+ Tree types = getTypes();
PropertyState primary = tree.getProperty(JcrConstants.JCR_PRIMARYTYPE);
if (primary != null && primary.getType() == Type.NAME) {
String name = primary.getValue(Type.NAME);
- if (oakNtName.equals(name)) {
+ if (isa(types, name, oakNtName)) {
return true;
- } else {
- typeNames.add(name);
}
}
PropertyState mixins = tree.getProperty(JcrConstants.JCR_MIXINTYPES);
if (mixins != null && mixins.getType() == Type.NAMES) {
for (String name : mixins.getValue(Type.NAMES)) {
- if (oakNtName.equals(name)) {
+ if (isa(types, name, oakNtName)) {
return true;
- } else {
- typeNames.add(name);
}
}
}
- Tree types = getTypes();
- LinkedList<String> queue = Lists.newLinkedList(typeNames);
- while (!queue.isEmpty()) {
- Tree type = types.getChild(queue.removeFirst());
- if (type != null) {
- PropertyState supertypes =
- type.getProperty(JcrConstants.JCR_SUPERTYPES);
- if (supertypes != null && supertypes.getType() == Type.NAMES) {
- for (String name : supertypes.getValue(Type.NAMES)) {
- if (oakNtName.equals(name)) {
- return true;
- } else if (typeNames.add(name)) {
- queue.addLast(name);
- }
- }
- }
- }
+ return false;
+ }
+
+ private static boolean isa(Tree types, String typeName, String superName) {
+ if (typeName.equals(superName)) {
+ return true;
}
- return false;
+ Tree type = types.getChild(typeName);
+ if (type == null) {
+ return false;
+ }
+
+ PropertyState supertypes = type.getProperty(OAK_SUPERTYPES);
+ return supertypes != null
+ && contains(supertypes.getValue(Type.NAMES), superName);
}
/**
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java?rev=1467235&r1=1467234&r2=1467235&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java Fri Apr 12 10:47:44 2013
@@ -17,7 +17,14 @@
package org.apache.jackrabbit.oak.plugins.nodetype;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.contains;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Sets.newHashSet;
+import static com.google.common.collect.Sets.newLinkedHashSet;
+import static java.util.Collections.emptyList;
import static org.apache.jackrabbit.JcrConstants.JCR_CHILDNODEDEFINITION;
+import static org.apache.jackrabbit.JcrConstants.JCR_ISMIXIN;
+import static org.apache.jackrabbit.JcrConstants.JCR_MANDATORY;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_MULTIPLE;
import static org.apache.jackrabbit.JcrConstants.JCR_NAME;
@@ -29,30 +36,43 @@ import static org.apache.jackrabbit.JcrC
import static org.apache.jackrabbit.JcrConstants.JCR_SUPERTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
+import static org.apache.jackrabbit.JcrConstants.NT_BASE;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT;
+import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
import static org.apache.jackrabbit.oak.api.Type.NAME;
import static org.apache.jackrabbit.oak.api.Type.NAMES;
import static org.apache.jackrabbit.oak.api.Type.STRING;
import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NODE_TYPES_PATH;
-
-import java.util.Queue;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_CHILD_NODE_DEFINITIONS;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MANDATORY_CHILD_NODES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MANDATORY_PROPERTIES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_CHILD_NODE_DEFINITIONS;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_PROPERTIES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_PROPERTY_DEFINITIONS;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_PROPERTY_DEFINITIONS;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_RESIDUAL_CHILD_NODE_DEFINITIONS;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_RESIDUAL_PROPERTY_DEFINITIONS;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUBTYPES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUPERTYPES;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Set;
-import com.google.common.collect.Queues;
-import com.google.common.collect.Sets;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
import org.apache.jackrabbit.oak.spi.commit.Validator;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
+import com.google.common.collect.Iterables;
+
/**
* Editor that validates the consistency of the in-content node type registry
* under {@code /jcr:system/jcr:nodeTypes} and maintains the access-optimized
- * version under {@code /jcr:system/oak:nodeTypes}.
+ * versions of node type information as defined in {@code oak:nodeType}.
*
* <ul>
* <li>validate new definitions</li>
@@ -66,71 +86,181 @@ class RegistrationEditor extends Default
private final NodeBuilder builder;
- private final Set<String> changedTypes = Sets.newHashSet();
+ private final Set<String> changedTypes = newHashSet();
+
+ private final Set<String> removedTypes = newHashSet();
- private final Set<String> removedTypes = Sets.newHashSet();
+ private boolean modified = false;
RegistrationEditor(NodeBuilder builder) {
this.builder = checkNotNull(builder);
}
- private void validateAndCompile(String name, NodeState after)
+ /**
+ * Validates the inheritance hierarchy of the identified node type and
+ * merges supertype information to the pre-compiled type information
+ * fields. This makes full type information directly accessible without
+ * having to traverse up the type hierarchy.
+ *
+ * @param types
+ * @param name
+ * @return
+ * @throws CommitFailedException
+ */
+ private void mergeSupertypes(NodeBuilder types, NodeBuilder type)
throws CommitFailedException {
- NodeBuilder types = builder.child(JCR_SYSTEM).child(JCR_NODE_TYPES);
+ if (type.getProperty(OAK_SUPERTYPES) == null) {
+ List<String> empty = Collections.emptyList();
+ type.setProperty(OAK_SUPERTYPES, empty, NAMES);
+
+ // - jcr:supertypes (NAME) protected multiple
+ PropertyState supertypes = type.getProperty(JCR_SUPERTYPES);
+ if (supertypes != null) {
+ for (String supername : supertypes.getValue(NAMES)) {
+ if (types.hasChildNode(supername)) {
+ NodeBuilder supertype = types.child(supername);
+ mergeSupertypes(types, supertype);
+ mergeSupertype(type, supertype.getNodeState());
+ } else {
+ throw new CommitFailedException(
+ CONSTRAINT, 35,
+ "Missing supertype " + supername);
+ }
+ }
+ }
+
+ if (!getBoolean(type, JCR_ISMIXIN)
+ && !contains(getNames(type, OAK_SUPERTYPES), NT_BASE)
+ && !NT_BASE.equals(type.getProperty(JCR_NODETYPENAME).getValue(NAME))) {
+ if (types.hasChildNode(NT_BASE)) {
+ NodeBuilder supertype = types.child(NT_BASE);
+ mergeSupertypes(types, supertype);
+ mergeSupertype(type, supertype.getNodeState());
+ } else {
+ throw new CommitFailedException(
+ CONSTRAINT, 35,
+ "Missing supertype " + NT_BASE);
+ }
+ }
+ }
+ }
+
+ private boolean getBoolean(NodeBuilder builder, String name) {
+ PropertyState property = builder.getProperty(name);
+ return property != null && property.getValue(BOOLEAN);
+ }
+
+ private Iterable<String> getNames(NodeBuilder builder, String name) {
+ PropertyState property = builder.getProperty(name);
+ if (property != null) {
+ return property.getValue(NAMES);
+ } else {
+ return Collections.<String>emptyList();
+ }
+ }
+
+ private void mergeSupertype(NodeBuilder type, NodeState supertype) {
+ String supername =
+ supertype.getProperty(JCR_NODETYPENAME).getValue(NAME);
+ addNameToList(type, OAK_SUPERTYPES, supername);
+ mergeNameList(type, supertype, OAK_SUPERTYPES);
+ mergeNameList(type, supertype, OAK_NAMED_PROPERTIES);
+ mergeNameList(type, supertype, OAK_MANDATORY_PROPERTIES);
+ mergeNameList(type, supertype, OAK_MANDATORY_CHILD_NODES);
+ mergeSubtree(type, supertype, OAK_NAMED_PROPERTY_DEFINITIONS, 2);
+ mergeSubtree(type, supertype, OAK_RESIDUAL_PROPERTY_DEFINITIONS, 1);
+ mergeSubtree(type, supertype, OAK_NAMED_CHILD_NODE_DEFINITIONS, 2);
+ mergeSubtree(type, supertype, OAK_RESIDUAL_CHILD_NODE_DEFINITIONS, 1);
+ }
+
+ private void mergeNameList(
+ NodeBuilder builder, NodeState state, String listName) {
+ LinkedHashSet<String> nameList =
+ newLinkedHashSet(getNames(builder, listName));
+ Iterables.addAll(
+ nameList, state.getProperty(listName).getValue(NAMES));
+ builder.setProperty(listName, nameList, NAMES);
+ }
+
+ private void mergeSubtree(NodeBuilder builder, NodeState state, String name, int depth) {
+ NodeState subtree = state.getChildNode(name);
+ if (subtree.exists()) {
+ if (!builder.hasChildNode(name)) {
+ builder.setNode(name, subtree);
+ } else if (depth > 0) {
+ NodeBuilder subbuilder = builder.child(name);
+ for (String subname : subtree.getChildNodeNames()) {
+ mergeSubtree(subbuilder, subtree, subname, depth - 1);
+ }
+ }
+ }
+ }
- String path = NODE_TYPES_PATH + "/" + name;
+ /**
+ * Validates and pre-compiles the named node type.
+ *
+ * @param types builder for the /jcr:system/jcr:nodeTypes node
+ * @param name name of the node type to validate and compile
+ * @throws CommitFailedException if type validation fails
+ */
+ private void validateAndCompileType(NodeBuilder types, String name)
+ throws CommitFailedException {
NodeBuilder type = types.child(name);
// - jcr:nodeTypeName (NAME) protected mandatory
- PropertyState nodeTypeName = after.getProperty(JCR_NODETYPENAME);
+ PropertyState nodeTypeName = type.getProperty(JCR_NODETYPENAME);
if (nodeTypeName == null
|| !name.equals(nodeTypeName.getValue(NAME))) {
throw new CommitFailedException(
- "Constraint", 34,
- "Unexpected " + JCR_NODETYPENAME + " in " + path);
- }
-
- // - jcr:supertypes (NAME) protected multiple
- PropertyState supertypes = after.getProperty(JCR_SUPERTYPES);
- if (supertypes != null) {
- for (String value : supertypes.getValue(NAMES)) {
- if (!types.hasChildNode(value)) {
- throw new CommitFailedException(
- "Constraint", 35,
- "Missing supertype " + value + " in " + path);
- }
- }
+ CONSTRAINT, 34,
+ "Unexpected " + JCR_NODETYPENAME + " in type " + name);
}
+ // Prepare the type node pre-compilation of the oak:nodeType info
+ Iterable<String> empty = emptyList();
type.setProperty(JCR_PRIMARYTYPE, "oak:nodeType", NAME);
- type.removeNode("oak:namedPropertyDefinitions");
- type.removeNode("oak:residualPropertyDefinitions");
- type.removeNode("oak:namedChildNodeDefinitions");
- type.removeNode("oak:residualChildNodeDefinitions");
+ type.removeProperty(OAK_SUPERTYPES);
+ type.setProperty(OAK_SUBTYPES, empty, NAMES);
+ type.setProperty(OAK_NAMED_PROPERTIES, empty, NAMES);
+ type.setProperty(OAK_MANDATORY_PROPERTIES, empty, NAMES);
+ type.setProperty(OAK_MANDATORY_CHILD_NODES, empty, NAMES);
+ type.removeNode(OAK_NAMED_PROPERTY_DEFINITIONS);
+ type.removeNode(OAK_RESIDUAL_PROPERTY_DEFINITIONS);
+ type.removeNode(OAK_NAMED_CHILD_NODE_DEFINITIONS);
+ type.removeNode(OAK_RESIDUAL_CHILD_NODE_DEFINITIONS);
// + jcr:propertyDefinition (nt:propertyDefinition)
// = nt:propertyDefinition protected sns
// + jcr:childNodeDefinition (nt:childNodeDefinition)
// = nt:childNodeDefinition protected sns
- for (ChildNodeEntry entry : after.getChildNodeEntries()) {
- String childName = entry.getName();
- if (childName.startsWith(JCR_PROPERTYDEFINITION)) {
- processPropertyDefinition(type, entry.getNodeState());
- } else if (childName.startsWith(JCR_CHILDNODEDEFINITION)) {
- processChildNodeDefinition(
- types, type, entry.getNodeState());
+ for (String childNodeName : type.getChildNodeNames()) {
+ NodeState definition = type.child(childNodeName).getNodeState();
+ if (childNodeName.startsWith(JCR_PROPERTYDEFINITION)) {
+ validateAndCompilePropertyDefinition(type, definition);
+ } else if (childNodeName.startsWith(JCR_CHILDNODEDEFINITION)) {
+ validateAndCompileChildNodeDefinition(types, type, definition);
}
}
}
- private void processPropertyDefinition(
+ private void addNameToList(NodeBuilder type, String name, String value) {
+ List<String> values;
+ values = newArrayList(getNames(type, name));
+ if (!values.contains(value)) {
+ values.add(value);
+ }
+ type.setProperty(name, values, NAMES);
+ }
+
+ private void validateAndCompilePropertyDefinition(
NodeBuilder type, NodeState definition)
throws CommitFailedException {
// - jcr:name (NAME) protected
PropertyState name = definition.getProperty(JCR_NAME);
NodeBuilder definitions;
if (name != null) {
- String escapedName = name.getValue(NAME);
+ String propertyName = name.getValue(NAME);
+ String escapedName = propertyName;
if (JCR_PRIMARYTYPE.equals(escapedName)) {
escapedName = "oak:primaryType";
} else if (JCR_MIXINTYPES.equals(escapedName)) {
@@ -138,15 +268,21 @@ class RegistrationEditor extends Default
} else if (JCR_UUID.equals(escapedName)) {
escapedName = "oak:uuid";
}
- definitions = type.child("oak:namedPropertyDefinitions");
+ definitions = type.child(OAK_NAMED_PROPERTY_DEFINITIONS);
definitions.setProperty(
- JCR_PRIMARYTYPE, "oak:namedPropertyDefinitions", NAME);
+ JCR_PRIMARYTYPE, OAK_NAMED_PROPERTY_DEFINITIONS, NAME);
definitions = definitions.child(escapedName);
+
+ // - jcr:mandatory (BOOLEAN) protected mandatory
+ PropertyState mandatory = definition.getProperty(JCR_MANDATORY);
+ if (mandatory != null && mandatory.getValue(BOOLEAN)) {
+ addNameToList(type, OAK_MANDATORY_PROPERTIES, propertyName);
+ }
} else {
- definitions = type.child("oak:residualPropertyDefinitions");
+ definitions = type.child(OAK_RESIDUAL_PROPERTY_DEFINITIONS);
}
definitions.setProperty(
- JCR_PRIMARYTYPE, "oak:propertyDefinitions", NAME);
+ JCR_PRIMARYTYPE, OAK_PROPERTY_DEFINITIONS, NAME);
// - jcr:requiredType (STRING) protected mandatory
// < 'STRING', 'URI', 'BINARY', 'LONG', 'DOUBLE',
@@ -160,7 +296,7 @@ class RegistrationEditor extends Default
// - jcr:multiple (BOOLEAN) protected mandatory
PropertyState multiple = definition.getProperty(JCR_MULTIPLE);
- if (multiple != null && multiple.getValue(Type.BOOLEAN)) {
+ if (multiple != null && multiple.getValue(BOOLEAN)) {
if ("BINARY".equals(key)) {
key = "BINARIES";
} else {
@@ -171,22 +307,29 @@ class RegistrationEditor extends Default
definitions.setNode(key, definition);
}
- private void processChildNodeDefinition(
+ private void validateAndCompileChildNodeDefinition(
NodeBuilder types, NodeBuilder type, NodeState definition)
throws CommitFailedException {
// - jcr:name (NAME) protected
PropertyState name = definition.getProperty(JCR_NAME);
NodeBuilder definitions;
if (name != null) {
- definitions = type.child("oak:namedChildNodeDefinitions");
+ String childNodeName = name.getValue(NAME);
+ definitions = type.child(OAK_NAMED_CHILD_NODE_DEFINITIONS);
definitions.setProperty(
- JCR_PRIMARYTYPE, "oak:namedChildNodeDefinitions", NAME);
- definitions = definitions.child(name.getValue(NAME));
+ JCR_PRIMARYTYPE, OAK_NAMED_CHILD_NODE_DEFINITIONS, NAME);
+ definitions = definitions.child(childNodeName);
+
+ // - jcr:mandatory (BOOLEAN) protected mandatory
+ PropertyState mandatory = definition.getProperty(JCR_MANDATORY);
+ if (mandatory != null && mandatory.getValue(BOOLEAN)) {
+ addNameToList(type, OAK_MANDATORY_CHILD_NODES, childNodeName);
+ }
} else {
- definitions = type.child("oak:residualChildNodeDefinitions");
+ definitions = type.child(OAK_RESIDUAL_CHILD_NODE_DEFINITIONS);
}
definitions.setProperty(
- JCR_PRIMARYTYPE, "oak:childNodeDefinitions", NAME);
+ JCR_PRIMARYTYPE, OAK_CHILD_NODE_DEFINITIONS, NAME);
// - jcr:requiredPrimaryTypes (NAME)
// = 'nt:base' protected mandatory multiple
@@ -205,123 +348,50 @@ class RegistrationEditor extends Default
}
}
- /**
- * Updates the {@link #changedTypes} set to contain also all subtypes
- * that may have been affected by the content changes even if they haven't
- * been directly modified.
- *
- * @param types {@code /jcr:system/jcr:nodeTypes} after the changes
- */
- private void findAllAffectedTypes(NodeState types) {
- Queue<String> queue = Queues.newArrayDeque(changedTypes);
- while (!queue.isEmpty()) {
- String name = queue.remove();
-
- // TODO: We should be able to do this with just one pass
- for (ChildNodeEntry entry : types.getChildNodeEntries()) {
- NodeState type = entry.getNodeState();
- PropertyState supertypes = type.getProperty(JCR_SUPERTYPES);
- if (supertypes != null) {
- for (String superName : supertypes.getValue(NAMES)) {
- if (name.equals(superName)) {
- if (!changedTypes.add(entry.getName())) {
- queue.add(entry.getName());
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Verifies that none of the remaining node types still references
- * one of the removed types.
- *
- * @param types {@code /jcr:system/jcr:nodeTypes} after the changes
- * @throws CommitFailedException if a removed type is still referenced
- */
- private void checkTypeReferencesToRemovedTypes(NodeState types)
- throws CommitFailedException {
- for (ChildNodeEntry entry : types.getChildNodeEntries()) {
- NodeState type = entry.getNodeState();
-
- // Are there any supertype references to removed types?
- PropertyState supertypes = type.getProperty(JCR_SUPERTYPES);
- if (supertypes != null) {
- for (String superName : supertypes.getValue(NAMES)) {
- if (removedTypes.contains(superName)) {
- throw new CommitFailedException(
- "Constraint", 31,
- "Removed type " + superName
- + " is still referenced as a supertype of "
- + entry.getName());
- }
- }
- }
-
- // Are there any child node definition references to removed types?
- for (ChildNodeEntry childEntry : types.getChildNodeEntries()) {
- String childName = childEntry.getName();
- if (childName.startsWith(JCR_CHILDNODEDEFINITION)) {
- NodeState definition = childEntry.getNodeState();
- PropertyState requiredTypes =
- definition.getProperty(JCR_REQUIREDTYPE);
- if (requiredTypes != null) {
- for (String required : requiredTypes.getValue(NAMES)) {
- if (removedTypes.contains(required)) {
- throw new CommitFailedException(
- "Constraint", 32,
- "Removed type " + required
- + " is still referenced as a required "
- + " primary child node type in "
- + entry.getName());
- }
- }
- }
- }
- }
- }
- }
-
//------------------------------------------------------------< Editor >--
@Override
public void leave(NodeState before, NodeState after)
throws CommitFailedException {
- if (!removedTypes.isEmpty()) {
- checkTypeReferencesToRemovedTypes(after);
- }
-
- if (!changedTypes.isEmpty()) {
- findAllAffectedTypes(after);
- }
+ if (modified) {
+ NodeBuilder types = builder.child(JCR_SYSTEM).child(JCR_NODE_TYPES);
+ for (String name : types.getChildNodeNames()) {
+ validateAndCompileType(types, name);
+ }
+ for (String name : types.getChildNodeNames()) {
+ mergeSupertypes(types, types.child(name));
+ }
+ for (String name : types.getChildNodeNames()) {
+ NodeBuilder type = types.child(name);
+ for (String supername : getNames(type, OAK_SUPERTYPES)) {
+ addNameToList(types.child(supername), OAK_SUBTYPES, name);
+ }
+ }
- if (!changedTypes.isEmpty() || !removedTypes.isEmpty()) {
- // TODO: Find and re-validate any nodes in the repository that
- // refer to any of the changed (or removed) node types.
+ if (!changedTypes.isEmpty() || !removedTypes.isEmpty()) {
+ // TODO: Find and re-validate any nodes in the repository that
+ // refer to any of the changed (or removed) node types.
+ }
}
}
@Override
- public Validator childNodeAdded(String name, NodeState after)
- throws CommitFailedException {
- validateAndCompile(name, after);
+ public Validator childNodeAdded(String name, NodeState after) {
+ modified = true;
return null;
}
@Override
public Validator childNodeChanged(
- String name, NodeState before, NodeState after)
- throws CommitFailedException {
- validateAndCompile(name, after);
+ String name, NodeState before, NodeState after) {
+ modified = true;
changedTypes.add(name);
return null;
}
@Override
- public Validator childNodeDeleted(String name, NodeState before)
- throws CommitFailedException {
+ public Validator childNodeDeleted(String name, NodeState before) {
+ modified = true;
removedTypes.add(name);
return null;
}
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=1467235&r1=1467234&r2=1467235&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 Fri Apr 12 10:47:44 2013
@@ -17,13 +17,13 @@
package org.apache.jackrabbit.oak.plugins.nodetype;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.newArrayList;
import static org.apache.jackrabbit.JcrConstants.JCR_ISMIXIN;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.JCR_REQUIREDTYPE;
-import static org.apache.jackrabbit.JcrConstants.JCR_SUPERTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_VALUECONSTRAINTS;
-import static org.apache.jackrabbit.JcrConstants.NT_BASE;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT;
import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
import static org.apache.jackrabbit.oak.api.Type.NAME;
import static org.apache.jackrabbit.oak.api.Type.NAMES;
@@ -33,7 +33,6 @@ import static org.apache.jackrabbit.oak.
import static org.apache.jackrabbit.oak.plugins.nodetype.constraint.Constraints.valueConstraint;
import java.util.List;
-import java.util.Queue;
import java.util.Set;
import javax.jcr.PropertyType;
@@ -49,8 +48,6 @@ import org.apache.jackrabbit.oak.spi.sta
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
-import com.google.common.collect.Queues;
-import com.google.common.collect.Sets;
/**
* Validator implementation that check JCR node type constraints.
@@ -69,6 +66,8 @@ class TypeEditor extends DefaultEditor {
private final NodeState types;
+ private final List<String> typeNames = newArrayList();
+
private EffectiveType effective = null;
TypeEditor(NodeState types) {
@@ -99,15 +98,14 @@ class TypeEditor extends DefaultEditor {
@Override
public void enter(NodeState before, NodeState after)
throws CommitFailedException {
- Iterable<String> names = computeEffectiveType(after);
+ computeEffectiveType(after);
// find matching entry in the parent node's effective type
// TODO: this should be in childNodeAdded()
- if (parent != null
- && parent.effective.getDefinition(nodeName, names) == null) {
+ if (parent != null && parent.effective.getDefinition(
+ nodeName, effective.getTypeNames()) == null) {
throw constraintViolation(
- 1, "Incorrect node type of child node " + nodeName
- + " with types " + Joiner.on(", ").join(names));
+ 1, "Incorrect node type of child node " + nodeName);
}
}
@@ -126,7 +124,7 @@ class TypeEditor extends DefaultEditor {
private CommitFailedException constraintViolation(int code, String message) {
return new CommitFailedException(
- "Constraint", code, getPath() + ": " + message);
+ CONSTRAINT, code, getPath() + ": " + message + " " + typeNames);
}
@Override
@@ -230,19 +228,17 @@ class TypeEditor extends DefaultEditor {
* of effective node type definitions.
*
* @param node node state
- * @return names of the types that make up the effective type
* @throws CommitFailedException if the effective node type is invalid
*/
- private Iterable<String> computeEffectiveType(NodeState node)
+ private void computeEffectiveType(NodeState node)
throws CommitFailedException {
List<NodeState> list = Lists.newArrayList();
- Set<String> names = Sets.newLinkedHashSet();
// primary type
PropertyState primary = node.getProperty(JCR_PRIMARYTYPE);
if (primary != null && primary.getType() == NAME) {
String name = primary.getValue(NAME);
- names.add(name);
+ typeNames.add(name);
NodeState type = types.getChildNode(name);
if (!type.exists()) {
@@ -263,57 +259,25 @@ class TypeEditor extends DefaultEditor {
PropertyState mixins = node.getProperty(JCR_MIXINTYPES);
if (mixins != null && mixins.getType() == NAMES) {
for (String name : mixins.getValue(NAMES)) {
- if (names.add(name)) {
- NodeState type = types.getChildNode(name);
- if (!type.exists()) {
- throw constraintViolation(
- 9, "Mixin node type " + name + " does not exist");
- } else if (!getBoolean(type, JCR_ISMIXIN)) {
- throw constraintViolation(
- 10, "Can not use primary type " + name + " as mixin");
- } else if (getBoolean(type, JCR_IS_ABSTRACT)) {
- throw constraintViolation(
- 11, "Can not use abstract type " + name + " as mixin");
- }
+ typeNames.add(name);
- list.add(type);
+ NodeState type = types.getChildNode(name);
+ if (!type.exists()) {
+ throw constraintViolation(
+ 9, "Mixin node type " + name + " does not exist");
+ } else if (!getBoolean(type, JCR_ISMIXIN)) {
+ throw constraintViolation(
+ 10, "Can not use primary type " + name + " as mixin");
+ } else if (getBoolean(type, JCR_IS_ABSTRACT)) {
+ throw constraintViolation(
+ 11, "Can not use abstract type " + name + " as mixin");
}
- }
- }
-
- // supertypes
- Queue<NodeState> queue = Queues.newArrayDeque(list);
- while (!queue.isEmpty()) {
- NodeState type = queue.remove();
-
- PropertyState supertypes = type.getProperty(JCR_SUPERTYPES);
- if (supertypes != null) {
- for (String name : supertypes.getValue(NAMES)) {
- if (names.add(name)) {
- NodeState supertype = types.getChildNode(name);
- if (supertype.exists()) {
- list.add(supertype);
- queue.add(supertype);
- } else {
- // TODO: ignore/warning/error?
- }
- }
- }
- }
- }
- // always include nt:base
- if (names.add(NT_BASE)) {
- NodeState base = types.getChildNode(NT_BASE);
- if (base.exists()) {
- list.add(base);
- } else {
- // TODO: ignore/warning/error?
+ list.add(type);
}
}
effective = new EffectiveType(list);
- return names;
}
private boolean getBoolean(NodeState node, String name) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1467235&r1=1467234&r2=1467235&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Fri Apr 12 10:47:44 2013
@@ -426,6 +426,11 @@
+ jcr:childNodeDefinition (nt:childNodeDefinition) = nt:childNodeDefinition protected sns
[oak:nodeType] > nt:nodeType
+ - oak:supertypes (NAME) protected multiple autocreated
+ - oak:subtypes (NAME) protected multiple autocreated
+ - oak:namedProperties (NAME) protected multiple autocreated
+ - oak:mandatoryProperties (NAME) protected multiple autocreated
+ - oak:mandatoryChildNodes (NAME) protected multiple autocreated
+ oak:namedPropertyDefinitions (oak:namedPropertyDefinitions) = oak:namedPropertyDefinitions protected mandatory
+ oak:residualPropertyDefinitions (oak:propertyDefinitions) = oak:propertyDefinitions protected mandatory
+ oak:namedChildNodeDefinitions (oak:namedChildNodeDefinitions) = oak:namedChildNodeDefinitions protected mandatory