You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by md...@apache.org on 2011/12/13 20:13:38 UTC

svn commit: r1213877 - in /jackrabbit/sandbox/jackrabbit-mk: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ jackrabbit-spi2microkernel/

Author: mduerig
Date: Tue Dec 13 19:13:38 2011
New Revision: 1213877

URL: http://svn.apache.org/viewvc?rev=1213877&view=rev
Log:
Microkernel based Jackrabbit prototype (WIP)
- remove support for orderable child nodes
- remove support for same name siblings

Modified:
    jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java
    jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java
    jackrabbit/sandbox/jackrabbit-mk/jackrabbit-spi2microkernel/pom.xml

Modified: jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java?rev=1213877&r1=1213876&r2=1213877&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java (original)
+++ jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java Tue Dec 13 19:13:38 2011
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.jcr2spi.hierarchy;
 
-import org.apache.commons.collections.list.AbstractLinkedList;
 import org.apache.jackrabbit.jcr2spi.state.Status;
 import org.apache.jackrabbit.spi.ChildInfo;
 import org.apache.jackrabbit.spi.Name;
@@ -26,16 +25,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.jcr.RepositoryException;
-import java.lang.ref.Reference;
-import java.lang.ref.SoftReference;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 
 /**
  * {@code ChildNodeEntries} represents a collection of {@code NodeEntry}s that
@@ -47,14 +40,9 @@ final class ChildNodeEntries {
     private boolean complete;
 
     /**
-     * Linked list of {@link NodeEntry} instances.
-     */
-    private final LinkedEntries entries = new LinkedEntries();
-
-    /**
      * Map used for lookup by name.
      */
-    private final NameMap entriesByName = new NameMap();
+    private final Map<Name, NodeEntry> entries = new HashMap<Name, NodeEntry>();
 
     private final NodeEntry parent;
     private final EntryFactory factory;
