Index: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java
===================================================================
--- jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java	(revision 679098)
+++ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java	(working copy)
@@ -16,46 +16,47 @@
  */
 package org.apache.jackrabbit.jcr2spi.hierarchy;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
+import org.apache.jackrabbit.jcr2spi.state.ChangeLog;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateLifeCycleListener;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.jcr2spi.state.Status;
+import org.apache.jackrabbit.jcr2spi.util.StateUtility;
+import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.IdFactory;
+import org.apache.jackrabbit.spi.ItemId;
 import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.Path;
-import org.apache.jackrabbit.spi.NodeId;
-import org.apache.jackrabbit.spi.Event;
-import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.PropertyId;
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
-import org.apache.jackrabbit.spi.IdFactory;
-import org.apache.jackrabbit.spi.PropertyId;
-import org.apache.jackrabbit.spi.PathFactory;
-import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.state.ItemState;
-import org.apache.jackrabbit.jcr2spi.state.ChangeLog;
-import org.apache.jackrabbit.jcr2spi.state.Status;
-import org.apache.jackrabbit.jcr2spi.state.PropertyState;
-import org.apache.jackrabbit.jcr2spi.state.ItemStateLifeCycleListener;
-import org.apache.jackrabbit.jcr2spi.util.StateUtility;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.name.PathBuilder;
-import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
-import org.apache.commons.collections.iterators.IteratorChain;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.ItemExistsException;
-import javax.jcr.RepositoryException;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.InvalidItemStateException;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.LinkedHashMap;
-
 /**
  * <code>NodeEntryImpl</code> implements common functionality for child
  * node entry implementations.
@@ -74,13 +75,13 @@
     /**
      * Insertion-ordered collection of NodeEntry objects.
      */
-    private ChildNodeEntries childNodeEntries;
+    public ChildNodeEntries childNodeEntries;
 
     /**
      * Map used to remember transiently removed or moved childNodeEntries, that
      * must not be retrieved from the persistent storage.
      */
