jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r158604 - in incubator/jackrabbit/trunk: applications/test/ src/java/org/apache/jackrabbit/core/observation/ src/java/org/apache/jackrabbit/core/state/ src/test/org/apache/jackrabbit/core/observation/ src/test/org/apache/jackrabbit/test/api/observation/
Date Tue, 22 Mar 2005 13:49:35 GMT
Author: mreutegg
Date: Tue Mar 22 05:49:33 2005
New Revision: 158604

URL: http://svn.apache.org/viewcvs?view=rev&rev=158604
Log:
- implemented observation events for Node.orderBefore()
- added test cases for Node.orderBefore()

Added:
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/ReorderTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/TestAll.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeReorderTest.java   (with props)
Modified:
    incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AddEventListenerTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventResult.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeMovedTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/TestAll.java

Modified: incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties (original)
+++ incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties Tue Mar 22 05:49:33 2005
@@ -215,6 +215,10 @@
 # observation configuration
 # ------------------------------------------------------------------------------
 
+# Test class: AddEventListenerTest
+# Test method: testNodeType
+javax.jcr.tck.AddEventListenerTest.testNodeType.nodetype2=nt:folder
+
 # Configuration settings for the serialization.
 # Note that the serialization test tries to use as many features of the repository
 # as possible, but fails silently if a feature is not available. You have to

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/observation/EventStateCollection.java Tue Mar 22 05:49:33 2005
@@ -22,6 +22,8 @@
 import org.apache.jackrabbit.core.Path;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.MalformedPathException;
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.state.ChangeLog;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.ItemStateManager;
@@ -33,6 +35,8 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -102,6 +106,7 @@
                 // 3) child node added
                 // 4) child node removed
                 // 5) node moved
+                // 6) node reordered
                 // cases 1) and 2) are detected with added and deleted states
                 // on the PropertyState itself.
                 // cases 3) and 4) are detected with added and deleted states
@@ -110,68 +115,36 @@
                 // when a child node is renamed. three nodes are changed when
                 // a node is really moved. In any case we are only interested in
                 // the node that actually got moved.
+                // in case 6) only one node state changes. the state of the
+                // parent node.
                 NodeState n = (NodeState) state;
                 if (n.getAddedParentUUIDs().size() > 0 && n.getRemovedParentUUIDs().size() > 0) {
                     // node moved
                     // generate node removed & node added event
                     String oldParentUUID = (String) n.getRemovedParentUUIDs().get(0);
-                    NodeTypeImpl nodeType = null;
-                    try {
-                        nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
-                    } catch (NoSuchNodeTypeException e) {
-                        // should never happen actually
-                        String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
-                        log.error(msg);
-                        throw new ItemStateException(msg, e);
-                    }
-                    // FIXME find more efficient way
-                    Path newPath = null;
-                    Path[] allPaths = null;
-                    try {
-                        newPath = hmgr.getPath(n.getId());
-                        allPaths = hmgr.getAllPaths(n.getId(), true);
-                    } catch (RepositoryException e) {
-                        // should never happen actually
-                        String msg = "Unable to resolve path for item: " + n.getId();
-                        log.error(msg);
-                        throw new ItemStateException(msg, e);
-                    }
+                    NodeState oldParent = (NodeState) changes.get(new NodeId(oldParentUUID));
+                    NodeTypeImpl oldParentNodeType = getNodeType(oldParent, session);
+                    Path newPath = getPath(n.getId(), hmgr);
+                    Path[] allPaths = getAllPaths(n.getId(), hmgr);
                     List paths = new ArrayList(Arrays.asList(allPaths));
                     paths.remove(newPath);
                     if (paths.size() > 0) {
                         Path removedPath = (Path) paths.get(0);
-                        Path parentPath = null;
-                        try {
-                            parentPath = removedPath.getAncestor(1);
-                        } catch (PathNotFoundException e) {
-                            // should never happen actually, root node cannot
-                            // be removed, thus path has always a parent
-                            String msg = "Path " + removedPath + " has no parent";
-                            log.error(msg);
-                            throw new ItemStateException(msg, e);
-                        }
                         events.add(EventState.childNodeRemoved(oldParentUUID,
-                                parentPath,
+                                getParent(removedPath),
                                 n.getUUID(),
                                 removedPath.getNameElement(),
-                                nodeType,
+                                oldParentNodeType,
                                 session));
 
                         String newParentUUID = (String) n.getAddedParentUUIDs().get(0);
-                        try {
-                            parentPath = newPath.getAncestor(1);
-                        } catch (PathNotFoundException e) {
-                            // should never happen actually, root node cannot
-                            // be 'added', thus path has always a parent
-                            String msg = "Path " + removedPath + " has no parent";
-                            log.error(msg);
-                            throw new ItemStateException(msg, e);
-                        }
+                        NodeState newParent = (NodeState) changes.get(new NodeId(newParentUUID));
+                        NodeTypeImpl newParentNodeType = getNodeType(newParent, session);
                         events.add(EventState.childNodeAdded(newParentUUID,
-                                parentPath,
+                                getParent(newPath),
                                 n.getUUID(),
                                 newPath.getNameElement(),
-                                nodeType,
+                                newParentNodeType,
                                 session));
                     } else {
                         log.error("Unable to calculate old path of moved node");
@@ -202,32 +175,17 @@
                             }
                         }
                         if (moved != null) {
-                            NodeTypeImpl nodeType = null;
-                            try {
-                                nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
-                            } catch (NoSuchNodeTypeException e) {
-                                // should never happen actually
-                                String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
-                                log.error(msg);
-                                throw new ItemStateException(msg, e);
-                            }
-                            Path newPath = null;
-                            Path parentPath = null;
+                            NodeTypeImpl nodeType = getNodeType(parent, session);
+                            Path newPath = getPath(state.getId(), hmgr);
+                            Path parentPath = getParent(newPath);
                             Path oldPath = null;
                             try {
-                                newPath = hmgr.getPath(state.getId());
-                                parentPath = newPath.getAncestor(1);
                                 oldPath = null;
                                 if (moved.getIndex() == 0) {
                                     oldPath = Path.create(parentPath, moved.getName(), false);
                                 } else {
                                     oldPath = Path.create(parentPath, moved.getName(), moved.getIndex(), false);
                                 }
-                            } catch (RepositoryException e) {
-                                // should never happen actually
-                                String msg = "Unable to resolve path for item: " + state.getId();
-                                log.error(msg);
-                                throw new ItemStateException(msg, e);
                             } catch (MalformedPathException e) {
                                 // should never happen actually
                                 String msg = "Malformed path for item: " + state.getId();
@@ -249,31 +207,50 @@
                         }
                     }
                 }
