jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject svn commit: r201999 - in /incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: ./ query/lucene/ state/ state/obj/ state/xml/ version/ virtual/ xml/
Date Mon, 27 Jun 2005 15:08:37 GMT
Author: stefan
Date: Mon Jun 27 08:08:35 2005
New Revision: 201999

URL: http://svn.apache.org/viewcvs?rev=201999&view=rev
Log:
JCR-129: applied patch supplied by serge as-is
(http://issues.apache.org/jira/browse/JCR-129)misc. NodeState optimizations:
- removed PropertyEntry class; the relevant
  NodeState methods (e.g. getPropertyEntries())
  now return QName's instead of PropertyEntry
  to avoid unneccessary object creation
- reimplemented internal ChildNodeEntries class
  for improved speed and efficiency

Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/BatchedItemOperations.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemValidator.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/NodeStateEx.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/BatchedItemOperations.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/BatchedItemOperations.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/BatchedItemOperations.java Mon Jun 27 08:08:35 2005
@@ -583,7 +583,7 @@
                             parentState);
 
             // check for name collisions
-            if (parentState.hasPropertyEntry(nodeName)) {
+            if (parentState.hasPropertyName(nodeName)) {
                 // there's already a property with that name
                 throw new ItemExistsException("cannot add child node '"
                         + nodeName.getLocalName() + "' to "
@@ -1003,7 +1003,7 @@
             RepositoryException, IllegalStateException {
 
         // check for name collisions with existing properties
-        if (parent.hasPropertyEntry(nodeName)) {
+        if (parent.hasPropertyName(nodeName)) {
             String msg = "there's already a property with name " + nodeName;
             log.debug(msg);
             throw new RepositoryException(msg);
@@ -1148,9 +1148,8 @@
         }
 
         // check for name collisions with existing properties
-        if (parent.hasPropertyEntry(propName)) {
-            PropertyId id = new PropertyId(parent.getUUID(),
-                    parent.getPropertyEntry(propName).getName());
+        if (parent.hasPropertyName(propName)) {
+            PropertyId id = new PropertyId(parent.getUUID(), propName);
             throw new ItemExistsException(safeGetJCRPath(id));
         }
 
@@ -1177,7 +1176,7 @@
         }
 
         // now add new property entry to parent
-        parent.addPropertyEntry(propName);
+        parent.addPropertyName(propName);
         // store parent
         stateMgr.store(parent);
 
@@ -1301,7 +1300,7 @@
          * this would have a negative impact on performance though...
          */
         NodeState nodeState = getNodeState(nodePath);
-        while (!nodeState.hasPropertyEntry(JCR_ISCHECKEDOUT)) {
+        while (!nodeState.hasPropertyName(JCR_ISCHECKEDOUT)) {
             if (nodePath.denotesRoot()) {
                 return;
             }
@@ -1528,16 +1527,16 @@
 
         // remove properties
         // use temp array to avoid ConcurrentModificationException
-        tmp = new ArrayList(targetState.getPropertyEntries());
+        tmp = new ArrayList(targetState.getPropertyNames());
         for (int i = 0; i < tmp.size(); i++) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) tmp.get(i);
+            QName propName = (QName) tmp.get(i);
             PropertyId propId =
-                    new PropertyId(targetState.getUUID(), entry.getName());
+                    new PropertyId(targetState.getUUID(), propName);
             try {
                 PropertyState propState =
                         (PropertyState) stateMgr.getItemState(propId);
                 // remove property entry
-                targetState.removePropertyEntry(propId.getName());
+                targetState.removePropertyName(propId.getName());
                 // destroy property state
                 stateMgr.destroy(propState);
             } catch (ItemStateException ise) {
@@ -1684,10 +1683,10 @@
                 newState.addChildNodeEntry(entry.getName(), newChildState.getUUID());
             }
             // copy properties
-            iter = srcState.getPropertyEntries().iterator();
+            iter = srcState.getPropertyNames().iterator();
             while (iter.hasNext()) {
-                NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
-                PropertyId propId = new PropertyId(srcState.getUUID(), entry.getName());
+                QName propName = (QName) iter.next();
+                PropertyId propId = new PropertyId(srcState.getUUID(), propName);
                 if (!srcAccessMgr.isGranted(propId, AccessManager.READ)) {
                     continue;
                 }
@@ -1709,14 +1708,14 @@
                 }
 
                 PropertyState newChildState =
-                        copyPropertyState(srcChildState, uuid, entry.getName());
+                        copyPropertyState(srcChildState, uuid, propName);
                 if (newChildState.getType() == PropertyType.REFERENCE) {
                     refTracker.processedReference(newChildState);
                 }
                 // store new property
                 stateMgr.store(newChildState);
                 // add new property entry to new node
-                newState.addPropertyEntry(entry.getName());
+                newState.addPropertyName(propName);
             }
             return newState;
         } catch (ItemStateException ise) {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java Mon Jun 27 08:08:35 2005
@@ -169,7 +169,7 @@
                     parentState.getChildNodeEntry(name, index);
             childId = new NodeId(nodeEntry.getUUID());
 
-        } else if (parentState.hasPropertyEntry(name)) {
+        } else if (parentState.hasPropertyName(name)) {
             // property
             if (index > 1) {
                 // properties can't have same name siblings

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java Mon Jun 27 08:08:35 2005
@@ -518,7 +518,7 @@
                          */
                         continue;
                     }
-                    if (!nodeState.hasPropertyEntry(pd.getName())) {
+                    if (!nodeState.hasPropertyName(pd.getName())) {
                         String msg = node.safeGetJCRPath()
                                 + ": mandatory property " + pd.getName()
                                 + " does not exist";

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java Mon Jun 27 08:08:35 2005
@@ -462,12 +462,12 @@
             throw new RepositoryException(msg);
         }
         NodeState nodeState = (NodeState) state;
-        Iterator iter = nodeState.getPropertyEntries().iterator();
+        Iterator iter = nodeState.getPropertyNames().iterator();
 
         while (iter.hasNext()) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
+            QName propName = (QName) iter.next();
 
-            PropertyId id = new PropertyId(parentId.getUUID(), entry.getName());
+            PropertyId id = new PropertyId(parentId.getUUID(), propName);
             // check read access
             if (session.getAccessManager().isGranted(id, AccessManager.READ)) {
                 return true;
@@ -497,11 +497,11 @@
         }
         NodeState nodeState = (NodeState) state;
         ArrayList childIds = new ArrayList();
-        Iterator iter = nodeState.getPropertyEntries().iterator();
+        Iterator iter = nodeState.getPropertyNames().iterator();
 
         while (iter.hasNext()) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
-            PropertyId id = new PropertyId(parentId.getUUID(), entry.getName());
+            QName propName = (QName) iter.next();
+            PropertyId id = new PropertyId(parentId.getUUID(), propName);
             // check read access
             if (session.getAccessManager().isGranted(id, AccessManager.READ)) {
                 childIds.add(id);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemValidator.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemValidator.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemValidator.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemValidator.java Mon Jun 27 08:08:35 2005
@@ -115,7 +115,7 @@
         PropDef[] pda = entPrimaryAndMixins.getMandatoryPropDefs();
         for (int i = 0; i < pda.length; i++) {
             PropDef pd = pda[i];
-            if (!nodeState.hasPropertyEntry(pd.getName())) {
+            if (!nodeState.hasPropertyName(pd.getName())) {
                 String msg = safeGetJCRPath(nodeState.getId())
                         + ": mandatory property " + pd.getName()
                         + " does not exist";

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java Mon Jun 27 08:08:35 2005
@@ -165,7 +165,7 @@
                     }
                     // check if property entry exists
                     NodeState thisState = (NodeState) state;
-                    if (thisState.hasPropertyEntry(pe.getName())) {
+                    if (thisState.hasPropertyName(pe.getName())) {
                         return new PropertyId(thisState.getUUID(), pe.getName());
                     } else {
                         // there's no property with that name
@@ -422,7 +422,7 @@
         status.clear();
 
         NodeState thisState = (NodeState) state;
-        if (thisState.hasPropertyEntry(name)) {
+        if (thisState.hasPropertyName(name)) {
             /**
              * the following call will throw ItemNotFoundException if the
              * current session doesn't have read access
@@ -481,7 +481,7 @@
         // modify the state of 'this', i.e. the parent node
         NodeState thisState = (NodeState) getOrCreateTransientItemState();
         // add new property entry
-        thisState.addPropertyEntry(name);
+        thisState.addPropertyName(name);
 
         return prop;
     }
@@ -570,7 +570,7 @@
         NodeState thisState = (NodeState) getOrCreateTransientItemState();
 
         // remove the property entry
-        if (!thisState.removePropertyEntry(propName)) {
+        if (!thisState.removePropertyName(propName)) {
             String msg = "failed to remove property " + propName + " of "
                     + safeGetJCRPath();
             log.debug(msg);
@@ -626,32 +626,32 @@
         // modify the state of 'this', i.e. the target node
         NodeState thisState = (NodeState) getOrCreateTransientItemState();
 
-        // remove child nodes
-        // use temp array to avoid ConcurrentModificationException
-        ArrayList tmp = new ArrayList(thisState.getChildNodeEntries());
-        // remove from tail to avoid problems with same-name siblings
-        for (int i = tmp.size() - 1; i >= 0; i--) {
-            NodeState.ChildNodeEntry entry =
-                    (NodeState.ChildNodeEntry) tmp.get(i);
-            // recursively remove child node
-            NodeId childId = new NodeId(entry.getUUID());
-            NodeImpl childNode = (NodeImpl) itemMgr.getItem(childId);
-            childNode.onRemove();
-
-            // remove the child node entry
-            thisState.removeChildNodeEntry(entry.getName(), entry.getIndex());
+        if (thisState.hasChildNodeEntries()) {
+            // remove child nodes
+            // use temp array to avoid ConcurrentModificationException
+            ArrayList tmp = new ArrayList(thisState.getChildNodeEntries());
+            // remove from tail to avoid problems with same-name siblings
+            for (int i = tmp.size() - 1; i >= 0; i--) {
+                NodeState.ChildNodeEntry entry =
+                        (NodeState.ChildNodeEntry) tmp.get(i);
+                // recursively remove child node
+                NodeId childId = new NodeId(entry.getUUID());
+                NodeImpl childNode = (NodeImpl) itemMgr.getItem(childId);
+                childNode.onRemove();
+                // remove the child node entry
+                thisState.removeChildNodeEntry(entry.getName(), entry.getIndex());
+            }
         }
 
         // remove properties
         // use temp array to avoid ConcurrentModificationException
-        tmp = new ArrayList(thisState.getPropertyEntries());
+        ArrayList tmp = new ArrayList(thisState.getPropertyNames());
         for (int i = 0; i < tmp.size(); i++) {
-            NodeState.PropertyEntry entry =
-                    (NodeState.PropertyEntry) tmp.get(i);
+            QName propName = (QName) tmp.get(i);
             // remove the property entry
-            thisState.removePropertyEntry(entry.getName());
+            thisState.removePropertyName(propName);
             // remove property
-            PropertyId propId = new PropertyId(thisState.getUUID(), entry.getName());
+            PropertyId propId = new PropertyId(thisState.getUUID(), propName);
             itemMgr.getItem(propId).setRemoved();
         }
 
@@ -759,7 +759,7 @@
 
         // check for name collisions
         NodeState thisState = (NodeState) state;
-        if (thisState.hasPropertyEntry(nodeName)) {
+        if (thisState.hasPropertyName(nodeName)) {
             // there's already a property with that name
             throw new ItemExistsException(itemMgr.safeGetJCRPath(nodePath));
         }
@@ -792,7 +792,7 @@
         NodeState thisState = (NodeState) state;
         // get or create jcr:mixinTypes property
         PropertyImpl prop;
-        if (thisState.hasPropertyEntry(JCR_MIXINTYPES)) {
+        if (thisState.hasPropertyName(JCR_MIXINTYPES)) {
             prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), JCR_MIXINTYPES));
         } else {
             // find definition for the jcr:mixinTypes property and create property
@@ -901,7 +901,7 @@
         // child node entries
         persistentState.setChildNodeEntries(transientState.getChildNodeEntries());
         // property entries
-        persistentState.setPropertyEntries(transientState.getPropertyEntries());
+        persistentState.setPropertyNames(transientState.getPropertyNames());
 
         // make state persistent
         stateMgr.store(persistentState);
@@ -1137,18 +1137,18 @@
         // defined by the specified mixin type
 
         // use temp array to avoid ConcurrentModificationException
-        ArrayList tmp = new ArrayList(thisState.getPropertyEntries());
+        ArrayList tmp = new ArrayList(thisState.getPropertyNames());
         Iterator iter = tmp.iterator();
         while (iter.hasNext()) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
-            PropertyImpl prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), entry.getName()));
+            QName propName = (QName) iter.next();
+            PropertyImpl prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), propName));
             // check if property has been defined by mixin type (or one of its supertypes)
             NodeTypeImpl declaringNT = (NodeTypeImpl) prop.getDefinition().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(entry.getName());
+                removeChildProperty(propName);
             }
         }
         // use temp array to avoid ConcurrentModificationException
@@ -1465,7 +1465,7 @@
         sanityCheck();
 
         NodeState thisState = (NodeState) state;
-        if (!thisState.hasPropertyEntry(name)) {
+        if (!thisState.hasPropertyName(name)) {
             return false;
         }
         PropertyId propId = new PropertyId(thisState.getUUID(), name);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java Mon Jun 27 08:08:35 2005
@@ -151,10 +151,10 @@
             // unknown uri<->prefix mappings
         }
 
-        List props = node.getPropertyEntries();
+        List props = node.getPropertyNames();
         for (Iterator it = props.iterator(); it.hasNext();) {
-            NodeState.PropertyEntry prop = (NodeState.PropertyEntry) it.next();
-            PropertyId id = new PropertyId(node.getUUID(), prop.getName());
+            QName propName = (QName) it.next();
+            PropertyId id = new PropertyId(node.getUUID(), propName);
             try {
                 PropertyState propState = (PropertyState) stateProvider.getItemState(id);
                 InternalValue[] values = propState.getValues();
@@ -257,14 +257,14 @@
                 // don't know how to index
                 return;
             }
-            if (node.hasPropertyEntry(JCR_MIMETYPE)) {
+            if (node.hasPropertyName(JCR_MIMETYPE)) {
                 PropertyState dataProp = (PropertyState) stateProvider.getItemState(new PropertyId(node.getUUID(), JCR_DATA));
                 PropertyState mimeTypeProp =
                     (PropertyState) stateProvider.getItemState(new PropertyId(node.getUUID(), JCR_MIMETYPE));
 
                 // jcr:encoding is not mandatory
                 String encoding = null;
-                if (node.hasPropertyEntry(JCR_ENCODING)) {
+                if (node.hasPropertyName(JCR_ENCODING)) {
                     PropertyState encodingProp =
                         (PropertyState) stateProvider.getItemState(new PropertyId(node.getUUID(), JCR_ENCODING));
                     encodingProp.getValues()[0].internalValue().toString();

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java Mon Jun 27 08:08:35 2005
@@ -20,7 +20,9 @@
 import org.apache.jackrabbit.core.QName;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.commons.collections.map.LinkedMap;
 import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.set.ListOrderedSet;
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -34,23 +36,34 @@
 import java.util.List;
 import java.util.Set;
 import java.util.Map;
+import java.util.Collection;
+import java.util.ListIterator;
 
 /**
  * <code>NodeState</code> represents the state of a <code>Node</code>.
  */
 public class NodeState extends ItemState {
 
-    static final long serialVersionUID = -3210487938753054604L;
+    /** Serialization UID of this class. */
+    static final long serialVersionUID = 2387880829766640392L;
 
+    /** the uuid of this node */
     protected String uuid;
+
+    /** the name of this node's primary type */
     protected QName nodeTypeName;
+
+    /** the names of this node's mixin types */
     protected Set mixinTypeNames = new HashSet();
+
+    /** id of this node's definition */
     protected NodeDefId defId;
 
-    // insertion-ordered collection of ChildNodeEntry objects
+    /** insertion-ordered collection of ChildNodeEntry objects */
     protected ChildNodeEntries childNodeEntries = new ChildNodeEntries();
-    // insertion-ordered collection of PropertyEntry objects
-    protected List propertyEntries = new ArrayList();
+
+    /** insertion-ordered set of property names (QName objects) */
+    protected ListOrderedSet propertyNames = new ListOrderedSet();
 
     /**
      * Listeners (weak references)
@@ -102,8 +115,8 @@
         mixinTypeNames.addAll(nodeState.getMixinTypeNames());
         defId = nodeState.getDefinitionId();
         uuid = nodeState.getUUID();
-        propertyEntries.clear();
-        propertyEntries.addAll(nodeState.getPropertyEntries());
+        propertyNames.clear();
+        propertyNames.addAll(nodeState.getPropertyNames());
         childNodeEntries.removeAll();
         childNodeEntries.addAll(nodeState.getChildNodeEntries());
     }
@@ -175,6 +188,16 @@
     }
 
     /**
+     * Determines if there are any child node entries.
+     *
+     * @return <code>true</code> if there are child node entries,
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasChildNodeEntries() {
+        return !childNodeEntries.isEmpty();
+    }
+
+    /**
      * Determines if there is a <code>ChildNodeEntry</code> with the
      * specified <code>name</code>.
      *
@@ -195,6 +218,18 @@
 
     /**
      * Determines if there is a <code>ChildNodeEntry</code> with the
+     * specified <code>uuid</code>.
+     *
+     * @param uuid UUID of the child node
+     * @return <code>true</code> if there is a <code>ChildNodeEntry</code> with
+     *         the specified <code>name</code>.
+     */
+    public synchronized boolean hasChildNodeEntry(String uuid) {
+        return childNodeEntries.get(uuid) != null;
+    }
+
+    /**
+     * Determines if there is a <code>ChildNodeEntry</code> with the
      * specified <code>name</code> and <code>index</code>.
      *
      * @param name  <code>QName</code> object specifying a node name
@@ -220,35 +255,15 @@
     }
 
     /**
-     * Determines if there is a <code>PropertyEntry</code> with the
-     * specified <code>QName</code>.
-     *
-     * @param propName <code>QName</code> object specifying a property name
-     * @return <code>true</code> if there is a <code>PropertyEntry</code> with
-     *         the specified <code>QName</code>.
-     */
-    public synchronized boolean hasPropertyEntry(QName propName) {
-        PropertyEntry entry = new PropertyEntry(propName);
-        return propertyEntries.contains(entry);
-    }
-
-    /**
-     * Returns the <code>PropertyEntry</code> with the specified name or
-     * <code>null</code> if there's no such entry.
+     * Determines if there is a property entry with the specified
+     * <code>QName</code>.
      *
      * @param propName <code>QName</code> object specifying a property name
-     * @return the <code>PropertyEntry</code> with the specified name or
-     *         <code>null</code> if there's no such entry.
+     * @return <code>true</code> if there is a property entry with the specified
+     *         <code>QName</code>.
      */
-    public synchronized PropertyEntry getPropertyEntry(QName propName) {
-        Iterator iter = propertyEntries.iterator();
-        while (iter.hasNext()) {
-            PropertyEntry entry = (PropertyEntry) iter.next();
-            if (propName.equals(entry.getName())) {
-                return entry;
-            }
-        }
-        return null;
+    public synchronized boolean hasPropertyName(QName propName) {
+        return propertyNames.contains(propName);
     }
 
     /**
@@ -281,7 +296,7 @@
      * Returns the <code>ChildNodeEntry</code> with the specified uuid or
      * <code>null</code> if there's no such entry.
      *
-     * @param uuid UUID of a child node state.
+     * @param uuid UUID of the child node
      * @return the <code>ChildNodeEntry</code> with the specified uuid or
      *         <code>null</code> if there's no such entry.
      * @see #addChildNodeEntry
@@ -300,7 +315,7 @@
      * @see #removeChildNodeEntry
      */
     public synchronized List getChildNodeEntries() {
-        return childNodeEntries.entries();
+        return childNodeEntries;
     }
 
     /**
@@ -352,9 +367,9 @@
     }
 
     /**
-     * Removes a <code>ChildNodeEntry<code>.
+     * Removes a <code>ChildNodeEntry</code>.
      *
-     * @param nodeName <code>ChildNodeEntry<code> object specifying a node name
+     * @param nodeName <code>ChildNodeEntry</code> object specifying a node name
      * @param index    1-based index if there are same-name child node entries
      * @return <code>true</code> if the specified child node entry was found
      *         in the list of child node entries and could be removed.
@@ -386,11 +401,7 @@
      * Removes all <code>ChildNodeEntry</code>s.
      */
     public synchronized void removeAllChildNodeEntries() {
-        Iterator iter = childNodeEntries.entries().iterator();
-        while (iter.hasNext()) {
-            ChildNodeEntry entry = (ChildNodeEntry) iter.next();
-            removeChildNodeEntry(entry.getUUID());
-        }
+        childNodeEntries.removeAll();
     }
 
     /**
@@ -404,59 +415,51 @@
     }
 
     /**
-     * Returns a list of <code>PropertyEntry</code> objects denoting the
-     * properties of this node.
+     * Returns the names of this node's properties as a list of
+     * <code>QNames</code> objects.
      *
-     * @return list of <code>PropertyEntry</code> objects
-     * @see #addPropertyEntry
-     * @see #removePropertyEntry
+     * @return list of <code>QNames</code> objects
+     * @see #addPropertyName
+     * @see #removePropertyName
      */
-    public synchronized List getPropertyEntries() {
-        return Collections.unmodifiableList(propertyEntries);
+    public synchronized List getPropertyNames() {
+        return propertyNames.asList();
     }
 
     /**
-     * Adds a <code>PropertyEntry</code>.
+     * Adds a property name entry.
      *
      * @param propName <code>QName</code> object specifying the property name
      */
-    public synchronized void addPropertyEntry(QName propName) {
-        PropertyEntry entry = new PropertyEntry(propName);
-        propertyEntries.add(entry);
+    public synchronized void addPropertyName(QName propName) {
+        propertyNames.add(propName);
     }
 
     /**
-     * Removes a <code>PropertyEntry</code>.
+     * Removes a property name entry.
      *
      * @param propName <code>QName</code> object specifying the property name
-     * @return <code>true</code> if the specified property entry was found
-     *         in the list of property entries and could be removed.
+     * @return <code>true</code> if the specified property name was found
+     *         in the list of property name entries and could be removed.
      */
-    public synchronized boolean removePropertyEntry(QName propName) {
-        PropertyEntry entry = new PropertyEntry(propName);
-        int pos = propertyEntries.indexOf(entry);
-        if (pos == -1) {
-            return false;
-        } else {
-            propertyEntries.remove(pos);
-            return true;
-        }
+    public synchronized boolean removePropertyName(QName propName) {
+        return propertyNames.remove(propName);
     }
 
     /**
-     * Removes all <code>PropertyEntry</code>s.
+     * Removes all property name entries.
      */
-    public synchronized void removeAllPropertyEntries() {
-        propertyEntries.clear();
+    public synchronized void removeAllPropertyNames() {
+        propertyNames.clear();
     }
 
     /**
-     * Sets the list of <code>PropertyEntry</code> objects denoting the
+     * Sets the list of <code>QName</code> objects denoting the
      * properties of this node.
      */
-    public synchronized void setPropertyEntries(List propEntries) {
-        propertyEntries.clear();
-        propertyEntries.addAll(propEntries);
+    public synchronized void setPropertyNames(List propNames) {
+        propertyNames.clear();
+        propertyNames.addAll(propNames);
     }
 
     /**
@@ -471,31 +474,33 @@
 
     //---------------------------------------------------------< diff methods >
     /**
-     * Returns a list of property entries, that do not exist in the overlayed
-     * node state but have been added to <i>this</i> node state.
+     * Returns a list of <code>QName</code>s denoting those properties that
+     * do not exist in the overlayed node state but have been added to
+     * <i>this</i> node state.
      *
-     * @return list of added property entries
+     * @return list of <code>QName</code>s denoting the properties that have
+     *         been added.
      */
-    public synchronized List getAddedPropertyEntries() {
+    public synchronized List getAddedPropertyNames() {
         if (!hasOverlayedState()) {
-            return Collections.unmodifiableList(propertyEntries);
+            return propertyNames.asList();
         }
 
         NodeState other = (NodeState) getOverlayedState();
-        ArrayList list = new ArrayList(propertyEntries);
-        list.removeAll(other.propertyEntries);
+        ArrayList list = new ArrayList(propertyNames);
+        list.removeAll(other.propertyNames);
         return list;
     }
 
     /**
-     * Returns a list of child node entries, that do not exist in the overlayed
+     * Returns a list of child node entries that do not exist in the overlayed
      * node state but have been added to <i>this</i> node state.
      *
      * @return list of added child node entries
      */
     public synchronized List getAddedChildNodeEntries() {
         if (!hasOverlayedState()) {
-            return Collections.unmodifiableList(childNodeEntries.entries());
+            return childNodeEntries;
         }
 
         NodeState other = (NodeState) getOverlayedState();
@@ -503,19 +508,21 @@
     }
 
     /**
-     * Returns a list of property entries, that exist in the overlayed node state
-     * but have been removed from <i>this</i> node state.
+     * Returns a list of <code>QName</code>s denoting those properties that
+     * exist in the overlayed node state but have been removed from
+     * <i>this</i> node state.
      *
-     * @return list of removed property entries
+     * @return list of <code>QName</code>s denoting the properties that have
+     *         been removed.
      */
-    public synchronized List getRemovedPropertyEntries() {
+    public synchronized List getRemovedPropertyNames() {
         if (!hasOverlayedState()) {
             return Collections.EMPTY_LIST;
         }
 
         NodeState other = (NodeState) getOverlayedState();
-        ArrayList list = new ArrayList(other.propertyEntries);
-        list.removeAll(propertyEntries);
+        ArrayList list = new ArrayList(other.propertyNames);
+        list.removeAll(propertyNames);
         return list;
     }
 
@@ -536,11 +543,11 @@
 
     /**
      * Returns a list of child node entries that exist both in <i>this</i> node
-     * state and in the overlayed node state, but have been reordered.
+     * state and in the overlayed node state but have been reordered.
      * <p/>
      * The list may include only the minimal set of nodes that have been
      * reordered. That is, even though a certain number of nodes have changed
-     * their context position, the list may include less that this number of
+     * their absolute position the list may include less that this number of
      * nodes.
      * <p/>
      * Example:<br/>
@@ -556,7 +563,7 @@
      *  + node3
      *  + node1
      * </pre>
-     * All nodes have changed their context position. The returned list however
+     * All nodes have changed their absolute position. The returned list however
      * may only return that <code>node1</code> has been reordered (from the
      * first position to the end).
      *
@@ -568,19 +575,19 @@
         }
 
         List others = new ArrayList();
-        others.addAll(((NodeState) getOverlayedState()).childNodeEntries.entries);
+        others.addAll(((NodeState) getOverlayedState()).getChildNodeEntries());
 
         List ours = new ArrayList();
-        ours.addAll(childNodeEntries.entries);
+        ours.addAll(childNodeEntries);
 
         // do a lazy init
         List reordered = null;
-        // remove added nodes from ours entries
+        // remove added nodes from 'our' entries
         ours.removeAll(getAddedChildNodeEntries());
-        // remove all removed nodes from others entries
+        // remove all removed nodes from 'other' entries
         others.removeAll(getRemovedChildNodeEntries());
-        // both entry list now contain the set of nodes that have not
-        // been removed or added. but they may have changed their position
+        // both entry lists now contain the set of nodes that have not
+        // been removed or added, but they may have changed their position.
         for (int i = 0; i < ours.size();) {
             ChildNodeEntry entry = (ChildNodeEntry) ours.get(i);
             ChildNodeEntry other = (ChildNodeEntry) others.get(i);
@@ -588,13 +595,13 @@
                 if (reordered == null) {
                     reordered = new ArrayList();
                 }
-                // Note, that this check will not necessarily find the
+                // Note that this check will not necessarily find the
                 // minimal reorder operations required to convert the overlayed
                 // child node entries into the current.
 
-                // is there a next entry
+                // is there a next entry?
                 if (i + 1 < ours.size()) {
-                    // if entry is the next in the other list, then probably
+                    // if entry is the next in the other list then probably
                     // the other entry at position <code>i</code> was reordered
                     if (entry.getUUID().equals(((ChildNodeEntry) others.get(i + 1)).getUUID())) {
                         // scan for the uuid of the other entry in our list
@@ -622,7 +629,7 @@
                     }
                 }
                 // if a reorder has been detected index <code>i</code> is not
-                // incremented, because entries will be shifted when the
+                // incremented because entries will be shifted when the
                 // reordered entry is removed.
             } else {
                 // no reorder, move to next child entry
@@ -671,7 +678,7 @@
 
     //-------------------------------------------------< misc. helper methods >
     /**
-     * Notify the listeners that some child node was added
+     * Notify the listeners that a child node entry has been added
      */
     protected void notifyNodeAdded(ChildNodeEntry added) {
         synchronized (listeners) {
@@ -687,7 +694,7 @@
     }
 
     /**
-     * Notify the listeners that the children nodes were replaced
+     * Notify the listeners that the child node entries have been replaced
      */
     protected void notifyNodesReplaced() {
         synchronized (listeners) {
@@ -702,7 +709,7 @@
     }
 
     /**
-     * Notify the listeners that some child node was removed
+     * Notify the listeners that a child node entry has been removed
      */
     protected void notifyNodeRemoved(ChildNodeEntry removed) {
         synchronized (listeners) {
@@ -734,31 +741,37 @@
      * <code>ChildNodeEntries</code> represents an insertion-ordered
      * collection of <code>ChildNodeEntry</code>s that also maintains
      * the index values of same-name siblings on insertion and removal.
+     * <p/>
+     * <code>ChildNodeEntries</code> also provides an unmodifiable
+     * <code>List</code> view.
      */
-    private static class ChildNodeEntries implements Serializable {
+    private static class ChildNodeEntries implements List, Serializable {
 
-        // insertion-ordered collection of entries
-        List entries;
-        // mapping from names to list of same-name sibling entries
-        Map names;
+        // insertion-ordered map of entries (key=uuid, value=entry)
+        LinkedMap entries;
+        // map used for lookup by name (key=uuid, value=1st same-name sibling entry)
+        Map nameMap;
 
         ChildNodeEntries() {
-            entries = new ArrayList();
-            names = new HashMap();
+            entries = new LinkedMap();
+            nameMap = new HashMap();
         }
 
         ChildNodeEntry add(QName nodeName, String uuid) {
-            List siblings = (List) names.get(nodeName);
-            if (siblings == null) {
-                siblings = new ArrayList();
-                names.put(nodeName, siblings);
+            ChildNodeEntry sibling = (ChildNodeEntry) nameMap.get(nodeName);
+            while (sibling != null && sibling.getNextSibling() != null) {
+                sibling = sibling.getNextSibling();
             }
 
-            int index = siblings.size() + 1;
+            int index = (sibling == null) ? 1 : sibling.getIndex() + 1;
 
             ChildNodeEntry entry = new ChildNodeEntry(nodeName, uuid, index);
-            siblings.add(entry);
-            entries.add(entry);
+            if (sibling == null) {
+                nameMap.put(nodeName, entry);
+            } else {
+                sibling.setNextSibling(entry);
+            }
+            entries.put(uuid, entry);
 
             return entry;
         }
@@ -773,8 +786,16 @@
         }
 
         public void removeAll() {
-            names.clear();
             entries.clear();
+            nameMap.clear();
+        }
+
+        ChildNodeEntry remove(String uuid) {
+            ChildNodeEntry entry = (ChildNodeEntry) entries.get(uuid);
+            if (entry != null) {
+                return remove(entry.getName(), entry.getIndex());
+           }
+            return entry;
         }
 
         public ChildNodeEntry remove(ChildNodeEntry entry) {
@@ -785,74 +806,75 @@
             if (index < 1) {
                 throw new IllegalArgumentException("index is 1-based");
             }
-            List siblings = (List) names.get(nodeName);
-            if (siblings == null) {
-                return null;
+
+            ChildNodeEntry sibling = (ChildNodeEntry) nameMap.get(nodeName);
+            ChildNodeEntry prevSibling = null;
+            while (sibling != null) {
+                if (sibling.getIndex() == index) {
+                    break;
+                }
+                prevSibling = sibling;
+                sibling = sibling.getNextSibling();
             }
-            if (index > siblings.size()) {
+            if (sibling == null) {
                 return null;
             }
-            // remove from siblings list
-            ChildNodeEntry removedEntry = (ChildNodeEntry) siblings.remove(index - 1);
+
             // remove from entries list
-            entries.remove(removedEntry);
+            entries.remove(sibling.getUUID());
 
-            if (siblings.size() == 0) {
-                // short cut
-                names.remove(nodeName);
-                return removedEntry;
+            // update linked list of siblings & name map entry
+            if (prevSibling != null) {
+                prevSibling.setNextSibling(sibling.getNextSibling());
+            } else {
+                // the head is removed from the linked siblings list,
+                // update name map
+                if (sibling.getNextSibling() == null) {
+                    nameMap.remove(nodeName);
+                } else {
+                    nameMap.put(nodeName, sibling.getNextSibling());
+                }
             }
-
             // update indices of subsequent same-name siblings
-            for (int i = index - 1; i < siblings.size(); i++) {
-                ChildNodeEntry oldEntry = (ChildNodeEntry) siblings.get(i);
-                ChildNodeEntry newEntry = new ChildNodeEntry(nodeName, oldEntry.getUUID(), oldEntry.getIndex() - 1);
-                // overwrite old entry with updated entry in siblings list
-                siblings.set(i, newEntry);
-                // overwrite old entry with updated entry in entries list
-                entries.set(entries.indexOf(oldEntry), newEntry);
+            ChildNodeEntry nextSibling = sibling.getNextSibling();
+            while (nextSibling != null) {
+                nextSibling.decIndex();
+                nextSibling = nextSibling.getNextSibling();
             }
 
-            return removedEntry;
+            return sibling;
         }
 
         List get(QName nodeName) {
-            List siblings = (List) names.get(nodeName);
-            if (siblings == null) {
+            ChildNodeEntry sibling = (ChildNodeEntry) nameMap.get(nodeName);
+            if (sibling == null) {
                 return Collections.EMPTY_LIST;
-            } else {
-                return Collections.unmodifiableList(siblings);
             }
-        }
-
-        ChildNodeEntry remove(String uuid) {
-            Iterator iter = entries.iterator();
-            while (iter.hasNext()) {
-                ChildNodeEntry entry = (ChildNodeEntry) iter.next();
-                if (entry.getUUID().equals(uuid)) {
-                    return remove(entry);
-                }
+            List siblings = new ArrayList();
+            while (sibling != null) {
+                siblings.add(sibling);
+                sibling = sibling.getNextSibling();
             }
-            return null;
+            return siblings;
         }
 
         ChildNodeEntry get(String uuid) {
-            Iterator iter = entries.iterator();
-            while (iter.hasNext()) {
-                ChildNodeEntry entry = (ChildNodeEntry) iter.next();
-                if (entry.getUUID().equals(uuid)) {
-                    return entry;
-                }
-            }
-            return null;
+            return (ChildNodeEntry) entries.get(uuid);
         }
 
-        Iterator iterator() {
-            return entries.iterator();
-        }
+        ChildNodeEntry get(QName nodeName, int index) {
+            if (index < 1) {
+                throw new IllegalArgumentException("index is 1-based");
+            }
 
-        List entries() {
-            return Collections.unmodifiableList(entries);
+            ChildNodeEntry sibling = (ChildNodeEntry) nameMap.get(nodeName);
+            while (sibling != null) {
+                if (sibling.getIndex() == index) {
+                    return sibling;
+                }
+                sibling = sibling.getNextSibling();
+            }
+            return null;
         }
 
         /**
@@ -860,87 +882,208 @@
          * <code>this</code> but not in <code>other</code>
          * <p/>
          * Note that two entries are considered identical in this context if
-         * they have the same name and uuid, i.e. the index is disregarded,
+         * they have the same name and uuid, i.e. the index is disregarded
          * whereas <code>ChildNodeEntry.equals(Object)</code> also compares
          * the index.
          *
          * @param other entries to be removed
-         * @return a new list of entries who do only exist in <code>this</code>
-         *         but not in <code>other</code>
+         * @return a new list of those entries that do only exist in
+         *         <code>this</code> but not in <code>other</code>
          */
         List removeAll(ChildNodeEntries other) {
             if (entries.isEmpty()) {
                 return Collections.EMPTY_LIST;
             }
-            if (other.entries.isEmpty()) {
-                return Collections.unmodifiableList(entries);
+            if (other.isEmpty()) {
+                return this;
             }
 
-            List result = new ArrayList(entries);
-
-            Iterator otherIter = other.entries.iterator();
-            while (otherIter.hasNext()) {
-                ChildNodeEntry otherEntry = (ChildNodeEntry) otherIter.next();
-                Iterator ourIter = entries.iterator();
-                while (ourIter.hasNext()) {
-                    ChildNodeEntry ourEntry = (ChildNodeEntry) ourIter.next();
-                    if (ourEntry.getName().equals(otherEntry.getName())
-                            && ourEntry.getUUID().equals(otherEntry.getUUID())) {
-                        result.remove(ourEntry);
-                    }
+            List result = new ArrayList();
+            Iterator iter = iterator();
+            while (iter.hasNext()) {
+                ChildNodeEntry entry = (ChildNodeEntry) iter.next();
+                ChildNodeEntry otherEntry = (ChildNodeEntry) other.get(entry.uuid);
+                if (otherEntry == null
+                        || !entry.getName().equals(otherEntry.getName())) {
+                    result.add(entry);
                 }
             }
+
             return result;
         }
-    }
 
-    /**
-     * base class for <code>PropertyEntry</code> and <code>ChildNodeEntry</code>
-     */
-    private abstract static class ChildEntry implements Serializable {
-        protected QName name;
+        //-------------------------------------------< unmodifiable List view >
+        public boolean contains(Object o) {
+            if (o instanceof ChildNodeEntry) {
+                return entries.containsKey(((ChildNodeEntry) o).uuid);
+            } else {
+                return false;
+            }
+        }
 
-        protected ChildEntry(QName name) {
-            this.name = name;
+        public boolean containsAll(Collection c) {
+            Iterator iter = c.iterator();
+            while (iter.hasNext()) {
+                if (!contains(iter.next())) {
+                    return false;
+                }
+            }
+            return true;
         }
 
-        public QName getName() {
-            return name;
+        public Object get(int index) {
+            return entries.getValue(index);
         }
-    }
 
-    /**
-     * <code>PropertyEntry</code> specifies the name of a property entry.
-     */
-    public static class PropertyEntry extends ChildEntry {
+        public int indexOf(Object o) {
+            if (o instanceof ChildNodeEntry) {
+                return entries.indexOf(((ChildNodeEntry) o).uuid);
+            } else {
+                return -1;
+            }
+        }
 
-        private int hash = 0;
+        public boolean isEmpty() {
+            return entries.isEmpty();
+        }
 
-        protected PropertyEntry(QName propName) {
-            super(propName);
+        public int lastIndexOf(Object o) {
+            // entries are unique
+            return indexOf(o);
         }
 
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
+        public Iterator iterator() {
+            return new OrderedMapIterator(entries.asList().listIterator(), entries);
+        }
+
+        public ListIterator listIterator() {
+            return new OrderedMapIterator(entries.asList().listIterator(), entries);
+        }
+
+        public ListIterator listIterator(int index) {
+            return new OrderedMapIterator(entries.asList().listIterator(index), entries);
+        }
+
+        public int size() {
+            return entries.size();
+        }
+
+        public List subList(int fromIndex, int toIndex) {
+            // @todo FIXME does not fulfil the contract of List.subList(int,int)
+            return Collections.unmodifiableList(new ArrayList(this).subList(fromIndex, toIndex));
+        }
+
+        public Object[] toArray() {
+            ChildNodeEntry[] array = new ChildNodeEntry[size()];
+            return toArray(array);
+        }
+
+        public Object[] toArray(Object a[]) {
+            if (!a.getClass().getComponentType().isAssignableFrom(ChildNodeEntry.class)) {
+                throw new ArrayStoreException();
             }
-            if (obj instanceof PropertyEntry) {
-                PropertyEntry other = (PropertyEntry) obj;
-                return name.equals(other.name);
+            if (a.length < size()) {
+                a = new ChildNodeEntry[size()];
             }
-            return false;
+            MapIterator iter = entries.mapIterator();
+            int i = 0;
+            while (iter.hasNext()) {
+                iter.next();
+                a[i] = entries.getValue(i);
+                i++;
+            }
+            while (i < a.length) {
+                a[i++] = null;
+            }
+            return a;
         }
 
-        public String toString() {
-            return name.toString();
+        public void add(int index, Object element) {
+            throw new UnsupportedOperationException();
         }
 
-        public int hashCode() {
-            // PropertyEntry is immutable, we can store the computed hash code value
-            if (hash == 0) {
-                hash = name.hashCode();
+        public boolean add(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean addAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean addAll(int index, Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Object remove(int index) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean removeAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean retainAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Object set(int index, Object element) {
+            throw new UnsupportedOperationException();
+        }
+
+        //----------------------------------------------------< inner classes >
+        class OrderedMapIterator implements ListIterator {
+
+            final ListIterator keyIter;
+            final Map entries;
+
+            OrderedMapIterator(ListIterator keyIter, Map entries) {
+                this.keyIter = keyIter;
+                this.entries = entries;
+            }
+
+            public boolean hasNext() {
+                return keyIter.hasNext();
+            }
+
+            public Object next() {
+                return entries.get(keyIter.next());
+            }
+
+            public boolean hasPrevious() {
+                return keyIter.hasPrevious();
+            }
+
+            public int nextIndex() {
+                return keyIter.nextIndex();
+            }
+
+            public Object previous() {
+                return entries.get(keyIter.previous());
+            }
+
+            public int previousIndex() {
+                return keyIter.previousIndex();
+            }
+
+            public void add(Object o) {
+                throw new UnsupportedOperationException();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            public void set(Object o) {
+                throw new UnsupportedOperationException();
             }
-            return hash;
         }
     }
 
@@ -948,15 +1091,18 @@
      * <code>ChildNodeEntry</code> specifies the name, index (in the case of
      * same-name siblings) and the UUID of a child node entry.
      */
-    public static class ChildNodeEntry extends ChildEntry {
-
-        private int hash = 0;
+    public static class ChildNodeEntry {
 
+        private QName name;
         private int index; // 1-based index for same-name siblings
         private String uuid;
+        private ChildNodeEntry nextSibling;
 
-        protected ChildNodeEntry(QName nodeName, String uuid, int index) {
-            super(nodeName);
+        private ChildNodeEntry(QName name, String uuid, int index) {
+            if (name == null) {
+                throw new IllegalArgumentException("name can not be null");
+            }
+            this.name = name;
 
             if (uuid == null) {
                 throw new IllegalArgumentException("uuid can not be null");
@@ -967,16 +1113,46 @@
                 throw new IllegalArgumentException("index is 1-based");
             }
             this.index = index;
+
+            nextSibling = null;
         }
 
         public String getUUID() {
             return uuid;
         }
 
+        public QName getName() {
+            return name;
+        }
+
         public int getIndex() {
             return index;
         }
 
+        public ChildNodeEntry getNextSibling() {
+            return nextSibling;
+        }
+
+        void setNextSibling(ChildNodeEntry nextSibling) {
+            if (nextSibling != null && !nextSibling.getName().equals(name)) {
+                throw new IllegalArgumentException("not a same-name sibling entry");
+            }
+
+            this.nextSibling = nextSibling;
+        }
+
+        int incIndex() {
+            return ++index;
+        }
+
+        int decIndex() {
+            if (index == 1) {
+                throw new IndexOutOfBoundsException();
+            }
+            return --index;
+        }
+
+        //---------------------------------------< java.lang.Object overrides >
         public boolean equals(Object obj) {
             if (this == obj) {
                 return true;
@@ -993,17 +1169,15 @@
             return name.toString() + "[" + index + "] -> " + uuid;
         }
 
+        /**
+         * Returns zero to satisfy the Object equals/hashCode contract.
+         * This class is mutable and not meant to be used as a hash key.
+         *
+         * @return always zero
+         * @see Object#hashCode()
+         */
         public int hashCode() {
-            // ChildNodeEntry is immutable, we can store the computed hash code value
-            int h = hash;
-            if (h == 0) {
-                h = 17;
-                h = 37 * h + name.hashCode();
-                h = 37 * h + uuid.hashCode();
-                h = 37 * h + index;
-                hash = h;
-            }
-            return h;
+            return 0;
         }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java Mon Jun 27 08:08:35 2005
@@ -412,6 +412,7 @@
         if (!transientStateMgr.hasAnyItemStatesInAttic()) {
             return Collections.EMPTY_LIST.iterator();
         }
+
         // collection of descendant transient states in attic:
         // the path serves as key and sort criteria
 
@@ -425,10 +426,8 @@
         TreeMap descendants = new TreeMap(new PathComparator());
         try {
             Path parentPath = zombieHierMgr.getPath(parentId);
-            /**
-             * walk through list of transient states in attic and check if
-             * they are descendants of the specified parent
-             */
+             // walk through list of transient states in attic and check if
+             // they are descendants of the specified parent
             Iterator iter = transientStateMgr.getEntriesInAttic();
             while (iter.hasNext()) {
                 ItemState state = (ItemState) iter.next();
@@ -445,7 +444,17 @@
         } catch (RepositoryException re) {
             log.warn("inconsistent hierarchy state", re);
         }
-
+/*
+        TreeMap descendants = new TreeMap();
+        Iterator iter = transientStateMgr.getEntriesInAttic();
+        while (iter.hasNext()) {
+            ItemState state = (ItemState) iter.next();
+            int depth = getAncestorCount(state, parentId.getUUID());
+            if (depth >= 0) {
+                descendants.put(new ItemStateKey(state, depth), state);
+            }
+        }
+*/
         return descendants.values().iterator();
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Mon Jun 27 08:08:35 2005
@@ -148,7 +148,7 @@
         rootState.setDefinitionId(nodeDefId);
 
         // create jcr:primaryType property
-        rootState.addPropertyEntry(propDef.getName());
+        rootState.addPropertyName(propDef.getName());
 
         PropertyState prop = createInstance(propDef.getName(), rootNodeUUID);
         prop.setValues(new InternalValue[]{InternalValue.create(Constants.REP_ROOT)});

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java Mon Jun 27 08:08:35 2005
@@ -175,11 +175,11 @@
             out.writeUTF(iter.next().toString());   // name
         }
         // properties (names)
-        c = state.getPropertyEntries();
+        c = state.getPropertyNames();
         out.writeInt(c.size()); // count
         for (Iterator iter = c.iterator(); iter.hasNext();) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
-            out.writeUTF(entry.getName().toString());   // name
+            QName propName = (QName) iter.next();
+            out.writeUTF(propName.toString());   // name
         }
         // child nodes (list of name/uuid pairs)
         c = state.getChildNodeEntries();
@@ -235,7 +235,7 @@
         // properties (names)
         count = in.readInt();   // count
         for (int i = 0; i < count; i++) {
-            state.addPropertyEntry(QName.valueOf(in.readUTF())); // name
+            state.addPropertyName(QName.valueOf(in.readUTF())); // name
         }
         // child nodes (list of name/uuid pairs)
         count = in.readInt();   // count

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java Mon Jun 27 08:08:35 2005
@@ -226,7 +226,7 @@
             while (walker.iterateElements(PROPERTY_ELEMENT)) {
                 String propName = walker.getAttribute(NAME_ATTRIBUTE);
                 // @todo deserialize type and values
-                state.addPropertyEntry(QName.valueOf(propName));
+                state.addPropertyName(QName.valueOf(propName));
             }
             walker.leaveElement();
         }
@@ -508,11 +508,11 @@
 
                 // properties
                 writer.write("\t<" + PROPERTIES_ELEMENT + ">\n");
-                iter = state.getPropertyEntries().iterator();
+                iter = state.getPropertyNames().iterator();
                 while (iter.hasNext()) {
-                    NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
+                    QName propName = (QName) iter.next();
                     writer.write("\t\t<" + PROPERTY_ELEMENT + " "
-                            + NAME_ATTRIBUTE + "=\"" + Text.encodeIllegalXMLCharacters(entry.getName().toString()) + "\">\n");
+                            + NAME_ATTRIBUTE + "=\"" + Text.encodeIllegalXMLCharacters(propName.toString()) + "\">\n");
                     // @todo serialize type, definition id and values
                     writer.write("\t\t</" + PROPERTY_ELEMENT + ">\n");
                 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/NodeStateEx.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/NodeStateEx.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/NodeStateEx.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/NodeStateEx.java Mon Jun 27 08:08:35 2005
@@ -131,11 +131,11 @@
      * @return
      */
     public PropertyState[] getProperties() throws ItemStateException {
-        List list = nodeState.getPropertyEntries();
+        List list = nodeState.getPropertyNames();
         PropertyState[] props = new PropertyState[list.size()];
         for (int i = 0; i < list.size(); i++) {
-            NodeState.PropertyEntry entry = (NodeState.PropertyEntry) list.get(i);
-            PropertyId propId = new PropertyId(nodeState.getUUID(), entry.getName());
+            QName propName = (QName) list.get(i);
+            PropertyId propId = new PropertyId(nodeState.getUUID(), propName);
             props[i] = (PropertyState) stateMgr.getItemState(propId);
         }
         return props;
@@ -262,7 +262,7 @@
             propState.setDefinitionId(pd.getId());
 
             // need to store nodestate
-            nodeState.addPropertyEntry(name);
+            nodeState.addPropertyName(name);
             if (nodeState.getStatus() == ItemState.STATUS_EXISTING) {
                 nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
             }
@@ -341,7 +341,7 @@
     }
 
     /**
-     * removes the property with the given name and 1-based index
+     * removes the property with the given name
      *
      * @param name
      * @return
@@ -349,14 +349,13 @@
      */
     public boolean removeProperty(QName name) throws RepositoryException {
         try {
-            NodeState.PropertyEntry entry = nodeState.getPropertyEntry(name);
-            if (entry == null) {
+            if (!nodeState.hasPropertyName(name)) {
                 return false;
             } else {
                 PropertyId propId = new PropertyId(nodeState.getUUID(), name);
                 ItemState state = stateMgr.getItemState(propId);
                 stateMgr.destroy(state);
-                nodeState.removePropertyEntry(name);
+                nodeState.removePropertyName(name);
                 nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
                 return true;
             }
@@ -484,10 +483,10 @@
 
         if (state.getStatus() != ItemState.STATUS_EXISTING) {
             // first store all transient properties
-            List props = state.getPropertyEntries();
+            List props = state.getPropertyNames();
             for (int i = 0; i < props.size(); i++) {
-                NodeState.PropertyEntry entry = (NodeState.PropertyEntry) props.get(i);
-                PropertyState pstate = (PropertyState) stateMgr.getItemState(new PropertyId(state.getUUID(), entry.getName()));
+                QName propName = (QName) props.get(i);
+                PropertyState pstate = (PropertyState) stateMgr.getItemState(new PropertyId(state.getUUID(), propName));
                 if (pstate.getStatus() != ItemState.STATUS_EXISTING) {
                     stateMgr.store(pstate);
                 }
@@ -528,10 +527,10 @@
     private void reload(NodeState state) throws ItemStateException {
         if (state.getStatus() != ItemState.STATUS_EXISTING) {
             // first discard all all transient properties
-            List props = state.getPropertyEntries();
+            List props = state.getPropertyNames();
             for (int i = 0; i < props.size(); i++) {
-                NodeState.PropertyEntry entry = (NodeState.PropertyEntry) props.get(i);
-                PropertyState pstate = (PropertyState) stateMgr.getItemState(new PropertyId(state.getUUID(), entry.getName()));
+                QName propName = (QName) props.get(i);
+                PropertyState pstate = (PropertyState) stateMgr.getItemState(new PropertyId(state.getUUID(), propName));
                 if (pstate.getStatus() != ItemState.STATUS_EXISTING) {
                     pstate.discard();
                 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java Mon Jun 27 08:08:35 2005
@@ -140,7 +140,7 @@
                 pt.setMultiValued(false);
                 pt.setType(PropertyType.NAME);
                 pt.setValues(new InternalValue[]{InternalValue.create(REP_VERSIONSTORAGE)});
-                root.addPropertyEntry(pt.getName());
+                root.addPropertyName(pt.getName());
                 ChangeLog cl = new ChangeLog();
                 cl.added(root);
                 cl.added(pt);
@@ -708,10 +708,10 @@
         if (state != null) {
             if (recursive && state instanceof NodeState) {
                 NodeState nState = (NodeState) state;
-                Iterator iter = nState.getPropertyEntries().iterator();
+                Iterator iter = nState.getPropertyNames().iterator();
                 while (iter.hasNext()) {
-                    NodeState.PropertyEntry pe = (NodeState.PropertyEntry) iter.next();
-                    invalidateItem(new PropertyId(nState.getUUID(), pe.getName()), false);
+                    QName propName = (QName) iter.next();
+                    invalidateItem(new PropertyId(nState.getUUID(), propName), false);
                 }
                 iter = nState.getChildNodeEntries().iterator();
                 while (iter.hasNext()) {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java Mon Jun 27 08:08:35 2005
@@ -211,7 +211,7 @@
 
             // handle some default prop states
             if (parent instanceof VirtualNodeState) {
-                return parent.hasPropertyEntry(id.getName());
+                return parent.hasPropertyName(id.getName());
             }
         } catch (ItemStateException e) {
             // ignore

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java Mon Jun 27 08:08:35 2005
@@ -177,7 +177,7 @@
         if (prop == null) {
             prop = stateMgr.createPropertyState(this, name, type, multiValued);
             properties.put(name, prop);
-            addPropertyEntry(name);
+            addPropertyName(name);
         }
         return prop;
     }
@@ -198,49 +198,6 @@
             }
             setMixinTypeNames(set);
             setPropertyValues(JCR_MIXINTYPES, PropertyType.NAME, values);
-        }
-    }
-
-    /**
-     * Creates a new VirtualChildNodeEntry
-     *
-     * @param nodeName
-     * @param uuid
-     * @param index
-     * @return
-     */
-    protected VirtualChildNodeEntry createChildNodeEntry(QName nodeName, String uuid, int index) {
-        return new VirtualChildNodeEntry(nodeName, uuid, index);
-    }
-
-    /**
-     * Creates a new VirtualPropertyEntry
-     *
-     * @param name
-     * @return
-     */
-    protected VirtualPropertyEntry createPropertyEntry(QName name) {
-        return new VirtualPropertyEntry(name);
-    }
-
-    /**
-     * Overload NodeState.ChildNodeEntry in order to create own ones.
-     */
-    public class VirtualChildNodeEntry extends NodeState.ChildNodeEntry {
-
-        protected VirtualChildNodeEntry(QName nodeName, String uuid, int index) {
-            super(nodeName, uuid, index);
-        }
-
-    }
-
-    /**
-     * Overload NodeState.PropertyEntry in order to create own ones.
-     */
-    public class VirtualPropertyEntry extends NodeState.PropertyEntry {
-
-        protected VirtualPropertyEntry(QName propName) {
-            super(propName);
         }
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?rev=201999&r1=201998&r2=201999&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Mon Jun 27 08:08:35 2005
@@ -274,7 +274,7 @@
             VersionHistory hist = session.getVersionManager().createVersionHistory(session, node);
 
             // jcr:versionHistory
-            if (!node.hasPropertyEntry(JCR_VERSIONHISTORY)) {
+            if (!node.hasPropertyName(JCR_VERSIONHISTORY)) {
                 def = itemOps.findApplicablePropertyDefinition(JCR_VERSIONHISTORY,
                         PropertyType.REFERENCE, false, node);
                 prop = itemOps.createPropertyState(node, JCR_VERSIONHISTORY,
@@ -283,7 +283,7 @@
             }
 
             // jcr:baseVersion
-            if (!node.hasPropertyEntry(JCR_BASEVERSION)) {
+            if (!node.hasPropertyName(JCR_BASEVERSION)) {
                 def = itemOps.findApplicablePropertyDefinition(JCR_BASEVERSION,
                         PropertyType.REFERENCE, false, node);
                 prop = itemOps.createPropertyState(node, JCR_BASEVERSION,
@@ -292,7 +292,7 @@
             }
 
             // jcr:predecessors
-            if (!node.hasPropertyEntry(JCR_PREDECESSORS)) {
+            if (!node.hasPropertyName(JCR_PREDECESSORS)) {
                 def = itemOps.findApplicablePropertyDefinition(JCR_PREDECESSORS,
                         PropertyType.REFERENCE, true, node);
                 prop = itemOps.createPropertyState(node, JCR_PREDECESSORS,
@@ -301,7 +301,7 @@
             }
 
             // jcr:isCheckedOut
-            if (!node.hasPropertyEntry(JCR_ISCHECKEDOUT)) {
+            if (!node.hasPropertyName(JCR_ISCHECKEDOUT)) {
                 def = itemOps.findApplicablePropertyDefinition(JCR_ISCHECKEDOUT,
                         PropertyType.BOOLEAN, false, node);
                 prop = itemOps.createPropertyState(node, JCR_ISCHECKEDOUT,
@@ -408,7 +408,7 @@
                         return;
                     }
 
-                    if (parent.hasPropertyEntry(nodeName)) {
+                    if (parent.hasPropertyName(nodeName)) {
                         /**
                          * a property with the same name already exists; if this property
                          * has been imported as well (e.g. through document view import
@@ -424,14 +424,14 @@
                             // rename conflicting property
                             // @todo use better reversible escaping scheme to create unique name
                             QName newName = new QName(nodeName.getNamespaceURI(), nodeName.getLocalName() + "_");
-                            if (parent.hasPropertyEntry(newName)) {
+                            if (parent.hasPropertyName(newName)) {
                                 newName = new QName(newName.getNamespaceURI(), newName.getLocalName() + "_");
                             }
                             PropertyState newProp =
                                     itemOps.createPropertyState(parent, newName,
                                             conflicting.getType(), conflicting.getValues().length);
                             newProp.setValues(conflicting.getValues());
-                            parent.removePropertyEntry(nodeName);
+                            parent.removePropertyName(nodeName);
                             itemOps.store(parent);
                             itemOps.destroy(conflicting);
                         }
@@ -494,7 +494,7 @@
                 PropertyState prop = null;
                 PropDef def = null;
 
-                if (node.hasPropertyEntry(propName)) {
+                if (node.hasPropertyName(propName)) {
                     // a property with that name already exists...
                     PropertyId idExisting = new PropertyId(node.getUUID(), propName);
                     PropertyState existing =



Mime
View raw message