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/18 17:21:52 UTC
svn commit: r1457846 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/
oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/
oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ oak-r...
Author: jukka
Date: Mon Mar 18 16:21:52 2013
New Revision: 1457846
URL: http://svn.apache.org/r1457846
Log:
OAK-411: Validator for node type management
Change the type registration validator into an editor that also compiles the property and child node definitions into a more conveniently accessed structure.
Extend type validation to cover more cases.
Added:
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/RegistrationEditorProvider.java
Removed:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationValidator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationValidatorProvider.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
Added: 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=1457846&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java Mon Mar 18 16:21:52 2013
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.nodetype;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_CHILDNODEDEFINITION;
+import static org.apache.jackrabbit.JcrConstants.JCR_MULTIPLE;
+import static org.apache.jackrabbit.JcrConstants.JCR_NAME;
+import static org.apache.jackrabbit.JcrConstants.JCR_NODETYPENAME;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.JCR_PROPERTYDEFINITION;
+import static org.apache.jackrabbit.JcrConstants.JCR_REQUIREDTYPE;
+import static org.apache.jackrabbit.JcrConstants.JCR_SUPERTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+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 java.util.Set;
+
+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.Queues;
+import com.google.common.collect.Sets;
+
+/**
+ * Editor that validates the consistency of the in-content node type registry
+ * under {@code /jcr:system/jcr:nodeTypes} and maintains the access-optimized
+ * version uncer {@code /jcr:system/oak:nodeTypes}.
+ *
+ * <ul>
+ * <li>validate new definitions</li>
+ * <li>detect collisions,</li>
+ * <li>prevent circular inheritance,</li>
+ * <li>reject modifications to definitions that render existing content invalid,</li>
+ * <li>prevent un-registration of built-in node types.</li>
+ * </ul>
+ */
+class RegistrationEditor extends DefaultEditor {
+
+ private final NodeBuilder builder;
+
+ private final Set<String> changedTypes = Sets.newHashSet();
+
+ private final Set<String> removedTypes = Sets.newHashSet();
+
+ RegistrationEditor(NodeBuilder builder) {
+ this.builder = checkNotNull(builder);
+ }
+
+ private void validateAndCompile(String name, NodeState after)
+ throws CommitFailedException {
+ NodeBuilder types = builder.child(JCR_SYSTEM).child(JCR_NODE_TYPES);
+
+ String path = NODE_TYPES_PATH + "/" + name;
+ NodeBuilder type = types.child(name);
+
+ // - jcr:nodeTypeName (NAME) protected mandatory
+ PropertyState nodeTypeName = after.getProperty(JCR_NODETYPENAME);
+ if (nodeTypeName == null
+ || !name.equals(nodeTypeName.getValue(NAME))) {
+ throw new CommitFailedException(
+ "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(
+ "Missing supertype " + value + " in " + path);
+ }
+ }
+ }
+
+ type.setProperty(JCR_PRIMARYTYPE, "oak:nodeType", NAME);
+ type.removeNode("oak:namedPropertyDefinitions");
+ type.removeNode("oak:residualPropertyDefinitions");
+ type.removeNode("oak:namedChildNodeDefinitions");
+ type.removeNode("oak:residualChildNodeDefinitions");
+
+ // + 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());
+ }
+ }
+ }
+
+ private void processPropertyDefinition(
+ 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:namedPropertyDefinitions");
+ definitions.setProperty(
+ JCR_PRIMARYTYPE, "oak:namedPropertyDefinitions", NAME);
+ definitions = definitions.child(name.getValue(NAME));
+ } else {
+ definitions = type.child("oak:residualChildNodeDefinitions");
+ }
+ definitions.setProperty(
+ JCR_PRIMARYTYPE, "oak:propertyDefinitions", NAME);
+
+ // - jcr:requiredType (STRING) protected mandatory
+ // < 'STRING', 'URI', 'BINARY', 'LONG', 'DOUBLE',
+ // 'DECIMAL', 'BOOLEAN', 'DATE', 'NAME', 'PATH',
+ // 'REFERENCE', 'WEAKREFERENCE', 'UNDEFINED'
+ String key = "UNDEFINED";
+ PropertyState requiredType = definition.getProperty(JCR_REQUIREDTYPE);
+ if (requiredType != null) {
+ key = requiredType.getValue(STRING);
+ }
+
+ // - jcr:multiple (BOOLEAN) protected mandatory
+ PropertyState multiple = definition.getProperty(JCR_MULTIPLE);
+ if (multiple != null && multiple.getValue(Type.BOOLEAN)) {
+ key = key + "-ARRAY";
+ }
+
+ definitions.setNode(key, definition);
+ }
+
+ private void processChildNodeDefinition(
+ 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:namedPropertyDefinitions");
+ definitions.setProperty(
+ JCR_PRIMARYTYPE, "oak:namedPropertyDefinitions", NAME);
+ definitions = definitions.child(name.getValue(NAME));
+ } else {
+ definitions = type.child("oak:residualChildNodeDefinitions");
+ }
+ definitions.setProperty(
+ JCR_PRIMARYTYPE, "oak:childNodeDefinitions", NAME);
+
+ // - jcr:requiredPrimaryTypes (NAME)
+ // = 'nt:base' protected mandatory multiple
+ PropertyState requiredTypes = definition.getProperty(JCR_REQUIREDTYPE);
+ if (requiredTypes != null) {
+ for (String key : requiredTypes.getValue(NAMES)) {
+ if (!types.hasChildNode(key)) {
+ throw new CommitFailedException(
+ "Unknown required primary type " + key);
+ } else if (!definitions.hasChildNode(key)) {
+ definitions.setNode(key, definition);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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(
+ "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(
+ "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 (!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);
+ return null;
+ }
+
+ @Override
+ public Validator childNodeChanged(
+ String name, NodeState before, NodeState after)
+ throws CommitFailedException {
+ validateAndCompile(name, after);
+ changedTypes.add(name);
+ return null;
+ }
+
+ @Override
+ public Validator childNodeDeleted(String name, NodeState before)
+ throws CommitFailedException {
+ removedTypes.add(name);
+ return null;
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditorProvider.java?rev=1457846&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditorProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditorProvider.java Mon Mar 18 16:21:52 2013
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.nodetype;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
+
+import javax.annotation.CheckForNull;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.SubtreeEditor;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * Provider for an editor that validates and processes node type information
+ * under {@code /jcr:system/jcr:nodeTypes} to make it more efficient to
+ * access when accessing or modifying related content in the repository.
+ */
+@Component
+@Service(EditorProvider.class)
+public class RegistrationEditorProvider implements EditorProvider {
+
+ @Override @CheckForNull
+ public Editor getRootEditor(
+ NodeState before, NodeState after, NodeBuilder builder) {
+ RegistrationEditor editor = new RegistrationEditor(builder);
+ return new SubtreeEditor(editor, JCR_SYSTEM, JCR_NODE_TYPES);
+ }
+}
\ No newline at end of file
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=1457846&r1=1457845&r2=1457846&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 Mon Mar 18 16:21:52 2013
@@ -425,6 +425,24 @@
+ jcr:propertyDefinition (nt:propertyDefinition) = nt:propertyDefinition protected sns
+ jcr:childNodeDefinition (nt:childNodeDefinition) = nt:childNodeDefinition protected sns
+[oak:nodeType] > nt:nodeType
+ + oak:namedPropertyDefinitions (oak:namedPropertyDefinitions) = oak:namedPropertyDefinitions protected mandatory
+ + oak:residualPropertyDefinitions (oak:propertyDefinitions) = oak:propertyDefinitions protected mandatory
+ + oak:namedChildNodeDefinitions (oak:namedChildNodeDefinitions) = oak:namedChildNodeDefinitions protected mandatory
+ + oak:residualChildNodeDefinitions (oak:childNodeDefinitions) = oak:childNodeDefinitions protected mandatory
+
+[oak:namedPropertyDefinitions]
+ + * (oak:propertyDefinitions) = oak:propertyDefinitions protected
+
+[oak:propertyDefinitions]
+ + * (nt:propertyDefinition) = nt:propertyDefinition protected
+
+[oak:namedChildNodeDefinitions]
+ + * (oak:childNodeDefinitions) = oak:childNodeDefinitions protected
+
+[oak:childNodeDefinitions]
+ + * (nt:childNodeDefinition) = nt:childNodeDefinition protected
+
/**
* This node type used to store a property definition within a node type definition,
* which itself is stored as an nt:nodeType node.
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1457846&r1=1457845&r2=1457846&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java Mon Mar 18 16:21:52 2013
@@ -33,7 +33,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.DefaultTypeEditor;
-import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationEditorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.TypeValidatorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
import org.apache.jackrabbit.oak.plugins.version.VersionHook;
@@ -71,7 +71,7 @@ public class Jcr {
with(new NameValidatorProvider());
with(new NamespaceValidatorProvider());
with(new TypeValidatorProvider());
- with(new RegistrationValidatorProvider());
+ with(new RegistrationEditorProvider());
with(new ConflictValidatorProvider());
with(new Property2IndexHookProvider());
Modified: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java?rev=1457846&r1=1457845&r2=1457846&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java Mon Mar 18 16:21:52 2013
@@ -35,7 +35,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.DefaultTypeEditor;
-import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationEditorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.TypeValidatorProvider;
import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
@@ -168,7 +168,7 @@ public class Main {
.with(new NameValidatorProvider())
.with(new NamespaceValidatorProvider())
.with(new TypeValidatorProvider())
- .with(new RegistrationValidatorProvider())
+ .with(new RegistrationEditorProvider())
.with(new DefaultTypeEditor())
.with(new Property2IndexHookProvider())
.with(securityProvider)