You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2012/01/06 11:42:37 UTC

svn commit: r1228068 - in /jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk: model/ util/

Author: stefan
Date: Fri Jan  6 10:42:37 2012
New Revision: 1228068

URL: http://svn.apache.org/viewvc?rev=1228068&view=rev
Log:
flat hierarchy support (WIP):

refactored child node entries collection

Added:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/EmptyIterator.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java
Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java?rev=1228068&r1=1228067&r2=1228068&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java Fri Jan  6 10:42:37 2012
@@ -18,7 +18,10 @@ package org.apache.jackrabbit.mk.model;
 
 import org.apache.jackrabbit.mk.store.RevisionProvider;
 import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.AbstractRangeIterator;
+import org.apache.jackrabbit.mk.util.EmptyIterator;
 import org.apache.jackrabbit.mk.util.PathUtils;
+import org.apache.jackrabbit.mk.util.RangeIterator;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -35,25 +38,24 @@ public abstract class AbstractNode imple
 
     protected HashMap<String, String> properties;
 
-    // map keeping insertion order
-    protected LinkedHashMap<String, ChildNodeEntry> childEntries;
+    protected ChildNodeEntries childEntries;
 
     protected AbstractNode() {
         this.properties = new HashMap<String, String>();
-        this.childEntries = new LinkedHashMap<String, ChildNodeEntry>();
+        this.childEntries = new ChildNodeEntries();
     }
 
     protected AbstractNode(Node other) {
         if (other instanceof AbstractNode) {
             AbstractNode srcNode = (AbstractNode) other;
             this.properties = (HashMap<String, String>) srcNode.properties.clone();
-            this.childEntries = (LinkedHashMap<String, ChildNodeEntry>) srcNode.childEntries.clone();
+            this.childEntries = (ChildNodeEntries) srcNode.childEntries.clone();
         } else {
             this.properties = new HashMap<String, String>(other.getProperties());
-            this.childEntries = new LinkedHashMap<String, ChildNodeEntry>(other.getChildNodeCount());
+            this.childEntries = new ChildNodeEntries();
             for (Iterator<ChildNodeEntry> it = other.getChildNodeEntries(); it.hasNext(); ) {
                 ChildNodeEntry cne = it.next();
-                this.childEntries.put(cne.getName(), cne);
+                this.childEntries.add(cne);
             }
         }
     }
@@ -67,25 +69,11 @@ public abstract class AbstractNode imple
     }
 
     public Iterator<String> getChildNodeNames(int offset, int count) {
-        if (offset < 0 || count < -1) {
-            throw new IllegalArgumentException();
-        }
-
-        if (offset == 0 && count == -1) {
-            return childEntries.keySet().iterator();
-        } else {
-            if (offset >= childEntries.size()) {
-                return new EmptyIterator<String>();
-            }
-            if (count == -1 || (offset + count) > childEntries.size()) {
-                count = childEntries.size() - offset;
-            }
-            return new RangeIterator<String>(childEntries.keySet().iterator(), offset, count);
-        }
+        return childEntries.getNames(offset, count);
     }
 
     public int getChildNodeCount() {
-        return childEntries.size();
+        return childEntries.getCount();
     }
 
     public Iterator<ChildNodeEntry> getChildNodeEntries() {
@@ -93,20 +81,7 @@ public abstract class AbstractNode imple
     }
 
     public Iterator<ChildNodeEntry> getChildNodeEntries(int offset, int count) {
-        if (offset < 0 || count < -1) {
-            throw new IllegalArgumentException();
-        }
-        if (offset == 0 && count == -1) {
-            return childEntries.values().iterator();
-        } else {
-            if (offset >= childEntries.size()) {
-                return new EmptyIterator<ChildNodeEntry>();
-            }
-            if (count == -1 || (offset + count) > childEntries.size()) {
-                count = childEntries.size() - offset;
-            }
-            return new RangeIterator<ChildNodeEntry>(childEntries.values().iterator(), offset, count);
-        }
+        return childEntries.getEntries(offset, count);
     }
 
     public Iterator<ChildNode> getChildNodes(int offset, int count, final RevisionProvider provider)
@@ -115,17 +90,17 @@ public abstract class AbstractNode imple
             throw new IllegalArgumentException();
         }
 