-    private ChildNodeAttic childNodeAttic;
+    private final ChildNodeAttic childNodeAttic;
 
     /**
      * Map of properties.<br>
@@ -380,7 +381,7 @@
         NodeEntryImpl entry = this;
         Path.Element[] elems = path.getElements();
         for (int i = 0; i < elems.length; i++) {
-            Path.Element elem = (Path.Element) elems[i];
+            Path.Element elem = elems[i];
             // check for root element
             if (elem.denotesRoot()) {
                 if (getParent() != null) {
@@ -1378,9 +1379,9 @@
      */
     private class RevertInfo implements ItemStateLifeCycleListener {
 
-        private NodeEntryImpl oldParent;
-        private Name oldName;
-        private int oldIndex;
+        private final NodeEntryImpl oldParent;
+        private final Name oldName;
+        private final int oldIndex;
 
         private Map reorderedChildren;
 
Index: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
===================================================================
--- jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java	(revision 679098)
+++ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java	(working copy)
@@ -18,8 +18,12 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
 
 import javax.jcr.ItemExistsException;
 import javax.jcr.ItemNotFoundException;
@@ -28,6 +32,7 @@
 
 import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
 import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntryImpl;
 import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
 import org.apache.jackrabbit.jcr2spi.nodetype.ItemDefinitionProvider;
 import org.apache.jackrabbit.spi.IdFactory;
@@ -142,7 +147,7 @@
     public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws ItemNotFoundException, RepositoryException {
         try {
             PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
-            return createDeepPropertyState(info, anyParent);
+            return createDeepPropertyState(info, anyParent, null);
         } catch (PathNotFoundException e) {
             throw new ItemNotFoundException(e.getMessage());
         }
@@ -187,7 +192,7 @@
     /**
      *
      * @param nodeId
-     * @param itemInfos
+     * @param infos
      * @param entry
      * @return
      * @throws ItemNotFoundException
@@ -200,13 +205,14 @@
             throws ItemNotFoundException, RepositoryException {
         NodeState nodeState;
         // first entry in the iterator is the originally requested Node.
-        if (itemInfos.hasNext()) {
-            NodeInfo first = (NodeInfo) itemInfos.next();
+        ItemInfos infos = new ItemInfos(itemInfos);
+        if (infos.hasNext()) {
+            NodeInfo first = (NodeInfo) infos.next();
             if (isDeep) {
                 // for a deep state, the hierarchy entry does not correspond to
                 // the given NodeEntry -> retrieve NodeState before executing
                 // validation check.
-                nodeState = createDeepNodeState(first, entry);
+                nodeState = createDeepNodeState(first, entry, infos);
                 assertMatchingPath(first, nodeState.getNodeEntry());
             } else {
                 // 'isDeep' == false -> the given NodeEntry must match to the
@@ -222,12 +228,12 @@
         // deal with all additional ItemInfos that may be present.
         NodeEntry parentEntry = nodeState.getNodeEntry();
         if (parentEntry.getStatus() != Status.INVALIDATED) {
-            while (itemInfos.hasNext()) {
-                ItemInfo info = (ItemInfo) itemInfos.next();
+            while (infos.hasNext()) {
+                ItemInfo info = (ItemInfo) infos.next();
                 if (info.denotesNode()) {
-                    createDeepNodeState((NodeInfo) info, parentEntry);
+                    createDeepNodeState((NodeInfo) info, parentEntry, infos);
                 } else {
-                    createDeepPropertyState((PropertyInfo) info, parentEntry);
+                    createDeepPropertyState((PropertyInfo) info, parentEntry, infos);
                 }
             }
         }
@@ -245,7 +251,7 @@
      */
     private NodeState createNodeState(NodeInfo info, NodeEntry entry) throws ItemNotFoundException, RepositoryException {
         // make sure the entry has the correct ItemId
-        // this make not be the case, if the hierachy has not been completely
+        // this make not be the case, if the hierarchy has not been completely
         // resolved yet -> if uniqueID is present, set it on this entry or on
         // the appropriate parent entry
         String uniqueID = info.getId().getUniqueID();
@@ -315,10 +321,13 @@
      *
      * @param info
      * @param anyParent
+     * @param infos
      * @return
      * @throws RepositoryException
      */
-    private NodeState createDeepNodeState(NodeInfo info, NodeEntry anyParent) throws RepositoryException {
+    private NodeState createDeepNodeState(NodeInfo info, NodeEntry anyParent, ItemInfos infos)
+            throws RepositoryException {
+
         try {
             // node for nodeId exists -> build missing entries in hierarchy
             // Note, that the path contained in NodeId does not reveal which
@@ -331,7 +340,7 @@
             for (int i = 0; i < missingElems.length; i++) {
                 Name name = missingElems[i].getName();
                 int index = missingElems[i].getNormalizedIndex();
-                entry = createIntermediateNodeEntry(entry, name, index);
+                entry = createIntermediateNodeEntry(entry, name, index, infos);
             }
             if (entry == anyParent) {
                 throw new RepositoryException("Internal error while getting deep itemState");
@@ -346,10 +355,13 @@
      *
      * @param info
      * @param anyParent
+     * @param infos
      * @return
      * @throws RepositoryException
      */
-    private PropertyState createDeepPropertyState(PropertyInfo info, NodeEntry anyParent) throws RepositoryException {
+    private PropertyState createDeepPropertyState(PropertyInfo info, NodeEntry anyParent,
+            ItemInfos infos) throws RepositoryException {
+
         try {
             // prop for propertyId exists -> build missing entries in hierarchy
             // Note, that the path contained in PropertyId does not reveal which
@@ -358,12 +370,13 @@
             Path relPath = anyParentPath.computeRelativePath(info.getPath());
             Path.Element[] missingElems = relPath.getElements();
             NodeEntry entry = anyParent;
+
             int i = 0;
             // NodeEntries except for the very last 'missingElem'
             while (i < missingElems.length - 1) {
                 Name name = missingElems[i].getName();
                 int index = missingElems[i].getNormalizedIndex();
-                entry = createIntermediateNodeEntry(entry, name, index);
+                entry = createIntermediateNodeEntry(entry, name, index, infos);
                 i++;
             }
             // create PropertyEntry for the last element if not existing yet
@@ -383,10 +396,20 @@
      * @param parentEntry
      * @param name
      * @param index
+     * @param infos
      * @return
      * @throws RepositoryException
      */
-    private static NodeEntry createIntermediateNodeEntry(NodeEntry parentEntry, Name name, int index) throws RepositoryException {
+    private static NodeEntry createIntermediateNodeEntry(NodeEntry parentEntry, Name name,
+            int index, ItemInfos infos) throws RepositoryException {
+
+        if ((infos != null) && ((NodeEntryImpl) parentEntry).childNodeEntries == null) {
+            Iterator childInfos = infos.getChildInfos(parentEntry.getWorkspaceId());
+            if (childInfos != null) {
+                parentEntry.setNodeEntries(childInfos);
+            }
+        }
+
         NodeEntry entry;
         if (parentEntry.hasNodeEntry(name, index)) {
             entry = parentEntry.getNodeEntry(name, index);
@@ -434,4 +457,66 @@
         return parent;
     }
 
+
+    private class ItemInfos implements Iterator {
+        private final List prefetchQueue = new LinkedList();
+        private final Map nodeInfos = new HashMap();
+        private final Iterator infos;
+
+        public ItemInfos(Iterator infos) {
+            super();
+            this.infos = infos;
+        }
+
+        public Iterator getChildInfos(NodeId nodeId) {
+            NodeInfo nodeInfo = (NodeInfo) nodeInfos.get(nodeId);
+            while (nodeInfo == null && prefetch()) {
+                nodeInfo = (NodeInfo) nodeInfos.get(nodeId);
+            }
+            return nodeInfo == null? null : nodeInfo.getChildInfos();
+        }
+
+        // -----------------------------------------------------< Iterator >---
+
+        public boolean hasNext() {
+            if (!prefetchQueue.isEmpty()) {
+                return true;
+            }
+            else {
+                return prefetch();
+            }
+        }
+
+        public Object next() {
+            if (prefetchQueue.isEmpty()) {
+                throw new NoSuchElementException();
+            }
+            else {
+                return prefetchQueue.remove(0);
+            }
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        // -----------------------------------------------------< private >---
+
+        private boolean prefetch() {
+            if (!infos.hasNext()) {
+                return false;
+            }
+            else {
+                ItemInfo info = (ItemInfo) infos.next();
+                prefetchQueue.add(info);
+                if (info.denotesNode()) {
+                    NodeInfo nodeInfo = (NodeInfo) info;
+                    nodeInfos.put(nodeInfo.getId(), nodeInfo);
+                }
+                return true;
+            }
+        }
+
+    }
+
 }
