You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2007/05/29 17:51:31 UTC

svn commit: r542571 [2/2] - in /jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi: ./ hierarchy/ nodetype/ operation/ state/ version/ xml/

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java Tue May 29 08:51:30 2007
@@ -22,7 +22,6 @@
 import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.Event;
 import org.apache.jackrabbit.spi.ItemId;
-import org.apache.jackrabbit.spi.ChildInfo;
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.IdFactory;
@@ -70,7 +69,7 @@
     private String uniqueID;
 
     /**
-     * insertion-ordered collection of NodeEntry objects
+     * Insertion-ordered collection of NodeEntry objects.
      */
     private ChildNodeEntries childNodeEntries;
 
@@ -81,16 +80,17 @@
     private ChildNodeAttic childNodeAttic;
 
     /**
-     * Map of properties. Key = {@link QName} of property. Value = {@link
-     * PropertyEntry}.
+     * Map of properties.<br>
+     * Key = {@link QName} of property,<br>
+     * Value = {@link PropertyEntry}.
      */
-    private final HashMap properties = new HashMap();
+    private final ChildPropertyEntries properties;
 
     /**
      * Map of properties which are deleted and have been re-created as transient
      * property with the same name.
      */
-    private final HashMap propertiesInAttic = new HashMap();
+    private final Map propertiesInAttic;
 
     /**
      * Upon transient 'move' ('rename') or 'reorder' of SNSs this
@@ -112,10 +112,14 @@
      * @param name      the name of the child node.
      * @param factory   the entry factory.
      */
-    NodeEntryImpl(NodeEntryImpl parent, QName name, String uniqueID, EntryFactory factory) {
+    private NodeEntryImpl(NodeEntryImpl parent, QName name, String uniqueID, EntryFactory factory) {
         super(parent, name, factory);
         this.uniqueID = uniqueID; // NOTE: don't use setUniqueID (for mod only)
-        this.childNodeAttic = new ChildNodeAttic();
+
+        properties = new ChildPropertyEntriesImpl(this, factory);
+
+        propertiesInAttic = new HashMap();
+        childNodeAttic = new ChildNodeAttic();
 
         factory.notifyEntryCreated(this);
     }
@@ -128,6 +132,18 @@
         return new NodeEntryImpl(null, QName.ROOT, null, factory);
     }
 
