jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r552873 [2/2] - in /jackrabbit/trunk/contrib/spi: jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/ jcr2spi/src/main...
Date Tue, 03 Jul 2007 15:19:04 GMT
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java Tue Jul  3 08:19:01 2007
@@ -150,75 +150,98 @@
      *
      * @param oldStatus
      * @param newStatus
-     * @param isWorkspaceState
      * @return true if a status change from <code>oldStatus</code> to
      * <code>newStatus</code> is allowed or if the two status are the same.
      */
-    public static boolean isValidStatusChange(int oldStatus, int newStatus,
-                                              boolean isWorkspaceState) {
+    public static boolean isValidStatusChange(int oldStatus, int newStatus) {
         if (oldStatus == newStatus) {
             return true;
         }
         boolean isValid = false;
-        if (isWorkspaceState) {
-            switch (newStatus) {
-                case INVALIDATED:
-                    isValid = (oldStatus == EXISTING);
-                    break;
-                case EXISTING:
-                    isValid = (oldStatus == MODIFIED);
-                    break;
-                case MODIFIED:
-                    // temporary state when workspace state is updated or refreshed
-                    isValid = (oldStatus == EXISTING || oldStatus == INVALIDATED);
-                    break;
-                case REMOVED:
-                    // existing or invalidated workspace state is externally removed
-                    isValid = (oldStatus == EXISTING || oldStatus == INVALIDATED);
-                    break;
-                // default: no other status possible : -> false
-            }
-        } else {
-            // valid status changes for session-states
-            switch (newStatus) {
-                case INVALIDATED:
-                    isValid = (oldStatus == EXISTING); // invalidate
-                    break;
-                case EXISTING:
-                    switch (oldStatus) {
-                        case INVALIDATED: /* refresh */
-                        case NEW: /* save */
-                        case EXISTING_MODIFIED: /* save, revert */
-                        case EXISTING_REMOVED:  /* revert */
-                        case STALE_MODIFIED:    /* revert */
-                        case MODIFIED:
-                            isValid = true;
-                            break;
-                            /* REMOVED, STALE_DESTROYED -> false */
-                    }
-                    break;
-                case EXISTING_MODIFIED:
-                    isValid = (oldStatus == EXISTING);
-                    break;
-                case EXISTING_REMOVED:
-                    isValid = (oldStatus == EXISTING || oldStatus == EXISTING_MODIFIED);
-                    break;
-                case STALE_MODIFIED:
-                case STALE_DESTROYED:
-                    isValid = (oldStatus == EXISTING_MODIFIED);
-                    break;
-                case REMOVED:
-                    isValid = (oldStatus == NEW || oldStatus == INVALIDATED ||
-                               oldStatus == EXISTING || oldStatus == EXISTING_REMOVED );
-                    break;
-                case MODIFIED:
-                    isValid = (oldStatus == EXISTING || oldStatus == INVALIDATED);
-                    break;
+        // valid status changes for session-states
+        switch (newStatus) {
+            case INVALIDATED:
+                isValid = (oldStatus == EXISTING); // invalidate
+                break;
+            case EXISTING:
+                switch (oldStatus) {
+                    case INVALIDATED: /* refresh */
+                    case NEW: /* save */
+                    case EXISTING_MODIFIED: /* save, revert */
+                    case EXISTING_REMOVED:  /* revert */
+                    case STALE_MODIFIED:    /* revert */
+                    case MODIFIED:
+                        isValid = true;
+                        break;
+                        /* REMOVED, STALE_DESTROYED -> false */
+                }
+                break;
+            case EXISTING_MODIFIED:
+                isValid = (oldStatus == EXISTING);
+                break;
+            case EXISTING_REMOVED:
+                isValid = (oldStatus == EXISTING || oldStatus == EXISTING_MODIFIED);
+                break;
+            case STALE_MODIFIED:
+            case STALE_DESTROYED:
+                isValid = (oldStatus == EXISTING_MODIFIED);
+                break;
+            case REMOVED:
+                // external removal always possible -> getNewStatus(int, int)
+                isValid = true;
+                break;
+            case MODIFIED:
+                // except for NEW states an external modification is always valid
+                if (oldStatus != NEW) {
+                    isValid = true;
+                }
+                break;
                 /* default:
                     NEW cannot change state to NEW -> false */
-            }
         }
         return isValid;
+    }
+
+    /**
+     * Returns the given <code>newStatusHint</code> unless the new status
+     * collides with a pending modification or removal which results in a
+     * stale item state.
+     *
+     * @param oldStatus
+     * @param newStatusHint
+     * @return new status that takes transient modification/removal into account.
+     */
+    public static int getNewStatus(int oldStatus, int newStatusHint) {
+        int newStatus;
+        switch (newStatusHint) {
+            case Status.MODIFIED:
+                // underlying state has been modified by external changes
+                if (oldStatus == Status.EXISTING || oldStatus == Status.INVALIDATED) {
+                    // temporarily set the state to MODIFIED in order to inform listeners.
+                    newStatus = Status.MODIFIED;
+                } else if (oldStatus == Status.EXISTING_MODIFIED) {
+                    // TODO: try to merge changes
+                    newStatus = Status.STALE_MODIFIED;
+                } else {
+                    // old status is EXISTING_REMOVED (or any other) => ignore.
+                    // a NEW state may never be marked modified.
+                    newStatus = oldStatus;
+                }
+                break;
+            case Status.REMOVED:
+                if (oldStatus == Status.EXISTING_MODIFIED) {
+                    newStatus = Status.STALE_DESTROYED;
+                } else {
+                    // applies both to NEW or to any other status
+                    newStatus = newStatusHint;
+                }
+                break;
+            default:
+                newStatus = newStatusHint;
+                break;
+
+        }
+        return newStatus;
     }
 
     /**

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java Tue Jul  3 08:19:01 2007
@@ -54,7 +54,7 @@
     public NodeState createNewNodeState(NodeEntry entry, QName nodetypeName,
                                         QNodeDefinition definition) {
 
-        NodeState nodeState = new NodeState(entry, nodetypeName, QName.EMPTY_ARRAY, definition, Status.NEW, false, this, defProvider);
+        NodeState nodeState = new NodeState(entry, nodetypeName, QName.EMPTY_ARRAY, this, definition, defProvider);
 
         // notify listeners that a node state has been created
         notifyCreated(nodeState);
@@ -67,7 +67,7 @@
      * @see TransientItemStateFactory#createNewPropertyState(PropertyEntry, QPropertyDefinition)
      */
     public PropertyState createNewPropertyState(PropertyEntry entry, QPropertyDefinition definition) {
-        PropertyState propState = new PropertyState(entry, definition.isMultiple(), definition, Status.NEW, false, this, defProvider);
+        PropertyState propState = new PropertyState(entry, this, definition, defProvider);
 
         // notify listeners that a property state has been created
         notifyCreated(propState);
@@ -81,9 +81,10 @@
      * @see ItemStateFactory#createRootState(NodeEntry)
      */
     public NodeState createRootState(NodeEntry entry) throws ItemNotFoundException, RepositoryException {
-        // retrieve state to overlay
-        NodeState overlayedState = workspaceStateFactory.createRootState(entry);
-        return buildNodeState(overlayedState, Status.EXISTING);
+        NodeState state = workspaceStateFactory.createRootState(entry);
+        notifyCreated(state);
+
+        return state;
     }
 
     /**
@@ -92,9 +93,10 @@
      */
     public NodeState createNodeState(NodeId nodeId, NodeEntry entry)
             throws ItemNotFoundException, RepositoryException {
-        // retrieve state to overlay
-        NodeState overlayedState = workspaceStateFactory.createNodeState(nodeId, entry);
-        return buildNodeState(overlayedState, getInitialStatus(entry.getParent()));
+        NodeState state = workspaceStateFactory.createNodeState(nodeId, entry);
+        notifyCreated(state);
+
+        return state;
     }
 
     /**
@@ -103,8 +105,10 @@
      */
     public NodeState createDeepNodeState(NodeId nodeId, NodeEntry anyParent)
             throws ItemNotFoundException, RepositoryException {
-        NodeState overlayedState = workspaceStateFactory.createDeepNodeState(nodeId, anyParent);
-        return buildNodeState(overlayedState, getInitialStatus(anyParent));
+        NodeState state = workspaceStateFactory.createDeepNodeState(nodeId, anyParent);
+        notifyCreated(state);
+
+        return state;
     }
 
     /**
@@ -114,17 +118,22 @@
     public PropertyState createPropertyState(PropertyId propertyId,
                                              PropertyEntry entry)
             throws ItemNotFoundException, RepositoryException {
-        // retrieve state to overlay
-        PropertyState overlayedState = workspaceStateFactory.createPropertyState(propertyId, entry);
-        return buildPropertyState(overlayedState, getInitialStatus(entry.getParent()));
+
+        PropertyState state = workspaceStateFactory.createPropertyState(propertyId, entry);
+        notifyCreated(state);
+
+        return state;
+
     }
 
     /**
      * @see ItemStateFactory#createDeepPropertyState(PropertyId, NodeEntry)
      */
     public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws ItemNotFoundException, RepositoryException {
-        PropertyState overlayedState = workspaceStateFactory.createDeepPropertyState(propertyId, anyParent);
-        return buildPropertyState(overlayedState, getInitialStatus(anyParent));
+        PropertyState state = workspaceStateFactory.createDeepPropertyState(propertyId, anyParent);
+        notifyCreated(state);
+
+        return state;
     }
 
     /**
@@ -143,53 +152,6 @@
         if (nodeState.getStatus() == Status.NEW) {
             return EmptyNodeReferences.getInstance();
         }
-
-        NodeState workspaceState = (NodeState) nodeState.getWorkspaceState();
-        return workspaceStateFactory.getNodeReferences(workspaceState);
-    }
-
-    //------------------------------------------------------------< private >---
-    /**
-     *
-     * @param overlayed
-     * @return
-     */
-    private NodeState buildNodeState(NodeState overlayed, int initialStatus) {
-        NodeState nodeState = new NodeState(overlayed, initialStatus, this);
-
-        notifyCreated(nodeState);
-        return nodeState;
-    }
-
-
-    /**
-     *
-     * @param overlayed
-     * @return
-     */
-    private PropertyState buildPropertyState(PropertyState overlayed, int initialStatus) {
-        PropertyState propState = new PropertyState(overlayed, initialStatus, this);
-
-        notifyCreated(propState);
-        return propState;
-    }
-
-    /**
-     *
-     * @param parent
-     * @return
-     */
-    private static int getInitialStatus(NodeEntry parent) {
-        int status = Status.EXISTING;
-        // walk up hiearchy and check if any of the parents is transiently
-        // removed, in which case the status must be set to EXISTING_REMOVED.
-        while (parent != null) {
-            if (parent.getStatus() == Status.EXISTING_REMOVED) {
-                status = Status.EXISTING_REMOVED;
-                break;
-            }
-            parent = parent.getParent();
-        }
-        return status;
+        return workspaceStateFactory.getNodeReferences(nodeState);
     }
 }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Tue Jul  3 08:19:01 2007
@@ -99,8 +99,6 @@
     NodeState createNewNodeState(QName nodeName, String uniqueID, QName nodeTypeName,
                                  QNodeDefinition definition, NodeState parent)
             throws RepositoryException {
-
-        parent.checkIsSessionState();
         NodeState nodeState = ((NodeEntry) parent.getHierarchyEntry()).addNewNodeEntry(nodeName, uniqueID, nodeTypeName, definition);
         parent.markModified();
 
@@ -124,11 +122,9 @@
                                          QPropertyDefinition definition,
                                          QValue[] values, int propertyType)
         throws ItemExistsException, ConstraintViolationException, RepositoryException {
-
-        parent.checkIsSessionState();
-        PropertyState propState = ((NodeEntry) parent.getHierarchyEntry()).addNewPropertyEntry(propName, definition);
         // NOTE: callers must make sure, the property type is not 'undefined'
-        propState.init(propertyType, values);
+        PropertyState propState = ((NodeEntry) parent.getHierarchyEntry()).addNewPropertyEntry(propName, definition);
+        propState.setValues(values, propertyType);
         parent.markModified();
 
         return propState;

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Jul  3 08:19:01 2007
@@ -71,8 +71,7 @@
      * @see ItemStateFactory#createRootState(NodeEntry)
      */
     public NodeState createRootState(NodeEntry entry) throws ItemNotFoundException, RepositoryException {
-        NodeInfo info = service.getNodeInfo(sessionInfo, service.getRootId(sessionInfo));
-        return createNodeState(info, entry);
+        return createNodeState(service.getRootId(sessionInfo), entry);
     }
 
     /**
@@ -84,47 +83,41 @@
      */
     public NodeState createNodeState(NodeId nodeId, NodeEntry entry)
             throws ItemNotFoundException, RepositoryException {
+        // build new node state from server information
         try {
-            NodeInfo info = service.getNodeInfo(sessionInfo, nodeId);
-            return createNodeState(info, entry);
+            NodeState nodeState;
+            if (entry.getStatus() == Status.INVALIDATED) {
+                // simple reload -> don't use batch-read
+                NodeInfo nInfo = service.getNodeInfo(sessionInfo, nodeId);
+                nodeState = createItemStates(nodeId, Collections.singletonList(nInfo).iterator(), entry, false);
+            } else {
+                Iterator infos = service.getItemInfos(sessionInfo, nodeId);
+                nodeState = createItemStates(nodeId, infos, entry, false);
+            }
+            if (nodeState == null) {
+                throw new ItemNotFoundException("HierarchyEntry does not belong to any existing ItemInfo.");
+            }
+            return nodeState;
         } catch (PathNotFoundException e) {
             throw new ItemNotFoundException(e.getMessage(), e);
         }
     }
 
+    /**
+     * @inheritDoc
+     * @see ItemStateFactory#createDeepNodeState(NodeId,NodeEntry)
+     */
     public NodeState createDeepNodeState(NodeId nodeId, NodeEntry anyParent) throws ItemNotFoundException, RepositoryException {
         try {
-            NodeInfo info = service.getNodeInfo(sessionInfo, nodeId);
-            // node for nodeId exists -> build missing entries in hierarchy
-            // Note, that the path contained in NodeId does not reveal which
-            // entries are missing -> calculate relative path.
-            Path anyParentPath = anyParent.getPath();
-            Path relPath = anyParentPath.computeRelativePath(info.getPath());
-            Path.PathElement[] missingElems = relPath.getElements();
-
-            NodeEntry entry = anyParent;
-            for (int i = 0; i < missingElems.length; i++) {
-                QName name = missingElems[i].getName();
-                int index = missingElems[i].getNormalizedIndex();
-                if (entry.hasNodeEntry(name, index)) {
-                    entry = entry.getNodeEntry(name, index);
-                } else {
-                    entry = entry.addNodeEntry(name, null, index);
-                }
-            }
-            if (entry == anyParent) {
-                throw new RepositoryException("Internal error while getting deep itemState");
-            }
-            return createNodeState(info, entry);
+            Iterator infos = service.getItemInfos(sessionInfo, nodeId);
+            return createItemStates(nodeId, infos, anyParent, true);
         } catch (PathNotFoundException e) {
             throw new ItemNotFoundException(e.getMessage(), e);
-        } catch (MalformedPathException e) {
-            throw new RepositoryException(e.getMessage(), e);
         }
     }
 
     /**
-     * Creates the property with information retrieved from the
+     * Creates the PropertyState with information retrieved from the
      * <code>RepositoryService</code>.
      *
      * @inheritDoc
@@ -135,45 +128,23 @@
             throws ItemNotFoundException, RepositoryException {
         try {
             PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
+            assertMatchingPath(info, entry);
             return createPropertyState(info, entry);
         } catch (PathNotFoundException e) {
             throw new ItemNotFoundException(e.getMessage());
         }
     }
 
+    /**
+     * @inheritDoc
+     * @see ItemStateFactory#createDeepPropertyState(PropertyId,NodeEntry)
+     */
     public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws ItemNotFoundException, RepositoryException {
         try {
             PropertyInfo info = service.getPropertyInfo(sessionInfo, propertyId);
-            // prop for propertyId exists -> build missing entries in hierarchy
-            // Note, that the path contained in PropertyId does not reveal which
-            // entries are missing -> calculate relative path.
-            Path anyParentPath = anyParent.getPath();
-            Path relPath = anyParentPath.computeRelativePath(info.getPath());
-            Path.PathElement[] missingElems = relPath.getElements();
-            NodeEntry entry = anyParent;
-            int i = 0;
-            // NodeEntries except for the very last 'missingElem'
-            while (i < missingElems.length - 1) {
-                QName name = missingElems[i].getName();
-                int index = missingElems[i].getNormalizedIndex();
-                if (entry.hasNodeEntry(name, index)) {
-                    entry = entry.getNodeEntry(name, index);
-                } else {
-                    entry = entry.addNodeEntry(name, null, index);
-                }
-                i++;
-            }
-            // create PropertyEntry for the last element if not existing yet
-            QName propName = missingElems[i].getName();
-            PropertyEntry propEntry = entry.getPropertyEntry(propName);
-            if (propEntry == null) {
-                propEntry = entry.addPropertyEntry(propName);
-            }
-            return createPropertyState(info, propEntry);
+            return createDeepPropertyState(info, anyParent);
         } catch (PathNotFoundException e) {
             throw new ItemNotFoundException(e.getMessage());
-        } catch (MalformedPathException e) {
-            throw new RepositoryException(e.getMessage());
         }
     }
 
@@ -193,9 +164,9 @@
      * @param nodeState
      */
     public NodeReferences getNodeReferences(NodeState nodeState) {
-        nodeState.checkIsWorkspaceState();
+        NodeEntry entry = nodeState.getNodeEntry();
         // shortcut
-        if (nodeState.getUniqueID() == null || !nodeState.hasPropertyName(QName.JCR_UUID)) {
+        if (entry.getUniqueID() == null || !entry.hasPropertyEntry(QName.JCR_UUID)) {
             // for sure not referenceable
             return EmptyNodeReferences.getInstance();
         }
@@ -203,16 +174,68 @@
         // nodestate has a unique ID and is potentially mix:referenceable
         // => try to retrieve references
         try {
-            NodeInfo info = service.getNodeInfo(sessionInfo, nodeState.getNodeId());
-            return new NodeReferencesImpl(info.getReferences());
+            NodeInfo nInfo = service.getNodeInfo(sessionInfo, entry.getWorkspaceId());
+            return new NodeReferencesImpl(nInfo.getReferences());
         } catch (RepositoryException e) {
-            log.debug("No references for NodeState " + nodeState);
-            return EmptyNodeReferences.getInstance();
+            // ignore
         }
+        // exception or no matching entry found.
+        log.debug("Unable to determine references for NodeState " + nodeState);
+        return EmptyNodeReferences.getInstance();
     }
 
     //------------------------------------------------------------< private >---
     /**
+     *
+     * @param nodeId
+     * @param itemInfos
+     * @param entry
+     * @return
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    private synchronized NodeState createItemStates(NodeId nodeId,
+                                                    Iterator itemInfos,
+                                                    NodeEntry entry,
+                                                    boolean isDeep)
+            throws ItemNotFoundException, RepositoryException {
+        NodeState nodeState;
+        // first entry in the iterator is the originally requested Node.
+        if (itemInfos.hasNext()) {
+            NodeInfo first = (NodeInfo) itemInfos.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);
+                assertMatchingPath(first, nodeState.getNodeEntry());
+            } else {
+                // 'isDeep' == false -> the given NodeEntry must match to the
+                // first ItemInfo retrieved from the iterator.
+                assertMatchingPath(first, entry);
+                nodeState = createNodeState(first, entry);
+            }
+        } else {
+            // empty iterator
+            throw new ItemNotFoundException("Node with id " + nodeId + " could not be found.");
+        }
+
+        // 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();
+                if (info.denotesNode()) {
+                    createDeepNodeState((NodeInfo) info, parentEntry);
+                } else {
+                    createDeepPropertyState((PropertyInfo) info, parentEntry);
+                }
+            }
+        }
+        return nodeState;
+    }
+
+    /**
      * Creates the node with information retrieved from <code>info</code>.
      *
      * @param info the <code>NodeInfo</code> to use to create the <code>NodeState</code>.
@@ -222,8 +245,6 @@
      * @throws RepositoryException
      */
     private NodeState createNodeState(NodeInfo info, NodeEntry entry) throws ItemNotFoundException, RepositoryException {
-        assertMatchingPath(info, entry);
-
         // make sure the entry has the correct ItemId
         // this make not be the case, if the hierachy has not been completely
         // resolved yet -> if uniqueID is present, set it on this entry or on
@@ -242,7 +263,7 @@
         QNodeDefinition definition = definitionProvider.getQNodeDefinition(entry, info);
 
         // now build the nodestate itself
-        NodeState state = new NodeState(entry, info.getNodetype(), info.getMixins(), definition, Status.EXISTING, true, this, definitionProvider);
+        NodeState state = new NodeState(entry, info, this, definition, definitionProvider);
 
         // update NodeEntry from the information present in the NodeInfo (prop entries)
         List propNames = new ArrayList();
@@ -272,10 +293,7 @@
      * @throws ItemNotFoundException
      * @throws RepositoryException
      */
-    private PropertyState createPropertyState(PropertyInfo info, PropertyEntry entry)
-            throws ItemNotFoundException, RepositoryException {
-        assertMatchingPath(info, entry);
-
+    private PropertyState createPropertyState(PropertyInfo info, PropertyEntry entry) {
         // make sure uuid part of id is correct
         String uniqueID = info.getId().getUniqueID();
         if (uniqueID != null) {
@@ -287,17 +305,108 @@
         QPropertyDefinition definition = definitionProvider.getQPropertyDefinition(entry, info);
 
         // build the PropertyState
-        PropertyState state = new PropertyState(entry, info.isMultiValued(), definition, Status.EXISTING, true, this, definitionProvider);
-        state.init(info.getType(), info.getValues());
+        PropertyState state = new PropertyState(entry, info, this, definition, definitionProvider);
 
-        //state.addListener(cache);
-        //cache.created(state);
         notifyCreated(state);
-
         return state;
     }
 
     /**
+     *
+     * @param info
+     * @param anyParent
+     * @return
+     * @throws RepositoryException
+     */
+    private NodeState createDeepNodeState(NodeInfo info, NodeEntry anyParent) throws RepositoryException {
+        try {
+            // node for nodeId exists -> build missing entries in hierarchy
+            // Note, that the path contained in NodeId does not reveal which
+            // entries are missing -> calculate relative path.
+            Path anyParentPath = anyParent.getPath();
+            Path relPath = anyParentPath.computeRelativePath(info.getPath());
+            Path.PathElement[] missingElems = relPath.getElements();
+
+            NodeEntry entry = anyParent;
+            for (int i = 0; i < missingElems.length; i++) {
+                QName name = missingElems[i].getName();
+                int index = missingElems[i].getNormalizedIndex();
+                entry = createIntermediateNodeEntry(entry, name, index);
+            }
+            if (entry == anyParent) {
+                throw new RepositoryException("Internal error while getting deep itemState");
+            }
+            return createNodeState(info, entry);
+        } catch (PathNotFoundException e) {
+            throw new ItemNotFoundException(e.getMessage(), e);
+        } catch (MalformedPathException e) {
+            throw new RepositoryException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     *
+     * @param info
+     * @param anyParent
+     * @return
+     * @throws RepositoryException
+     */
+    private PropertyState createDeepPropertyState(PropertyInfo info, NodeEntry anyParent) throws RepositoryException {
+        try {
+            // prop for propertyId exists -> build missing entries in hierarchy
+            // Note, that the path contained in PropertyId does not reveal which
+            // entries are missing -> calculate relative path.
+            Path anyParentPath = anyParent.getPath();
+            Path relPath = anyParentPath.computeRelativePath(info.getPath());
+            Path.PathElement[] missingElems = relPath.getElements();
+            NodeEntry entry = anyParent;
+            int i = 0;
+            // NodeEntries except for the very last 'missingElem'
+            while (i < missingElems.length - 1) {
+                QName name = missingElems[i].getName();
+                int index = missingElems[i].getNormalizedIndex();
+                entry = createIntermediateNodeEntry(entry, name, index);
+                i++;
+            }
+            // create PropertyEntry for the last element if not existing yet
+            QName propName = missingElems[i].getName();
+            PropertyEntry propEntry = entry.getPropertyEntry(propName);
+            if (propEntry == null) {
+                propEntry = entry.addPropertyEntry(propName);
+            }
+            return createPropertyState(info, propEntry);
+        } catch (PathNotFoundException e) {
+            throw new ItemNotFoundException(e.getMessage());
+        } catch (MalformedPathException e) {
+            throw new RepositoryException(e.getMessage());
+        }
+    }
+
+    /**
+     *
+     * @param parentEntry
+     * @param name
+     * @param index
+     * @return
+     * @throws RepositoryException
+     */
+    private static NodeEntry createIntermediateNodeEntry(NodeEntry parentEntry, QName name, int index) throws RepositoryException {
+        /*
+        HierarchyEntry entry = parentEntry.lookupDeepEntry(Path.create(name, index));
+        if (entry == null || !entry.denotesNode()) {
+            entry = parentEntry.addNodeEntry(name, null, index);
+        }
+        */
+        NodeEntry entry;
+        if (parentEntry.hasNodeEntry(name, index)) {
+            entry = parentEntry.getNodeEntry(name, index);
+        } else {
+            entry = parentEntry.addNodeEntry(name, null, index);
+        }
+        return entry;
+    }
+
+    /**
      * Validation check: Path of the given ItemInfo must match to the Path of
      * the HierarchyEntry. This is required for Items that are identified by
      * a uniqueID that may move within the hierarchy upon restore or clone.
@@ -309,11 +418,19 @@
      */
     private static void assertMatchingPath(ItemInfo info, HierarchyEntry entry)
             throws ItemNotFoundException, RepositoryException {
-        if (!info.getPath().equals(entry.getWorkspacePath())) {
+        Path infoPath = info.getPath();
+        if (!infoPath.equals(entry.getWorkspacePath())) {
+            // TODO: handle external move of nodes (parents) identified by uniqueID
             throw new ItemNotFoundException("HierarchyEntry does not belong the given ItemInfo.");
         }
     }
 
+    /**
+     *
+     * @param entry
+     * @param degree
+     * @return
+     */
     private static NodeEntry getAncestor(HierarchyEntry entry, int degree) {
         NodeEntry parent = entry.getParent();
         degree--;
@@ -326,6 +443,7 @@
         }
         return parent;
     }
+
     //-----------------------------------------------------< NodeReferences >---
     /**
      * <code>NodeReferences</code> represents the references (i.e. properties of

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java Tue Jul  3 08:19:01 2007
@@ -67,7 +67,6 @@
     }
 
     public static boolean isMovedState(NodeState state) {
-        state.checkIsSessionState();
         if (state.isRoot()) {
             // the root state cannot be moved
             return false;

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java Tue Jul  3 08:19:01 2007
@@ -81,11 +81,11 @@
         throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
     }
 
-    public NodeEntry getVersionableNodeState(NodeState versionState) {
+    public NodeEntry getVersionableNodeEntry(NodeState versionState) {
         throw new UnsupportedOperationException();
     }
 
-    public NodeEntry getVersionHistoryNodeState(NodeState versionableState) {
+    public NodeEntry getVersionHistoryEntry(NodeState versionableState) {
         throw new UnsupportedOperationException();
     }
 }

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Jul  3 08:19:01 2007
@@ -424,7 +424,12 @@
         }
     }
 
-    private void refreshEntry(NodeEntry entry) throws RepositoryException {
+    /**
+     * 
+     * @param entry
+     * @throws RepositoryException
+     */
+    private static void refreshEntry(NodeEntry entry) throws RepositoryException {
         // TODO: check again.. is this correct? or should NodeEntry be altered
         entry.getNodeState();
     }

Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java Tue Jul  3 08:19:01 2007
@@ -176,12 +176,12 @@
      * @param versionState
      * @return
      */
-    public NodeEntry getVersionableNodeState(NodeState versionState) throws RepositoryException;
+    public NodeEntry getVersionableNodeEntry(NodeState versionState) throws RepositoryException;
 
     /**
      *
      * @param versionableState
      * @return
      */
-    public NodeEntry getVersionHistoryNodeState(NodeState versionableState) throws RepositoryException;
+    public NodeEntry getVersionHistoryEntry(NodeState versionableState) throws RepositoryException;
 }

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=552873&r1=552872&r2=552873
==============================================================================
--- 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 Jul  3 08:19:01 2007
@@ -57,14 +57,12 @@
     }
 
     public void checkin(NodeState nodeState) throws RepositoryException {
-        NodeState wspState = getWorkspaceState(nodeState);
-        Operation ci = Checkin.create(wspState, this);
+        Operation ci = Checkin.create(nodeState, this);
         workspaceManager.execute(ci);
     }
 
     public void checkout(NodeState nodeState) throws RepositoryException {
-        NodeState wspState = getWorkspaceState(nodeState);
-        Operation co = Checkout.create(wspState, this);
+        Operation co = Checkout.create(nodeState, this);
         workspaceManager.execute(co);
     }
 
@@ -114,55 +112,41 @@
     }
 
     public void removeVersion(NodeState versionHistoryState, NodeState versionState) throws RepositoryException {
-        NodeState wspVersionState = getWorkspaceState(versionState);
-        Operation op = RemoveVersion.create(wspVersionState, getWorkspaceState(versionHistoryState), this);
+        Operation op = RemoveVersion.create(versionState, versionHistoryState, this);
         workspaceManager.execute(op);
     }
 
     public void addVersionLabel(NodeState versionHistoryState, NodeState versionState, QName qLabel, boolean moveLabel) throws RepositoryException {
-        NodeState wspVHState = getWorkspaceState(versionHistoryState);
-        NodeState wspVState = getWorkspaceState(versionState);
-        Operation op = AddLabel.create(wspVHState, wspVState, qLabel, moveLabel);
+        Operation op = AddLabel.create(versionHistoryState, versionState, qLabel, moveLabel);
         workspaceManager.execute(op);
     }
 
     public void removeVersionLabel(NodeState versionHistoryState, NodeState versionState, QName qLabel) throws RepositoryException {
-        NodeState wspVHState = getWorkspaceState(versionHistoryState);
-        NodeState wspVState = getWorkspaceState(versionState);
-        Operation op = RemoveLabel.create(wspVHState, wspVState, qLabel);
+        Operation op = RemoveLabel.create(versionHistoryState, versionState, qLabel);
         workspaceManager.execute(op);
     }
 
     public void restore(NodeState nodeState, Path relativePath, NodeState versionState, boolean removeExisting) throws RepositoryException {
-        NodeState wspState = getWorkspaceState(nodeState);
-        NodeState wspVState = getWorkspaceState(versionState);
-        Operation op = Restore.create(wspState, relativePath, wspVState, removeExisting);
+        Operation op = Restore.create(nodeState, relativePath, versionState, removeExisting);
         workspaceManager.execute(op);
     }
 
     public void restore(NodeState[] versionStates, boolean removeExisting) throws RepositoryException {
-        NodeState[] wspStates = new NodeState[versionStates.length];
-        for (int i = 0; i < versionStates.length; i++) {
-            wspStates[i] = getWorkspaceState(versionStates[i]);
-        }
-
-        Operation op = Restore.create(wspStates, removeExisting);
+        Operation op = Restore.create(versionStates, removeExisting);
         workspaceManager.execute(op);
     }
 
     public IdIterator merge(NodeState nodeState, String workspaceName, boolean bestEffort) throws RepositoryException {
-        NodeState wspState = getWorkspaceState(nodeState);
-        Merge op = Merge.create(wspState, workspaceName, bestEffort, this);
+        Merge op = Merge.create(nodeState, workspaceName, bestEffort, this);
         workspaceManager.execute(op);
         return op.getFailedIds();
     }
 
     public void resolveMergeConflict(NodeState nodeState, NodeState versionState,
                                      boolean done) throws RepositoryException {
-        NodeState wspState = getWorkspaceState(nodeState);
-        NodeId vId = getWorkspaceState(versionState).getNodeId();
+        NodeId vId = versionState.getNodeId();
 
-        PropertyState mergeFailedState = wspState.getPropertyState(QName.JCR_MERGEFAILED);
+        PropertyState mergeFailedState = nodeState.getPropertyState(QName.JCR_MERGEFAILED);
         QValue[] vs = mergeFailedState.getValues();
 
         NodeId[] mergeFailedIds = new NodeId[vs.length - 1];
@@ -176,7 +160,7 @@
             // part of 'jcr:mergefailed' any more
         }
 
-        PropertyState predecessorState = wspState.getPropertyState(QName.JCR_PREDECESSORS);
+        PropertyState predecessorState = nodeState.getPropertyState(QName.JCR_PREDECESSORS);
         vs = predecessorState.getValues();
 
         int noOfPredecessors = (done) ? vs.length + 1 : vs.length;
@@ -190,11 +174,11 @@
         if (done) {
             predecessorIds[i] = vId;
         }
-        Operation op = ResolveMergeConflict.create(wspState, mergeFailedIds, predecessorIds, done);
+        Operation op = ResolveMergeConflict.create(nodeState, mergeFailedIds, predecessorIds, done);
         workspaceManager.execute(op);
     }
 
-    public NodeEntry getVersionableNodeState(NodeState versionState) throws RepositoryException {
+    public NodeEntry getVersionableNodeEntry(NodeState versionState) throws RepositoryException {
         NodeState ns = versionState.getChildNodeState(QName.JCR_FROZENNODE, Path.INDEX_DEFAULT);
         PropertyState ps = ns.getPropertyState(QName.JCR_FROZENUUID);
         String uniqueID = ps.getValue().toString();
@@ -203,23 +187,10 @@
         return (NodeEntry) workspaceManager.getHierarchyManager().getHierarchyEntry(versionableId);
     }
 
-    public NodeEntry getVersionHistoryNodeState(NodeState versionableState) throws RepositoryException {
+    public NodeEntry getVersionHistoryEntry(NodeState versionableState) throws RepositoryException {
         PropertyState ps = versionableState.getPropertyState(QName.JCR_VERSIONHISTORY);
         String uniqueID = ps.getValue().getString();
         NodeId vhId = workspaceManager.getIdFactory().createNodeId(uniqueID);
         return (NodeEntry) workspaceManager.getHierarchyManager().getHierarchyEntry(vhId);
-    }
-
-    //------------------------------------------------------------< private >---
-    /**
-     * If the given <code>NodeState</code> has an overlayed state, the overlayed
-     * (workspace) state will be returned. Otherwise the given state is returned.
-     *
-     * @param nodeState
-     * @return The overlayed state or the given state, if this one does not have
-     * an overlayed state.
-     */
-    private NodeState getWorkspaceState(NodeState nodeState) {
-        return (NodeState) nodeState.getWorkspaceState();
     }
 }

Modified: jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/client/ClientRepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/client/ClientRepositoryService.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/client/ClientRepositoryService.java (original)
+++ jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/client/ClientRepositoryService.java Tue Jul  3 08:19:01 2007
@@ -25,7 +25,6 @@
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.PropertyId;
-import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.spi.PropertyInfo;
 import org.apache.jackrabbit.spi.Batch;
 import org.apache.jackrabbit.spi.LockInfo;
@@ -35,6 +34,7 @@
 import org.apache.jackrabbit.spi.EventBundle;
 import org.apache.jackrabbit.spi.QNodeTypeDefinitionIterator;
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.spi.rmi.remote.RemoteRepositoryService;
 import org.apache.jackrabbit.spi.rmi.remote.RemoteSessionInfo;
 import org.apache.jackrabbit.spi.rmi.remote.RemoteIterator;
@@ -259,6 +259,19 @@
             throws ItemNotFoundException, RepositoryException {
         try {
             return remoteService.getNodeInfo(getRemoteSessionInfo(sessionInfo), nodeId);
+        } catch (RemoteException e) {
+            throw new RemoteRepositoryException(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId)
+            throws ItemNotFoundException, RepositoryException {
+        try {
+            RemoteIterator it = remoteService.getItemInfos(getRemoteSessionInfo(sessionInfo), nodeId);
+            return new ClientIterator(it);
         } catch (RemoteException e) {
             throw new RemoteRepositoryException(e);
         }

Modified: jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/remote/RemoteRepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/remote/RemoteRepositoryService.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/remote/RemoteRepositoryService.java (original)
+++ jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/remote/RemoteRepositoryService.java Tue Jul  3 08:19:01 2007
@@ -21,13 +21,13 @@
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.PropertyId;
-import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.spi.PropertyInfo;
 import org.apache.jackrabbit.spi.LockInfo;
 import org.apache.jackrabbit.spi.EventFilter;
 import org.apache.jackrabbit.spi.EventBundle;
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
 import org.apache.jackrabbit.spi.SessionInfo;
+import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.name.Path;
 
@@ -192,6 +192,16 @@
      * @see org.apache.jackrabbit.spi.RepositoryService#getNodeInfo(org.apache.jackrabbit.spi.SessionInfo, org.apache.jackrabbit.spi.NodeId)
      */
     public NodeInfo getNodeInfo(RemoteSessionInfo sessionInfo, NodeId nodeId)
+            throws RepositoryException, RemoteException;
+
+    /**
+     * @param sessionInfo
+     * @param nodeId
+     * @return
+     * @throws RemoteException if an error occurs.
+     * @see org.apache.jackrabbit.spi.RepositoryService#getNodeInfo(org.apache.jackrabbit.spi.SessionInfo, org.apache.jackrabbit.spi.NodeId)
+     */
+    public RemoteIterator getItemInfos(RemoteSessionInfo sessionInfo, NodeId nodeId)
             throws RepositoryException, RemoteException;
 
     /**

Modified: jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/server/ServerRepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/server/ServerRepositoryService.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/server/ServerRepositoryService.java (original)
+++ jackrabbit/trunk/contrib/spi/spi-rmi/src/main/java/org/apache/jackrabbit/spi/rmi/server/ServerRepositoryService.java Tue Jul  3 08:19:01 2007
@@ -52,6 +52,7 @@
 import org.apache.jackrabbit.spi.ChildInfo;
 import org.apache.jackrabbit.spi.EventIterator;
 import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.ItemInfo;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.name.Path;
 
@@ -215,7 +216,7 @@
     public NodeId getRootId(RemoteSessionInfo sessionInfo)
             throws RepositoryException, RemoteException {
         try {
-            return createSerializableNodeId(
+            return idFactory.createSerializableNodeId(
                     service.getRootId(getSessionInfo(sessionInfo)));
         } catch (RepositoryException e) {
             throw getRepositoryException(e);
@@ -279,29 +280,36 @@
             throws RepositoryException, RemoteException {
         try {
             NodeInfo nInfo = service.getNodeInfo(getSessionInfo(sessionInfo), nodeId);
-            if (nInfo instanceof Serializable) {
-                return nInfo;
+            return NodeInfoImpl.createSerializableNodeInfo(nInfo, idFactory);
+        } catch (RepositoryException e) {
+            throw getRepositoryException(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public RemoteIterator getItemInfos(RemoteSessionInfo sessionInfo, NodeId nodeId)
+            throws RepositoryException, RemoteException {
+        try {
+            Iterator it = service.getItemInfos(getSessionInfo(sessionInfo), nodeId);
+            if (it instanceof RemoteIterator) {
+                return (RemoteIterator) it;
             } else {
-                PropertyId[] refs = nInfo.getReferences();
-                PropertyId[] serRefs = new PropertyId[refs.length];
-                for (int i = 0; i < serRefs.length; i++) {
-                    serRefs[i] = createSerializablePropertyId(refs[i]);
-                }
-                NodeId parentId = null;
-                if (nInfo.getParentId() != null) {
-                    parentId = createSerializableNodeId(nInfo.getParentId());
+                List serializables = new ArrayList();
+                while (it.hasNext()) {
+                    ItemInfo info = (ItemInfo) it.next();
+                    if (info instanceof Serializable) {
+                        serializables.add(info);
+                    } else {
+                        if (info.denotesNode()) {
+                            serializables.add(NodeInfoImpl.createSerializableNodeInfo((NodeInfo) info, idFactory));
+                        } else {
+                            serializables.add(PropertyInfoImpl.createSerializablePropertyInfo((PropertyInfo) info, idFactory));
+                        }
+                    }
                 }
-                return new NodeInfoImpl(parentId, nInfo.getQName(),
-                        nInfo.getPath(),
-                        createSerializableNodeId(nInfo.getId()),
-                        nInfo.getIndex(), nInfo.getNodetype(),
-                        nInfo.getMixins(), serRefs,
-                        new IteratorHelper(nInfo.getPropertyIds()) {
-                            public ItemId nextId() {
-                                return createSerializablePropertyId(
-                                        (PropertyId) super.nextId());
-                            }
-                        });
+                return new ServerIterator(serializables.iterator(), DEFAULT_BUFFER_SIZE);
             }
         } catch (RepositoryException e) {
             throw getRepositoryException(e);
@@ -314,8 +322,7 @@
     public RemoteIterator getChildInfos(RemoteSessionInfo sessionInfo,
                                   NodeId parentId) throws RepositoryException, RemoteException {
         try {
-            Iterator childInfos = service.getChildInfos(
-                    getSessionInfo(sessionInfo), parentId);
+            Iterator childInfos = service.getChildInfos(getSessionInfo(sessionInfo), parentId);
             return new ServerIterator(new IteratorHelper(childInfos) {
                 public Object next() {
                     ChildInfo cInfo = (ChildInfo) super.next();
@@ -339,14 +346,8 @@
                                         PropertyId propertyId)
             throws RepositoryException, RemoteException {
         try {
-            PropertyInfo propInfo = service.getPropertyInfo(
-                    getSessionInfo(sessionInfo), propertyId);
-            return new PropertyInfoImpl(
-                    createSerializableNodeId(propInfo.getParentId()),
-                    propInfo.getQName(), propInfo.getPath(),
-                    createSerializablePropertyId(propInfo.getId()),
-                    propInfo.getType(), propInfo.isMultiValued(),
-                    propInfo.getValues());
+            PropertyInfo propInfo = service.getPropertyInfo(getSessionInfo(sessionInfo), propertyId);
+            return PropertyInfoImpl.createSerializablePropertyInfo(propInfo, idFactory);
         } catch (RepositoryException e) {
             throw getRepositoryException(e);
         }
@@ -477,7 +478,7 @@
                 return new LockInfoImpl(lockInfo.getLockToken(),
                         lockInfo.getOwner(), lockInfo.isDeep(),
                         lockInfo.isSessionScoped(),
-                        createSerializableNodeId(lockInfo.getNodeId()));
+                        idFactory.createSerializableNodeId(lockInfo.getNodeId()));
             }
         } catch (RepositoryException e) {
             throw getRepositoryException(e);
@@ -500,7 +501,7 @@
                 return new LockInfoImpl(lockInfo.getLockToken(),
                         lockInfo.getOwner(), lockInfo.isDeep(),
                         lockInfo.isSessionScoped(),
-                        createSerializableNodeId(lockInfo.getNodeId()));
+                        idFactory.createSerializableNodeId(lockInfo.getNodeId()));
             }
         } catch (RepositoryException e) {
             throw getRepositoryException(e);
@@ -744,13 +745,13 @@
                     Event e = it.nextEvent();
                     ItemId id;
                     if (e.getItemId().denotesNode()) {
-                        id = createSerializableNodeId((NodeId) e.getItemId());
+                        id = idFactory.createSerializableNodeId((NodeId) e.getItemId());
                     } else {
-                        id = createSerializablePropertyId((PropertyId) e.getItemId());
+                        id = idFactory.createSerializablePropertyId((PropertyId) e.getItemId());
                     }
                     Event serEvent = new EventImpl(e.getType(),
                             e.getQPath(), id,
-                            createSerializableNodeId(e.getParentId()),
+                            idFactory.createSerializableNodeId(e.getParentId()),
                             e.getPrimaryNodeTypeName(),
                             e.getMixinTypeNames(), e.getUserID());
                     events.add(serEvent);
@@ -884,40 +885,6 @@
         } else {
             throw new RepositoryException("Unknown RemoteSessionInfo: " +
                     ((RemoteObject) sInfo).getRef());
-        }
-    }
-
-    /**
-     * Checks if the passed <code>nodeId</code> is serializable and if it is not
-     * creates a serializable version for the given <code>nodeId</code>.
-     *
-     * @param nodeId the node id to check.
-     * @return a serializable version of <code>nodeId</code> or the passed
-     *         nodeId itself it is already serializable.
-     */
-    private NodeId createSerializableNodeId(NodeId nodeId) {
-        if (nodeId instanceof Serializable) {
-            return nodeId;
-        } else {
-            return idFactory.createNodeId(nodeId.getUniqueID(), nodeId.getPath());
-        }
-    }
-
-    /**
-     * Checks if the passed <code>propId</code> is serializable and if it is not
-     * creates a serializable version for the given <code>propId</code>.
-     *
-     * @param propId the property id to check.
-     * @return a serializable version of <code>propId</code> or the passed
-     *         propId itself it is already serializable.
-     */
-    private PropertyId createSerializablePropertyId(PropertyId propId) {
-        if (propId instanceof Serializable) {
-            return propId;
-        } else {
-            return idFactory.createPropertyId(
-                    createSerializableNodeId(propId.getParentId()),
-                    propId.getQName());
         }
     }
 

Modified: jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java (original)
+++ jackrabbit/trunk/contrib/spi/spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java Tue Jul  3 08:19:01 2007
@@ -145,7 +145,6 @@
     public boolean isGranted(SessionInfo sessionInfo, ItemId itemId, String[] actions) throws RepositoryException;
 
     //------------------------------------------------------< Reading items >---
-
     /**
      * The <code>NodeId</code> of the root node may basically have two
      * characteristics. If the root node can be identified with a unique ID the
@@ -206,7 +205,36 @@
     public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws ItemNotFoundException, RepositoryException;
 
     /**
-     * Returns a collection of <code>ChildInfo</code>s present on the
+     * Method used to 'batch-read' from the persistent storage. It returns the
+     * <code>NodeInfo</code> for the given <code>NodeId</code> as the first
+     * element in the <code>Iterator</code>. In addition the iterator may contain
+     * child <code>ItemInfo</code>s down to a certain depth. The configuration
+     * process however is left to the implementation.
+     *
+     * @param sessionInfo
+     * @param nodeId
+     * @return An <code>Iterator</code> of <code>ItemInfo</code>s containing
+     * at least a single element: the <code>NodeInfo</code> that represents
+     * the Node identified by the given <code>NodeId</code>. If the Iterator
+     * contains multiple elements, the first is expected to represent the Node
+     * identified by the given <code>NodeId</code> and all subsequent elements
+     * must represent children of that <code>Node</code>.
+     * @throws javax.jcr.ItemNotFoundException
+     * @throws javax.jcr.RepositoryException
+     * @see javax.jcr.Session#getItem(String)
+     * @see javax.jcr.Node#getNode(String)
+     * @see javax.jcr.version.VersionHistory#getAllVersions()
+     * @see javax.jcr.version.VersionHistory#getVersion(String)
+     * @see javax.jcr.version.VersionHistory#getVersionByLabel(String)
+     * @see javax.jcr.version.VersionHistory#getRootVersion()
+     * @see javax.jcr.Node#getBaseVersion()
+     * @see javax.jcr.Node#getVersionHistory()
+     * @see javax.jcr.version.Version#getContainingHistory()
+     */
+    public Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId) throws ItemNotFoundException, RepositoryException;
+
+    /**
+     * Returns an Iterator of <code>ChildInfo</code>s present on the
      * Node represented by the given parentId.
      *
      * @param sessionInfo

Modified: jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java Tue Jul  3 08:19:01 2007
@@ -112,7 +112,6 @@
 import org.apache.jackrabbit.spi.Batch;
 import org.apache.jackrabbit.spi.RepositoryService;
 import org.apache.jackrabbit.spi.SessionInfo;
-import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.spi.PropertyInfo;
 import org.apache.jackrabbit.spi.QueryInfo;
 import org.apache.jackrabbit.spi.QNodeTypeDefinitionIterator;
@@ -132,6 +131,7 @@
 import org.apache.jackrabbit.spi.ChildInfo;
 import org.apache.jackrabbit.spi.QValue;
 import org.apache.jackrabbit.spi.QValueFactory;
+import org.apache.jackrabbit.spi.NodeInfo;
 import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.uuid.UUID;
 import org.apache.jackrabbit.value.ValueFormat;
@@ -787,6 +787,112 @@
                 }
             }
             return nInfo;
+        } catch (IOException e) {
+            throw new RepositoryException(e);
+        } catch (DavException e) {
+            throw ExceptionConverter.generate(e);
+        } catch (MalformedPathException e) {
+            throw new RepositoryException(e);
+        } finally {
+            if (method != null) {
+                method.releaseConnection();
+            }
+        }
+    }
+
+    /**
+     * @see RepositoryService#getItemInfos(SessionInfo, NodeId)
+     */
+    public Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId) throws ItemNotFoundException, RepositoryException {
+        // set of properties to be retrieved
+        DavPropertyNameSet nameSet = new DavPropertyNameSet();
+        nameSet.add(ItemResourceConstants.JCR_NAME);
+        nameSet.add(ItemResourceConstants.JCR_INDEX);
+        nameSet.add(ItemResourceConstants.JCR_PARENT);
+        nameSet.add(ItemResourceConstants.JCR_PRIMARYNODETYPE);
+        nameSet.add(ItemResourceConstants.JCR_MIXINNODETYPES);
+        nameSet.add(ItemResourceConstants.JCR_REFERENCES);
+        nameSet.add(ItemResourceConstants.JCR_UUID);
+        nameSet.add(ItemResourceConstants.JCR_PATH);
+        nameSet.add(DavPropertyName.RESOURCETYPE);
+
+        DavMethodBase method = null;
+        try {
+            String uri = getItemUri(nodeId, sessionInfo);
+            method = new PropFindMethod(uri, nameSet, DEPTH_1);
+            getClient(sessionInfo).executeMethod(method);
+            method.checkSuccess();
+
+            MultiStatusResponse[] responses = method.getResponseBodyAsMultiStatus().getResponses();
+            if (responses.length < 1) {
+                throw new ItemNotFoundException("Unable to retrieve the node with id " + nodeId);
+            }
+
+            MultiStatusResponse nodeResponse = null;
+            List childResponses = new ArrayList();
+            for (int i = 0; i < responses.length; i++) {
+                if (isSameResource(uri, responses[i])) {
+                    nodeResponse = responses[i];
+                } else {
+                    childResponses.add(responses[i]);
+                }
+            }
+
+            if (nodeResponse == null) {
+                throw new ItemNotFoundException("Unable to retrieve the node " + nodeId);
+            }
+
+            DavPropertySet propSet = nodeResponse.getProperties(DavServletResponse.SC_OK);
+            Object type = propSet.get(DavPropertyName.RESOURCETYPE).getValue();
+            if (type == null) {
+                // the given id points to a Property instead of a Node
+                throw new ItemNotFoundException("No node for id " + nodeId);
+            }
+
+            NamespaceResolver resolver = new NamespaceResolverImpl(sessionInfo);
+
+            NodeId parentId = getParentId(propSet, sessionInfo);
+            NodeId id = uriResolver.buildNodeId(parentId, nodeResponse, sessionInfo.getWorkspaceName());
+            NodeInfoImpl nInfo = new NodeInfoImpl(id, parentId, propSet, resolver);
+            if (propSet.contains(ItemResourceConstants.JCR_REFERENCES)) {
+                HrefProperty refProp = new HrefProperty(propSet.get(ItemResourceConstants.JCR_REFERENCES));
+                Iterator hrefIter = refProp.getHrefs().iterator();
+                while(hrefIter.hasNext()) {
+                    String propertyHref = hrefIter.next().toString();
+                    PropertyId propertyId = uriResolver.getPropertyId(propertyHref, sessionInfo);
+                    nInfo.addReference(propertyId);
+                }
+            }
+
+            List infos = new ArrayList(responses.length);
+            infos.add(nInfo);
+
+            for (Iterator it = childResponses.iterator(); it.hasNext();) {
+                MultiStatusResponse resp = (MultiStatusResponse) it.next();
+                DavPropertySet childProps = resp.getProperties(DavServletResponse.SC_OK);
+                if (childProps.contains(DavPropertyName.RESOURCETYPE) &&
+                    childProps.get(DavPropertyName.RESOURCETYPE).getValue() != null) {
+                    // any other resource type than default (empty) is represented by a node item
+                    parentId = getParentId(childProps, sessionInfo);
+                    id = uriResolver.buildNodeId(parentId, resp, sessionInfo.getWorkspaceName());
+                    nInfo = new NodeInfoImpl(id, parentId, childProps, resolver);
+                    if (childProps.contains(ItemResourceConstants.JCR_REFERENCES)) {
+                        HrefProperty refProp = new HrefProperty(childProps.get(ItemResourceConstants.JCR_REFERENCES));
+                        Iterator hrefIter = refProp.getHrefs().iterator();
+                        while(hrefIter.hasNext()) {
+                            String propertyHref = hrefIter.next().toString();
+                            PropertyId propertyId = uriResolver.getPropertyId(propertyHref, sessionInfo);
+                            nInfo.addReference(propertyId);
+                        }
+                    }
+                    infos.add(nInfo);
+                } else {
+                    PropertyId childId = uriResolver.buildPropertyId(nInfo.getId(), resp, sessionInfo.getWorkspaceName());
+                    nInfo.addPropertyId(childId);
+                    // TODO: due to missing 'value/values' property PropertyInfo cannot be built
+                }
+            }
+            return infos.iterator();
         } catch (IOException e) {
             throw new RepositoryException(e);
         } catch (DavException e) {

Added: jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java?view=auto&rev=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java (added)
+++ jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java Tue Jul  3 08:19:01 2007
@@ -0,0 +1,65 @@
+/*
+ * $Id$
+ *
+ * Copyright 1997-2005 Day Management AG
+ * Barfuesserplatz 6, 4001 Basel, Switzerland
+ * All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * Day Management AG, ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Day.
+ */
+package org.apache.jackrabbit.spi2jcr;
+
+import org.apache.jackrabbit.name.QName;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * <code>BatchReadConfig</code> defines if and how deep child item
+ * information should be retrieved, when accessing a <code>Node</code>.
+ * The configuration is based on node type names.
+ */
+public class BatchReadConfig {
+
+    public static final int DEPTH_DEFAULT = 0;
+    public static final int DEPTH_INFINITE = -1;
+
+    private Map depthMap = new HashMap(0);
+
+    /**
+     * Return the depth for the given qualified node type name. If the name is
+     * not defined in this configuration, the {@link #DEPTH_DEFAULT default value}
+     * is returned.
+     *
+     * @param ntName
+     * @return {@link #DEPTH_INFINITE -1} If all child infos should be return or
+     * any value greater than {@link #DEPTH_DEFAULT 0} if only parts of the
+     * subtree should be returned. If the given nodetype name is not defined
+     * in this configuration, the default depth {@link #DEPTH_DEFAULT 0} will
+     * be returned.
+     */
+    public int getDepth(QName ntName) {
+        if (depthMap.containsKey(ntName)) {
+            return ((Integer) (depthMap.get(ntName))).intValue();
+        } else {
+            return DEPTH_DEFAULT;
+        }
+    }
+
+    /**
+     * Define the batch-read depth for the given node type name.
+     * 
+     * @param ntName
+     * @param depth
+     */
+    public void setDepth(QName ntName, int depth) {
+        if (ntName == null || depth < DEPTH_INFINITE) {
+            throw new IllegalArgumentException();
+        }
+        depthMap.put(ntName, new Integer(depth));
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/BatchReadConfig.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Modified: jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java?view=diff&rev=552873&r1=552872&r2=552873
==============================================================================
--- jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/spi2jcr/src/main/java/org/apache/jackrabbit/spi2jcr/RepositoryServiceImpl.java Tue Jul  3 08:19:01 2007
@@ -41,8 +41,10 @@
 import org.apache.jackrabbit.name.NoPrefixDeclaredException;
 import org.apache.jackrabbit.name.NameFormat;
 import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.name.NameException;
 import org.apache.jackrabbit.value.QValueFactoryImpl;
 import org.apache.jackrabbit.value.ValueFormat;
+import org.apache.jackrabbit.JcrConstants;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Credentials;
@@ -67,6 +69,8 @@
 import javax.jcr.Workspace;
 import javax.jcr.ImportUUIDBehavior;
 import javax.jcr.Value;
+import javax.jcr.ItemVisitor;
+import javax.jcr.util.TraversingItemVisitor;
 import javax.jcr.observation.ObservationManager;
 import javax.jcr.observation.EventListener;
 import javax.jcr.query.InvalidQueryException;
@@ -108,6 +112,12 @@
     private final Repository repository;
 
     /**
+     * The configuration map used to determine the maximal depth of child
+     * items to be accessed upon a call to {@link getNodeInfo(SessionInfo, NodeId)}.
+     */
+    private final BatchReadConfig batchReadConfig;
+
+    /**
      * The id factory.
      */
     private final IdFactoryImpl idFactory = (IdFactoryImpl) IdFactoryImpl.getInstance();
@@ -128,9 +138,12 @@
      * <code>repository</code>.
      *
      * @param repository a JCR repository instance.
+     * @param batchReadConfig
+     * {@link #getNodeInfo(SessionInfo, NodeId)}.
      */
-    public RepositoryServiceImpl(Repository repository) {
+    public RepositoryServiceImpl(Repository repository, BatchReadConfig batchReadConfig) {
         this.repository = repository;
+        this.batchReadConfig = batchReadConfig;
         this.supportsObservation = "true".equals(repository.getDescriptor(Repository.OPTION_OBSERVATION_SUPPORTED));
     }
 
@@ -296,8 +309,47 @@
     public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId)
             throws ItemNotFoundException, RepositoryException {
         SessionInfoImpl sInfo = getSessionInfoImpl(sessionInfo);
-        return new NodeInfoImpl(getNode(nodeId, sInfo),
-                idFactory, sInfo.getNamespaceResolver());
+        Node node = getNode(nodeId, sInfo);
+        NodeInfo info = new NodeInfoImpl(node, idFactory, sInfo.getNamespaceResolver());
+        return info;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId)
+            throws ItemNotFoundException, RepositoryException {
+        final SessionInfoImpl sInfo = getSessionInfoImpl(sessionInfo);
+        Node node = getNode(nodeId, sInfo);
+        QName ntName = null;
+        try {
+            ntName = NameFormat.parse(node.getProperty(JcrConstants.JCR_PRIMARYTYPE).getString(), sInfo.getNamespaceResolver());
+        } catch (NameException e) {
+            // ignore. should never occur
+        }
+        int depth = batchReadConfig.getDepth(ntName);
+        if (depth == BatchReadConfig.DEPTH_DEFAULT) {
+            NodeInfo info = new NodeInfoImpl(node, idFactory, sInfo.getNamespaceResolver());
+            return Collections.singletonList(info).iterator();
+        } else {
+            final List itemInfos = new ArrayList();
+            ItemVisitor visitor = new TraversingItemVisitor(false, depth) {
+                protected void entering(Property property, int i) throws RepositoryException {
+                    itemInfos.add(new PropertyInfoImpl(property, idFactory, sInfo.getNamespaceResolver(), getQValueFactory()));
+                }
+                protected void entering(Node node, int i) throws RepositoryException {
+                    itemInfos.add(new NodeInfoImpl(node, idFactory, sInfo.getNamespaceResolver()));
+                }
+                protected void leaving(Property property, int i) {
+                    // nothing to do
+                }
+                protected void leaving(Node node, int i) {
+                    // nothing to do
+                }
+            };
+            visitor.visit(node);
+            return itemInfos.iterator();
+        }
     }
 
     /**



Mime
View raw message