+                // check if child nodes of modified node state have been reordered
+                List reordered = n.getReorderedChildNodeEntries();
+                NodeTypeImpl nodeType = getNodeType(n, session);
+                if (reordered.size() > 0) {
+                    // create a node removed and a node added event for every
+                    // reorder
+                    for (Iterator ro = reordered.iterator(); ro.hasNext();) {
+                        NodeState.ChildNodeEntry child = (NodeState.ChildNodeEntry) ro.next();
+                        QName name = child.getName();
+                        int index = (child.getIndex() != 1) ? child.getIndex() : 0;
+                        Path parentPath = getPath(n.getId(), hmgr);
+                        Path.PathElement addedElem = Path.create(name, index).getNameElement();
+                        // get removed index
+                        NodeState overlayed = (NodeState) n.getOverlayedState();
+                        List removedChild = overlayed.getChildNodeEntries(child.getUUID());
+                        if (removedChild.size() == 0) {
+                            throw new ItemStateException("Unable to retrieve old child index for item: " + child.getUUID());
+                        }
+                        NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) removedChild.get(0);
+                        int oldIndex = (entry.getIndex() != 1) ? entry.getIndex() : 0;
+                        Path.PathElement removedElem = Path.create(name, oldIndex).getNameElement();
+
+                        events.add(EventState.childNodeRemoved(n.getUUID(),
+                                parentPath,
+                                child.getUUID(),
+                                removedElem,
+                                nodeType,
+                                session));
+
+                        events.add(EventState.childNodeAdded(n.getUUID(),
+                                parentPath,
+                                child.getUUID(),
+                                addedElem,
+                                nodeType,
+                                session));
+                    }
+                }
             } else {
                 // property changed
-                Path path = null;
-                Path parentPath = null;
-                try {
-                    path = hmgr.getPath(state.getId());
-                    parentPath = path.getAncestor(1);
-                } catch (RepositoryException e) {
-                    // should never happen actually
-                    String msg = "Unable to resolve path for item: " + state.getId();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
-                }
+                Path path = getPath(state.getId(), hmgr);
                 NodeState parent = (NodeState) provider.getItemState(new NodeId(state.getParentUUID()));
-                NodeTypeImpl nodeType = null;
-                try {
-                    nodeType = session.getNodeTypeManager().getNodeType(parent.getNodeTypeName());
-                } catch (NoSuchNodeTypeException e) {
-                    // should never happen actually
-                    String msg = "Item " + parent.getId() + " has unknown node type: " + parent.getNodeTypeName();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
-                }
+                NodeTypeImpl nodeType = getNodeType(parent, session);
                 events.add(EventState.propertyChanged(state.getParentUUID(),
-                        parentPath,
+                        getParent(path),
                         path.getNameElement(),
                         nodeType,
                         session));
@@ -284,28 +261,18 @@
             if (state.isNode()) {
                 // node created
                 NodeState n = (NodeState) state;
-                NodeTypeImpl nodeType = null;
-                try {
-                    nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
-                } catch (NoSuchNodeTypeException e) {
-                    // should never happen actually
-                    String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
-                }
-                Path path = null;
-                Path parentPath = null;
-                try {
-                    path = hmgr.getPath(n.getId());
-                    parentPath = path.getAncestor(1);
-                } catch (RepositoryException e) {
-                    // should never happen actually
-                    String msg = "Unable to resolve path for item: " + n.getId();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
+                NodeId parentId = new NodeId(n.getParentUUID());
+                NodeState parent = null;
+                // unknown if parent node is also new
+                if (provider.hasItemState(parentId)) {
+                    parent = (NodeState) provider.getItemState(parentId);
+                } else {
+                    parent = (NodeState) changes.get(parentId);
                 }
+                NodeTypeImpl nodeType = getNodeType(parent, session);
+                Path path = getPath(n.getId(), hmgr);
                 events.add(EventState.childNodeAdded(n.getParentUUID(),
-                        parentPath,
+                        getParent(path),
                         n.getUUID(),
                         path.getNameElement(),
                         nodeType,
@@ -313,28 +280,10 @@
             } else {
                 // property created / set
                 NodeState n = (NodeState) changes.get(new NodeId(state.getParentUUID()));
-                NodeTypeImpl nodeType = null;
-                try {
-                    nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
-                } catch (NoSuchNodeTypeException e) {
-                    // should never happen actually
-                    String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
-                }
-                Path path = null;
-                Path parentPath = null;
-                try {
-                    path = hmgr.getPath(state.getId());
-                    parentPath = path.getAncestor(1);
-                } catch (RepositoryException e) {
-                    // should never happen actually
-                    String msg = "Unable to resolve path for item: " + n.getId();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
-                }
+                NodeTypeImpl nodeType = getNodeType(n, session);
+                Path path = getPath(state.getId(), hmgr);
                 events.add(EventState.propertyAdded(state.getParentUUID(),
-                        parentPath,
+                        getParent(path),
                         path.getNameElement(),
                         nodeType,
                         session));
@@ -345,31 +294,16 @@
             if (state.isNode()) {
                 // node deleted
                 NodeState n = (NodeState) state;
-                NodeTypeImpl nodeType = null;
-                try {
-                    nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
-                } catch (NoSuchNodeTypeException e) {
-                    // should never happen actually
-                    String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
-                }
-                try {
-                    Path[] paths = hmgr.getAllPaths(state.getId(), true);
-                    for (int i = 0; i < paths.length; i++) {
-                        Path parentPath = paths[i].getAncestor(1);
-                        events.add(EventState.childNodeRemoved(n.getParentUUID(),
-                                parentPath,
-                                n.getUUID(),
-                                paths[i].getNameElement(),
-                                nodeType,
-                                session));
-                    }
-                } catch (RepositoryException e) {
-                    // should never happen actually
-                    String msg = "Unable to resolve path for item: " + n.getId();
-                    log.error(msg);
-                    throw new ItemStateException(msg, e);
+                NodeState parent = (NodeState) provider.getItemState(new NodeId(n.getParentUUID()));
+                NodeTypeImpl nodeType = getNodeType(parent, session);
+                Path[] paths = getAllPaths(state.getId(), hmgr);
+                for (int i = 0; i < paths.length; i++) {
+                    events.add(EventState.childNodeRemoved(n.getParentUUID(),
+                            getParent(paths[i]),
+                            n.getUUID(),
+                            paths[i].getNameElement(),
+                            nodeType,
+                            session));
                 }
             } else {
                 // property removed
@@ -377,31 +311,14 @@
                 try {
                     NodeState n = (NodeState) changes.get(new NodeId(state.getParentUUID()));
                     // node state exists -> only property removed
-                    NodeTypeImpl nodeType = null;
-                    try {
-                        nodeType = session.getNodeTypeManager().getNodeType(n.getNodeTypeName());
-                    } catch (NoSuchNodeTypeException e) {
-                        // should never happen actually
-                        String msg = "Item " + state.getId() + " has unknown node type: " + n.getNodeTypeName();
-                        log.error(msg);
-                        throw new ItemStateException(msg, e);
-                    }
-                    Path paths[] = null;
-                    try {
-                        paths = hmgr.getAllPaths(state.getId(), true);
-                        for (int i = 0; i < paths.length; i++) {
-                            Path parentPath = paths[i].getAncestor(1);
-                            events.add(EventState.propertyRemoved(state.getParentUUID(),
-                                    parentPath,
-                                    paths[i].getNameElement(),
-                                    nodeType,
-                                    session));
-                        }
-                    } catch (RepositoryException e) {
-                        // should never happen actually
-                        String msg = "Unable to resolve path for item: " + n.getId();
-                        log.error(msg);
-                        throw new ItemStateException(msg, e);
+                    NodeTypeImpl nodeType = getNodeType(n, session);
+                    Path paths[] = getAllPaths(state.getId(), hmgr);
+                    for (int i = 0; i < paths.length; i++) {
+                        events.add(EventState.propertyRemoved(state.getParentUUID(),
+                                getParent(paths[i]),
+                                paths[i].getNameElement(),
+                                nodeType,
+                                session));
                     }
                 } catch (NoSuchItemStateException e) {
                     // also node removed -> do not create an event
@@ -431,5 +348,80 @@
      */
     Iterator iterator() {
         return events.iterator();
+    }
+
+    /**
+     * Resolves the node type name in <code>node</code> into a {@link NodeType}
+     * object using the {@link NodeTypeManager} of <code>session</code>.
+     * @param node the node.
+     * @param session the session.
+     * @return the {@link NodeType} of <code>node</code>.
+     * @throws ItemStateException if the nodetype cannot be resolved.
+     */
+    private NodeTypeImpl getNodeType(NodeState node, SessionImpl session)
+            throws ItemStateException {
+        try {
+            return session.getNodeTypeManager().getNodeType(node.getNodeTypeName());
+        } catch (NoSuchNodeTypeException e) {
+            // should never happen actually
+            String msg = "Item " + node.getId() + " has unknown node type: " + node.getNodeTypeName();
+            log.error(msg);
+            throw new ItemStateException(msg, e);
+        }
+    }
+
+    /**
+     * Returns the path of the parent node of node at <code>path</code>..
+     * @param p the path.
+     * @return the parent path.
+     * @throws ItemStateException if <code>p</code> does not have a parent
+     * path. E.g. <code>p</code> designates root.
+     */
+    private Path getParent(Path p) throws ItemStateException {
+        try {
+            return p.getAncestor(1);
+        } catch (PathNotFoundException e) {
+            // should never happen actually
+            String msg = "Unable to resolve parent for path: " + p;
+            log.error(msg);
+            throw new ItemStateException(msg, e);
+        }
+    }
+
+    /**
+     * Resolves the path of the Item with id <code>itemId</code>.
+     * @param itemId the id of the item.
+     * @return the path of the item.
+     * @throws ItemStateException if the path cannot be resolved.
+     */
+    private Path getPath(ItemId itemId, HierarchyManager hmgr)
+            throws ItemStateException {
+        try {
+            return hmgr.getPath(itemId);
+        } catch (RepositoryException e) {
+            // should never happen actually
+            String msg = "Unable to resolve path for item: " + itemId;
+            log.error(msg);
+            throw new ItemStateException(msg, e);
+        }
+    }
+
+    /**
+     * Resolves all paths of the Item with id <code>itemId</code> including
+     * the zombie paths.
+     * @param itemId the id of the item.
+     * @return the paths of the item.
+     * @throws ItemStateException if the paths cannot be resolved.
+     */
+    private Path[] getAllPaths(ItemId itemId, HierarchyManager hmgr)
+            throws ItemStateException {
+        try {
+            return hmgr.getAllPaths(itemId, true);
+        } catch (RepositoryException e) {
+            // should never happen actually
+            String msg = "Unable to resolve paths for item: " + itemId;
+            log.error(msg);
+            throw new ItemStateException(msg, e);
+        }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/NodeState.java Tue Mar 22 05:49:33 2005
@@ -588,6 +588,108 @@
         return other.childNodeEntries.removeAll(childNodeEntries);
     }
 
+    /**
+     * Returns a list of child node entries, that exist both in <i>this</i> node
+     * state and in the overlayed node state, but have been reordered.
+     * <p/>
+     * The list may include only the minimal set of nodes that have been
+     * reordered. That is, even though a certain number of nodes have changed
+     * their context position, the list may include less that this number of
+     * nodes.
+     * <p/>
+     * Example:<br/>
+     * Initial state:
+     * <pre>
+     *  + node1
+     *  + node2
+     *  + node3
+     * </pre>
+     * After reorder:
+     * <pre>
+     *  + node2
+     *  + node3
+     *  + node1
+     * </pre>
+     * All nodes have changed their context position. The returned list however
+     * may only return that <code>node1</code> has been reordered (from the
+     * first position to the end).
+     *
+     * @return list of reordered child node enties.
+     */
+    public synchronized List getReorderedChildNodeEntries() {
+        if (!hasOverlayedState()) {
+            return Collections.EMPTY_LIST;
+        }
+
+        List others = new ArrayList();
+        others.addAll(((NodeState) getOverlayedState()).childNodeEntries.entries);
+
+        List ours = new ArrayList();
+        ours.addAll(childNodeEntries.entries);
+
+        // do a lazy init
+        List reordered = null;
+        // remove added nodes from ours entries
+        ours.removeAll(getAddedChildNodeEntries());
+        // remove all removed nodes from others entries
+        others.removeAll(getRemovedChildNodeEntries());
+        // both entry list now contain the set of nodes that have not
+        // been removed or added. but they may have changed their position
+        for (int i = 0; i < ours.size();) {
+            ChildNodeEntry entry = (ChildNodeEntry) ours.get(i);
+            ChildNodeEntry other = (ChildNodeEntry) others.get(i);
+            if (!entry.getUUID().equals(other.getUUID())) {
+                if (reordered == null) {
+                    reordered = new ArrayList();
+                }
+                // Note, that this check will not necessarily find the
+                // minimal reorder operations required to convert the overlayed
+                // child node entries into the current.
+
+                // is there a next entry
+                if (i + 1 < ours.size()) {
+                    // if entry is the next in the other list, then probably
+                    // the other entry at position <code>i</code> was reordered
+                    if (entry.getUUID().equals(((ChildNodeEntry) others.get(i + 1)).getUUID())) {
+                        // scan for the uuid of the other entry in our list
+                        for (int j = i; j < ours.size(); j++) {
+                            if (((ChildNodeEntry) ours.get(j)).getUUID().equals(other.uuid)) {
+                                // found it
+                                entry = (ChildNodeEntry) ours.get(j);
+                                break;
+                            }
+                        }
+                    }
+                }
+
+                reordered.add(entry);
+                // remove the entry from both lists
+                // entries > i are already cleaned
+                for (int j = i; j < ours.size(); j++) {
+                    if (((ChildNodeEntry) ours.get(j)).getUUID().equals(entry.getUUID())) {
+                        ours.remove(j);
+                    }
+                }
+                for (int j = i; j < ours.size(); j++) {
+                    if (((ChildNodeEntry) others.get(j)).getUUID().equals(entry.getUUID())) {
+                        others.remove(j);
+                    }
+                }
+                // if a reorder has been detected index <code>i</code> is not
+                // incremented, because entries will be shifted when the
+                // reordered entry is removed.
+            } else {
+                // no reorder, move to next child entry
+                i++;
+            }
+        }
+        if (reordered == null) {
+            return Collections.EMPTY_LIST;
+        } else {
+            return reordered;
+        }
+    }
+
     //--------------------------------------------------< ItemState overrides >
     /**
      * Sets the UUID of the parent <code>NodeState</code>.

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/ReorderTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/ReorderTest.java?view=auto&rev=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/ReorderTest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/ReorderTest.java Tue Mar 22 05:49:33 2005
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.observation;
+
+import org.apache.jackrabbit.test.api.observation.AbstractObservationTest;
+import org.apache.jackrabbit.test.api.observation.EventResult;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.observation.Event;
+
+/**
+ * Tests implementation specific aspects of the observation manager.
+ */
+public class ReorderTest extends AbstractObservationTest {
+
+    /**
+     * Tests if reordering a child node triggers a {@link javax.jcr.observation.Event#NODE_REMOVED}
+     * and a {@link javax.jcr.observation.Event#NODE_ADDED} event with same name siblings. Furthermore
+     * a node is removed in the same save scope.
+     * <p/>
+     * Because of the one reorder operation, three nodes change their index. And
+     * actually four nodes change their context position. The minimal events
+     * that may be triggered only includes one pair of remove/add node events
+     * (plus the additional event for the removed node).
+     */
+    public void testNodeReorderComplex()
+            throws RepositoryException, NotExecutableException {
+        if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+            throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+        }
+
+        /**
+         * Initial tree:
+         *  + testroot
+         *      + nodename1[1]
+         *      + nodename1[2]
+         *      + nodename2
+         *      + nodename1[3]
+         *      + nodename1[4]
+         *      + nodename3
+         *
+         * After reorder:
+         *  + testroot
+         *      + nodename1[1]
+         *      + nodename2
+         *      + nodename1[2] (was 3)
+         *      + nodename1[3] (was 4)
+         *      + nodename1[4] (was 2)
+         */
+        Node n = testRootNode.addNode(nodeName1, testNodeType);
+        if (!n.getDefinition().allowSameNameSibs()) {
+            throw new NotExecutableException("Node at " + testRoot + " does not allow same name siblings with name " + nodeName1);
+        }
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName2, testNodeType);
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName3, testNodeType);
+        testRootNode.save();
+        EventResult addNodeListener = new EventResult(log);
+        EventResult removeNodeListener = new EventResult(log);
+        addEventListener(addNodeListener, Event.NODE_ADDED);
+        addEventListener(removeNodeListener, Event.NODE_REMOVED);
+        testRootNode.orderBefore(nodeName1 + "[2]", null);
+        testRootNode.getNode(nodeName3).remove();
+        testRootNode.save();
+        removeEventListener(addNodeListener);
+        removeEventListener(removeNodeListener);
+        Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        // not deterministic, there exist various re-order seqences. the minimal
+        // is:
+        // nodename1[2] has been reordered to the end + nodeName3 has been removed
+        checkNodeAdded(added, new String[]{nodeName1 + "[4]"});
+        checkNodeRemoved(removed, new String[]{nodeName1 + "[2]", nodeName3});
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/ReorderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/TestAll.java?view=auto&rev=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/TestAll.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/TestAll.java Tue Mar 22 05:49:33 2005
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.observation;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all jackrabbit specific testcases for the
+ * observation module.
+ */
+public class TestAll extends TestCase {
+
+    /**
+     * Returns a <code>Test</code> suite that executes all tests inside this
+     * package.
+     *
+     * @return a <code>Test</code> suite that executes all tests inside this
+     *         package.
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite("Observation tests");
+
+        suite.addTestSuite(ReorderTest.class);
+
+        return suite;
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/observation/TestAll.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AbstractObservationTest.java Tue Mar 22 05:49:33 2005
@@ -32,7 +32,7 @@
  * This class implements the basic {@link #setUp} and {@link #tearDown()}
  * methods for the observation test cases.
  */
-abstract class AbstractObservationTest extends AbstractJCRTest {
+public abstract class AbstractObservationTest extends AbstractJCRTest {
 
     /**
      * Default wait timeout for events: 5000 ms

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AddEventListenerTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AddEventListenerTest.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AddEventListenerTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/AddEventListenerTest.java Tue Mar 22 05:49:33 2005
@@ -21,6 +21,7 @@
 import javax.jcr.observation.Event;
 import javax.jcr.RepositoryException;
 import javax.jcr.Node;
+import javax.jcr.Session;
 
 /**
  * Tests the options for addEventListener().
@@ -144,7 +145,11 @@
      * Tests if events are only generated for specified node types.
      */
     public void testNodeType() throws RepositoryException {
+        String nodetype2 = getProperty("nodetype2");
         EventResult listener = new EventResult(log);
+        Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+        Node n2 = testRootNode.addNode(nodeName2, nodetype2);
+        testRootNode.save();
         obsMgr.addEventListener(listener,
                 Event.NODE_ADDED,
                 testRoot,
@@ -152,12 +157,20 @@
                 null,
                 new String[]{testNodeType},
                 false);
-        testRootNode.addNode(nodeName1, testNodeType);
-        testRootNode.addNode(nodeName2, ntBase);
-        testRootNode.save();
+        Session s = helper.getSuperuserSession();
+        try {
+            Node n = (Node) s.getItem(n1.getPath());
+            n.addNode(nodeName3, ntBase);
+            n = (Node) s.getItem(n2.getPath());
+            n.addNode(nodeName3, nodetype2);
+            n = (Node) s.getItem(testRoot);
+            n.save();
+        } finally {
+            s.logout();
+        }
         obsMgr.removeEventListener(listener);
         Event[] events = listener.getEvents(DEFAULT_WAIT_TIMEOUT);
-        checkNodeAdded(events, new String[]{nodeName1});
+        checkNodeAdded(events, new String[]{nodeName1 + "/" + nodeName3});
     }
 
     //-------------------------< internal >-------------------------------------

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventResult.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventResult.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventResult.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/EventResult.java Tue Mar 22 05:49:33 2005
@@ -35,7 +35,7 @@
  * only one of the methods can be called for an expected event delivery. Calling
  * the 'other' method will block until the next events are delivered.
  */
-class EventResult implements EventListener {
+public class EventResult implements EventListener {
 
     /**
      * The <code>EventIterator</code> delivered to this <code>EventListener</code>
@@ -57,7 +57,7 @@
      *
      * @param log log messages are written to this <code>Logger</code>.
      */
-    EventResult(PrintWriter log) {
+    public EventResult(PrintWriter log) {
         this.log = log;
         try {
             sync.acquire();

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeMovedTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeMovedTest.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeMovedTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeMovedTest.java Tue Mar 22 05:49:33 2005
@@ -39,10 +39,22 @@
 public class NodeMovedTest extends AbstractObservationTest {
 
     /**
-     * Tests if node removed and node added event is triggered when a node
+     * Tests if node removed and node added event is triggered when a tree
      * is moved.
      */
-    public void testMoveNode() throws RepositoryException {
+    public void testMoveTree() throws RepositoryException {
+        /**
+         * Initial tree:
+         *  + testroot
+         *      + nodename1
+         *          + nodename2
+         *
+         * After move:
+         *  + testroot
+         *      + nodename3
+         *          + nodename2
+         */
+
         Node n1 = testRootNode.addNode(nodeName1, testNodeType);
         n1.addNode(nodeName2, testNodeType);
         testRootNode.save();
@@ -58,5 +70,39 @@
         Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
         checkNodeAdded(added, new String[]{nodeName3});
         checkNodeRemoved(removed, new String[]{nodeName1});
+    }
+
+    /**
+     * Tests if node removed and node added event is triggered when a node
+     * is moved.
+     */
+    public void testMoveNode() throws RepositoryException {
+        /**
+         * Initial tree:
+         *  + testroot
+         *      + nodename1
+         *          + nodename2
+         *
+         * After move:
+         *  + testroot
+         *      + nodename1
+         *      + nodename2
+         */
+
+        Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+        Node n2 = n1.addNode(nodeName2, testNodeType);
+        testRootNode.save();
+        EventResult addNodeListener = new EventResult(log);
+        EventResult removeNodeListener = new EventResult(log);
+        addEventListener(addNodeListener, Event.NODE_ADDED);
+        addEventListener(removeNodeListener, Event.NODE_REMOVED);
+        superuser.move(n2.getPath(), testRoot + "/" + nodeName2);
+        testRootNode.save();
+        removeEventListener(addNodeListener);
+        removeEventListener(removeNodeListener);
+        Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        checkNodeAdded(added, new String[]{nodeName2});
+        checkNodeRemoved(removed, new String[]{nodeName1 + "/" + nodeName2});
     }
 }

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeReorderTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeReorderTest.java?view=auto&rev=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeReorderTest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeReorderTest.java Tue Mar 22 05:49:33 2005
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.test.api.observation;
+
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.observation.Event;
+
+/**
+ * Tests if {@link javax.jcr.Node#orderBefore(String, String)} operations trigger
+ * the appropriate observation events.
+ * <p/>
+ * @tck.config testroot must allow orderable child nodes of type
+ * <code>nodetype</code>, otherwise the test cases throw a
+ * {@link NotExecutableException}. Some tests are only executed if the node
+ * at <code>testroot</code> support same name sibling child nodes.
+ * @tck.config nodetype node type that allows child nodes of the same type.
+ * @tck.config nodename1 child node name of type <code>nodetype</code>
+ * @tck.config nodename2 child node name of type <code>nodetype</code>
+ * @tck.config nodename3 child node name of type <code>nodetype</code>
+ *
+ * @test
+ * @sources NodeReorderTest.java
+ * @executeClass org.apache.jackrabbit.test.api.observation.NodeReorderTest
+ * @keywords observation
+ */
+public class NodeReorderTest extends AbstractObservationTest {
+
+    /**
+     * Tests if reordering a child node triggers a {@link Event#NODE_REMOVED}
+     * and a {@link Event#NODE_ADDED} event.
+     */
+    public void testNodeReorder()
+            throws RepositoryException, NotExecutableException {
+        if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+            throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+        }
+
+        /**
+         * Initial tree:
+         *  + testroot
+         *      + nodename1
+         *      + nodename2
+         *      + nodename3
+         *
+         * After reorder:
+         *  + testroot
+         *      + nodename1
+         *      + nodename3
+         *      + nodename2
+         */
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName2, testNodeType);
+        testRootNode.addNode(nodeName3, testNodeType);
+        testRootNode.save();
+        EventResult addNodeListener = new EventResult(log);
+        EventResult removeNodeListener = new EventResult(log);
+        addEventListener(addNodeListener, Event.NODE_ADDED);
+        addEventListener(removeNodeListener, Event.NODE_REMOVED);
+        testRootNode.orderBefore(nodeName3, nodeName2);
+        testRootNode.save();
+        removeEventListener(addNodeListener);
+        removeEventListener(removeNodeListener);
+        Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        // either
+        // 1) nodename2 has been reordered to the end
+        // or:
+        // 2) nodename3 has been reordered before nodename2
+        // that is, the following event sets are correct:
+        // 1) nodename2:remove, nodename2:add
+        // or:
+        // 2) nodename3:remove, nodename3:add
+
+        // if true, check for option 1)
+        boolean reorderEnd = false;
+        for (int i = 0; i < added.length; i++) {
+            if (added[i].getPath().endsWith(nodeName2)) {
+                reorderEnd = true;
+                break;
+            }
+        }
+        if (reorderEnd) {
+            checkNodeAdded(added, new String[]{nodeName2});
+            checkNodeRemoved(removed, new String[]{nodeName2});
+        } else {
+            checkNodeAdded(added, new String[]{nodeName3});
+            checkNodeRemoved(removed, new String[]{nodeName3});
+        }
+    }
+
+    /**
+     * Tests if reordering a child node triggers a {@link Event#NODE_REMOVED}
+     * and a {@link Event#NODE_ADDED} event with same name siblings.
+     */
+    public void testNodeReorderSameName()
+            throws RepositoryException, NotExecutableException {
+        if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+            throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+        }
+
+        /**
+         * Initial tree:
+         *  + testroot
+         *      + nodename1[1]
+         *      + nodename1[2]
+         *      + nodename1[3]
+         *
+         * After reorder:
+         *  + testroot
+         *      + nodename1[1]
+         *      + nodename1[2] (was 3)
+         *      + nodename1[3] (was 2)
+         */
+        Node n = testRootNode.addNode(nodeName1, testNodeType);
+        if (!n.getDefinition().allowSameNameSibs()) {
+            throw new NotExecutableException("Node at " + testRoot + " does not allow same name siblings with name " + nodeName1);
+        }
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.save();
+        EventResult addNodeListener = new EventResult(log);
+        EventResult removeNodeListener = new EventResult(log);
+        addEventListener(addNodeListener, Event.NODE_ADDED);
+        addEventListener(removeNodeListener, Event.NODE_REMOVED);
+        testRootNode.orderBefore(nodeName1 + "[3]", nodeName1 + "[2]");
+        //testRootNode.orderBefore(nodeName1 + "[2]", null);
+        testRootNode.save();
+        removeEventListener(addNodeListener);
+        removeEventListener(removeNodeListener);
+        Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        // either
+        // 1) nodename1[2] has been reordered to the end
+        // or:
+        // 2) nodename1[3] has been reordered before nodename1[2]
+        // that is, the following event sets are correct:
+        // 1) nodename1[2]:remove, nodename1[3]:add
+        // or:
+        // 2) nodename1[3]:remove, nodename1[2]:add
+
+        // if true, check for option 1)
+        boolean reorderEnd = false;
+        for (int i = 0; i < added.length; i++) {
+            if (added[i].getPath().endsWith(nodeName1 + "[3]")) {
+                reorderEnd = true;
+                break;
+            }
+        }
+        if (reorderEnd) {
+            checkNodeAdded(added, new String[]{nodeName1 + "[3]"});
+            checkNodeRemoved(removed, new String[]{nodeName1 + "[2]"});
+        } else {
+            checkNodeAdded(added, new String[]{nodeName1 + "[2]"});
+            checkNodeRemoved(removed, new String[]{nodeName1 + "[3]"});
+        }
+    }
+
+    /**
+     * Tests if reordering a child node triggers a {@link Event#NODE_REMOVED}
+     * and a {@link Event#NODE_ADDED} event with same name siblings. Furthermore
+     * a node is removed in the same save scope.
+     */
+    public void testNodeReorderSameNameWithRemove()
+            throws RepositoryException, NotExecutableException {
+        if (!testRootNode.getDefinition().getDeclaringNodeType().hasOrderableChildNodes()) {
+            throw new NotExecutableException("Node at '" + testRoot + "' does not support orderable child nodes.");
+        }
+
+        /**
+         * Initial tree:
+         *  + testroot
+         *      + nodename1[1]
+         *      + nodename2
+         *      + nodename1[2]
+         *      + nodename1[3]
+         *      + nodename3
+         *
+         * After reorder:
+         *  + testroot
+         *      + nodename1[1]
+         *      + nodename2
+         *      + nodename1[2] (was 3)
+         *      + nodename1[3] (was 2)
+         */
+        Node n = testRootNode.addNode(nodeName1, testNodeType);
+        if (!n.getDefinition().allowSameNameSibs()) {
+            throw new NotExecutableException("Node at " + testRoot + " does not allow same name siblings with name " + nodeName1);
+        }
+        testRootNode.addNode(nodeName2, testNodeType);
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName1, testNodeType);
+        testRootNode.addNode(nodeName3, testNodeType);
+        testRootNode.save();
+        EventResult addNodeListener = new EventResult(log);
+        EventResult removeNodeListener = new EventResult(log);
+        addEventListener(addNodeListener, Event.NODE_ADDED);
+        addEventListener(removeNodeListener, Event.NODE_REMOVED);
+        testRootNode.orderBefore(nodeName1 + "[2]", null);
+        testRootNode.getNode(nodeName3).remove();
+        testRootNode.save();
+        removeEventListener(addNodeListener);
+        removeEventListener(removeNodeListener);
+        Event[] added = addNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        Event[] removed = removeNodeListener.getEvents(DEFAULT_WAIT_TIMEOUT);
+        // either
+        // 1) nodename1[2] has been reordered to the end
+        // or:
+        // 2) nodename1[3] has been reordered before nodename1[2]
+        //
+        // that is, the following event sets are correct:
+        // 1) nodename1[2]:remove, nodename1[3]:add, nodename3:remove
+        // or:
+        // 2) nodename1[3]:remove, nodename1[2]:add, nodename3:remove
+
+        // if true, check for option 1)
+        boolean reorderEnd = false;
+        for (int i = 0; i < added.length; i++) {
+            if (added[i].getPath().endsWith(nodeName1 + "[3]")) {
+                reorderEnd = true;
+                break;
+            }
+        }
+        if (reorderEnd) {
+            checkNodeAdded(added, new String[]{nodeName1 + "[3]"});
+            checkNodeRemoved(removed, new String[]{nodeName1 + "[2]", nodeName3});
+        } else {
+            checkNodeAdded(added, new String[]{nodeName1 + "[2]"});
+            checkNodeRemoved(removed, new String[]{nodeName1 + "[3]", nodeName3});
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/NodeReorderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/TestAll.java?view=diff&r1=158603&r2=158604
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/TestAll.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/observation/TestAll.java Tue Mar 22 05:49:33 2005
@@ -42,6 +42,7 @@
         suite.addTestSuite(NodeAddedTest.class);
         suite.addTestSuite(NodeRemovedTest.class);
         suite.addTestSuite(NodeMovedTest.class);
+        suite.addTestSuite(NodeReorderTest.class);
         suite.addTestSuite(PropertyAddedTest.class);
         suite.addTestSuite(PropertyChangedTest.class);
         suite.addTestSuite(PropertyRemovedTest.class);



Mime
View raw message