Author: jukka
Date: Tue Jul 23 15:37:36 2013
New Revision: 1506119
URL: http://svn.apache.org/r1506119
Log:
OAK-767: Implement Node#removeMixin
Aling the removeMixin() logic with that of Jackrabbit
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/NodeDelegate.java
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/NodeDelegate.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/NodeDelegate.java?rev=1506119&r1=1506118&r2=1506119&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/NodeDelegate.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/NodeDelegate.java
Tue Jul 23 15:37:36 2013
@@ -16,30 +16,6 @@
*/
package org.apache.jackrabbit.oak.jcr.delegate;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.jcr.InvalidItemStateException;
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Tree.Status;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.IdentifierManager;
-import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
-import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
-import org.apache.jackrabbit.oak.util.TreeUtil;
-
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.collect.Iterables.addAll;
import static com.google.common.collect.Iterables.contains;
@@ -48,6 +24,7 @@ import static com.google.common.collect.
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.singletonList;
import static org.apache.jackrabbit.JcrConstants.JCR_ISMIXIN;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_MULTIPLE;
@@ -76,6 +53,33 @@ import static org.apache.jackrabbit.oak.
import static org.apache.jackrabbit.oak.util.TreeUtil.getBoolean;
import static org.apache.jackrabbit.oak.util.TreeUtil.getNames;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Tree.Status;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.IdentifierManager;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+
/**
* {@code NodeDelegate} serve as internal representations of {@code Node}s.
* Most methods of this class throw an {@code InvalidItemStateException}
@@ -390,34 +394,44 @@ public class NodeDelegate extends ItemDe
// the client take care of that before save(), as it's hard to tell
// whether removing such items really is the right thing to do.
- Tree types = sessionDelegate.getRoot().getTree(NODE_TYPES_PATH);
- Tree type = types.getChild(typeName);
+ Tree typeRoot = sessionDelegate.getRoot().getTree(NODE_TYPES_PATH);
+ List<Tree> removed = singletonList(typeRoot.getChild(typeName));
+ List<Tree> remaining = getNodeTypes(tree, typeRoot);
- Tree properties = type.getChild(OAK_NAMED_PROPERTY_DEFINITIONS);
- for (Tree definitions : properties.getChildren()) {
- String name = definitions.getName();
- if (name.equals("oak:primaryType")
- || name.equals("oak:mixinTypes")) {
- continue;
- } else if (name.equals("oak:uuid")) {
- name = JCR_UUID;
- }
- for (Tree definition : definitions.getChildren()) {
- if (getBoolean(definition, JCR_PROTECTED)) {
+ for (PropertyState property : tree.getProperties()) {
+ String name = property.getName();
+ Type<?> type = property.getType();
+
+ Tree oldDefinition = findMatchingPropertyDefinition(
+ removed, name, type, true);
+ if (oldDefinition != null) {
+ Tree newDefinition = findMatchingPropertyDefinition(
+ remaining, name, type, true);
+ if (newDefinition == null
+ || (getBoolean(oldDefinition, JCR_PROTECTED)
+ && !getBoolean(newDefinition, JCR_PROTECTED)))
{
tree.removeProperty(name);
}
}
}
- Tree childNodes = type.getChild(OAK_NAMED_CHILD_NODE_DEFINITIONS);
- for (Tree definitions : childNodes.getChildren()) {
- String name = definitions.getName();
- for (Tree definition : definitions.getChildren()) {
- if (getBoolean(definition, JCR_PROTECTED)) {
- Tree child = tree.getChild(name);
- if (child.exists()) {
- child.remove();
- }
+ for (Tree child : tree.getChildren()) {
+ String name = child.getName();
+ Set<String> typeNames = newLinkedHashSet();
+ for (Tree type : getNodeTypes(child, typeRoot)) {
+ typeNames.add(TreeUtil.getName(type, JCR_NODETYPENAME));
+ addAll(typeNames, getNames(type, OAK_SUPERTYPES));
+ }
+
+ Tree oldDefinition = findMatchingChildNodeDefinition(
+ removed, name, typeNames);
+ if (oldDefinition != null) {
+ Tree newDefinition = findMatchingChildNodeDefinition(
+ remaining, name, typeNames);
+ if (newDefinition == null
+ || (getBoolean(oldDefinition, JCR_PROTECTED)
+ && !getBoolean(newDefinition, JCR_PROTECTED)))
{
+ child.remove();
}
}
}
@@ -450,7 +464,7 @@ public class NodeDelegate extends ItemDe
}
Tree definition = findMatchingPropertyDefinition(
- tree, name, type, exactTypeMatch);
+ getNodeTypes(tree), name, type, exactTypeMatch);
if (definition == null) {
throw new ConstraintViolationException(
"No matching property definition: " + propertyState);
@@ -471,11 +485,18 @@ public class NodeDelegate extends ItemDe
return new PropertyDelegate(sessionDelegate, tree, name);
}
- private Tree findMatchingPropertyDefinition(
- Tree tree, String propertyName, Type<?> propertyType,
- boolean exactTypeMatch) {
- Tree typeRoot = sessionDelegate.getRoot().getTree(NODE_TYPES_PATH);
+ /**
+ * Returns the type nodes of the primary and mixin types of the given node.
+ *
+ * @param tree node
+ * @return primary and mixin type nodes
+ */
+ private List<Tree> getNodeTypes(Tree tree) {
+ Root root = sessionDelegate.getRoot();
+ return getNodeTypes(tree, root.getTree(NODE_TYPES_PATH));
+ }
+ private List<Tree> getNodeTypes(Tree tree, Tree typeRoot) {
// Find applicable node types
List<Tree> types = newArrayList();
String primaryName = TreeUtil.getName(tree, JCR_PRIMARYTYPE);
@@ -487,6 +508,12 @@ public class NodeDelegate extends ItemDe
types.add(typeRoot.getChild(mixinName));
}
+ return types;
+ }
+
+ private Tree findMatchingPropertyDefinition(
+ List<Tree> types, String propertyName, Type<?> propertyType,
+ boolean exactTypeMatch) {
// Escape the property name for looking up a matching definition
String escapedName;
if (JCR_PRIMARYTYPE.equals(propertyName)) {
@@ -550,6 +577,36 @@ public class NodeDelegate extends ItemDe
return null;
}
+ private Tree findMatchingChildNodeDefinition(
+ List<Tree> types, String childNodeName, Set<String> typeNames) {
+ // First look for a matching named property definition
+ for (Tree type : types) {
+ Tree definitions = type
+ .getChild(OAK_NAMED_CHILD_NODE_DEFINITIONS)
+ .getChild(childNodeName);
+ for (String typeName : typeNames) {
+ Tree definition = definitions.getChild(typeName);
+ if (definition.exists()) {
+ return definition;
+ }
+ }
+ }
+
+ // Then look through any residual property definitions
+ for (Tree type : types) {
+ Tree definitions = type
+ .getChild(OAK_RESIDUAL_CHILD_NODE_DEFINITIONS);
+ for (String typeName : typeNames) {
+ Tree definition = definitions.getChild(typeName);
+ if (definition.exists()) {
+ return definition;
+ }
+ }
+ }
+
+ return null;
+ }
+
/**
* Add a child node
*