jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r704361 [1/5] - in /jackrabbit/trunk: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/o...
Date Tue, 14 Oct 2008 07:48:24 GMT
Author: angela
Date: Tue Oct 14 00:48:22 2008
New Revision: 704361

URL: http://svn.apache.org/viewvc?rev=704361&view=rev
Log:
JCR-1799 updating events swallowed (CacheBehavior.OBSERVATION)   	
JCR-1783 incomplete changelog when combining move with removal of new destination parent

Added:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AddPropertyTest.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ExternalModificationTest.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetPropertyTest.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MixinModificationTest.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveCombinedTest.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveToNewTest.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RemoveMovedNodeTest.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeAttic.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryValidation.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManager.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManagerImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/PropertyEntry.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/PropertyEntryImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/UniqueIdResolver.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AbstractCopy.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AbstractOperation.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddNode.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddProperty.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkin.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Checkout.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Clone.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Copy.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/LockOperation.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/LockRefresh.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/LockRelease.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Merge.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Operation.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Remove.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveVersion.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ReorderNodes.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/ResolveMergeConflict.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Restore.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetPropertyValue.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Update.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/WorkspaceImport.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientISFactory.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateFactory.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/LogUtil.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/StateUtility.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/HierarchyNodeTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/MoveNewTreeTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/NodeOrderTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshMovedTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RefreshTrueTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RemoveNodeTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ReorderMoveTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/RevertMoveTest.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/nodetype/AddMixinTest.java
    jackrabbit/trunk/jackrabbit-spi2jcr/pom.xml
    jackrabbit/trunk/jackrabbit-spi2jcr/src/test/java/org/apache/jackrabbit/spi2jcr/RepositoryStubImpl.java

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java Tue Oct 14 00:48:22 2008
@@ -236,15 +236,16 @@
     public void refresh(boolean keepChanges) throws InvalidItemStateException, RepositoryException {
         // check session status
         session.checkIsAlive();
+        int status = state.getStatus();
         // check if item has been removed by this or another session
-        if (Status.isTerminal(state.getStatus()) || Status.EXISTING_REMOVED == state.getStatus()) {
+        if (Status.isTerminal(status) || Status.EXISTING_REMOVED == status) {
             throw new InvalidItemStateException("Item '" + this + "' doesn't exist anymore");
         }
 
         /* If 'keepChanges' is true, items that do not have changes pending have
            their state refreshed to reflect the current saved state */
         if (keepChanges) {
-            if (state.getStatus() != Status.NEW  &&
+            if (status != Status.NEW  &&
                 session.getCacheBehaviour() != CacheBehaviour.OBSERVATION) {
                 // merge current transient modifications with latest changes
                 // from the 'server'.
@@ -254,7 +255,7 @@
             }
         } else {
             // check status of item state
-            if (state.getStatus() == Status.NEW) {
+            if (status == Status.NEW) {
                 String msg = "Cannot refresh a new item (" + safeGetJCRPath() + ").";
                 log.debug(msg);
                 throw new RepositoryException(msg);
@@ -416,7 +417,7 @@
         }
         // now check if valid
         if (!state.isValid()) {
-            throw new InvalidItemStateException("Item '" + this + "' doesn't exist anymore");
+            throw new InvalidItemStateException("Item '" + this + "' doesn't exist anymore. (Status = " +Status.getName(state.getStatus())+ ")");
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java Tue Oct 14 00:48:22 2008
@@ -127,12 +127,8 @@
             HierarchyEntry entry = (HierarchyEntry) iter.next();
             try {
                 nextItem = itemMgr.getItem(entry);
-            } catch (ItemNotFoundException e) {
-                log.debug("Ignoring nonexistent item " + entry);
-                // reduce the size ... and try the next one
-                size--;
             } catch (RepositoryException e) {
-                log.error("failed to fetch item " + entry + ", skipping...", e);
+                log.warn("Failed to fetch item " + entry + ", skipping.", e.getMessage());
                 // reduce the size... and try the next one
                 size--;
             }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java Tue Oct 14 00:48:22 2008
@@ -1272,17 +1272,9 @@
         Operation an = AddNode.create(getNodeState(), nodeName, nodeTypeName, null);
         session.getSessionItemStateManager().execute(an);
 
-        // retrieve id of state that has been created during execution of AddNode
-        NodeEntry entry;
-        List cne = getNodeEntry().getNodeEntries(nodeName);
-        if (definition.allowsSameNameSiblings()) {
-            // TODO TOBEFIXED find proper solution. problem with SNSs
-            entry = ((NodeEntry)cne.get(cne.size()-1));
-        } else {
-            entry = ((NodeEntry)cne.get(0));
-        }
         // finally retrieve the new node
-        return (Node) itemMgr.getItem(entry);
+        List addedStates = ((AddNode) an).getAddedStates();
+        return (Node) itemMgr.getItem(((NodeState) addedStates.get(0)).getHierarchyEntry());
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java Tue Oct 14 00:48:22 2008
@@ -703,7 +703,7 @@
             try {
                 ItemState target = changeLog.getTarget();
                 batch = service.createBatch(sessionInfo, target.getId());
-                Iterator it = changeLog.getOperations();
+                Iterator it = changeLog.getOperations().iterator();
                 while (it.hasNext()) {
                     Operation op = (Operation) it.next();
                     log.debug("executing " + op.getName());

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeAttic.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeAttic.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeAttic.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeAttic.java Tue Oct 14 00:48:22 2008
@@ -116,12 +116,17 @@
         attic.add(movedEntry);
     }
 
-    void remove(NodeEntryImpl movedEntry) {
+    boolean remove(NodeEntryImpl movedEntry) {
         if (attic.contains(movedEntry)) {
-            attic.remove(movedEntry);
+            return attic.remove(movedEntry);
         }
+        return false;
     }
 
+    Iterator iterator() {
+        return attic.iterator();
+    }
+    
     void clear() {
         if (attic != null) {
             attic.clear();

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java Tue Oct 14 00:48:22 2008
@@ -18,7 +18,6 @@
 
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
-import org.apache.jackrabbit.spi.ChildInfo;
 
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.RepositoryException;
@@ -33,6 +32,13 @@
 public interface ChildNodeEntries {
 
     /**
+     * @return <code>true</code> if this <code>ChildNodeEntries</code> have
+     * been updated or completely loaded without being invalidated in the
+     * mean time.
+     */
+    boolean isComplete();
+
+    /**
      * Mark <code>ChildNodeEntries</code> in order to force reloading the
      * entries.
      */
@@ -88,16 +94,6 @@
     NodeEntry get(Name nodeName, String uniqueID);
 
     /**
-     * Find the matching NodeEntry for the given <code>ChildInfo</code>. Returns
-     * <code>null</code> if no matching entry can be found. NOTE, that no check
-     * for validity of the entries is made.
-     *
-     * @param childInfo
-     * @return matching entry or <code>null</code>.
-     */
-    NodeEntry get(ChildInfo childInfo);
-
-    /**
      * Adds a <code>NodeEntry</code> to the end of the list. Same as
      * {@link #add(NodeEntry, int)}, where the index is {@link Path#INDEX_UNDEFINED}.
      *
@@ -123,9 +119,10 @@
      * Adds a the new  <code>NodeEntry</code> before <code>beforeEntry</code>.
      *
      * @param entry
+     * @param index
      * @param beforeEntry
      */
-    void add(NodeEntry entry, NodeEntry beforeEntry);
+    void add(NodeEntry entry, int index, NodeEntry beforeEntry);
 
     /**
      * Removes the child node entry refering to the node state.

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java Tue Oct 14 00:48:22 2008
@@ -65,33 +65,6 @@
     private final NodeEntry parent;
     private final EntryFactory factory;
 
-    /**
-     * Create a new <code>ChildNodeEntries</code> collection and retrieve
-     * the entries from the persistent layer if the parent is neither
-     * NEW nor in a terminal status.
-     */
-    ChildNodeEntriesImpl(NodeEntry parent, EntryFactory factory) throws ItemNotFoundException, RepositoryException {
-        this.parent = parent;
-        this.factory = factory;
-
-        if (parent.getStatus() != Status.NEW && !Status.isTerminal(parent.getStatus())) {
-            NodeId id = parent.getWorkspaceId();
-            Iterator childNodeInfos = factory.getItemStateFactory().getChildNodeInfos(id);
-            // simply add all child entries to the empty collection
-            while (childNodeInfos.hasNext()) {
-                ChildInfo ci = (ChildInfo) childNodeInfos.next();
-                NodeEntry entry = factory.createNodeEntry(parent, ci.getName(), ci.getUniqueID());
-                add(entry, ci.getIndex());
-            }
-        } /* else: cannot retrieve child-entries from persistent layer. the parent
-           * is NEW (transient only) or already removed from the persistent layer.
-           */
-
-        /* all child infos have been read from the persistent layer therefore
-           mark this child-node-entries as 'complete' */
-        complete = true;
-    }
-
      /**
       * Create a new <code>ChildNodeEntries</code> collection from the given
       * <code>childNodeInfos</code> instead of retrieving them from the
@@ -122,10 +95,24 @@
      }
 
     /**
-     * @see ChildNodeEntries#getStatus()
+     * @param childEntry
+     * @return The node entry that directly follows the given <code>childEntry</code>
+     * or <code>null</code> if the given <code>childEntry</code> has no successor
+     * or was not found in this <code>ChildNodeEntries</code>.
+     */
+    NodeEntry getNext(NodeEntry childEntry) {
+        LinkedEntries.LinkNode ln = entries.getLinkNode(childEntry);
+        LinkedEntries.LinkNode nextLn = (ln == null) ? null : ln.getNextLinkNode();
+        return (nextLn == null) ? null : nextLn.getNodeEntry();
+    }
+
+    /**
+     * @see ChildNodeEntries#isComplete()
      */
-    public int getStatus() {
-        return status;
+    public boolean isComplete() {
+        return (status == STATUS_OK && complete) ||
+                parent.getStatus() == Status.NEW ||
+                Status.isTerminal(parent.getStatus());
     }
 
     /**
@@ -139,8 +126,7 @@
      * @see ChildNodeEntries#reload()
      */
     public synchronized void reload() throws ItemNotFoundException, RepositoryException {
-        if (status == STATUS_OK && complete ||
-            parent.getStatus() == Status.NEW || Status.isTerminal(parent.getStatus())) {
+        if (isComplete()) {
             // nothing to do
             return;
         }
@@ -150,45 +136,38 @@
         update(childNodeInfos);
     }
 
+    /**
+     * Update the child node entries according to the child-infos obtained
+     * from the persistent layer.
+     * NOTE: the status of the entries already present is not respected. Thus
+     * new or removed entries are not touched in order not to modify the
+     * transient status of the parent. Operations that affect the set or order
+     * of child entries (AddNode, Move, Reorder) currently assert the
+     * completeness of the ChildNodeEntries, therefore avoiding an update
+     * resulting in inconsistent entries.
+     *
+     * @param childNodeInfos
+     * @see HierarchyEntry#reload(boolean, boolean) that ignores items with
+     * pending changes.
+     * @see org.apache.jackrabbit.jcr2spi.operation.AddNode
+     * @see org.apache.jackrabbit.jcr2spi.operation.Move
+     * @see org.apache.jackrabbit.jcr2spi.operation.Reorder
+     */
     synchronized void update(Iterator childNodeInfos) {
-        // TODO: should existing (not-new) entries that are not present in the childInfos be removed?
-        // create list from all ChildInfos (for multiple loop)
-        List cInfos = new ArrayList();
+        // insert missing entries and reorder all if necessary.
+        LinkedEntries.LinkNode prevLN = null;
         while (childNodeInfos.hasNext()) {
-            cInfos.add(childNodeInfos.next());
-        }
-        // first make sure the ordering of all existing entries is ok
-        NodeEntry entry = null;
-        for (Iterator it = cInfos.iterator(); it.hasNext();) {
-            ChildInfo ci = (ChildInfo) it.next();
-            NodeEntry nextEntry = get(ci);
-            if (nextEntry != null) {
-                if (entry != null) {
-                    reorder(entry, nextEntry);
-                }
-                entry = nextEntry;
-            }
-        }
-        // then insert the 'new' entries
-        List newEntries = new ArrayList();
-        for (Iterator it = cInfos.iterator(); it.hasNext();) {
-            ChildInfo ci = (ChildInfo) it.next();
-            NodeEntry beforeEntry = get(ci);
-            if (beforeEntry == null) {
-                NodeEntry ne = factory.createNodeEntry(parent, ci.getName(), ci.getUniqueID());
-                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++) {
-                    add((NodeEntry) newEntries.get(i), beforeEntry);
-                }
-                newEntries.clear();
-            }
-        }
-        // deal with new entries at the end
-        for (int i = 0; i < newEntries.size(); i++) {
-            add((NodeEntry) newEntries.get(i));
+            ChildInfo ci = (ChildInfo) childNodeInfos.next();
+            LinkedEntries.LinkNode ln = entriesByName.getLinkNode(ci.getName(), ci.getIndex(), ci.getUniqueID());
+            if (ln == null) {
+                // add missing at the correct position.
+                NodeEntry entry = factory.createNodeEntry(parent, ci.getName(), ci.getUniqueID());
+                ln = internalAddAfter(entry, ci.getIndex(), prevLN);
+            } else if (prevLN != null) {
+                // assert correct order of existing
+                reorderAfter(ln, prevLN);
+            }
+            prevLN = ln;
         }
         // finally reset the status
         status = STATUS_OK;
@@ -241,26 +220,6 @@
     }
 
     /**
-     * @see ChildNodeEntries#get(ChildInfo)
-     */
-    public NodeEntry get(ChildInfo childInfo) {
-        String uniqueID = childInfo.getUniqueID();
-        NodeEntry child = null;
-        if (uniqueID != null) {
-            child = get(childInfo.getName(), uniqueID);
-        }
-        // try to load the child entry by name and index.
-        // this is required in case of a null uniqueID OR if the child entry has
-        // been created but never been resolved and therefore the uniqueID might
-        // be unknown.
-        if (child == null) {
-            int index = childInfo.getIndex();
-            child = entriesByName.getNodeEntry(childInfo.getName(), index);
-        }
-        return child;
-    }
-
-    /**
      * Adds a <code>NodeEntry</code> to the end of the list. Same as
      * {@link #add(NodeEntry, int)}, where the index is {@link Path#INDEX_UNDEFINED}.
      *
@@ -282,6 +241,24 @@
     }
 
     /**
+     * @see ChildNodeEntries#add(NodeEntry, int, NodeEntry)
+     */
+    public synchronized void add(NodeEntry entry, int index, NodeEntry beforeEntry) {
+        if (beforeEntry != null) {
+            // the link node where the new entry is ordered before
+            LinkedEntries.LinkNode beforeLN = entries.getLinkNode(beforeEntry);
+            if (beforeLN == null) {
+                throw new NoSuchElementException();
+            }
+            LinkedEntries.LinkNode insertLN = internalAdd(entry, index);
+            reorder(entry.getName(), insertLN, beforeLN);
+        } else {
+            // 'before' is null -> simply append new entry at the end
+            add(entry);
+        }
+    }
+
+    /**
      *
      * @param entry
      * @param index
@@ -308,8 +285,8 @@
         }
 
         // add new entry
-        LinkedEntries.LinkNode ln = entries.add(entry);
-        entriesByName.put(nodeName, ln);
+        LinkedEntries.LinkNode ln = entries.add(entry, index);
+        entriesByName.put(nodeName, index, ln);
 
         // reorder the child entries if, the new entry must be inserted rather
         // than appended at the end of the list.
@@ -320,21 +297,18 @@
     }
 
     /**
-     * @see ChildNodeEntries#add(NodeEntry, NodeEntry)
+     * Add the specified new entry after the specified <code>insertAfter</code>.
+     *
+     * @param newEntry
+     * @param index
+     * @param insertAfter
+     * @return
      */
-    public synchronized void add(NodeEntry entry, NodeEntry beforeEntry) {
-        if (beforeEntry != null) {
-            // the link node where the new entry is ordered before
-            LinkedEntries.LinkNode beforeLN = entries.getLinkNode(beforeEntry);
-            if (beforeLN == null) {
-                throw new NoSuchElementException();
-            }
-            LinkedEntries.LinkNode insertLN = internalAdd(entry, Path.INDEX_UNDEFINED);
-            reorder(entry.getName(), insertLN, beforeLN);
-        } else {
-            // 'before' is null -> simply append new entry at the end
-            add(entry);
-        }
+    private LinkedEntries.LinkNode internalAddAfter(NodeEntry newEntry, int index,
+                                                    LinkedEntries.LinkNode insertAfter) {
+        LinkedEntries.LinkNode ln = entries.addAfter(newEntry, index, insertAfter);
+        entriesByName.put(newEntry.getName(), index, ln);
+        return ln;
     }
 
     /**
@@ -411,7 +385,7 @@
                     LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
                     if (ln == beforeLN) {
                         break;
-                    } else if (ln != insertLN && ln.getNodeEntry().getName().equals(insertName)) {
+                    } else if (ln != insertLN && insertName.equals(ln.qName)) {
                         position++;
                     } // else: ln == inserLN OR no SNS -> not relevant for position count
                 }
@@ -422,6 +396,60 @@
         entries.reorderNode(insertLN, beforeLN);
     }
 
+    /**
+     *
+     * @param insertEntry
+     * @param afterEntry
+     */
+    private void reorderAfter(LinkedEntries.LinkNode insertLN, LinkedEntries.LinkNode afterLN) {
+        // the link node to move
+        if (insertLN == null) {
+            throw new NoSuchElementException();
+        }
+        // the link node where insertLN is ordered after
+        if (afterLN == null) {
+            // move to first position
+            afterLN = entries.getHeader();
+        }
+
+        LinkedEntries.LinkNode currentAfter = afterLN.getNextLinkNode();
+        if (currentAfter == insertLN) {
+            log.debug("Already ordered behind 'afterEntry'.");
+            // nothing to do
+            return;
+        } else {
+            // reorder named map
+            Name insertName = insertLN.qName;
+            if (entriesByName.containsSiblings(insertName)) {
+                int position = -1; // default: reorder to the end.
+                if (afterLN == entries.getHeader()) {
+                    // move to the beginning
+                    position = 0;
+                } else {
+                    // count all SNS-entries that are before 'afterLN' in order to
+                    // determine the new position of the reordered node regarding
+                    // his siblings.
+                    position = 0;
+                    for (Iterator it = entries.linkNodeIterator(); it.hasNext(); ) {
+                        LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
+                        if (!insertName.equals(ln.qName)) {
+                            continue; // not a SNS -> not relevant for position count
+                        }
+                        if (ln != insertLN) {
+                            position++;
+                        } // ln == inserLN -> not relevant for position count
+                        if (ln == afterLN) {
+                            break;
+                        }
+                    }
+                }
+                entriesByName.reorder(insertName, insertLN, position);
+            }
+            // reorder in linked list
+            entries.reorderNode(insertLN, afterLN.getNextLinkNode());
+        }
+    }
+
     //-------------------------------------------------< AbstractLinkedList >---
     /**
      * An implementation of a linked list which provides access to the internal
@@ -455,19 +483,49 @@
             return null;
         }
 
+        private LinkedEntries.LinkNode getHeader() {
+            return (LinkedEntries.LinkNode) header;
+        }
+
         /**
-         * Adds a child node entry to this list.
+         * Adds a child node entry at the end of this list.
          *
          * @param cne the child node entry to add.
+         * @param index
          * @return the LinkNode which refers to the added <code>NodeEntry</code>.
          */
-        LinkedEntries.LinkNode add(NodeEntry cne) {
-            LinkedEntries.LinkNode ln = new LinkedEntries.LinkNode(cne);
+        LinkedEntries.LinkNode add(NodeEntry cne, int index) {
+            LinkedEntries.LinkNode ln = new LinkedEntries.LinkNode(cne, index);
             addNode(ln, header);
             return ln;
         }
 
         /**
+         * Adds the given child node entry to this list after the specified
+         * <code>entry</code> or at the beginning if <code>entry</code> is
+         * <code>null</code>.
+         *
+         * @param cne the child node entry to add.
+         * @param index
+         * @param node after which to insert the new entry
+         * @return the LinkNode which refers to the added <code>NodeEntry</code>.
+         */
+        LinkedEntries.LinkNode addAfter(NodeEntry cne, int index, LinkedEntries.LinkNode insertAfter) {
+            LinkedEntries.LinkNode newNode;
+            if (insertAfter == null) {
+                // insert at the beginning
+                newNode = new LinkedEntries.LinkNode(cne, index);
+                addFirst(cne);
+            } else if (insertAfter.getNextLinkNode() == null) {
+                newNode = add(cne, index);
+            } else {
+                newNode = new LinkedEntries.LinkNode(cne, index);
+                addNode(newNode, insertAfter.getNextLinkNode());
+            }
+            return newNode;
+        }
+
+        /**
          * Remove the LinkEntry the contains the given NodeEntry as value.
          *
          * @param cne NodeEntry to be removed.
@@ -507,7 +565,7 @@
          * @see AbstractLinkedList#createNode(Object)
          */
         protected Node createNode(Object value) {
-            return new LinkedEntries.LinkNode(value);
+            return new LinkedEntries.LinkNode(value, Path.INDEX_DEFAULT);
         }
 
         /**
@@ -538,8 +596,10 @@
                 qName = null;
             }
 
-            protected LinkNode(Object value) {
-                super(new WeakReference(value));
+            protected LinkNode(Object value, int index) {
+                // add weak reference from linkNode to the NodeEntry (value)
+                // unless the entry is a SNSibling. TODO: review again.
+                super(index > Path.INDEX_DEFAULT ? value : new WeakReference(value));
                 qName = ((NodeEntry) value).getName();
             }
 
@@ -548,10 +608,17 @@
             }
 
             protected Object getValue() {
-                Reference val = (Reference) super.getValue();
+                Object val = super.getValue();
+                NodeEntry ne;
+                if (val == null) {
+                    ne = null;
+                } else if (val instanceof Reference) {
+                    ne = (NodeEntry) ((Reference) val).get();
+                } else {
+                    ne = (NodeEntry) val;
+                }
                 // if the nodeEntry has been g-collected in the mean time
                 // create a new NodeEntry in order to avoid returning null.
-                NodeEntry ne = (val == null) ?  null : (NodeEntry) val.get();
                 if (ne == null && this != header) {
                     ne = factory.createNodeEntry(parent, qName, null);
                     super.setValue(new WeakReference(ne));
@@ -715,7 +782,35 @@
             }
         }
 
-        public void put(Name qName, LinkedEntries.LinkNode value) {
+        public LinkedEntries.LinkNode getLinkNode(Name qName, int index, String uniqueID) {
+            if (uniqueID != null) {
+                // -> try if any entry matches.
+                // if none matches it be might that entry doesn't have uniqueID
+                // set yet -> search without uniqueID
+                LinkedEntries.LinkNode val = (LinkedEntries.LinkNode) nameMap.get(qName);
+                if (val != null) {
+                    if (uniqueID.equals(val.getNodeEntry().getUniqueID())) {
+                        return val;
+                    }
+                } else {
+                    // look in snsMap
+                    List l = (List) snsMap.get(qName);
+                    if (l != null) {
+                        for (Iterator it = l.iterator(); it.hasNext();) {
+                            LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
+                            if (uniqueID.equals(ln.getNodeEntry().getUniqueID())) {
+                                return ln;
+                            }
+                        }
+                    }
+                }
+            }
+            // no uniqueID passed or not match.
+            // try to load the child entry by name and index.
+            return getLinkNode(qName, index);
+        }
+
+        public void put(Name qName, int index, LinkedEntries.LinkNode value) {
             // if 'nameMap' already contains a single entry -> move it to snsMap
             LinkedEntries.LinkNode single = (LinkedEntries.LinkNode) nameMap.remove(qName);
             List l;
@@ -729,9 +824,16 @@
             }
 
             if (l == null) {
+                // no same name siblings -> simply put to the name map.
                 nameMap.put(qName, value);
             } else {
-                l.add(value);
+                // sibling(s) already present -> insert into the list
+                int position = index - 1;
+                if (position < 0 || position > l.size()) {
+                    l.add(value); // invalid position -> append at the end.
+                } else {
+                    l.add(position, value); // insert with the correct index.
+                }
             }
         }
 
@@ -753,12 +855,11 @@
                 return;
             }
             // reorder sns in the name-list
-            if (position < 0) {
+            sns.remove(insertValue);
+            if (position < 0 || position > sns.size()) {
                 // simply move to end of list
-                sns.remove(insertValue);
                 sns.add(insertValue);
             } else {
-                sns.remove(insertValue);
                 sns.add(position, insertValue);
             }
         }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java Tue Oct 14 00:48:22 2008
@@ -75,9 +75,9 @@
     /**
      * Remove the collection entry with the given <code>Name</code>.
      *
-     * @param propertyName
-     * @return true If this <code>ChildPropertyEntries</code> contained any
-     * entry with the given <code>Name</code>. False otherwise.
+     * @param propertyEntry
+     * @return true If this <code>ChildPropertyEntries</code> contained the
+     * given entry. False otherwise.
      */
-    public boolean remove(Name propertyName);
+    public boolean remove(PropertyEntry propertyEntry);
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java Tue Oct 14 00:48:22 2008
@@ -115,9 +115,16 @@
     }
 
     /**
-     * @see ChildPropertyEntries#remove(Name)
+     * @see ChildPropertyEntries#remove(PropertyEntry)
      */
-    public boolean remove(Name propertyName) {
-        return properties.remove(propertyName) != null;
+    public boolean remove(PropertyEntry propertyEntry) {
+        Name pName = propertyEntry.getName();
+        PropertyEntry pe = get(pName);
+        if (pe == propertyEntry) {
+            properties.remove(pName);
+            return true;
+        } else {
+            return false;
+        }
     }
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryValidation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryValidation.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryValidation.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryValidation.java Tue Oct 14 00:48:22 2008
@@ -18,6 +18,7 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.jcr2spi.state.Status;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.ItemNotFoundException;
@@ -81,6 +82,23 @@
     }
 
     /**
+     * Returns <code>true</code> if the given childnode entry is not
+     * <code>null</code> and resolves to a NodeState, that is neither NEW
+     * nor REMOVED.
+     *
+     * @param cne NodeEntry to check.
+     * @return <code>true</code> if the given entry is valid.
+     */
+    static boolean isValidWorkspaceNodeEntry(NodeEntry cne) {
+        // shortcut.
+        if (cne == null) {
+            return false;
+        }
+        int status = cne.getStatus();
+        return status != Status.NEW && status != Status.REMOVED;
+    }
+
+    /**
      * Returns <code>true</code> if the given childproperty entry is not
      * <code>null</code> and resolves to a PropertyState, that is valid or if the
      * childproperty entry has not been resolved up to now (assuming the corresponding
@@ -101,7 +119,7 @@
                 // may occur if the cached state is marked 'INVALIDATED' and
                 // does not exist any more on the persistent layer -> invalid.
             } catch (RepositoryException e) {
-                // probably deleted in the meantime. should not occur.
+                // probably removed in the meantime. should not occur.
             }
         } else {
             // assume entry is valid // TODO check if this assumption is correct.

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntry.java Tue Oct 14 00:48:22 2008
@@ -19,8 +19,8 @@
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 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.operation.Operation;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.InvalidItemStateException;
@@ -106,9 +106,8 @@
      * Set the ItemState this hierarchyEntry will be resolved to.
      *
      * @param state
-     * @throws IllegalStateException If the entry has already been resolved.
      */
-    public void setItemState(ItemState state) throws IllegalStateException;
+    public void setItemState(ItemState state);
 
     /**
      * Invalidates the underlying <code>ItemState</code> if available. If the
@@ -133,7 +132,7 @@
     /**
      * Reloads this hierarchy entry and the corresponding ItemState, if this
      * entry has already been resolved. If '<code>keepChanges</code>' is true,
-     * states with transient changes are left untouched in order to obtain stale
+     * states with transient changes are left untouched in order to detect stale
      * item states. Otherwise this state gets its data reloaded from the
      * persistent storage. If '<code>recursive</code>' the complete hierarchy
      * below this entry is reloaded as well.
@@ -165,18 +164,9 @@
     public void remove();
 
     /**
-     * Checks if the underlying <code>ItemState</code> is available and if it
-     * has been transiently modified or if is new or stale modified. If either of
-     * the conditions is true, the state is added to the <code>ChangeLog</code>.
-     * If this <code>HierarchyEntry</code> has children it will call
-     * {@link #collectStates(ChangeLog, boolean)} recursively.
-     *
-     * @param changeLog the <code>ChangeLog</code> collecting the transient
-     * item states present in a given tree.
-     * @param throwOnStale If the given flag is true, this methods throws
-     * InvalidItemStateException if this state is stale.
-     * @throws InvalidItemStateException if <code>throwOnStale</code> is true and
-     * this state is stale.
+     * Clean up this entry upon {@link Operation#undo()} or {@link Operation#persisted()}.
+     *
+     * @param transientOperation
      */
-    public void collectStates(ChangeLog changeLog, boolean throwOnStale) throws InvalidItemStateException;
+    public void complete(Operation transientOperation) throws RepositoryException;
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java Tue Oct 14 00:48:22 2008
@@ -16,17 +16,17 @@
  */
 package org.apache.jackrabbit.jcr2spi.hierarchy;
 
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.Path;
 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.ItemStateFactory;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
 import javax.jcr.InvalidItemStateException;
 import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
 import java.lang.ref.WeakReference;
 
 /**
@@ -93,8 +93,9 @@
         if (state == null) {
             try {
                 state = doResolve();
-                // only set 'target' if not already by upon resolution
-                if (!isAvailable()) {
+                // set the item state unless 'setItemState' has already been
+                // called by the ItemStateFactory (recall internalGetItemState)
+                if (internalGetItemState() == null) {
                     setItemState(state);
                 }
             } catch (ItemNotFoundException e) {
@@ -129,7 +130,6 @@
     abstract Path buildPath(boolean workspacePath) throws RepositoryException;
 
     /**
-     *
      * @return
      */
     ItemState internalGetItemState() {
@@ -140,16 +140,6 @@
         return state;
     }
 
-    /**
-     *
-     * @param entry
-     */
-    static void removeEntry(HierarchyEntryImpl entry) {
-        ItemState state = entry.internalGetItemState();
-        if (state != null) {
-            state.setStatus(Status.REMOVED);
-        }
-    }
     //-----------------------------------------------------< HierarchyEntry >---
     /**
      * @inheritDoc
@@ -218,13 +208,26 @@
      * @see HierarchyEntry#setItemState(ItemState)
      */
     public synchronized void setItemState(ItemState state) {
-        if (state == null || (denotesNode() && !state.isNode()) || (!denotesNode() && state.isNode())) {
+        ItemState currentState = internalGetItemState();
+        if (state == null || state == currentState || denotesNode() != state.isNode()) {
             throw new IllegalArgumentException();
         }
-        if (isAvailable()) {
-            throw new IllegalStateException("HierarchyEntry has already been resolved.");
+        if (currentState == null) {
+            // not connected yet to an item state. either a new entry or
+            // an unresolved hierarchy entry.
+            target = new WeakReference(state);
+        } else {
+            // was already resolved before -> merge the existing state
+            // with the passed state.
+            int currentStatus = currentState.getStatus();
+            boolean keepChanges = Status.isTransient(currentStatus) || Status.isStale(currentStatus);
+            boolean modified = currentState.merge(state, keepChanges);
+            if (currentStatus == Status.INVALIDATED) {
+                currentState.setStatus(Status.EXISTING);
+            } else if (modified) {
+                currentState.setStatus(Status.MODIFIED);
+            } // else: not modified. just leave status as it is.
         }
-        target = new WeakReference(state);
     }
 
     /**
@@ -234,10 +237,7 @@
     public void invalidate(boolean recursive) {
         ItemState state = internalGetItemState();
         if (state != null) {
-            // session-state TODO: only invalidate if existing?
-            if (state.getStatus() == Status.EXISTING) {
-                state.setStatus(Status.INVALIDATED);
-            }
+            state.setStatus(Status.INVALIDATED);
         }
     }
 
@@ -256,53 +256,71 @@
         switch (oldStatus) {
             case Status.EXISTING_MODIFIED:
             case Status.STALE_MODIFIED:
-                // revert state from overlayed
+                // revert state modifications
                 state.revert();
                 state.setStatus(Status.EXISTING);
                 break;
             case Status.EXISTING_REMOVED:
-                // revert state from overlayed
+                // revert state modifications
                 state.revert();
                 state.setStatus(Status.EXISTING);
-                if (!denotesNode()) {
-                    parent.revertPropertyRemoval((PropertyEntry) this);
-                }
                 break;
             case Status.NEW:
                 // reverting a NEW state is equivalent to its removal.
-                remove();
+                // however: don't remove the complete hierarchy
+                state.setStatus(Status.REMOVED);
+                parent.internalRemoveChildEntry(this);
                 break;
             case Status.STALE_DESTROYED:
-                // overlayed does not exist any more -> remove it
+                // overlayed does not exist any more -> reverting of pending
+                // transient changes (that lead to the stale status) can be
+                // omitted and the entry is complete removed instead.
                 remove();
                 break;
             default:
                 // Cannot revert EXISTING, REMOVED, INVALIDATED, MODIFIED states.
-                // State was implicitely reverted
+                // State was implicitely reverted or external modifications
+                // reverted the modification.
                 log.debug("State with status " + oldStatus + " cannot be reverted.");
         }
     }
 
-     /**
+    /**
      * {@inheritDoc}
      * @see HierarchyEntry#reload(boolean, boolean)
      */
     public void reload(boolean keepChanges, boolean recursive) {
-        ItemState state = internalGetItemState();
-        if (state == null) {
-            // nothing to do. entry will be validated upon resolution.
+        int status = getStatus();
+        if (status == Status._UNDEFINED_) {
+            // unresolved: entry will be loaded and validated upon resolution.
+            return;
+        }
+        if (Status.isTransient(status) || Status.isStale(status) || Status.isTerminal(status)) {
+            // transient || stale: avoid reloading
+            // new || terminal: cannot be reloaded from persistent layer anyway.
+            log.debug("Skip reload for item with status " + Status.getName(status) + ".");
             return;
         }
-        /*
-        if keepChanges is true only existing or invalidated states must be
-        updated. otherwise the state gets updated and might be marked 'Stale'
-        if transient changes are present and the workspace-state is modified.
-        */
-        // TODO: check again if 'reload' is not possible for transiently-modified state
-        if (!keepChanges || state.getStatus() == Status.EXISTING
-            || state.getStatus() == Status.INVALIDATED) {
-            // reload the workspace state from the persistent layer
-            state.reload(keepChanges);
+        /**
+         * Retrieved a fresh ItemState from the persistent layer. Which will
+         * then be merged into the current state.
+         */
+        try {
+            ItemStateFactory isf = factory.getItemStateFactory();
+            if (denotesNode()) {
+                NodeEntry ne = (NodeEntry) this;
+                isf.createNodeState(ne.getWorkspaceId(), ne);
+            } else {
+                PropertyEntry pe = (PropertyEntry) this;
+                isf.createPropertyState(pe.getWorkspaceId(), pe);
+            }
+        } catch (ItemNotFoundException e) {
+            // remove hierarchyEntry including all children
+            log.debug("Item '" + getName() + "' cannot be found on the persistent layer -> remove.");
+            remove();
+        } catch (RepositoryException e) {
+            // TODO: rather throw?
+            log.error("Exception while reloading item: " + e);
         }
     }
 
@@ -320,15 +338,12 @@
         // it in order to determine the current status.
         if (state.getStatus() == Status.INVALIDATED) {
             reload(false, false);
-            // check if upon reload the item has been removed -> nothing to do
-            if (Status.isTerminal(state.getStatus())) {
-                return;
-            }
         }
 
         switch (state.getStatus()) {
             case Status.NEW:
-                remove();
+                state.setStatus(Status.REMOVED);
+                parent.internalRemoveChildEntry(this);
                 break;
             case Status.EXISTING:
             case Status.EXISTING_MODIFIED:
@@ -344,38 +359,4 @@
                 throw new RepositoryException("Cannot transiently remove an ItemState with status " + Status.getName(state.getStatus()));
         }
     }
-
-    /**
-     * {@inheritDoc}
-     * @see HierarchyEntry#collectStates(ChangeLog, boolean)
-     */
-    public void collectStates(ChangeLog changeLog, boolean throwOnStale) throws InvalidItemStateException {
-        ItemState state = internalGetItemState();
-        if (state == null) {
-            // nothing to do
-            return;
-        }
-
-        if (throwOnStale && Status.isStale(state.getStatus())) {
-            String msg = "Cannot save changes: " + state + " has been modified externally.";
-            log.debug(msg);
-            throw new InvalidItemStateException(msg);
-        }
-        // only interested in transient modifications or stale states
-        switch (state.getStatus()) {
-            case Status.NEW:
-                changeLog.added(state);
-                break;
-            case Status.EXISTING_MODIFIED:
-            case Status.STALE_MODIFIED:
-            case Status.STALE_DESTROYED:
-                changeLog.modified(state);
-                break;
-            case Status.EXISTING_REMOVED:
-                changeLog.deleted(state);
-                break;
-            default:
-                log.debug("Collecting states: Ignored ItemState with status " + Status.getName(state.getStatus()));
-        }
-    }
 }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEventListener.java Tue Oct 14 00:48:22 2008
@@ -28,6 +28,7 @@
 import org.apache.jackrabbit.spi.Path;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.PathNotFoundException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
@@ -142,9 +143,24 @@
             progress = false;
             for (Iterator it = addEvents.iterator(); it.hasNext();) {
                 Event ev = (Event) it.next();
-                NodeEntry parent = (ev.getParentId() != null) ? (NodeEntry) hierarchyMgr.lookup(ev.getParentId()) : null;
-                if (parent != null) {
-                    parent.refresh(ev);
+                NodeId parentId = ev.getParentId();
+                HierarchyEntry parent = null;
+                if (parentId != null) {
+                    parent = hierarchyMgr.lookup(parentId);
+                    if (parent == null && ev.getPath() != null && parentId.getUniqueID() != null) {
+                        // parentID contains a uniqueID part -> try to lookup
+                        // the parent by path.
+                        try {
+                            Path parentPath = ev.getPath().getAncestor(1);
+                            parent = hierarchyMgr.lookup(parentPath);
+                        } catch (PathNotFoundException e) {
+                            // should not occur
+                            log.debug(e.getMessage());
+                        }
+                    }
+                }
+                if (parent != null && parent.denotesNode()) {
+                    ((NodeEntry) parent).refresh(ev);
                     it.remove();
                     progress = true;
                 }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManager.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManager.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManager.java Tue Oct 14 00:48:22 2008
@@ -41,7 +41,7 @@
     public NodeEntry getRootEntry();
 
     /**
-     * Lookup of <code>HierarchyEntry</code> workspace Id, that may be different
+     * Lookup of <code>HierarchyEntry</code> by its workspace Id that may be different
      * if a entry (or any of its ancestors) has been transiently moved or
      * reordered.<p/>
      * If the Hierarchy already lists the entry with the given workspaceItemId it is
@@ -55,6 +55,20 @@
     public HierarchyEntry lookup(ItemId workspaceItemId);
 
     /**
+     * Lookup of <code>HierarchyEntry</code> by its workspace path that may be different
+     * if a entry (or any of its ancestors) has been transiently moved or
+     * reordered.<p/>
+     * If the Hierarchy already lists the entry with the given path it is
+     * returned otherwise <code>null</code>. See {@link #getHierarchyEntry(Path)}
+     * for a method that resolves the ItemId including lookup in the persistence
+     * layer if the entry has not been loaded yet.
+     *
+     * @param workspaceItemId
+     * @return
+     */
+    public HierarchyEntry lookup(Path workspacePath);
+
+    /**
      * Resolves a itemId into a <code>HierarchyEntry</code>.
      *
      * @param itemId

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManagerImpl.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyManagerImpl.java Tue Oct 14 00:48:22 2008
@@ -83,6 +83,13 @@
     }
 
     /**
+     * @see HierarchyManager#lookup(Path)
+     */
+    public HierarchyEntry lookup(Path workspacePath) {
+        return rootEntry.lookupDeepEntry(workspacePath);
+    }
+
+    /**
      * @see HierarchyManager#getHierarchyEntry(ItemId)
      */
     public HierarchyEntry getHierarchyEntry(ItemId itemId) throws ItemNotFoundException, RepositoryException {

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java?rev=704361&r1=704360&r2=704361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java Tue Oct 14 00:48:22 2008
@@ -17,18 +17,19 @@
 package org.apache.jackrabbit.jcr2spi.hierarchy;
 
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
-import org.apache.jackrabbit.jcr2spi.state.PropertyState;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.NodeId;
 import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QPropertyDefinition;
 import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.QValue;
 
 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.Collection;
@@ -41,7 +42,7 @@
     /**
      * @return the <code>NodeId</code> of this child node entry.
      */
-    public NodeId getId();
+    public NodeId getId() throws InvalidItemStateException, RepositoryException;
 
     /**
      * Returns the ID that must be used for resolving this entry OR loading its
@@ -52,7 +53,7 @@
      * @return
      * @see #getId()
      */
-    public NodeId getWorkspaceId();
+    public NodeId getWorkspaceId() throws InvalidItemStateException, RepositoryException;
 
     /**
      * @return the unique ID of the node state which is referenced by this
@@ -71,8 +72,10 @@
      * @return the index of this child node entry to suppport same-name siblings.
      * If the index of this entry cannot be determined
      * {@link org.apache.jackrabbit.spi.Path#INDEX_UNDEFINED} is returned.
+     * @throws InvalidItemStateException
+     * @throws RepositoryException
      */
-    public int getIndex();
+    public int getIndex() throws InvalidItemStateException, RepositoryException;
 
     /**
      * @return the referenced <code>NodeState</code>.
@@ -206,7 +209,7 @@
      * @return
      * @throws RepositoryException If an error occurs.
      */
-    public NodeState addNewNodeEntry(Name nodeName, String uniqueID, Name primaryNodeType, QNodeDefinition definition) throws RepositoryException;
+    public NodeEntry addNewNodeEntry(Name nodeName, String uniqueID, Name primaryNodeType, QNodeDefinition definition) throws RepositoryException;
 
     /**
      * Determines if there is a property entry with the specified <code>Name</code>.
@@ -275,18 +278,21 @@
      * @throws ItemExistsException
      * @throws RepositoryException if an unexpected error occurs.
      */
-    public void addPropertyEntries(Collection propNames) throws ItemExistsException, RepositoryException;
+    public void setPropertyEntries(Collection propNames) throws ItemExistsException, RepositoryException;
 
     /**
      * Add a new, transient <code>PropertyEntry</code> to this <code>NodeEntry</code>
      * and return the <code>PropertyState</code> associated with the new entry.
      *
      * @param propName
-     * @return The PropertyState associated with the new property entry.
+     * @param definition
+     * @param values
+     * @param propertyType
+     * @return the new entry.
      * @throws ItemExistsException
-     * @throws RepositoryException if an unexpected error occurs.
+     * @throws RepositoryException
      */
-    public PropertyState addNewPropertyEntry(Name propName, QPropertyDefinition definition) throws ItemExistsException, RepositoryException;
+    public PropertyEntry addNewPropertyEntry(Name propName, QPropertyDefinition definition, QValue[] values, int propertyType) throws ItemExistsException, RepositoryException;
 
     /**
      * Reorders this NodeEntry before the sibling entry specified by the given



Mime
View raw message