@@ -79,40 +67,22 @@ final class ChildNodeEntries {
          if (childNodeInfos != null) {
              while (childNodeInfos.hasNext()) {
                  ChildInfo ci = childNodeInfos.next();
+                 if (ci.getIndex() > Path.INDEX_DEFAULT) {
+                     IllegalArgumentException e = new IllegalArgumentException("Invalid index: " + ci.getIndex());
+                     log.error(e.getMessage(), e);
+                     throw e;
+                 }
                  NodeEntry entry = factory.createNodeEntry(parent, ci.getName(), ci.getUniqueID());
-                 add(entry, ci.getIndex());
+                 add(entry);
              }
              complete = true;
-         } else {
+         }
+         else {
              complete = false;
          }
      }
 
     /**
-     * @param childEntry
-     * @return The node entry that directly follows the given {@code childEntry}
-     * or {@code null} if the given {@code childEntry} has no successor
-     * or was not found in this {@code ChildNodeEntries}.
-     */
-    NodeEntry getNext(NodeEntry childEntry) {
-        LinkedEntries.LinkNode ln = entries.getLinkNode(childEntry);
-        LinkedEntries.LinkNode nextLn = ln == null ? null : ln.getNextLinkNode();
-        return nextLn == null ? null : nextLn.getNodeEntry();
-    }
-
-    /**
-     * @param childEntry
-     * @return The node entry that directly precedes the given {@code childEntry}
-     * or {@code null} if the given {@code childEntry} is the first
-     * or was not found in this {@code ChildNodeEntries}.
-     */
-    NodeEntry getPrevious(NodeEntry childEntry) {
-        LinkedEntries.LinkNode ln = entries.getLinkNode(childEntry);
-        LinkedEntries.LinkNode prevLn = ln == null ? null : ln.getPreviousLinkNode();
-        return prevLn == null ? null : prevLn.getNodeEntry();
-    }
-
-    /**
      * @return {@code true} if this {@code ChildNodeEntries} have
      * been updated or completely loaded without being invalidated in the
      * mean time.
@@ -134,8 +104,8 @@ final class ChildNodeEntries {
             return;
         }
 
-        NodeId id = parent.getWorkspaceId();
-        Iterator<ChildInfo> childNodeInfos = factory.getItemStateFactory().getChildNodeInfos(id);
+        NodeId nodeId = parent.getWorkspaceId();
+        Iterator<ChildInfo> childNodeInfos = factory.getItemStateFactory().getChildNodeInfos(nodeId);
         update(childNodeInfos);
     }
 
@@ -158,26 +128,13 @@ final class ChildNodeEntries {
      */
     synchronized void update(Iterator<ChildInfo> childNodeInfos) {
         // insert missing entries and reorder all if necessary.
-        LinkedEntries.LinkNode prevLN = null;
         while (childNodeInfos.hasNext()) {
-            ChildInfo ci = childNodeInfos.next();
-            LinkedEntries.LinkNode ln = entriesByName.getLinkNode(ci.getName(), ci.getIndex(), ci.getUniqueID());
-            if (ln == null) {
+            ChildInfo info = childNodeInfos.next();
+            if (entries.get(info.getName()) == 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
-                if (prevLN == ln) {
-                    // there was an existing entry but it's the same as the one
-                    // created/retrieved before. getting here indicates that
-                    // the SPI implementation provided invalid childNodeInfos.
-                    log.error("ChildInfo iterator contains multiple entries with the same name|index or uniqueID -> ignore ChildNodeInfo.");
-                } else {
-                    reorderAfter(ln, prevLN);
-                }
+                NodeEntry entry = factory.createNodeEntry(parent, info.getName(), info.getUniqueID());
+                add(entry);
             }
-            prevLN = ln;
         }
         // finally reset the status
         complete = true;
@@ -190,42 +147,12 @@ final class ChildNodeEntries {
      * @return Iterator over all NodeEntry object
      */
     public Iterator<NodeEntry> iterator() {
-        List<NodeEntry> l = new ArrayList<NodeEntry>(entries.size());
-        for (Iterator<LinkedEntries.LinkNode> it = entries.linkNodeIterator(); it.hasNext();) {
-            l.add(it.next().getNodeEntry());
-        }
-        return Collections.unmodifiableList(l).iterator();
-    }
-
-    /**
-     * Returns a {@code List} of {@code NodeEntry}s for the
-     * given {@code nodeName}. This method does <b>not</b> filter out
-     * removed {@code NodeEntry}s.
-     *
-     * @param nodeName the child node name.
-     * @return same name sibling nodes with the given {@code nodeName}.
-     */
-    public List<NodeEntry> get(Name nodeName) {
-        return entriesByName.getList(nodeName);
+        // avoid concurrent modification exception
+        return new ArrayList<NodeEntry>(entries.values()).iterator();
     }
 
-    /**
-     * Returns the {@code NodeEntry} with the given
-     * {@code nodeName} and {@code index}. Note, that this method
-     * does <b>not</b> filter out removed {@code NodeEntry}s.
-     *
-     * @param nodeName name of the child node entry.
-     * @param index    the index of the child node entry.
-     * @return the {@code NodeEntry} or {@code null} if there
-     * is no such {@code NodeEntry}.
-     */
-    public NodeEntry get(Name nodeName, int index) {
-        if (index < Path.INDEX_DEFAULT) {
-            IllegalArgumentException e = new IllegalArgumentException("index is 1-based");
-            log.error(e.getMessage(), e);
-            throw e;
-        }
-        return entriesByName.getNodeEntry(nodeName, index);
+    public NodeEntry get(Name nodeName) {
+        return entries.get(nodeName);
     }
 
     /**
@@ -243,709 +170,30 @@ final class ChildNodeEntries {
             log.error(e.getMessage(), e);
             throw e;
         }
-        for (NodeEntry cne : get(nodeName)) {
-            if (uniqueID.equals(cne.getUniqueID())) {
-                return cne;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Adds a {@code NodeEntry} to the end of the list. Same as
-     * {@link #add(NodeEntry, int)}, where the index is {@link Path#INDEX_UNDEFINED}.
-     *
-     * @param cne the {@code NodeEntry} to add.
-     */
-     public synchronized void add(NodeEntry cne) {
-        internalAdd(cne, Path.INDEX_UNDEFINED);
-     }
-
-    /**
-     * Adds a {@code NodeEntry}.<br>
-     * Note the following special cases:
-     * <ol>
-     * <li>If an entry with the given index already exists, the the new sibling
-     * is inserted before.</li>
-     * <li>If the given index is bigger that the last entry in the siblings list,
-     * intermediate entries will be created.</li>
-     * </ol>
-     *
-     * @param cne the {@code NodeEntry} to add.
-     */
-    public synchronized void add(NodeEntry cne, int index) {
-        if (index < Path.INDEX_UNDEFINED) {
-            IllegalArgumentException e = new IllegalArgumentException("Invalid index" + index);
-            log.error(e.getMessage(), e);
-            throw e;
-        }
-        internalAdd(cne, index);
-    }
-
-    /**
-     * Adds a the new  {@code NodeEntry} before {@code beforeEntry}.
-     *
-     * @param entry
-     * @param index
-     * @param beforeEntry
-     */
-    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
-     * @return the {@code LinkNode} belonging to the added entry.
-     */
-    private LinkedEntries.LinkNode internalAdd(NodeEntry entry, int index) {
-        Name nodeName = entry.getName();
-
-        // retrieve ev. sibling node with same index. if index is 'undefined'
-        // the existing entry is always null and no reordering occurs.
-        LinkedEntries.LinkNode existing = null;
-        if (index >= Path.INDEX_DEFAULT) {
-            existing = entriesByName.getLinkNode(nodeName, index);
-        }
 
-        // in case index greater than default -> create intermediate entries.
-        // TODO: in case of orderable node the order in the 'linked-entries' must be respected.
-        for (int i = Path.INDEX_DEFAULT; i < index; i++) {
-            LinkedEntries.LinkNode previous = entriesByName.getLinkNode(nodeName, i);
-            if (previous == null) {
-                NodeEntry sibling = factory.createNodeEntry(parent, nodeName, null);
-                internalAdd(sibling, i);
-            }
-        }
-
-        // add new entry
-        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.
-        if (existing != null) {
-            reorder(nodeName, ln, existing);
-        }
-        return ln;
+        NodeEntry nodeEntry = entries.get(nodeName);
+        return nodeEntry != null && uniqueID.equals(nodeEntry.getUniqueID())
+            ? nodeEntry
+            : null;
     }
 
     /**
-     * Add the specified new entry after the specified {@code insertAfter}.
+     * Adds a {@code NodeEntry} to the end of the list. Same as
      *
-     * @param newEntry
-     * @param index
-     * @param insertAfter
-     * @return the {@code LinkNode} associated with the {@code newEntry}.
+     * @param nodeEntry the {@code NodeEntry} to add.
      */
-    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;
+    public synchronized void add(NodeEntry nodeEntry) {
+        entries.put(nodeEntry.getName(), nodeEntry);
     }
 
     /**
      * Removes the child node entry referring to the node state.
      *
-     * @param childEntry the entry to be removed.
+     * @param nodeEntry the entry to be removed.
      * @return the removed entry or {@code null} if there is no such entry.
      */
-    public synchronized NodeEntry remove(NodeEntry childEntry) {
-        LinkedEntries.LinkNode ln = entries.removeNodeEntry(childEntry);
-        if (ln != null) {
-            entriesByName.remove(childEntry.getName(), ln);
-            return childEntry;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Reorders an existing {@code NodeEntry} before another
-     * {@code NodeEntry}. If {@code beforeEntry} is
-     * {@code null} {@code insertEntry} is moved to the end of the
-     * child node entries.
-     *
-     * @param insertEntry the NodeEntry to move.
-     * @param beforeEntry the NodeEntry where {@code insertEntry} is
-     * reordered to.
-     * @return the NodeEntry that followed the 'insertEntry' before the reordering.
-     * @throws NoSuchElementException if {@code insertEntry} or
-     * {@code beforeEntry} does not have a {@code NodeEntry}
-     * in this {@code ChildNodeEntries}.
-     */
-    public synchronized NodeEntry reorder(NodeEntry insertEntry, NodeEntry beforeEntry) {
-        // the link node to move
-        LinkedEntries.LinkNode insertLN = entries.getLinkNode(insertEntry);
-        if (insertLN == null) {
-            throw new NoSuchElementException();
-        }
-        // the link node where insertLN is ordered before
-        LinkedEntries.LinkNode beforeLN = beforeEntry != null ? entries.getLinkNode(beforeEntry) : null;
-        if (beforeEntry != null && beforeLN == null) {
-            throw new NoSuchElementException();
-        }
-
-        NodeEntry previousBefore = insertLN.getNextLinkNode().getNodeEntry();
-        if (previousBefore != beforeEntry) {
-            reorder(insertEntry.getName(), insertLN, beforeLN);
-        }
-        return previousBefore;
-    }
-
-    /**
-     * Reorders an existing {@code NodeEntry} after another
-     * {@code NodeEntry}. If {@code afterEntry} is
-     * {@code null} {@code insertEntry} is moved to the beginning of
-     * the child node entries.
-     *
-     * @param insertEntry the NodeEntry to move.
-     * @param afterEntry the NodeEntry where {@code insertEntry} is
-     * reordered behind.
-     * @throws NoSuchElementException if {@code insertEntry} or
-     * {@code afterEntry} does not have a {@code NodeEntry}
-     * in this {@code ChildNodeEntries}.
-     */
-    public void reorderAfter(NodeEntry insertEntry, NodeEntry afterEntry) {
-        // the link node to move
-        LinkedEntries.LinkNode insertLN = entries.getLinkNode(insertEntry);
-        if (insertLN == null) {
-            throw new NoSuchElementException();
-        }
-        // the link node where insertLN is ordered before
-        LinkedEntries.LinkNode afterLN = afterEntry != null ? entries.getLinkNode(afterEntry) : null;
-        if (afterEntry != null && afterLN == null) {
-            throw new NoSuchElementException();
-        }
-
-        LinkedEntries.LinkNode previousLN = insertLN.getPreviousLinkNode();
-        if (previousLN != afterLN) {
-            reorderAfter(insertLN, afterLN);
-        } // else: already in correct position. nothing to do
-    }
-
-    /**
-     *
-     * @param insertName
-     * @param insert
-     * @param beforeLN
-     */
-    private void reorder(Name insertName, LinkedEntries.LinkNode insert, LinkedEntries.LinkNode beforeLN) {
-        // reorder named map
-        if (entriesByName.containsSiblings(insertName)) {
-            int position;
-            if (beforeLN == null) {
-                // reorder to the end -> use illegal position as marker
-                position = - 1;
-            } else {
-                // count all SNS-entries that are before 'beforeLN' in order to
-                // determine the new position of the reordered node regarding
-                // his siblings.
-                position = 0;
-                for (Iterator<LinkedEntries.LinkNode> it = entries.linkNodeIterator(); it.hasNext(); ) {
-                    LinkedEntries.LinkNode ln = it.next();
-                    if (ln == beforeLN) {
-                        break;
-                    } else if (ln != insert && insertName.equals(ln.name)) {
-                        position++;
-                    } // else: ln == insertLN OR no SNS -> not relevant for position count
-                }
-            }
-            entriesByName.reorder(insertName, insert, position);
-        }
-        // reorder in linked list
-        entries.reorderNode(insert, beforeLN);
-    }
-
-    /**
-     *
-     * @param insertLN
-     * @param afterLN
-     */
-    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
-        } else {
-            // reorder named map
-            Name insertName = insertLN.name;
-            if (entriesByName.containsSiblings(insertName)) {
-                int position; 
-                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<LinkedEntries.LinkNode> it = entries.linkNodeIterator(); it.hasNext(); ) {
-                        LinkedEntries.LinkNode ln = it.next();
-                        if (insertName.equals(ln.name) && ln != insertLN) {
-                            position++;
-                        }
-                        if (ln == afterLN) {
-                            break;
-                        }
-                    }
-                }
-                entriesByName.reorder(insertName, insertLN, position);
-            }
-            // reorder in linked list
-            entries.reorderNode(insertLN, currentAfter);
-        }
-    }
-
-    //-------------------------------------------------< AbstractLinkedList >---
-    
-    /**
-     * An implementation of a linked list which provides access to the internal
-     * LinkNode which links the entries of the list.
-     */
-    private final class LinkedEntries extends AbstractLinkedList {
-
-        LinkedEntries() {
-            init();
-        }
-
-        /**
-         * Returns the matching {@code LinkNode} from a list or a single
-         * {@code LinkNode}. This method will return {@code null}
-         * if none of the entries matches either due to missing entry for given
-         * state name or due to missing availability of the {@code NodeEntry}.
-         *
-         * @param nodeEntry the {@code NodeEntry} that is compared to the
-         * resolution of any {@code NodeEntry} that matches by name.
-         * @return the matching {@code LinkNode} or {@code null}
-         */
-        private LinkedEntries.LinkNode getLinkNode(NodeEntry nodeEntry) {
-            for (Iterator<LinkedEntries.LinkNode> it = linkNodeIterator(); it.hasNext();) {
-                LinkedEntries.LinkNode ln = it.next();
-                if (ln.getNodeEntry() == nodeEntry) {
-                    return ln;
-                }
-            }
-            // not found
-            return null;
-        }
-
-        private LinkedEntries.LinkNode getHeader() {
-            return (LinkedEntries.LinkNode) header;
-        }
-
-        /**
-         * 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}.
-         */
-        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} or at the beginning if {@code entry} is
-         * {@code null}.
-         *
-         * @param cne the child node entry to add.
-         * @param index
-         * @param insertAfter after which to insert the new entry
-         * @return the LinkNode which refers to the added {@code NodeEntry}.
-         */
-        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);
-                addNode(newNode, header);
-            } 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.
-         * @return LinkedEntries.LinkNode that has been removed.
-         */
-        LinkedEntries.LinkNode removeNodeEntry(NodeEntry cne) {
-            LinkedEntries.LinkNode ln = getLinkNode(cne);
-            if (ln != null) {
-                ln.remove();
-            }
-            return ln;
-        }
-
-        /**
-         * Reorders an existing {@code LinkNode} before another existing
-         * {@code LinkNode}. If {@code before} is {@code null}
-         * the {@code insert} node is moved to the end of the list.
-         *
-         * @param insert the node to reorder.
-         * @param before the node where to reorder node {@code insert}.
-         */
-        void reorderNode(LinkedEntries.LinkNode insert, LinkedEntries.LinkNode before) {
-            removeNode(insert);
-            if (before == null) {
-                addNode(insert, header);
-            } else {
-                addNode(insert, before);
-            }
-        }
-
-        /**
-         * Create a new {@code LinkNode} for a given {@link NodeEntry}
-         * {@code value}.
-         *
-         * @param value a child node entry.
-         * @return a wrapping {@link LinkedEntries.LinkNode}.
-         */
-        @Override
-        protected Node createNode(Object value) {
-            return new LinkedEntries.LinkNode(value, Path.INDEX_DEFAULT);
-        }
-
-        @Override
-        protected Node createHeaderNode() {
-            return new LinkedEntries.LinkNode();
-        }
-
-        /**
-         * @return iterator over all LinkNode entries in this list.
-         */
-        private Iterator<LinkedEntries.LinkNode> linkNodeIterator() {
-            return new LinkNodeIterator();
-        }
-
-        //----------------------------------------------------------------------
-        /**
-         * Extends the {@code AbstractLinkedList.Node}.
-         */
-        private final class LinkNode extends Node {
-
-            private final Name name;
-
-            protected LinkNode() {
-                name = null;
-            }
-
-            protected LinkNode(Object value, int index) {
-                // add soft reference from linkNode to the NodeEntry (value)
-                // unless the entry is a SNSibling. TODO: review again.
-                super(index > Path.INDEX_DEFAULT ? value : new SoftReference<Object>(value));
-                name = ((NodeEntry) value).getName();
-            }
-
-            @Override
-            protected void setValue(Object value) {
-                UnsupportedOperationException e = new UnsupportedOperationException("remove");
-                log.error(e.getMessage(), e);
-                throw e;
-            }
-
-            @Override
-            protected Object 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.
-                if (ne == null && this != header) {
-                    ne = factory.createNodeEntry(parent, name, null);
-                    super.setValue(new SoftReference<NodeEntry>(ne));
-                }
-                return ne;
-            }
-
-            /**
-             * @return the wrapped {@code NodeEntry}.
-             */
-            public NodeEntry getNodeEntry() {
-                return (NodeEntry) getValue();
-            }
-
-            /**
-             * Removes this {@code LinkNode} from the linked list.
-             */
-            public void remove() {
-                removeNode(this);
-            }
-
-            /**
-             * @return the next LinkNode.
-             */
-            public LinkedEntries.LinkNode getNextLinkNode() {
-                return (LinkedEntries.LinkNode) getNextNode();
-            }
-
-            /**
-             * @return the next LinkNode.
-             */
-            public LinkedEntries.LinkNode getPreviousLinkNode() {
-                return (LinkedEntries.LinkNode) getPreviousNode();
-            }
-        }
-
-        //----------------------------------------------------------------------
-        private class LinkNodeIterator implements Iterator<LinkedEntries.LinkNode> {
-
-            private LinkedEntries.LinkNode next = ((LinkedEntries.LinkNode) header).getNextLinkNode();
-            private final int expectedModCount = modCount;
-
-            @Override
-            public boolean hasNext() {
-                checkModCount();
-                return next != header;
-            }
-
-            @Override
-            public LinkedEntries.LinkNode next() {
-                checkModCount();
-                if (!hasNext()) {
-                    throw new NoSuchElementException();
-                }
-                LinkedEntries.LinkNode n = next;
-                next = next.getNextLinkNode();
-                return n;
-            }
-
-            @Override
-            public void remove() {
-                UnsupportedOperationException e = new UnsupportedOperationException("remove");
-                log.error(e.getMessage(), e);
-                throw e;
-            }
-
-            private void checkModCount() {
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
-                }
-            }
-        }
+    public synchronized NodeEntry remove(NodeEntry nodeEntry) {
+        return entries.remove(nodeEntry.getName());
     }
 