+    /**
+     *
+     * @param parent
+     * @param name
+     * @param uniqueId
+     * @param factory
+     * @return
+     */
+    static NodeEntry createNodeEntry(NodeEntryImpl parent, QName name, String uniqueId, EntryFactory factory) {
+        return new NodeEntryImpl(parent, name, uniqueId, factory);
+    }
+
     //-----------------------------------------------------< HierarchyEntry >---
     /**
      * Returns true.
@@ -147,7 +163,7 @@
         if (recursive) {
             // invalidate all child entries including properties present in the
             // attic (removed props shadowed by a new property with the same name).
-            for (Iterator it = getAllChildEntries(false, true); it.hasNext();) {
+            for (Iterator it = getAllChildEntries(true); it.hasNext();) {
                 HierarchyEntry ce = (HierarchyEntry) it.next();
                 ce.invalidate(recursive);
             }
@@ -175,7 +191,7 @@
         // did not cause this entry to be removed -> therefore check status.
         if (recursive && !Status.isTerminal(getStatus())) {
             // recursivly reload all entries including props that are in the attic.
-            for (Iterator it = getAllChildEntries(true, true); it.hasNext();) {
+            for (Iterator it = getAllChildEntries(true); it.hasNext();) {
                 HierarchyEntry ce = (HierarchyEntry) it.next();
                 ce.reload(keepChanges, recursive);
             }
@@ -194,7 +210,7 @@
     public void revert() throws RepositoryException {
         // move all properties from attic back to properties map
         if (!propertiesInAttic.isEmpty()) {
-            properties.putAll(propertiesInAttic);
+            properties.addAll(propertiesInAttic.values());
             propertiesInAttic.clear();
         }
 
@@ -208,14 +224,14 @@
      * @see HierarchyEntry#transientRemove()
      */
     public void transientRemove() throws RepositoryException {
-        for (Iterator it = getAllChildEntries(true, false); it.hasNext();) {
+        for (Iterator it = getAllChildEntries(false); it.hasNext();) {
             HierarchyEntry ce = (HierarchyEntry) it.next();
             ce.transientRemove();
         }
 
         if (!propertiesInAttic.isEmpty()) {
             // move all properties from attic back to properties map
-            properties.putAll(propertiesInAttic);
+            properties.addAll(propertiesInAttic.values());
             propertiesInAttic.clear();
         }
 
@@ -240,7 +256,7 @@
         // now traverse all child-entries and mark the attached states removed
         // without removing the child-entries themselves. this is not required
         // since this (i.e. the parent is removed as well).
-        for (Iterator it = getAllChildEntries(true, true); it.hasNext();) {
+        for (Iterator it = getAllChildEntries(true); it.hasNext();) {
             HierarchyEntryImpl ce = (HierarchyEntryImpl) it.next();
             removeEntry(ce);
         }
@@ -259,7 +275,7 @@
         super.collectStates(changeLog, throwOnStale);
 
         // collect transient child states including properties in attic.
-        for (Iterator it = getAllChildEntries(true, true); it.hasNext();) {
+        for (Iterator it = getAllChildEntries(true); it.hasNext();) {
             HierarchyEntry ce = (HierarchyEntry) it.next();
             ce.collectStates(changeLog, throwOnStale);
         }
@@ -363,31 +379,27 @@
             if (elem.denotesRoot()) {
                 if (getParent() != null) {
                     throw new RepositoryException("NodeEntry out of 'hierarchy'" + path.toString());
-                } else {
-                    continue;
                 }
+                continue;
             }
 
             int index = elem.getNormalizedIndex();
             QName name = elem.getName();
 
-            // first try to resolve to nodeEntry or property entry
-            NodeEntry cne = (entry.childNodeEntries == null) ? null : entry.childNodeEntries.get(name, index);
+            // first try to resolve to known node or property entry
+            NodeEntry cne = (entry.childNodeEntries == null) ? null : entry.getNodeEntry(name, index, false);
             if (cne != null) {
                 entry = (NodeEntryImpl) cne;
-            } else if (index == Path.INDEX_DEFAULT && entry.properties.containsKey(name)
-                && i == path.getLength() - 1) {
+            } else if (index == Path.INDEX_DEFAULT && i == path.getLength() - 1 && entry.properties.contains(name)) {
                 // property must not have index && must be final path element
-                return (PropertyEntry) entry.properties.get(name);
+                return entry.properties.get(name);
             } else {
                 // no valid entry
                 // -> check for moved child entry in node-attic
-                // -> check if child points to a removed sns
-                if (entry.childNodeAttic.contains(name, index)) {
-                    throw new PathNotFoundException(path.toString());
-                } else if (entry.childNodeEntries != null) {
-                    int noSNS = entry.childNodeEntries.get(name).size() + entry.childNodeAttic.get(name).size();
-                    if (index <= noSNS) {
+                // -> check if child points to a removed/moved sns
+                if (entry.childNodeEntries != null) {
+                    List siblings = entry.childNodeEntries.get(name);
+                    if (entry.containsAtticChild(siblings, name, index)) {
                         throw new PathNotFoundException(path.toString());
                     }
                 }
@@ -414,23 +426,24 @@
                     throw new RepositoryException("Invalid path");
                 }
 
-                NodeId anyId = entry.getId();
+                NodeId parentId = entry.getId();
                 IdFactory idFactory = entry.factory.getIdFactory();
-                NodeId nodeId = idFactory.createNodeId(anyId, remainingPath);
-                try {
-                    NodeState state = entry.factory.getItemStateFactory().createDeepNodeState(nodeId, entry);
-                    return state.getHierarchyEntry();
-                } catch (ItemNotFoundException e) {
+
+                NodeId nodeId = idFactory.createNodeId(parentId, remainingPath);
+                NodeEntry ne = entry.loadNodeEntry(nodeId);
+                if (ne != null) {
+                    return ne;
+                } else {
                     if (index != Path.INDEX_DEFAULT) {
-                        throw new PathNotFoundException(path.toString(), e);
+                        throw new PathNotFoundException(path.toString());
                     }
-                    // possibly  propstate
-                    try {
-                        nodeId = (remainingPath.getLength() == 1) ? anyId : idFactory.createNodeId(anyId, remainingPath.getAncestor(1));
-                        PropertyId id = idFactory.createPropertyId(nodeId, remainingPath.getNameElement().getName());
-                        PropertyState state = entry.factory.getItemStateFactory().createDeepPropertyState(id, entry);
-                        return state.getHierarchyEntry();
-                    } catch (ItemNotFoundException ise) {
+                    // maybe a property entry exists
+                    parentId = (remainingPath.getLength() == 1) ? parentId : idFactory.createNodeId(parentId, remainingPath.getAncestor(1));
+                    PropertyId propId = idFactory.createPropertyId(parentId, remainingPath.getNameElement().getName());
+                    PropertyEntry pe = entry.loadPropertyEntry(propId);
+                    if (pe != null) {
+                        return pe;
+                    } else {
                         throw new PathNotFoundException(path.toString());
                     }
                 }
@@ -451,16 +464,15 @@
                 if (getParent() != null) {
                     log.warn("NodeEntry out of 'hierarchy'" + workspacePath.toString());
                     return null;
-                } else {
-                    continue;
                 }
+                continue;
             }
 
             int index = elem.getNormalizedIndex();
             QName childName = elem.getName();
 
             // first try to resolve node
-            NodeEntry cne = entry.lookupNodeEntry(childName, index);
+            NodeEntry cne = entry.lookupNodeEntry(null, childName, index);
             if (cne != null) {
                 entry = (NodeEntryImpl) cne;
             } else if (index == Path.INDEX_DEFAULT && i == workspacePath.getLength() - 1) {
@@ -483,11 +495,7 @@
             if (namedEntries.isEmpty()) {
                 return false;
             } else {
-                // copy list since during validation the childNodeEntries may be
-                // modified if upon NodeEntry.getItemState the entry is removed.
-                List l = new ArrayList(namedEntries.size());
-                l.addAll(namedEntries);
-                return EntryValidation.containsValidNodeEntry(l.iterator());
+                return EntryValidation.containsValidNodeEntry(namedEntries.iterator());
             }
         } catch (RepositoryException e) {
             log.debug("Unable to determine if a child node with name " + nodeName + " exists.");
@@ -501,7 +509,7 @@
      */
     public synchronized boolean hasNodeEntry(QName nodeName, int index) {
         try {
-            return EntryValidation.isValidNodeEntry(childNodeEntries().get(nodeName, index));
+            return getNodeEntry(nodeName, index) != null;
         } catch (RepositoryException e) {
             log.debug("Unable to determine if a child node with name " + nodeName + " exists.");
             return false;
@@ -513,37 +521,30 @@
      * @see NodeEntry#getNodeEntry(QName, int)
      */
     public synchronized NodeEntry getNodeEntry(QName nodeName, int index) throws RepositoryException {
-        NodeEntry cne = childNodeEntries().get(nodeName, index);
-        if (EntryValidation.isValidNodeEntry(cne)) {
-            return cne;
-        } else {
-            return null;
-        }
+        return getNodeEntry(nodeName, index, false);
     }
 
-
     /**
      * @inheritDoc
-     * @see NodeEntry#getNodeEntry(NodeId)
+     * @see NodeEntry#getNodeEntry(QName, int, boolean)
      */
-    public synchronized NodeEntry getNodeEntry(NodeId childId) throws RepositoryException {
-        String uid = childId.getUniqueID();
-        Path path = childId.getPath();
-        NodeEntry cne;
-        if (uid != null && path == null) {
-            // retrieve child-entry by uid
-            cne = childNodeEntries().get(null, uid);
-        } else {
-           // retrieve child-entry by name and index
-            Path.PathElement nameElement = path.getNameElement();
-            cne = childNodeEntries().get(nameElement.getName(), nameElement.getIndex());
-        }
-
-        if (EntryValidation.isValidNodeEntry(cne)) {
-            return cne;
-        } else {
-            return null;
+    public NodeEntry getNodeEntry(QName nodeName, int index, boolean loadIfNotFound) throws RepositoryException {
+        List entries = childNodeEntries().get(nodeName);
+        NodeEntry cne = null;
+        if (entries.size() >= index) {
+            // position of entry might differ from index-1 if a SNS with lower
+            // index has been transiently removed.
+            for (int i = index-1; i < entries.size() && cne == null; i++) {
+                NodeEntry ne = (NodeEntry) entries.get(i);
+                if (EntryValidation.isValidNodeEntry(ne)) {
+                    cne = ne;
+                }
+            }
+        } else if (loadIfNotFound && !containsAtticChild(entries, nodeName, index)) {
+            NodeId cId = factory.getIdFactory().createNodeId(getId(), Path.create(nodeName, index));
+            cne = loadNodeEntry(cId);
         }
+        return cne;
     }
 
     /**
@@ -552,11 +553,10 @@
      */
     public synchronized Iterator getNodeEntries() throws RepositoryException {
         Collection entries = new ArrayList();
-        Object[] arr = childNodeEntries().toArray();
-        for (int i = 0; i < arr.length; i++) {
-            NodeEntry cne = (NodeEntry) arr[i];
-            if (EntryValidation.isValidNodeEntry(cne)) {
-                entries.add(cne);
+        for (Iterator it = childNodeEntries().iterator(); it.hasNext();) {
+            NodeEntry entry = (NodeEntry) it.next();
+            if (EntryValidation.isValidNodeEntry(entry)) {
+                entries.add(entry);
             }
         }
         return Collections.unmodifiableCollection(entries).iterator();
@@ -598,9 +598,9 @@
      */
     public NodeState addNewNodeEntry(QName nodeName, String uniqueID,
                                      QName primaryNodeType, QNodeDefinition definition) throws RepositoryException {
-        NodeEntryImpl entry = internalAddNodeEntry(nodeName, uniqueID, Path.INDEX_UNDEFINED, childNodeEntries());
+        NodeEntry entry = internalAddNodeEntry(nodeName, uniqueID, Path.INDEX_UNDEFINED, childNodeEntries());
         NodeState state = factory.getItemStateFactory().createNewNodeState(entry, primaryNodeType, definition);
-        entry.internalSetItemState(state);
+        ((NodeEntryImpl) entry).internalSetItemState(state);
         return state;
     }
 
@@ -612,9 +612,9 @@
      * @param childEntries
      * @return
      */
-    private NodeEntryImpl internalAddNodeEntry(QName nodeName, String uniqueID,
+    private NodeEntry internalAddNodeEntry(QName nodeName, String uniqueID,
                                                int index, ChildNodeEntries childEntries) {
-        NodeEntryImpl entry = new NodeEntryImpl(this, nodeName, uniqueID, factory);
+        NodeEntry entry = factory.createNodeEntry(this, nodeName, uniqueID);
         childEntries.add(entry, index);
         return entry;
     }
@@ -624,7 +624,7 @@
      * @see NodeEntry#hasPropertyEntry(QName)
      */
     public synchronized boolean hasPropertyEntry(QName propName) {
-        PropertyEntry entry = (PropertyEntry) properties.get(propName);
+        PropertyEntry entry = properties.get(propName);
         return EntryValidation.isValidPropertyEntry(entry);
     }
 
@@ -633,7 +633,7 @@
      * @see NodeEntry#getPropertyEntry(QName)
      */
     public synchronized PropertyEntry getPropertyEntry(QName propName) {
-        PropertyEntry entry = (PropertyEntry) properties.get(propName);
+        PropertyEntry entry = properties.get(propName);
         if (EntryValidation.isValidPropertyEntry(entry)) {
             return entry;
         } else {
@@ -643,6 +643,21 @@
 
     /**
      * @inheritDoc
+     * @see NodeEntry#getPropertyEntry(QName, boolean)
+     */
+    public PropertyEntry getPropertyEntry(QName propName, boolean loadIfNotFound) throws RepositoryException {
+        PropertyEntry entry = properties.get(propName);
+        if (entry == null && loadIfNotFound) {
+            PropertyId propId = factory.getIdFactory().createPropertyId(getId(), propName);
+            entry = loadPropertyEntry(propId);
+        } else if (!EntryValidation.isValidPropertyEntry(entry)) {
+            entry = null;
+        }
+        return entry;
+    }
+
+    /**
+     * @inheritDoc
      * @see NodeEntry#getPropertyEntries()
      */
     public synchronized Iterator getPropertyEntries() {
@@ -651,7 +666,7 @@
             // filter out removed properties
             props = new ArrayList();
             // use array since upon validation the entry might be removed.
-            Object[] arr = properties.values().toArray();
+            Object[] arr = properties.getPropertyEntries().toArray();
             for (int i = 0; i < arr.length; i++) {
                 PropertyEntry propEntry = (PropertyEntry) arr[i];
                 if (EntryValidation.isValidPropertyEntry(propEntry)) {
@@ -660,7 +675,7 @@
             }
         } else {
             // no need to filter out properties, there are no removed properties
-            props = properties.values();
+            props = properties.getPropertyEntries();
         }
         return Collections.unmodifiableCollection(props).iterator();
     }
@@ -682,8 +697,8 @@
      * @return
      */
     private PropertyEntry internalAddPropertyEntry(QName propName) {
-        PropertyEntry entry = PropertyEntryImpl.create(this, propName, factory);
-        properties.put(propName, entry);
+        PropertyEntry entry = factory.createPropertyEntry(this, propName);
+        properties.add(entry);
 
         // if property-name is jcr:uuid or jcr:mixin this affects this entry
         // and the attached nodeState.
@@ -699,13 +714,13 @@
      */
     public void addPropertyEntries(Collection propNames) throws ItemExistsException, RepositoryException {
         Set diff = new HashSet();
-        diff.addAll(properties.keySet());
+        diff.addAll(properties.getPropertyNames());
         boolean containsExtra = diff.removeAll(propNames);
 
         // add all entries that are missing
         for (Iterator it = propNames.iterator(); it.hasNext();) {
             QName propName = (QName) it.next();
-            if (!properties.containsKey(propName)) {
+            if (!properties.contains(propName)) {
                 addPropertyEntry(propName);
             }
         }
@@ -717,7 +732,7 @@
         if (containsExtra && (state == null || state.getStatus() == Status.INVALIDATED)) {
             for (Iterator it = diff.iterator(); it.hasNext();) {
                 QName propName = (QName) it.next();
-                PropertyEntry pEntry = (PropertyEntry) properties.get(propName);
+                PropertyEntry pEntry = properties.get(propName);
                 if (pEntry != null) {
                     pEntry.remove();
                 }
@@ -732,7 +747,7 @@
     public PropertyState addNewPropertyEntry(QName propName, QPropertyDefinition definition)
             throws ItemExistsException, RepositoryException {
         // check for an existing property
-        PropertyEntry existing = (PropertyEntry) properties.get(propName);
+        PropertyEntry existing = properties.get(propName);
         if (existing != null) {
             try {
                 PropertyState existingState = existing.getPropertyState();
@@ -759,8 +774,8 @@
         }
 
         // add the property entry
-        PropertyEntry entry = PropertyEntryImpl.create(this, propName, factory);
-        properties.put(propName, entry);
+        PropertyEntry entry = factory.createPropertyEntry(this, propName);
+        properties.add(entry);
 
         PropertyState state = factory.getItemStateFactory().createNewPropertyState(entry, definition);
         ((PropertyEntryImpl) entry).internalSetItemState(state);
@@ -771,16 +786,14 @@
     /**
      * @param propName
      */
-    PropertyEntry internalRemovePropertyEntry(QName propName) {
-        PropertyEntry cpe = (PropertyEntry) properties.remove(propName);
-        if (cpe == null) {
-            cpe = (PropertyEntry) propertiesInAttic.remove(propName);
+    void internalRemovePropertyEntry(QName propName) {
+        if (!properties.remove(propName)) {
+            propertiesInAttic.remove(propName);
         }
         // special properties
         if (StateUtility.isUuidOrMixin(propName)) {
             notifyUUIDorMIXINRemoved(propName);
         }
-        return cpe;
     }
 
     /**
@@ -847,28 +860,36 @@
         QName eventName = childEvent.getQPath().getNameElement().getName();
         switch (childEvent.getType()) {
             case Event.NODE_ADDED:
+                if (childNodeEntries == null) {
+                    // childNodeEntries not yet loaded -> ignore
+                    return;
+                }
+
                 int index = childEvent.getQPath().getNameElement().getNormalizedIndex();
                 String uniqueChildID = null;
                 if (childEvent.getItemId().getPath() == null) {
                     uniqueChildID = childEvent.getItemId().getUniqueID();
                 }
-                // first check if no matching child entry exists.
+
                 // TODO: TOBEFIXED for SNSs
-                if (childNodeEntries != null) {
-                    NodeEntry cne;
-                    if (uniqueChildID != null) {
-                        cne = childNodeEntries.get(eventName, uniqueChildID);
-                    } else {
-                        cne = childNodeEntries.get(eventName, index);
-                    }
+                // first check if no matching child entry exists.
+                NodeEntry cne;
+                if (uniqueChildID != null) {
+                    cne = childNodeEntries.get(eventName, uniqueChildID);
                     if (cne == null) {
-                        internalAddNodeEntry(eventName, uniqueChildID, index, childNodeEntries);
-                    } else {
-                        // child already exists -> deal with NEW entries, that were
-                        // added by some other session.
-                        // TODO: TOBEFIXED
+                        // entry may exist but without having uniqueID resolved
+                        cne = childNodeEntries.get(eventName, index);
                     }
-                } // else: childNodeEntries not yet loaded -> ignore
+                } else {
+                    cne = childNodeEntries.get(eventName, index);
+                }
+                if (cne == null) {
+                    internalAddNodeEntry(eventName, uniqueChildID, index, childNodeEntries);
+                } else {
+                    // child already exists -> deal with NEW entries, that were
+                    // added by some other session.
+                    // TODO: TOBEFIXED
+                }
                 break;
 
             case Event.PROPERTY_ADDED:
@@ -967,7 +988,7 @@
             throw new RepositoryException("Invalid index " + index + " with nodeEntry " + nEntry);
         }
 
-        // TODO: check again. special treatment for index 0 for consistency with PathFormat.parse
+        // TODO: check again. special treatment for default index for consistency with PathFormat.parse
         if (index == Path.INDEX_DEFAULT) {
             builder.addLast(name);
         } else {
@@ -986,7 +1007,7 @@
         }
         QName propName = propertyEntry.getQName();
         if (propertiesInAttic.containsKey(propName)) {
-            properties.put(propName, propertiesInAttic.remove(propName));
+            properties.add((PropertyEntry) propertiesInAttic.remove(propName));
         } // else: propEntry has never been moved to the attic (see 'addPropertyEntry')
     }
 
@@ -1027,6 +1048,36 @@
     }
 
     /**
+     *
+     * @param childId
+     * @return
+     */
+    private NodeEntry loadNodeEntry(NodeId childId) throws RepositoryException {
+        try {
+            NodeState state = factory.getItemStateFactory().createDeepNodeState(childId, this);
+            return state.getNodeEntry();
+        } catch (ItemNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     *
+     * @param childId
+     * @return
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    private PropertyEntry loadPropertyEntry(PropertyId childId) throws RepositoryException {
+        try {
+            PropertyState state = factory.getItemStateFactory().createDeepPropertyState(childId, this);
+            return (PropertyEntry) state.getHierarchyEntry();
+        } catch (ItemNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
      * Searches the child-entries of this NodeEntry for a matching child.
      * Since {@link #refresh(Event)} must always be called on the parent
      * NodeEntry, there is no need to check if a given event id would point
@@ -1038,44 +1089,37 @@
      */
     private HierarchyEntry lookupEntry(ItemId eventId, Path eventPath) {
         QName childName = eventPath.getNameElement().getName();
-        HierarchyEntry child = null;
+        HierarchyEntry child;
         if (eventId.denotesNode()) {
             String uniqueChildID = (eventId.getPath() == null) ? eventId.getUniqueID() : null;
-            // for external node-removal the attic must be consulted first
-            // in order to be able to apply the changes to the proper node-entry.
-            if (uniqueChildID != null) {
-                child = childNodeAttic.get(uniqueChildID);
-                if (child == null && childNodeEntries != null) {
-                    child = childNodeEntries.get(childName, uniqueChildID);
-                }
-            }
-            if (child == null) {
-                int index = eventPath.getNameElement().getNormalizedIndex();
-                child = lookupNodeEntry(childName, index);
-            }
+            int index = eventPath.getNameElement().getNormalizedIndex();
+            child = lookupNodeEntry(uniqueChildID, childName, index);
         } else {
             child = lookupPropertyEntry(childName);
         }
-        if (child != null) {
-            // a NEW hierarchyEntry may never be affected by an external
-            // modification -> return null.
-            ItemState state = ((HierarchyEntryImpl) child).internalGetItemState();
-            if (state != null && state.getStatus() == Status.NEW) {
-                return null;
-            }
-        }
-        return child;
+        // a NEW hierarchyEntry may never be affected by an external modification
+        // -> return null.
+        return (child == null || child.getStatus() == Status.NEW) ? null : child;
     }
 
-    private NodeEntryImpl lookupNodeEntry(QName childName, int index) {
-        NodeEntryImpl child = (NodeEntryImpl) childNodeAttic.get(childName, index);
-        if (child == null && childNodeEntries != null) {
-            List namedChildren = childNodeEntries.get(childName);
-            for (Iterator it = namedChildren.iterator(); it.hasNext(); ) {
-                NodeEntryImpl c = (NodeEntryImpl) it.next();
-                if (c.matches(childName, index)) {
-                    child = c;
-                    break;
+    private NodeEntry lookupNodeEntry(String uniqueChildId, QName childName, int index) {
+        NodeEntry child = null;
+        if (uniqueChildId != null) {
+            child = childNodeAttic.get(uniqueChildId);
+            if (child == null && childNodeEntries != null) {
+                child = childNodeEntries.get(childName, uniqueChildId);
+            }
+        }
+        if (child == null) {
+            child = childNodeAttic.get(childName, index);
+            if (child == null && childNodeEntries != null) {
+                List namedChildren = childNodeEntries.get(childName);
+                for (Iterator it = namedChildren.iterator(); it.hasNext(); ) {
+                    NodeEntryImpl c = (NodeEntryImpl) it.next();
+                    if (c.matches(childName, index)) {
+                        child = c;
+                        break;
+                    }
                 }
             }
         }
@@ -1088,7 +1132,7 @@
         // property with the same name.
         PropertyEntry child = (PropertyEntry) propertiesInAttic.get(childName);
         if (child == null) {
-            child = (PropertyEntry) properties.get(childName);
+            child = properties.get(childName);
         }
         return child;
     }
@@ -1136,17 +1180,17 @@
     }
 
     /**
-     *
-     * @return
+     * @return The <code>ChildNodeEntries</code> defined for this
+     * <code>NodeEntry</code>. Please note, that this method never returns
+     * <code>null</code>, since the child node entries are loaded/reloaded
+     * in case they have not been loaded yet.
      */
     private ChildNodeEntries childNodeEntries() throws InvalidItemStateException, RepositoryException {
         try {
             if (childNodeEntries == null) {
-                childNodeEntries = new ChildNodeEntries(this);
-                loadChildNodeEntries();
+                childNodeEntries = new ChildNodeEntriesImpl(this, factory);
             } else if (childNodeEntries.getStatus() == ChildNodeEntries.STATUS_INVALIDATED) {
-                reloadChildNodeEntries(childNodeEntries);
-                childNodeEntries.setStatus(ChildNodeEntries.STATUS_OK);
+                childNodeEntries.reload();
             }
         } catch (ItemNotFoundException e) {
             log.debug("NodeEntry does not exist (anymore) -> remove.");
@@ -1156,68 +1200,6 @@
         return childNodeEntries;
     }
 
-    private void loadChildNodeEntries() throws ItemNotFoundException, RepositoryException {
-
-        if (getStatus() == Status.NEW || Status.isTerminal(getStatus())) {
-            return; // cannot retrieve child-entries from persistent layer
-        }
-
-        NodeId id = getWorkspaceId();
-        Iterator it = factory.getItemStateFactory().getChildNodeInfos(id);
-        // simply add all child entries to the empty collection
-        while (it.hasNext()) {
-            ChildInfo ci = (ChildInfo) it.next();
-            internalAddNodeEntry(ci.getName(), ci.getUniqueID(), ci.getIndex(), childNodeEntries);
-        }
-    }
-
-    private void reloadChildNodeEntries(ChildNodeEntries cnEntries) throws ItemNotFoundException, RepositoryException {
-        if (getStatus() == Status.NEW || Status.isTerminal(getStatus())) {
-            // nothing to do
-            return;
-        }
-        NodeId id = getWorkspaceId();
-        Iterator it = factory.getItemStateFactory().getChildNodeInfos(id);
-        // create list from all ChildInfos (for multiple loop)
-        List cInfos = new ArrayList();
-        while (it.hasNext()) {
-            cInfos.add((ChildInfo) it.next());
-        }
-        // first make sure the ordering of all existing entries is ok
-        NodeEntry entry = null;
-        for (it = cInfos.iterator(); it.hasNext();) {
-            ChildInfo ci = (ChildInfo) it.next();
-            NodeEntry nextEntry = cnEntries.get(ci);
-            if (nextEntry != null) {
-                if (entry != null) {
-                    cnEntries.reorder(entry, nextEntry);
-                }
-                entry = nextEntry;
-            }
-        }
-        // then insert the 'new' entries
-        List newEntries = new ArrayList();
-        for (it = cInfos.iterator(); it.hasNext();) {
-            ChildInfo ci = (ChildInfo) it.next();
-            NodeEntry beforeEntry = cnEntries.get(ci);
-            if (beforeEntry == null) {
-                NodeEntry ne = new NodeEntryImpl(this, ci.getName(), ci.getUniqueID(), factory);
-                newEntries.add(ne);
-            } else {
-                // insert all new entries from the list BEFORE the existing
-                // 'nextEntry'. Then clear the list.
-                for (int i = 0; i < newEntries.size(); i++) {
-                    cnEntries.add((NodeEntry) newEntries.get(i), beforeEntry);
-                }
-                newEntries.clear();
-            }
-        }
-        // deal with new entries at the end
-        for (int i = 0; i < newEntries.size(); i++) {
-            cnEntries.add((NodeEntry) newEntries.get(i));
-        }
-    }
-
     /**
      * Returns an Iterator over all children entries, that currently are loaded
      * with this NodeEntry. NOTE, that if the childNodeEntries have not been
@@ -1229,26 +1211,23 @@
      * @param includeAttic
      * @return
      */
-    private Iterator getAllChildEntries(boolean createNewList, boolean includeAttic) {
-        Iterator[] its;
-        if (createNewList) {
-            List props = new ArrayList(properties.values());
-            List children = (childNodeEntries == null) ? Collections.EMPTY_LIST : new ArrayList(childNodeEntries);
-            if (includeAttic) {
-                List attic = new ArrayList(propertiesInAttic.values());
-                its = new Iterator[] {attic.iterator(), props.iterator(), children.iterator()};
-            } else {
-                its = new Iterator[] {props.iterator(), children.iterator()};
-            }
-        } else {
-            Iterator children = (childNodeEntries == null) ? Collections.EMPTY_LIST.iterator() : childNodeEntries.iterator();
-            if (includeAttic) {
-                its = new Iterator[] {propertiesInAttic.values().iterator(), properties.values().iterator(), children};
-            } else {
-                its = new Iterator[] {properties.values().iterator(), children};
-            }
+    private Iterator getAllChildEntries(boolean includeAttic) {
+        IteratorChain chain = new IteratorChain();
+        // attic
+        if (includeAttic) {
+            Collection attic = propertiesInAttic.values();
+            chain.addIterator(new ArrayList(attic).iterator());
+        }
+        // add props
+        synchronized (properties) {
+            Collection props = properties.getPropertyEntries();
+            chain.addIterator(props.iterator());
+        }
+        // add childNodeEntries
+        if (childNodeEntries != null) {
+            chain.addIterator(childNodeEntries.iterator());
         }
-        return new IteratorChain(its);
+        return chain;
     }
 
     /**
@@ -1278,6 +1257,33 @@
         throw new ItemNotFoundException("No valid child entry for NodeEntry " + cne);
     }
 
+    /**
+     * Returns true if the attic contains a matching child entry or if any of
+     * the remaining child entries present in the siblings list has been modified
+     * in a way that its original index is equal to the given child index.
+     *
+     * @param siblings
+     * @param childName
+     * @param childIndex
+     * @return
+     */
+    private boolean containsAtticChild(List siblings, QName childName, int childIndex) {
+        // check if a matching entry exists in the attic
+        if (childNodeAttic.contains(childName, childIndex)) {
+            return true;
+        }
+        // in case of reordered/moved SNSs we also have to look for a child
+        // entry, which hold the given index before
+        if (getStatus() == Status.EXISTING_MODIFIED) {
+            for (Iterator it = siblings.iterator(); it.hasNext();) {
+                NodeEntryImpl child = (NodeEntryImpl) it.next();
+                if (!EntryValidation.isValidNodeEntry(child) || (child.revertInfo != null && child.revertInfo.oldIndex == childIndex)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
     /**
      * If 'revertInfo' is null it gets created from the current information
      * present on this entry.

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java Tue May 29 08:51:30 2007
@@ -20,7 +20,7 @@
 import org.apache.jackrabbit.jcr2spi.util.Dumpable;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.jcr2spi.state.Status;
-import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
@@ -334,18 +334,16 @@
                 // TODO: check if correct (and only used for creating new)
                 QName primaryType = nodeState.getNodeTypeName();
                 allNtNames = new QName[] { primaryType }; // default
-                PropertyEntry mixins = nodeState.getNodeEntry().getPropertyEntry(QName.JCR_MIXINTYPES);
-                if (mixins != null) {
-                    try {
-                        QValue[] values = mixins.getPropertyState().getValues();
-                        allNtNames = new QName[values.length + 1];
-                        for (int i = 0; i < values.length; i++) {
-                            allNtNames[i] = values[i].getQName();
-                        }
-                        allNtNames[values.length] = primaryType;
-                    } catch (RepositoryException e) {
-                        // ignore
+                try {
+                    PropertyState mixins = nodeState.getPropertyState(QName.JCR_MIXINTYPES);
+                    QValue[] values = mixins.getValues();
+                    allNtNames = new QName[values.length + 1];
+                    for (int i = 0; i < values.length; i++) {
+                        allNtNames[i] = values[i].getQName();
                     }
+                    allNtNames[values.length] = primaryType;
+                } catch (RepositoryException e) {
+                    // ignore: apparently no jcr:mixinTypes property exists.
                 }
             }
             return getEffectiveNodeType(allNtNames);
@@ -390,7 +388,7 @@
                 return ent;
             } catch (NodeTypeConflictException ntce) {
                 // should never get here as all known node types should be valid!
-                String msg = "internal error: encountered invalid registered node type " + ntName;
+                String msg = "Internal error: encountered invalid registered node type " + ntName;
                 log.debug(msg);
                 throw new NoSuchNodeTypeException(msg, ntce);
             }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java Tue May 29 08:51:30 2007
@@ -79,7 +79,9 @@
         try {
             NodeEntry vhEntry = (NodeEntry) versionHistoryState.getHierarchyEntry();
             NodeEntry lnEntry = vhEntry.getNodeEntry(QName.JCR_VERSIONLABELS, Path.INDEX_DEFAULT);
-            lnEntry.invalidate(moveLabel);
+            if (lnEntry != null) {
+                lnEntry.invalidate(moveLabel);
+            }
         } catch (RepositoryException e) {
             log.debug(e.getMessage());
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java Tue May 29 08:51:30 2007
@@ -166,12 +166,14 @@
             throw new ItemExistsException("Move destination already exists (Property).");
         } else if (destEntry.hasNodeEntry(destName)) {
             NodeEntry existing = destEntry.getNodeEntry(destName, Path.INDEX_DEFAULT);
-            try {
-                if (!existing.getNodeState().getDefinition().allowsSameNameSiblings()) {
-                    throw new ItemExistsException("Node existing at move destination does not allow same name siblings.");
+            if (existing != null) {
+                try {
+                    if (!existing.getNodeState().getDefinition().allowsSameNameSiblings()) {
+                        throw new ItemExistsException("Node existing at move destination does not allow same name siblings.");
+                    }
+                } catch (ItemNotFoundException e) {
+                    // existing apparent not valid any more -> probably no conflict
                 }
-            } catch (ItemNotFoundException e) {
-                // existing apparent not valid any more -> probably no conflict
             }
         }
 

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java Tue May 29 08:51:30 2007
@@ -76,7 +76,9 @@
         try {
             NodeEntry vhEntry = (NodeEntry) versionHistoryState.getHierarchyEntry();
             NodeEntry lnEntry = vhEntry.getNodeEntry(QName.JCR_VERSIONLABELS, Path.INDEX_DEFAULT);
-            lnEntry.invalidate(true);
+            if (lnEntry != null) {
+                lnEntry.invalidate(true);
+            }
         } catch (RepositoryException e) {
             log.debug(e.getMessage());
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java Tue May 29 08:51:30 2007
@@ -18,8 +18,6 @@
 
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
-import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.spi.NodeId;
 
 import javax.jcr.RepositoryException;
@@ -46,13 +44,10 @@
         addAffectedItemState(nodeState);
         // add the jcr:mixinTypes property state as affected if it already exists
         // and therefore gets modified by this operation.
-        PropertyEntry pe = ((NodeEntry) nodeState.getHierarchyEntry()).getPropertyEntry(QName.JCR_MIXINTYPES);
-        if (pe != null) {
-            try {
-                addAffectedItemState(pe.getPropertyState());
-            } catch (RepositoryException e) {
-                // should never occur
-            }
+        try {
+            addAffectedItemState(nodeState.getPropertyState(QName.JCR_MIXINTYPES));
+        } catch (RepositoryException e) {
+            // jcr:mixinTypes does not exist -> ignore
         }
     }
 

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java Tue May 29 08:51:30 2007
@@ -58,6 +58,11 @@
     private int status;
 
     /**
+     * The hierarchy entry this state belongs to.
+     */
+    private HierarchyEntry hierarchyEntry;
+
+    /**
      * Listeners (weak references)
      */
     private final transient Collection listeners = new WeakIdentityCollection(5);
@@ -82,7 +87,8 @@
      * @param isWorkspaceState
      */
     protected ItemState(int initialStatus, boolean isWorkspaceState,
-                        ItemStateFactory isf, ItemDefinitionProvider definitionProvider) {
+                        HierarchyEntry entry, ItemStateFactory isf,
+                        ItemDefinitionProvider definitionProvider) {
         switch (initialStatus) {
             case Status.EXISTING:
             case Status.NEW:
@@ -93,11 +99,15 @@
                 log.debug(msg);
                 throw new IllegalArgumentException(msg);
         }
-        overlayedState = null;
-
+        if (entry == null) {
+            throw new IllegalArgumentException("Cannot build ItemState from 'null' HierarchyEntry");
+        }
+        this.hierarchyEntry = entry;
         this.isf = isf;
         this.definitionProvider = definitionProvider;
         this.isWorkspaceState = isWorkspaceState;
+
+        overlayedState = null;
     }
 
     /**
@@ -119,6 +129,10 @@
                 log.debug(msg);
                 throw new IllegalArgumentException(msg);
         }
+        if (overlayedState.getHierarchyEntry() == null) {
+            throw new IllegalArgumentException("Cannot build ItemState from 'null' HierarchyEntry");
+        }
+        this.hierarchyEntry = overlayedState.getHierarchyEntry();
         this.isf = isf;
         this.isWorkspaceState = false;
         this.definitionProvider = overlayedState.definitionProvider;
@@ -131,7 +145,9 @@
      *
      * @return The <code>HierarchyEntry</code> corresponding to this <code>ItemState</code>.
      */
-    public abstract HierarchyEntry getHierarchyEntry();
+    public HierarchyEntry getHierarchyEntry() {
+        return hierarchyEntry;
+    }
 
     /**
      * Returns <code>true</code> if this item state is valid, that is its status

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java Tue May 29 08:51:30 2007
@@ -19,11 +19,9 @@
 import org.apache.commons.collections.iterators.IteratorChain;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
 import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
-import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
 import org.apache.jackrabbit.jcr2spi.util.StateUtility;
 import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
 import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.name.Path;
 import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.ItemId;
 import org.apache.jackrabbit.spi.QNodeDefinition;
@@ -47,8 +45,6 @@
 
     private static Logger log = LoggerFactory.getLogger(NodeState.class);
 
-    private final NodeEntry hierarchyEntry;
-
     /**
      * the name of this node's primary type
      */
@@ -75,8 +71,7 @@
                         QNodeDefinition definition, int initialStatus,
                         boolean isWorkspaceState,
                         ItemStateFactory isf, ItemDefinitionProvider definitionProvider) {
-        super(initialStatus, isWorkspaceState, isf, definitionProvider);
-        this.hierarchyEntry = entry;
+        super(initialStatus, isWorkspaceState, entry, isf, definitionProvider);
         this.nodeTypeName = nodeTypeName;
         setMixinTypeNames(mixinTypeNames);
         this.definition = definition;
@@ -93,7 +88,6 @@
         super(overlayedState, initialStatus, isf);
 
         synchronized (overlayedState) {
-            hierarchyEntry = overlayedState.hierarchyEntry;
             nodeTypeName = overlayedState.nodeTypeName;
             definition = overlayedState.definition;
             if (mixinTypeNames != null) {
@@ -104,13 +98,6 @@
 
     //----------------------------------------------------------< ItemState >---
     /**
-     * @see ItemState#getHierarchyEntry()
-     */
-    public HierarchyEntry getHierarchyEntry() {
-        return hierarchyEntry;
-    }
-
-    /**
      * Determines if this item state represents a node.
      *
      * @return always true
@@ -216,7 +203,7 @@
 
     /**
      * TODO improve
-     * !! Used by NodeEntryImpl and NodeState only
+     * Used by NodeEntryImpl and NodeState only
      *
      * @param mixinTypeNames
      */
@@ -283,7 +270,8 @@
     /**
      * Utility
      * Returns the child <code>NodeState</code> with the specified name
-     * and index or <code>null</code> if there's no matching, valid entry.
+     * and index. Throws <code>ItemNotFoundException</code> if there's no
+     * matching, valid entry.
      *
      * @param nodeName <code>QName</code> object specifying a node name.
      * @param index 1-based index if there are same-name child node entries.
@@ -292,11 +280,11 @@
      * @throws RepositoryException
      */
     public NodeState getChildNodeState(QName nodeName, int index) throws ItemNotFoundException, RepositoryException {
-        NodeEntry child = getNodeEntry().getNodeEntry(nodeName, index);
-        if (child != null) {
-            return child.getNodeState();
+        NodeEntry ne = getNodeEntry().getNodeEntry(nodeName, index, true);
+        if (ne != null) {
+            return ne.getNodeState();
         } else {
-            // TODO: correct?
+            // does not exist (any more) or is a property
             throw new ItemNotFoundException("Child node "+ nodeName +" with index " + index + " does not exist.");
         }
     }
@@ -313,7 +301,9 @@
     }
 
     /**
-     * Utility method that returns the property state with the given name.
+     * Utility method that returns the property state with the given name or
+     * throws an <code>ItemNotFoundException</code> if no matching, valid
+     * property could be found.
      *
      * @param propertyName The name of the property state to return.
      * @throws ItemNotFoundException If there is no (valid) property state
@@ -321,13 +311,13 @@
      * @throws RepositoryException If an error occurs while retrieving the
      * property state.
      *
-     * @see NodeEntry#getPropertyEntry(QName)
+     * @see NodeEntry#getPropertyEntry(QName, boolean)
      * @see PropertyEntry#getPropertyState()
      */
     public PropertyState getPropertyState(QName propertyName) throws ItemNotFoundException, RepositoryException {
-        HierarchyEntry child = getNodeEntry().getDeepEntry(Path.create(propertyName, Path.INDEX_UNDEFINED));
-        if (child != null && !child.denotesNode()) {
-            return ((PropertyEntry) child).getPropertyState();
+        PropertyEntry pe = getNodeEntry().getPropertyEntry(propertyName, true);
+        if (pe != null) {
+            return pe.getPropertyState();
         } else {
             throw new ItemNotFoundException("Child Property with name " + propertyName + " does not exist.");
         }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java Tue May 29 08:51:30 2007
@@ -28,7 +28,6 @@
 import org.apache.jackrabbit.jcr2spi.nodetype.ValueConstraint;
 import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
 import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
-import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,11 +41,6 @@
     private static Logger log = LoggerFactory.getLogger(PropertyState.class);
 
     /**
-     * The PropertyEntry associated with the state
-     */
-    private final PropertyEntry hierarchyEntry;
-
-    /**
      * Property definition
      */
     private QPropertyDefinition definition;
@@ -77,7 +71,6 @@
                             ItemStateFactory isf) {
         super(overlayedState, initialStatus, isf);
 
-        this.hierarchyEntry = overlayedState.hierarchyEntry;
         this.definition = overlayedState.definition;
         this.multiValued = overlayedState.multiValued;
 
@@ -94,9 +87,8 @@
     protected PropertyState(PropertyEntry entry, boolean multiValued, QPropertyDefinition definition,
                             int initialStatus, boolean isWorkspaceState,
                             ItemStateFactory isf, ItemDefinitionProvider definitionProvider) {
-        super(initialStatus, isWorkspaceState, isf, definitionProvider);
+        super(initialStatus, isWorkspaceState, entry, isf, definitionProvider);
 
-        this.hierarchyEntry = entry;
         this.definition = definition;
         this.multiValued = multiValued;
         init(PropertyType.UNDEFINED, QValue.EMPTY_ARRAY);
@@ -126,13 +118,6 @@
 
 
     //----------------------------------------------------------< ItemState >---
-    /**
-     * @see ItemState#getHierarchyEntry()
-     */
-    public HierarchyEntry getHierarchyEntry() {
-        return hierarchyEntry;
-    }
-
     /**
      * Always returns false.
      *

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java Tue May 29 08:51:30 2007
@@ -165,11 +165,9 @@
             }
             // create PropertyEntry for the last element if not existing yet
             QName propName = missingElems[i].getName();
-            PropertyEntry propEntry;
-            if (!entry.hasPropertyEntry(propName)) {
+            PropertyEntry propEntry = entry.getPropertyEntry(propName);
+            if (propEntry == null) {
                 propEntry = entry.addPropertyEntry(propName);
-            } else {
-                propEntry = entry.getPropertyEntry(propName);
             }
             return createPropertyState(info, propEntry);
         } catch (PathNotFoundException e) {
@@ -309,7 +307,7 @@
      * @throws ItemNotFoundException
      * @throws RepositoryException
      */
-    private void assertMatchingPath(ItemInfo info, HierarchyEntry entry)
+    private static void assertMatchingPath(ItemInfo info, HierarchyEntry entry)
             throws ItemNotFoundException, RepositoryException {
         if (!info.getPath().equals(entry.getWorkspacePath())) {
             throw new ItemNotFoundException("HierarchyEntry does not belong the given ItemInfo.");

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java Tue May 29 08:51:30 2007
@@ -64,11 +64,12 @@
         super(itemMgr, session, state, listeners);
         this.vhEntry = (NodeEntry) state.getHierarchyEntry();
 
-        // retrieve nodestate of the jcr:versionLabels node
-        if (vhEntry.hasNodeEntry(QName.JCR_VERSIONLABELS)) {
-            labelNodeEntry = vhEntry.getNodeEntry(QName.JCR_VERSIONLABELS, Path.INDEX_DEFAULT);
-        } else {
-            throw new VersionException("nt:versionHistory requires a mandatory, autocreated child node jcr:versionLabels.");
+        // retrieve hierarchy entry of the jcr:versionLabels node
+        labelNodeEntry = vhEntry.getNodeEntry(QName.JCR_VERSIONLABELS, Path.INDEX_DEFAULT, true);
+        if (labelNodeEntry == null) {
+            String msg = "Unexpected error: nt:versionHistory requires a mandatory, autocreated child node jcr:versionLabels.";
+            log.error(msg);
+            throw new VersionException(msg);
         }
     }
 
@@ -92,14 +93,13 @@
      */
     public Version getRootVersion() throws RepositoryException {
         checkStatus();
-        if (vhEntry.hasNodeEntry(QName.JCR_ROOTVERSION)) {
-            NodeEntry vEntry = vhEntry.getNodeEntry(QName.JCR_ROOTVERSION, Path.INDEX_DEFAULT);
-            return (Version) itemMgr.getItem(vEntry);
-        } else {
+        NodeEntry vEntry = vhEntry.getNodeEntry(QName.JCR_ROOTVERSION, Path.INDEX_DEFAULT, true);
+        if (vEntry == null) {
             String msg = "Unexpected error: VersionHistory state does not contain a root version child node entry.";
             log.error(msg);
             throw new RepositoryException(msg);
         }
+        return (Version) itemMgr.getItem(vEntry);
     }
 
     /**
@@ -146,8 +146,7 @@
      */
     public Version getVersionByLabel(String label) throws RepositoryException {
         checkStatus();
-        NodeState vState = getVersionStateByLabel(getQLabel(label));
-        return (Version) itemMgr.getItem(vState.getHierarchyEntry());
+        return getVersionByLabel(getQLabel(label));
     }
 
     /**
@@ -177,7 +176,8 @@
     public void removeVersionLabel(String label) throws VersionException, RepositoryException {
         checkStatus();
         QName qLabel = getQLabel(label);
-        NodeState vState = getVersionStateByLabel(getQLabel(label));
+        Version version = getVersionByLabel(qLabel);
+        NodeState vState = getVersionState(version.getName());
         // delegate to version manager that operates on workspace directely
         session.getVersionManager().removeVersionLabel((NodeState) getItemState(), vState, qLabel);
     }
@@ -218,7 +218,7 @@
         QName[] qLabels = getQLabels();
         for (int i = 0; i < qLabels.length; i++) {
             if (qLabels[i].equals(l)) {
-                String uuid = getVersionStateByLabel(qLabels[i]).getUniqueID();
+                String uuid = getVersionByLabel(qLabels[i]).getUUID();
                 return vUUID.equals(uuid);
             }
         }
@@ -263,7 +263,7 @@
         List vlabels = new ArrayList();
         QName[] qLabels = getQLabels();
         for (int i = 0; i < qLabels.length; i++) {
-            String uuid = getVersionStateByLabel(qLabels[i]).getUniqueID();
+            String uuid = getVersionByLabel(qLabels[i]).getUUID();
             if (vUUID.equals(uuid)) {
                 try {
                     vlabels.add(NameFormat.format(qLabels[i], session.getNamespaceResolver()));
@@ -364,7 +364,7 @@
         try {
             QName vQName = NameFormat.parse(versionName, session.getNamespaceResolver());
             refreshEntry(vhEntry);
-            NodeEntry vEntry = vhEntry.getNodeEntry(vQName, Path.INDEX_DEFAULT);
+            NodeEntry vEntry = vhEntry.getNodeEntry(vQName, Path.INDEX_DEFAULT, true);
             if (vEntry == null) {
                 throw new VersionException("Version '" + versionName + "' does not exist in this version history.");
             } else {
@@ -376,22 +376,21 @@
     }
 
     /**
-     *
+     * 
      * @param qLabel
      * @return
      * @throws VersionException
      * @throws RepositoryException
      */
-    private NodeState getVersionStateByLabel(QName qLabel) throws VersionException, RepositoryException {
-        refreshEntry(labelNodeEntry);
-        if (labelNodeEntry.hasPropertyEntry(qLabel)) {
-            // retrieve reference property value -> and retrieve referenced node
-            PropertyEntry pEntry = labelNodeEntry.getPropertyEntry(qLabel);
-            Node version = ((Property) itemMgr.getItem(pEntry)).getNode();
-            return getVersionState(version.getName());
-        } else {
+    private Version getVersionByLabel(QName qLabel) throws VersionException, RepositoryException {
+         refreshEntry(labelNodeEntry);
+        // retrieve reference property value -> and retrieve referenced node
+        PropertyEntry pEntry = labelNodeEntry.getPropertyEntry(qLabel, true);
+        if (pEntry == null) {
             throw new VersionException("Version with label '" + qLabel + "' does not exist.");
         }
+        Node version = ((Property) itemMgr.getItem(pEntry)).getNode();
+        return (Version) version;
     }
 
     /**

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java Tue May 29 08:51:30 2007
@@ -86,7 +86,7 @@
         try {
             // NOTE: since the hierarchy might not be completely loaded or some
             // entry might even not be accessible, the check may not detect
-            // a checked-in parent. ok, as long as the 'server' find out upon
+            // a checked-in parent. ok, as long as the 'server' finds out upon
             // save or upon executing the workspace operation.
             while (!nodeEntry.hasPropertyEntry(QName.JCR_ISCHECKEDOUT)) {
                 NodeEntry parent = nodeEntry.getParent();

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java Tue May 29 08:51:30 2007
@@ -475,6 +475,7 @@
             }
 
             // and set mixin types
+            // TODO: missing validation
             Operation sm = SetMixin.create(childState, nodeInfo.getMixinNames());
             stateMgr.execute(sm);
             return childState;