-        if (offset >= childEntries.size()) {
+        if (offset >= childEntries.getCount()) {
             return new EmptyIterator<ChildNode>();
         }
 
         // todo support embedded/in-lined sub-trees
 
-        if (count == -1 || (offset + count) > childEntries.size()) {
-            count = childEntries.size() - offset;
+        if (count == -1 || (offset + count) > childEntries.getCount()) {
+            count = childEntries.getCount() - offset;
         }
 
-        return new AbstractRangeIterator<ChildNode>(childEntries.values().iterator(), offset, count) {
+        return new AbstractRangeIterator<ChildNode>(childEntries.getEntries(0, -1), offset, count) {
             @Override
             protected ChildNode doNext() {
                 ChildNodeEntry cne = (ChildNodeEntry) it.next();
@@ -182,23 +157,33 @@ public abstract class AbstractNode imple
 
         // compare child node entries
 
-        // todo efficiently handle large child node lists
-
-        Map<String, ChildNodeEntry> oldEntries, newEntries;
         if (other instanceof AbstractNode) {
-            oldEntries = childEntries;
-            newEntries = ((AbstractNode) other).childEntries;
-        } else {
-            oldEntries = new LinkedHashMap<String, ChildNodeEntry>(getChildNodeCount());
-            for (Iterator<ChildNodeEntry> it = getChildNodeEntries(0, -1); it.hasNext(); ) {
-                ChildNodeEntry cne = it.next();
-                oldEntries.put(cne.getName(), cne);
-            }
-            newEntries = new LinkedHashMap<String, ChildNodeEntry>(other.getChildNodeCount());
-            for (Iterator<ChildNodeEntry> it = other.getChildNodeEntries(0, -1); it.hasNext(); ) {
-                ChildNodeEntry cne = it.next();
-                newEntries.put(cne.getName(), cne);
-            }
+            ChildNodeEntries otherEntries = ((AbstractNode) other).childEntries;
+            for (Iterator<ChildNodeEntry> it = childEntries.getAdded(otherEntries); it.hasNext(); ) {
+                ChildNodeEntry added = it.next();
+                handler.childNodeAdded(added.getName(), added.getId());
+            }
+            for (Iterator<ChildNodeEntry> it = childEntries.getRemoved(otherEntries); it.hasNext(); ) {
+                ChildNodeEntry removed = it.next();
+                handler.childNodeDeleted(removed.getName(), removed.getId());
+            }
+            for (Iterator<ChildNodeEntry> it = childEntries.getModified(otherEntries); it.hasNext(); ) {
+                ChildNodeEntry old = it.next();
+                ChildNodeEntry modified = otherEntries.get(old.getName());
+                handler.childNodeChanged(old.getName(), old.getId(), modified.getId());
+            }
+            return;
+        }
+
+        Map<String, ChildNodeEntry> oldEntries = new LinkedHashMap<String, ChildNodeEntry>(getChildNodeCount());
+        for (Iterator<ChildNodeEntry> it = getChildNodeEntries(0, -1); it.hasNext(); ) {
+            ChildNodeEntry cne = it.next();
+            oldEntries.put(cne.getName(), cne);
+        }
+        Map<String, ChildNodeEntry> newEntries = new LinkedHashMap<String, ChildNodeEntry>(other.getChildNodeCount());
+        for (Iterator<ChildNodeEntry> it = other.getChildNodeEntries(0, -1); it.hasNext(); ) {
+            ChildNodeEntry cne = it.next();
+            newEntries.put(cne.getName(), cne);
         }
         if (!oldEntries.equals(newEntries)) {
             Set<String> set = new HashSet<String>();
@@ -221,64 +206,4 @@ public abstract class AbstractNode imple
             }
         }
     }
-
-    //--------------------------------------------------------< inner classes >
-
-    static class EmptyIterator<T> implements Iterator<T> {
-
-        public boolean hasNext() {
-            return false;
-        }
-
-        public T next() {
-            throw new NoSuchElementException();
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    static abstract class AbstractRangeIterator<T> implements Iterator<T> {
-
-        final Iterator<?> it;
-        int count;
-
-        public AbstractRangeIterator(Iterator<?> it, int offset, int count) {
-            while (offset-- > 0 && it.hasNext()) {
-                it.next();
-            }
-            this.count = count;
-            this.it = it;
-        }
-
-        public boolean hasNext() {
-            return (count > 0 && it.hasNext());
-        }
-
-        public T next() {
-            if (count-- > 0) {
-                return doNext();
-            }
-            throw new NoSuchElementException();
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-        
-        protected abstract T doNext();
-    }
-
-    static class RangeIterator<T> extends AbstractRangeIterator<T> {
-
-        public RangeIterator(Iterator<T> it, int offset, int count) {
-            super(it, offset, count);
-        }
-
-        @Override
-        protected T doNext() {
-            return (T) it.next();
-        }
-    }
 }

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java?rev=1228068&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java Fri Jan  6 10:42:37 2012
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.mk.model;
+
+import org.apache.jackrabbit.mk.util.AbstractFilteringIterator;
+import org.apache.jackrabbit.mk.util.EmptyIterator;
+import org.apache.jackrabbit.mk.util.RangeIterator;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+class ChildNodeEntries implements Cloneable {
+
+    protected static final Iterator<ChildNodeEntry> EMPTY_ITER = new EmptyIterator<ChildNodeEntry>();
+    
+    protected LinkedHashMap<String, ChildNodeEntry> entries;
+    
+    ChildNodeEntries() {
+        entries = new LinkedHashMap<String, ChildNodeEntry>();
+    }
+
+    @Override
+    protected Object clone()  {
+        ChildNodeEntries clone = null;
+        try {
+            clone = (ChildNodeEntries) super.clone();
+        } catch (CloneNotSupportedException e) {
+            // can't possibly get here
+        }
+        clone.entries = (LinkedHashMap<String, ChildNodeEntry>) entries.clone();
+        return clone;
+    }
+
+    //-------------------------------------------------------------< read ops >
+    int getCount() {
+        return entries.size();
+    }
+
+    ChildNodeEntry get(String name) {
+        return entries.get(name);
+    }
+
+    Iterator<String> getNames(int offset, int count) {
+        if (offset < 0 || count < -1) {
+            throw new IllegalArgumentException();
+        }
+
+        if (offset == 0 && count == -1) {
+            return entries.keySet().iterator();
+        } else {
+            if (offset >= entries.size()) {
+                return new EmptyIterator<String>();
+            }
+            if (count == -1 || (offset + count) > entries.size()) {
+                count = entries.size() - offset;
+            }
+            return new RangeIterator<String>(entries.keySet().iterator(), offset, count);
+        }
+    }
+
+    Iterator<ChildNodeEntry> getEntries(int offset, int count) {
+        if (offset < 0 || count < -1) {
+            throw new IllegalArgumentException();
+        }
+        if (offset == 0 && count == -1) {
+            return entries.values().iterator();
+        } else {
+            if (offset >= entries.size()) {
+                return new EmptyIterator<ChildNodeEntry>();
+            }
+            if (count == -1 || (offset + count) > entries.size()) {
+                count = entries.size() - offset;
+            }
+            return new RangeIterator<ChildNodeEntry>(entries.values().iterator(), offset, count);
+        }
+    }
+
+    //------------------------------------------------------------< write ops >
+    ChildNodeEntry add(ChildNodeEntry entry) {
+        return entries.put(entry.getName(), entry);
+    }
+
+    ChildNodeEntry remove(String name) {
+        return entries.remove(name);
+    }
+
+    ChildNodeEntry rename(String oldName, String newName) {
+        if (oldName.equals(newName)) {
+            return entries.get(oldName);
+        }
+        LinkedHashMap<String, ChildNodeEntry> clone =
+                (LinkedHashMap<String, ChildNodeEntry>) entries.clone();
+        entries.clear();
+        ChildNodeEntry oldCNE = null;
+        for (Map.Entry<String, ChildNodeEntry> entry : clone.entrySet()) {
+            if (entry.getKey().equals(oldName)) {
+                oldCNE = entry.getValue();
+                entries.put(newName, new ChildNodeEntry(newName, oldCNE.getId()));
+            } else {
+                entries.put(entry.getKey(), entry.getValue());
+            }
+        }
+        return oldCNE;
+    }
+
+    ChildNodeEntry moveAfter(String name, String sibling) {
+        ChildNodeEntry target = entries.remove(name);
+        if (target == null) {
+            return null;
+        }
+
+        if (sibling == null) {
+            // move to bottom (re-adding it will append it)
+            entries.put(target.getName(), target);
+            return target;
+        } else {
+            LinkedHashMap<String, ChildNodeEntry> clone =
+                    (LinkedHashMap<String, ChildNodeEntry>) entries.clone();
+            entries.clear();
+            for (Map.Entry<String, ChildNodeEntry> entry : clone.entrySet()) {
+                entries.put(entry.getKey(), entry.getValue());
+                if (entry.getKey().equals(sibling)) {
+                    entries.put(name, target);
+                }
+            }
+        }
+        return target;
+    }
+
+    ChildNodeEntry moveBefore(String name, String sibling) {
+        ChildNodeEntry target = entries.remove(name);
+        if (target == null) {
+            return null;
+        }
+
+        if (sibling == null) {
+            // move to bottom (re-adding it will append it)
+            entries.put(target.getName(), target);
+            return target;
+        } else {
+            LinkedHashMap<String, ChildNodeEntry> clone =
+                    (LinkedHashMap<String, ChildNodeEntry>) entries.clone();
+            entries.clear();
+            for (Map.Entry<String, ChildNodeEntry> entry : clone.entrySet()) {
+                entries.put(entry.getKey(), entry.getValue());
+                if (entry.getKey().equals(sibling)) {
+                    entries.put(name, target);
+                }
+            }
+        }
+        return target;
+    }
+
+    //-------------------------------------------------------------< diff ops >
+    Iterator<ChildNodeEntry> getAdded(final ChildNodeEntries other) {
+        if (entries.equals(other)) {
+            return EMPTY_ITER;            
+        }
+        
+        return new AbstractFilteringIterator<ChildNodeEntry>(other.getEntries(0, -1)) {
+            @Override
+            protected boolean include(ChildNodeEntry entry) {
+                return !entries.containsKey(entry.getName());
+            }
+        };
+    }
+
+    Iterator<ChildNodeEntry> getRemoved(final ChildNodeEntries other) {
+        if (entries.equals(other)) {
+            return EMPTY_ITER;
+        }
+
+        return new AbstractFilteringIterator<ChildNodeEntry>(entries.values().iterator()) {
+            @Override
+            protected boolean include(ChildNodeEntry entry) {
+                return other.get(entry.getName()) == null;
+            }
+        };
+    }
+
+    Iterator<ChildNodeEntry> getModified(final ChildNodeEntries other) {
+        if (entries.equals(other)) {
+            return EMPTY_ITER;
+        }
+
+        return new AbstractFilteringIterator<ChildNodeEntry>(entries.values().iterator()) {
+            @Override
+            protected boolean include(ChildNodeEntry entry) {
+                ChildNodeEntry namesake = other.get(entry.getName());
+                return (namesake != null && !namesake.getId().equals(entry.getId()));
+            }
+        };
+    }
+
+    //--------------------------------------------------------< inner classes >
+}

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java?rev=1228068&r1=1228067&r2=1228068&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java Fri Jan  6 10:42:37 2012
@@ -16,9 +16,6 @@
  */
 package org.apache.jackrabbit.mk.model;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 /**
  *
  */
@@ -32,7 +29,7 @@ public class MutableNode extends Abstrac
     }
 
     public ChildNodeEntry add(ChildNodeEntry newEntry) {
-        return childEntries.put(newEntry.getName(), newEntry);
+        return childEntries.add(newEntry);
     }
     
     public ChildNodeEntry remove(String name) {
@@ -40,21 +37,6 @@ public class MutableNode extends Abstrac
     }
 
     public ChildNodeEntry rename(String oldName, String newName) {
-        if (oldName.equals(newName)) {
-            return childEntries.get(oldName);
-        }
-        LinkedHashMap<String, ChildNodeEntry> clone = 
-                (LinkedHashMap<String, ChildNodeEntry>) childEntries.clone();
-        childEntries.clear();
-        ChildNodeEntry oldCNE = null;
-        for (Map.Entry<String, ChildNodeEntry> entry : clone.entrySet()) {
-            if (entry.getKey().equals(oldName)) {
-                oldCNE = entry.getValue();
-                childEntries.put(newName, new ChildNodeEntry(newName, oldCNE.getId()));
-            } else {
-                childEntries.put(entry.getKey(), entry.getValue());
-            }
-        }
-        return oldCNE;
+        return childEntries.rename(oldName, newName);
     }
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java?rev=1228068&r1=1228067&r2=1228068&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java Fri Jan  6 10:42:37 2012
@@ -18,11 +18,11 @@ package org.apache.jackrabbit.mk.model;
 
 import org.apache.jackrabbit.mk.store.RevisionProvider;
 import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.UnmodifiableIterator;
 
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.NoSuchElementException;
 
 /**
  *
@@ -35,10 +35,8 @@ public class StoredNode extends Abstract
         this.id = id;
         this.properties.putAll(properties);
         while (cneIt.hasNext()) {
-            ChildNodeEntry cne = cneIt.next();
-            childEntries.put(cne.getName(), cne);
+            childEntries.add(cneIt.next());
         }
-        this.childEntries.putAll(childEntries);
     }
 
     public StoredNode(String id, Node node) {
@@ -78,27 +76,4 @@ public class StoredNode extends Abstract
         }
         return result;
     }
-
-    //--------------------------------------------------------< inner classes >
-
-    static class UnmodifiableIterator<T> implements Iterator<T> {
-        
-        final Iterator<T> it;
-
-        public UnmodifiableIterator(Iterator<T> it) {
-            this.it = it;
-        }
-
-        public boolean hasNext() {
-            return it.hasNext();
-        }
-
-        public T next() {
-            return it.next();
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
 }

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java?rev=1228068&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java Fri Jan  6 10:42:37 2012
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.mk.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * 
+ */
+public abstract class AbstractFilteringIterator<T> implements Iterator<T> {
+
+    protected final Iterator<T> it;
+    protected int count;
+
+    protected T next = null;
+
+    public AbstractFilteringIterator(Iterator<T> it) {
+        this.it = it;
+    }
+
+    public boolean hasNext() {
+        while (next == null && it.hasNext()) {
+            T entry = it.next();
+            if (include(entry)) {
+                next = entry;
+            }
+        }
+
+        return next != null;
+    }
+    
+    abstract protected boolean include(T entry);
+
+    public T next() {
+        if (hasNext()) {
+            T entry = next;
+            next = null;
+            return entry;
+        } else {
+            throw new NoSuchElementException();
+        }
+    }
+
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java?rev=1228068&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java Fri Jan  6 10:42:37 2012
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.mk.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ *
+ */
+public abstract class AbstractRangeIterator<T> implements Iterator<T> {
+
+    protected final Iterator<?> it;
+    protected int count;
+
+    public AbstractRangeIterator(Iterator<?> it, int offset, int count) {
+        while (offset-- > 0 && it.hasNext()) {
+            it.next();
+        }
+        this.count = count;
+        this.it = it;
+    }
+
+    public boolean hasNext() {
+        return (count > 0 && it.hasNext());
+    }
+
+    public T next() {
+        if (count-- > 0) {
+            return doNext();
+        }
+        throw new NoSuchElementException();
+    }
+
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    protected abstract T doNext();
+}

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/EmptyIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/EmptyIterator.java?rev=1228068&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/EmptyIterator.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/EmptyIterator.java Fri Jan  6 10:42:37 2012
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.mk.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ *
+ */
+public class EmptyIterator<T> implements Iterator<T> {
+
+    public boolean hasNext() {
+        return false;
+    }
+
+    public T next() {
+        throw new NoSuchElementException();
+    }
+
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
\ No newline at end of file

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java?rev=1228068&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java Fri Jan  6 10:42:37 2012
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.mk.util;
+
+import java.util.Iterator;
+
+/**
+ *
+ */
+public class RangeIterator<T> extends AbstractRangeIterator<T> {
+
+    public RangeIterator(Iterator<T> it, int offset, int count) {
+        super(it, offset, count);
+    }
+
+    @Override
+    protected T doNext() {
+        return (T) it.next();
+    }
+}
\ No newline at end of file

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java?rev=1228068&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java Fri Jan  6 10:42:37 2012
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.mk.util;
+
+import java.util.Iterator;
+
+/**
+ *
+ */
+public class UnmodifiableIterator<T> implements Iterator<T> {
+
+    final Iterator<T> it;
+
+    public UnmodifiableIterator(Iterator<T> it) {
+        this.it = it;
+    }
+
+    public boolean hasNext() {
+        return it.hasNext();
+    }
+
+    public T next() {
+        return it.next();
+    }
+
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}