-
-
-    //--------------------------------------------------------------------------
-    
-    /**
-     * Mapping of Name to LinkNode OR List of LinkNode(s) in case of SNSiblings.
-     */
-    private static class NameMap {
-
-        private final Map<Name, List<LinkedEntries.LinkNode>> snsMap = new HashMap<Name, List<LinkedEntries.LinkNode>>();
-        private final Map<Name, LinkedEntries.LinkNode> nameMap = new HashMap<Name, LinkedEntries.LinkNode>();
-
-        /**
-         * Return true if more than one NodeEntry with the given name exists.
-         *
-         * @param name
-         * @return true if more than one NodeEntry with the given name exists.
-         */
-        public boolean containsSiblings(Name name) {
-            return snsMap.containsKey(name);
-        }
-
-        /**
-         * Returns a single {@code NodeEntry} or an unmodifiable
-         * {@code List} of NodeEntry objects.
-         *
-         *
-         * @param name
-         * @return a single {@code NodeEntry} or a {@code List} of
-         * NodeEntry objects.
-         */
-        private List<NodeEntry> get(Name name) {
-            LinkedEntries.LinkNode val = nameMap.get(name);
-            if (val != null) {
-                return Collections.singletonList(val.getNodeEntry());
-            } else {
-                List<LinkedEntries.LinkNode> l = snsMap.get(name);
-                if (l != null) {
-                    List<NodeEntry> nodeEntries = new ArrayList<NodeEntry>(l.size());
-                    for (LinkedEntries.LinkNode ln : l) {
-                        nodeEntries.add(ln.getNodeEntry());
-                    }
-                    return nodeEntries;
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Returns a unmodifiable List of NodeEntry objects even if the name map
-         * only contains a single entry for the given name. If no matching entry
-         * exists for the given {@code Name} an empty list is returned.
-         *
-         * @param name
-         * @return list of entries or an empty list.
-         */
-        public List<NodeEntry> getList(Name name) {
-            List<NodeEntry> nodeEntries = get(name);
-            if (nodeEntries == null) {
-                return Collections.emptyList();
-            } else  {
-                return Collections.unmodifiableList(new ArrayList<NodeEntry>(nodeEntries));
-            }
-        }
-
-        public NodeEntry getNodeEntry(Name name, int index) {
-            List<NodeEntry> obj = get(name);
-            return obj == null
-                ? null
-                : findMatchingEntry(obj, index);
-        }
-
-        public LinkedEntries.LinkNode getLinkNode(Name name, int index) {
-            if (index < Path.INDEX_DEFAULT) {
-                IllegalArgumentException e = new IllegalArgumentException("Illegal index " + index);
-                log.error(e.getMessage(), e);
-                throw e;
-            }
-
-            LinkedEntries.LinkNode val = nameMap.get(name);
-            if (val != null) {
-                return index == Path.INDEX_DEFAULT ? val : null;
-            } else {
-                // look in snsMap
-                List<LinkedEntries.LinkNode> l = snsMap.get(name);
-                int pos = index - 1; // Index of NodeEntry is 1-based
-                return l != null && pos < l.size() ? l.get(pos) : null;
-            }
-        }
-
-        public LinkedEntries.LinkNode getLinkNode(Name name, 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 = nameMap.get(name);
-                if (val != null) {
-                    if (uniqueID.equals(val.getNodeEntry().getUniqueID())) {
-                        return val;
-                    }
-                } else {
-                    // look in snsMap
-                    List<LinkedEntries.LinkNode> l = snsMap.get(name);
-                    if (l != null) {
-                        for (LinkedEntries.LinkNode ln : l) {
-                            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(name, index);
-        }
-
-        public void put(Name name, int index, LinkedEntries.LinkNode value) {
-            // if 'nameMap' already contains a single entry -> move it to snsMap
-            LinkedEntries.LinkNode single = nameMap.remove(name);
-            List<LinkedEntries.LinkNode> l;
-            if (single != null) {
-                l = new ArrayList<LinkedEntries.LinkNode>();
-                l.add(single);
-                snsMap.put(name, l);
-            } else {
-                // if 'snsMap' already contains list
-                l = snsMap.get(name);
-            }
-
-            if (l == null) {
-                // no same name siblings -> simply put to the name map.
-                nameMap.put(name, value);
-            } else {
-                // 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.
-                }
-            }
-        }
-
-        public LinkedEntries.LinkNode remove(Name name, LinkedEntries.LinkNode value) {
-            LinkedEntries.LinkNode rm = nameMap.remove(name);
-            if (rm == null) {
-                List<LinkedEntries.LinkNode> l = snsMap.get(name);
-                if (l != null && l.remove(value)) {
-                    rm = value;
-                }
-            }
-            return rm;
-        }
-
-        public void reorder(Name name, LinkedEntries.LinkNode insertValue, int position) {
-            List<LinkedEntries.LinkNode> sns = snsMap.get(name);
-            if (sns == null) {
-                // no same name siblings -> no special handling required
-                return;
-            }
-            // reorder sns in the name-list
-            sns.remove(insertValue);
-            if (position < 0 || position > sns.size()) {
-                // simply move to end of list
-                sns.add(insertValue);
-            } else {
-                sns.add(position, insertValue);
-            }
-        }
-
-        /**
-         *
-         * @param siblings
-         * @param index
-         * @return matching entry or {@code null}.
-         */
-        private static NodeEntry findMatchingEntry(List<NodeEntry> siblings, int index) {
-            // shortcut if index can never match
-            if (index > siblings.size()) {
-                return null;
-            } else {
-                return siblings.get(index - 1);
-            }
-        }
-    }
 }

Modified: jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java?rev=1213877&r1=1213876&r2=1213877&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java (original)
+++ jackrabbit/sandbox/jackrabbit-mk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java Tue Dec 13 19:13:38 2011
@@ -55,6 +55,7 @@ import javax.jcr.ItemExistsException;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -358,7 +359,7 @@ public class NodeEntry extends Hierarchy
      * @return the index of this child node entry to support 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 javax.jcr.InvalidItemStateException
      * @throws RepositoryException
      */
     public int getIndex() throws RepositoryException {
@@ -384,7 +385,7 @@ public class NodeEntry extends Hierarchy
      *
      * @param path
      * @return the entry at the given path.
-     * @throws PathNotFoundException
+     * @throws javax.jcr.PathNotFoundException
      * @throws RepositoryException
      */
     public NodeEntry getDeepNodeEntry(Path path) throws RepositoryException {
@@ -418,7 +419,7 @@ public class NodeEntry extends Hierarchy
 
                 // -> check for moved child entry in node-attic
                 // -> check if child points to a removed/moved sns
-                List<NodeEntry> siblings = entry.childNodeEntries.get(name);
+                List<NodeEntry> siblings = Collections.singletonList(entry.childNodeEntries.get(name));
                 if (entry.containsAtticChild(siblings, name, index)) {
                     throw new PathNotFoundException(factory.saveGetJCRPath(path));
                 }
@@ -501,7 +502,7 @@ public class NodeEntry extends Hierarchy
                 }
                 // -> check for moved child entry in node-attic
                 // -> check if child points to a removed/moved sns
-                List<NodeEntry> siblings = entry.childNodeEntries.get(name);
+                List<NodeEntry> siblings = Collections.singletonList(entry.childNodeEntries.get(name));
                 if (entry.containsAtticChild(siblings, name, index)) {
                     throw new PathNotFoundException(factory.saveGetJCRPath(path));
                 }
@@ -592,7 +593,7 @@ public class NodeEntry extends Hierarchy
      * the specified {@code nodeName}.
      */
     public synchronized boolean hasNodeEntry(Name nodeName) {
-        List<NodeEntry> namedEntries = childNodeEntries.get(nodeName);
+        List<NodeEntry> namedEntries = Collections.singletonList(childNodeEntries.get(nodeName));
         return !namedEntries.isEmpty() && EntryValidation.containsValidNodeEntry(namedEntries.iterator());
     }
 
@@ -643,7 +644,7 @@ public class NodeEntry extends Hierarchy
      * @throws RepositoryException If an unexpected error occurs.
      */
     public NodeEntry getNodeEntry(Name nodeName, int index, boolean loadIfNotFound) throws RepositoryException {
-        List<NodeEntry> entries = childNodeEntries.get(nodeName);
+        List<NodeEntry> entries = Collections.singletonList(childNodeEntries.get(nodeName));
         NodeEntry cne = null;
         if (entries.size() >= index) {
             // position of entry might differ from index-1 if a SNS with lower
@@ -698,7 +699,7 @@ public class NodeEntry extends Hierarchy
      * @throws RepositoryException If an unexpected error occurs.
      */
     public synchronized List<NodeEntry> getNodeEntries(Name nodeName) throws RepositoryException {
-        List<NodeEntry> namedEntries = getCompleteChildNodeEntries().get(nodeName);
+        List<NodeEntry> namedEntries = Collections.singletonList(getCompleteChildNodeEntries().get(nodeName));
         if (namedEntries.isEmpty()) {
             return Collections.emptyList();
         } else {
@@ -720,7 +721,7 @@ public class NodeEntry extends Hierarchy
      *
      * @param childInfos
      */
-    public void setNodeEntries(Iterator<ChildInfo> childInfos) {
+    public void setNodeEntries(Iterator<ChildInfo> childInfos) throws UnsupportedRepositoryOperationException {
         if (childNodeAttic.isEmpty()) {
             childNodeEntries.update(childInfos);
         } else {
@@ -745,7 +746,9 @@ public class NodeEntry extends Hierarchy
      * @param uniqueID
      * @return the {@code NodeEntry}.
      */
-    public NodeEntry getOrAddNodeEntry(Name nodeName, int index, String uniqueID) {
+    public NodeEntry getOrAddNodeEntry(Name nodeName, int index, String uniqueID)
+            throws UnsupportedRepositoryOperationException {
+
         NodeEntry ne = lookupNodeEntry(uniqueID, nodeName, index);
         if (ne == null) {
             ne = internalAddNodeEntry(nodeName, uniqueID, index);
@@ -764,7 +767,8 @@ public class NodeEntry extends Hierarchy
      * @param definition
      * @return
      */
-    public NodeEntry addNewNodeEntry(Name nodeName, String uniqueID, Name primaryNodeType, QNodeDefinition definition) {
+    public NodeEntry addNewNodeEntry(Name nodeName, String uniqueID, Name primaryNodeType, QNodeDefinition definition)
+            throws UnsupportedRepositoryOperationException {
         
         NodeEntry entry = internalAddNodeEntry(nodeName, uniqueID, Path.INDEX_UNDEFINED);
         NodeState state = getItemStateFactory().createNewNodeState(entry, primaryNodeType, definition);
@@ -942,14 +946,7 @@ public class NodeEntry extends Hierarchy
      * @throws RepositoryException If an unexpected error occurs.
      */
     public void orderBefore(NodeEntry beforeEntry) throws RepositoryException {
-        if (Status.NEW == getStatus()) {
-            // new states get remove upon revert
-            parent.childNodeEntries.reorder(this, beforeEntry);
-        } else {
-            createRevertInfo();
-            // now reorder child entries on parent
-            parent.childNodeEntries.reorder(this, beforeEntry);
-        }
+        throw new UnsupportedRepositoryOperationException("orderBefore");
     }
 
     /**
@@ -1067,8 +1064,14 @@ public class NodeEntry extends Hierarchy
      * @return the added entry.
      */
     private NodeEntry internalAddNodeEntry(Name nodeName, String uniqueID, int index) {
+        if (index > Path.INDEX_DEFAULT) {
+            IllegalArgumentException e = new IllegalArgumentException("Invalid index: " + index);
+            log.error(e.getMessage(), e);
+            throw e;
+        }
+
         NodeEntry entry = factory.createNodeEntry(this, nodeName, uniqueID);
-        childNodeEntries.add(entry, index);
+        childNodeEntries.add(entry);
         return entry;
     }
 
@@ -1213,6 +1216,12 @@ public class NodeEntry extends Hierarchy
     }
 
     private NodeEntry lookupNodeEntry(String uniqueChildId, Name childName, int index) {
+        if (index > Path.INDEX_DEFAULT) {
+            IllegalArgumentException e = new IllegalArgumentException("Invalid index: " + index);
+            log.error(e.getMessage(), e);
+            throw e;
+        }
+
         NodeEntry child = null;
         if (uniqueChildId != null) {
             child = childNodeAttic.get(uniqueChildId);
@@ -1223,7 +1232,7 @@ public class NodeEntry extends Hierarchy
         if (child == null) {
             child = childNodeAttic.get(childName, index);
             if (child == null && childNodeEntries != null) {
-                child = childNodeEntries.get(childName, index);
+                child = childNodeEntries.get(childName);
             }
         }
         return child;
@@ -1335,7 +1344,8 @@ public class NodeEntry extends Hierarchy
      * this {@code NodeEntry}.
      */
     private int getChildIndex(NodeEntry cne, boolean wspIndex) throws RepositoryException {
-        List<NodeEntry> sns = new ArrayList<NodeEntry>(childNodeEntries.get(cne.getName()));
+        List<NodeEntry> sns = new ArrayList<NodeEntry>();
+        sns.add(childNodeEntries.get(cne.getName()));
 
         if (wspIndex) {
             List<NodeEntry> atticSiblings = childNodeAttic.get(cne.getName());
@@ -1648,7 +1658,7 @@ public class NodeEntry extends Hierarchy
         // now restore moved entry with the old name and index and re-add
         // it to its original parent
         name = revertInfo.oldName;
-        parent.childNodeEntries.add(this, revertInfo.oldIndex, revertInfo.oldSuccessor);
+        parent.childNodeEntries.add(this);
     }
 
     private static Name[] getMixinNames(PropertyState propertyState) {
@@ -1677,15 +1687,11 @@ public class NodeEntry extends Hierarchy
         private final NodeEntry oldParent;
         private final Name oldName;
         private final int oldIndex;
-        private final NodeEntry oldSuccessor;
-        private final NodeEntry oldPredecessor;
 
         private RevertInfo() throws RepositoryException {
             oldParent = parent;
             oldName = name;
             oldIndex = getIndex();
-            oldSuccessor = parent.childNodeEntries.getNext(NodeEntry.this);
-            oldPredecessor = parent.childNodeEntries.getPrevious(NodeEntry.this);
         }
 
         private boolean isMoved() {
@@ -1695,8 +1701,6 @@ public class NodeEntry extends Hierarchy
         private void dispose(boolean persisted) {
             if (!persisted) {
                 NodeEntry ne = NodeEntry.this;
-                ChildNodeEntries parentCNEs = parent.childNodeEntries;
-                parentCNEs.reorderAfter(ne, revertInfo.oldPredecessor);
                 try {
                     if (oldIndex != ne.getIndex()) {
                         // TODO: fix

Modified: jackrabbit/sandbox/jackrabbit-mk/jackrabbit-spi2microkernel/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mk/jackrabbit-spi2microkernel/pom.xml?rev=1213877&r1=1213876&r2=1213877&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mk/jackrabbit-spi2microkernel/pom.xml (original)
+++ jackrabbit/sandbox/jackrabbit-mk/jackrabbit-spi2microkernel/pom.xml Tue Dec 13 19:13:38 2011
@@ -281,6 +281,13 @@
                                         org.apache.jackrabbit.test.api.NodeTest#testRefreshInvalidItemStateException
                                         org.apache.jackrabbit.test.api.NodeTest#testSaveOnNewNodeRepositoryException
 
+                                        <!-- Not supported reorder -->
+                                        org.apache.jackrabbit.test.api.observation.NodeReorderTest#testNodeReorder
+                                        org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest#testOrderBeforePlaceAtEndParentSave
+                                        org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest#testOrderBeforePlaceAtEndSessionSave
+                                        org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest#testOrderBeforeSecondToFirstParentSave
+                                        org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest#testOrderBeforeSecondToFirstSessionSave
+
                                         <!-- fixme: Microkernel indexer does not properly handler multi valued properties -->
                                         org.apache.jackrabbit.test.api.GetWeakReferencesTest#testMultiValues
                                         org.apache.jackrabbit.test.api.GetWeakReferencesTest#testMultiValuesWithName
@@ -290,9 +297,6 @@
                                         org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveNode
                                         org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveWithRemove
 
-                                        <!-- fixme: reorder is not yet implemented -->
-                                        org.apache.jackrabbit.test.api.observation.NodeReorderTest#testNodeReorder
-
                                         <!-- fixme: filtering by uuid, nodetype is not yet implemented -->
                                         org.apache.jackrabbit.test.api.observation.AddEventListenerTest#testNodeType
                                         org.apache.jackrabbit.test.api.observation.AddEventListenerTest#testUUID