You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2009/06/10 18:10:18 UTC

svn commit: r783412 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: BatchedItemOperations.java NodeImpl.java

Author: stefan
Date: Wed Jun 10 16:10:16 2009
New Revision: 783412

URL: http://svn.apache.org/viewvc?rev=783412&view=rev
Log:
JCR-2130: Node.removeMixin() should not remove valid items

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=783412&r1=783411&r2=783412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java Wed Jun 10 16:10:16 2009
@@ -1524,6 +1524,7 @@
         // compute system generated values
         Name declaringNT = def.getDeclaringNodeType();
         Name name = def.getName();
+        // TODO JCR-2116: Built-In Node Types; => adapt to JCR 2.0 built-in node types (mix:created, etc)
         if (NameConstants.MIX_REFERENCEABLE.equals(declaringNT)) {
             // mix:referenceable node type
             if (NameConstants.JCR_UUID.equals(name)) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=783412&r1=783411&r2=783412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Wed Jun 10 16:10:16 2009
@@ -300,6 +300,7 @@
 
         // compute system generated values
         NodeTypeImpl nt = (NodeTypeImpl) def.getDeclaringNodeType();
+        // TODO JCR-2116: Built-In Node Types; => adapt to JCR 2.0 built-in node types (mix:created, etc)
         if (nt.getQName().equals(NameConstants.MIX_REFERENCEABLE)) {
             // mix:referenceable node type
             if (name.equals(NameConstants.JCR_UUID)) {
@@ -1132,13 +1133,13 @@
         NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
 
         // build effective node type of remaining mixin's & primary type
-        Set remainingMixins = new HashSet(state.getMixinTypeNames());
+        Set remainingMixins = new HashSet<Name>(state.getMixinTypeNames());
         // remove name of target mixin
         remainingMixins.remove(mixinName);
-        EffectiveNodeType entRemaining;
+        EffectiveNodeType entResulting;
         try {
             // build effective node type representing primary type including remaining mixin's
-            entRemaining = ntReg.getEffectiveNodeType(
+            entResulting = ntReg.getEffectiveNodeType(
                     state.getNodeTypeName(), remainingMixins);
         } catch (NodeTypeConflictException e) {
             throw new ConstraintViolationException(e.getMessage(), e);
@@ -1152,7 +1153,7 @@
         NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
         if ((NameConstants.MIX_REFERENCEABLE.equals(mixinName)
                 || mixin.isDerivedFrom(NameConstants.MIX_REFERENCEABLE))
-                && !entRemaining.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
+                && !entResulting.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
             // removing this mixin would effectively remove mix:referenceable:
             // make sure no references exist
             PropertyIterator iter = getReferences();
@@ -1168,7 +1169,7 @@
          */
         if ((NameConstants.MIX_LOCKABLE.equals(mixinName)
                 || mixin.isDerivedFrom(NameConstants.MIX_LOCKABLE))
-                && !entRemaining.includesNodeType(NameConstants.MIX_LOCKABLE)
+                && !entResulting.includesNodeType(NameConstants.MIX_LOCKABLE)
                 && isLocked()) {
             throw new ConstraintViolationException(mixinName + " can not be removed: the node is locked.");
         }
@@ -1189,27 +1190,76 @@
             return;
         }
 
-        // walk through properties and child nodes and remove those that have
-        // been defined by the specified mixin type
+        // walk through properties and child nodes and remove those that aren't
+        // accomodated by the resulting new effective node type (see JCR-2130)
         boolean success = false;
         try {
             // use temp set to avoid ConcurrentModificationException
-            HashSet set = new HashSet(thisState.getPropertyNames());
+            HashSet set = new HashSet<Name>(thisState.getPropertyNames());
             for (Iterator iter = set.iterator(); iter.hasNext();) {
                 Name propName = (Name) iter.next();
                 PropertyState propState = (PropertyState) stateMgr.getItemState(new PropertyId(thisState.getNodeId(), propName));
                 // check if property has been defined by mixin type (or one of its supertypes)
                 PropertyDefinition def = ntMgr.getPropertyDefinition(propState.getDefinitionId());
                 NodeTypeImpl declaringNT = (NodeTypeImpl) def.getDeclaringNodeType();
-                if (!entRemaining.includesNodeType(declaringNT.getQName())) {
-                    // the remaining effective node type doesn't include the
-                    // node type that declared this property, it is thus safe
-                    // to remove it
-                    removeChildProperty(propName);
+                if (!entResulting.includesNodeType(declaringNT.getQName())) {
+                    // the resulting effective node type doesn't include the
+                    // node type that declared this property
+
+                    // try to find new applicable definition first and
+                    // redefine property if possible (JCR-2130)
+                    try {
+                        PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
+                        if (prop.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected properties immediately
+                            removeChildProperty(propName);
+                            continue;
+                        }
+                        PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(
+                                propName, propState.getType(),
+                                propState.isMultiValued(), false);
+                        if (pdi.getRequiredType() != PropertyType.UNDEFINED
+                                && pdi.getRequiredType() != propState.getType()) {
+                            // value conversion required
+                            if (propState.isMultiValued()) {
+                                // convert value
+                                Value[] values =
+                                        ValueHelper.convert(
+                                                prop.getValues(),
+                                                pdi.getRequiredType(),
+                                                session.getValueFactory());
+                                // redefine property
+                                prop.onRedefine(pdi.unwrap().getId());
+                                // set converted values
+                                prop.setValue(values);
+                            } else {
+                                // convert value
+                                Value value =
+                                        ValueHelper.convert(
+                                                prop.getValue(),
+                                                pdi.getRequiredType(),
+                                                session.getValueFactory());
+                                // redefine property
+                                prop.onRedefine(pdi.unwrap().getId());
+                                // set converted values
+                                prop.setValue(value);
+                            }
+                        } else {
+                            // redefine property
+                            prop.onRedefine(pdi.unwrap().getId());
+                        }
+                    } catch (ValueFormatException vfe) {
+                        // value conversion failed, remove it
+                        removeChildProperty(propName);
+                    } catch (ConstraintViolationException cve) {
+                        // no suitable definition found for this property,
+                        // remove it
+                        removeChildProperty(propName);
+                    }
                 }
             }
             // use temp array to avoid ConcurrentModificationException
-            ArrayList list = new ArrayList(thisState.getChildNodeEntries());
+            ArrayList list = new ArrayList<ChildNodeEntry>(thisState.getChildNodeEntries());
             // start from tail to avoid problems with same-name siblings
             for (int i = list.size() - 1; i >= 0; i--) {
                 ChildNodeEntry entry = (ChildNodeEntry) list.get(i);
@@ -1217,11 +1267,27 @@
                 NodeDefinition def = ntMgr.getNodeDefinition(nodeState.getDefinitionId());
                 // check if node has been defined by mixin type (or one of its supertypes)
                 NodeTypeImpl declaringNT = (NodeTypeImpl) def.getDeclaringNodeType();
-                if (!entRemaining.includesNodeType(declaringNT.getQName())) {
-                    // the remaining effective node type doesn't include the
-                    // node type that declared this child node, it is thus safe
-                    // to remove it
-                    removeChildNode(entry.getName(), entry.getIndex());
+                if (!entResulting.includesNodeType(declaringNT.getQName())) {
+                    // the resulting effective node type doesn't include the
+                    // node type that declared this child node
+
+                    try {
+                        NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
+                        if (node.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected child node immediately
+                            removeChildNode(entry.getName(), entry.getIndex());
+                            continue;
+                        }
+                        NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(
+                                entry.getName(),
+                                nodeState.getNodeTypeName());
+                        // redefine node
+                        node.onRedefine(ndi.unwrap().getId());
+                    } catch (ConstraintViolationException cve) {
+                        // no suitable definition found for this child node,
+                        // remove it
+                        removeChildNode(entry.getName(), entry.getIndex());
+                    }
                 }
             }
             success = true;
@@ -4768,6 +4834,11 @@
                     // redefine property if possible
                     try {
                         PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
+                        if (prop.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected properties immediately
+                            removeChildProperty(propName);
+                            continue;
+                        }
                         PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(
                                 propName, propState.getType(),
                                 propState.isMultiValued(), false);
@@ -4830,11 +4901,16 @@
                     // try to find new applicable definition first and
                     // redefine node if possible
                     try {
+                        NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
+                        if (node.getDefinition().isProtected()) {
+                            // remove 'orphaned' protected child node immediately
+                            removeChildNode(entry.getName(), entry.getIndex());
+                            continue;
+                        }
                         NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(
                                 entry.getName(),
                                 nodeState.getNodeTypeName());
                         // redefine node
-                        NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
                         node.onRedefine(ndi.unwrap().getId());
                         // update collection of added definitions
                         addedDefs.remove(ndi.unwrap());