You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2009/08/05 19:55:16 UTC

svn commit: r801340 [10/13] - in /directory/apacheds/trunk: core-entry/src/main/java/org/apache/directory/server/core/entry/ core-entry/src/test/java/org/apache/directory/server/core/entry/ core-integ/src/main/java/org/apache/directory/server/core/inte...

Modified: directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/DupsCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/DupsCursor.java?rev=801340&r1=801339&r2=801340&view=diff
==============================================================================
--- directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/DupsCursor.java (original)
+++ directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/DupsCursor.java Wed Aug  5 17:55:15 2009
@@ -1,466 +1,466 @@
-/*
- *  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.directory.server.core.partition.impl.btree.jdbm;
-
-
-import jdbm.btree.BTree;
-
-import org.apache.directory.server.core.avltree.ArrayTree;
-import org.apache.directory.server.core.avltree.ArrayTreeCursor;
-import org.apache.directory.server.xdbm.Tuple;
-import org.apache.directory.server.xdbm.AbstractTupleCursor;
-import org.apache.directory.shared.ldap.cursor.Cursor;
-import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * A Cursor over a BTree which manages duplicate keys.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$
- */
-class DupsCursor<K,V> extends AbstractTupleCursor<K,V>
-{
-    private static final Logger LOG = LoggerFactory.getLogger( DupsCursor.class.getSimpleName() );
-    
-    /**
-     * The JDBM backed table this Cursor traverses over.
-     */
-    private final JdbmTable<K,V> table;
-
-    /**
-     * An wrappedCursor Cursor which returns Tuples whose values are
-     * DupsContainer objects representing either AvlTrees or BTreeRedirect
-     * objects used to store the values of duplicate keys.  It does not return
-     * different values for the same key.
-     */
-    private final DupsContainerCursor<K,V> containerCursor;
-
-    /**
-     * The current Tuple returned from the wrappedCursor DupsContainerCursor.
-     */
-    private final Tuple<K,DupsContainer<V>> containerTuple = new Tuple<K, DupsContainer<V>>();
-
-    /**
-     * A Cursor over a set of value objects for the current key held in the
-     * containerTuple.  A new Cursor will be set for each new key as we
-     * traverse.  The Cursor traverses over either a AvlTree object full
-     * of values in a multi-valued key or it traverses over a BTree which
-     * contains the values in the key field of it's Tuples.
-     */
-    private Cursor<V> dupsCursor;
-
-    /**
-     * The Tuple that is used to return values via the get() method. This
-     * same Tuple instance will be returned every time.  At different
-     * positions it may return different values for the same key.
-     */
-    private final Tuple<K,V> returnedTuple = new Tuple<K,V>();
-
-    /**
-     * Whether or not a value is available when get() is called.
-     */
-    private boolean valueAvailable;
-
-
-    public DupsCursor( JdbmTable<K,V> table ) throws Exception
-    {
-        this.table = table;
-        this.containerCursor = new DupsContainerCursor<K,V>( table );
-        LOG.debug( "Created on table {}", table );
-    }
-
-
-    public boolean available()
-    {
-        return valueAvailable;
-    }
-
-
-    public void beforeKey( K key ) throws Exception
-    {
-        beforeValue( key, null );
-    }
-
-
-    public void beforeValue( K key, V value ) throws Exception
-    {
-        checkNotClosed( "beforeValue()" );
-        containerCursor.before( new Tuple<K,DupsContainer<V>>( key, null ) );
-
-        if ( containerCursor.next() )
-        {
-            containerTuple.setBoth( containerCursor.get() );
-            DupsContainer<V> values = containerTuple.getValue();
-
-            if ( values.isArrayTree() )
-            {
-                ArrayTree<V> set = values.getArrayTree();
-                dupsCursor = new ArrayTreeCursor<V>( set );
-            }
-            else
-            {
-                BTree tree = table.getBTree( values.getBTreeRedirect() );
-                dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
-            }
-
-            if ( value == null )
-            {
-                return;
-            }
-
-            // advance the dupsCursor only if we're on same key
-            if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
-            {
-                dupsCursor.before( value );
-            }
-
-            return;
-        }
-
-        clearValue();
-        containerTuple.setKey( null );
-        containerTuple.setValue( null );
-    }
-
-
-    public void afterKey( K key ) throws Exception
-    {
-        afterValue( key, null );
-    }
-
-
-    public void afterValue( K key, V value ) throws Exception
-    {
-        checkNotClosed( "afterValue()" );
-        /*
-         * There is a subtle difference between after and before handling
-         * with duplicate key values.  Say we have the following tuples:
-         *
-         * (0, 0)
-         * (1, 1)
-         * (1, 2)
-         * (1, 3)
-         * (2, 2)
-         *
-         * If we request an after cursor on (1, 2).  We must make sure that
-         * the container cursor does not advance after the entry with key 1
-         * since this would result in us skip returning (1. 3) on the call to
-         * next which will incorrectly return (2, 2) instead.
-         *
-         * So if the value is null in the element then we don't care about
-         * this obviously since we just want to advance past the duplicate key
-         * values all together.  But when it is not null, then we want to
-         * go right before this key instead of after it.
-         */
-
-        if ( value == null )
-        {
-            containerCursor.after( new Tuple<K,DupsContainer<V>>( key, null ) );
-        }
-        else
-        {
-            containerCursor.before( new Tuple<K,DupsContainer<V>>( key, null ) );
-        }
-
-        if ( containerCursor.next() )
-        {
-            containerTuple.setBoth( containerCursor.get() );
-            DupsContainer<V> values = containerTuple.getValue();
-
-            if ( values.isArrayTree() )
-            {
-                ArrayTree<V> set = values.getArrayTree();
-                dupsCursor = new ArrayTreeCursor<V>( set );
-            }
-            else
-            {
-                BTree tree = table.getBTree( values.getBTreeRedirect() );
-                dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
-            }
-
-            if ( value == null )
-            {
-                return;
-            }
-
-            // only advance the dupsCursor if we're on same key
-            if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
-            {
-                dupsCursor.after( value );
-            }
-
-            return;
-        }
-
-        clearValue();
-        containerTuple.setKey( null );
-        containerTuple.setValue( null );
-    }
-
-
-    public void before( Tuple<K,V> element ) throws Exception
-    {
-        beforeValue( element.getKey(), element.getValue() );
-    }
-
-
-    public void after( Tuple<K,V> element ) throws Exception
-    {
-        afterValue( element.getKey(), element.getValue() );
-    }
-
-
-    public void beforeFirst() throws Exception
-    {
-        checkNotClosed( "beforeFirst()" );
-        clearValue();
-        containerCursor.beforeFirst();
-        containerTuple.setKey( null );
-        containerTuple.setValue( null );
-        dupsCursor = null;
-    }
-
-
-    public void afterLast() throws Exception
-    {
-        checkNotClosed( "afterLast()" );
-        clearValue();
-        containerCursor.afterLast();
-        containerTuple.setKey( null );
-        containerTuple.setValue( null );
-        dupsCursor = null;
-    }
-
-
-    public boolean first() throws Exception
-    {
-        checkNotClosed( "first()" );
-        clearValue();
-        dupsCursor = null;
-
-        if ( containerCursor.first() )
-        {
-            containerTuple.setBoth( containerCursor.get() );
-            DupsContainer<V> values = containerTuple.getValue();
-
-            if ( containerTuple.getValue().isArrayTree() )
-            {
-                dupsCursor = new ArrayTreeCursor<V>( values.getArrayTree() );
-            }
-            else
-            {
-                BTree bt = table.getBTree( values.getBTreeRedirect() );
-                dupsCursor = new KeyBTreeCursor<V>( bt, table.getValueComparator() );
-            }
-
-            /*
-             * Since only tables with duplicate keys enabled use this
-             * cursor, entries must have at least one value, and therefore
-             * call to last() will always return true.
-             */
-            dupsCursor.first();
-            valueAvailable =  true;
-            returnedTuple.setKey( containerTuple.getKey() );
-            returnedTuple.setValue( dupsCursor.get() );
-            return true;
-        }
-
-        return false;
-    }
-
-
-    public boolean last() throws Exception
-    {
-        checkNotClosed( "last()" );
-        clearValue();
-        dupsCursor = null;
-
-        if ( containerCursor.last() )
-        {
-            containerTuple.setBoth( containerCursor.get() );
-            DupsContainer<V> values = containerTuple.getValue();
-
-            if ( values.isArrayTree() )
-            {
-                ArrayTree<V> set = values.getArrayTree();
-                dupsCursor = new ArrayTreeCursor<V>( set );
-            }
-            else
-            {
-                BTree tree = table.getBTree( values.getBTreeRedirect() );
-                dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
-            }
-
-            /*
-             * Since only tables with duplicate keys enabled use this
-             * cursor, entries must have at least one value, and therefore
-             * call to last() will always return true.
-             */
-            dupsCursor.last();
-            valueAvailable = true;
-            returnedTuple.setKey( containerTuple.getKey() );
-            returnedTuple.setValue( dupsCursor.get() );
-            return true;
-        }
-
-        return false;
-    }
-
-
-
-    private void clearValue()
-    {
-        returnedTuple.setKey( null );
-        returnedTuple.setValue( null );
-        valueAvailable = false;
-    }
-
-
-    public boolean previous() throws Exception
-    {
-        checkNotClosed( "previous()" );
-        /*
-         * If the iterator over the values of the current key is null or is
-         * extinguished then we need to advance to the previous key.
-         */
-        if ( null == dupsCursor || ! dupsCursor.previous() )
-        {
-            /*
-             * If the wrappedCursor cursor has more elements we get the previous
-             * key/AvlTree Tuple to work with and get a cursor over it's
-             * values.
-             */
-            if ( containerCursor.previous() )
-            {
-                containerTuple.setBoth( containerCursor.get() );
-                DupsContainer<V> values = containerTuple.getValue();
-
-                if ( values.isArrayTree() )
-                {
-                    ArrayTree<V> set = values.getArrayTree();
-                    dupsCursor = new ArrayTreeCursor<V>( set );
-                }
-                else
-                {
-                    BTree tree = table.getBTree( values.getBTreeRedirect() );
-                    dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
-                }
-
-                /*
-                 * Since only tables with duplicate keys enabled use this
-                 * cursor, entries must have at least one value, and therefore
-                 * call to previous() after bringing the cursor to afterLast()
-                 * will always return true.
-                 */
-                dupsCursor.afterLast();
-                dupsCursor.previous();
-            }
-            else
-            {
-                dupsCursor = null;
-                return false;
-            }
-        }
-
-        returnedTuple.setKey( containerTuple.getKey() );
-        returnedTuple.setValue( dupsCursor.get() );
-        return valueAvailable = true;
-    }
-
-
-    public boolean next() throws Exception
-    {
-        checkNotClosed( "next()" );
-        /*
-         * If the iterator over the values of the current key is null or is
-         * extinguished then we need to advance to the next key.
-         */
-        if ( null == dupsCursor || ! dupsCursor.next() )
-        {
-            /*
-             * If the wrappedCursor cursor has more elements we get the next
-             * key/AvlTree Tuple to work with and get a cursor over it.
-             */
-            if ( containerCursor.next() )
-            {
-                containerTuple.setBoth( containerCursor.get() );
-                DupsContainer<V> values = containerTuple.getValue();
-
-                if ( values.isArrayTree() )
-                {
-                    ArrayTree<V> set = values.getArrayTree();
-                    dupsCursor = new ArrayTreeCursor<V>( set );
-                }
-                else
-                {
-                    BTree tree = table.getBTree( values.getBTreeRedirect() );
-                    dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
-                }
-
-                /*
-                 * Since only tables with duplicate keys enabled use this
-                 * cursor, entries must have at least one value, and therefore
-                 * call to next() after bringing the cursor to beforeFirst()
-                 * will always return true.
-                 */
-                dupsCursor.beforeFirst();
-                dupsCursor.next();
-            }
-            else
-            {
-                dupsCursor = null;
-                return false;
-            }
-        }
-
-        /*
-         * If we get to this point then cursor has more elements and
-         * containerTuple holds the Tuple containing the key and the btree or
-         * AvlTree of values for that key which the Cursor traverses.  All we
-         * need to do is populate our tuple object with the key and the value
-         * in the cursor.
-         */
-        returnedTuple.setKey( containerTuple.getKey() );
-        returnedTuple.setValue( dupsCursor.get() );
-        return valueAvailable = true;
-    }
-
-
-    public Tuple<K,V> get() throws Exception
-    {
-        checkNotClosed( "get()" );
-
-        if ( ! valueAvailable )
-        {
-            throw new InvalidCursorPositionException();
-        }
-
-        return returnedTuple;
-    }
-
-
-    public boolean isElementReused()
-    {
-        return true;
-    }
-}
+/*
+ *  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.directory.server.core.partition.impl.btree.jdbm;
+
+
+import jdbm.btree.BTree;
+
+import org.apache.directory.server.core.avltree.ArrayTree;
+import org.apache.directory.server.core.avltree.ArrayTreeCursor;
+import org.apache.directory.server.xdbm.Tuple;
+import org.apache.directory.server.xdbm.AbstractTupleCursor;
+import org.apache.directory.shared.ldap.cursor.Cursor;
+import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Cursor over a BTree which manages duplicate keys.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class DupsCursor<K,V> extends AbstractTupleCursor<K,V>
+{
+    private static final Logger LOG = LoggerFactory.getLogger( DupsCursor.class.getSimpleName() );
+    
+    /**
+     * The JDBM backed table this Cursor traverses over.
+     */
+    private final JdbmTable<K,V> table;
+
+    /**
+     * An wrappedCursor Cursor which returns Tuples whose values are
+     * DupsContainer objects representing either AvlTrees or BTreeRedirect
+     * objects used to store the values of duplicate keys.  It does not return
+     * different values for the same key.
+     */
+    private final DupsContainerCursor<K,V> containerCursor;
+
+    /**
+     * The current Tuple returned from the wrappedCursor DupsContainerCursor.
+     */
+    private final Tuple<K,DupsContainer<V>> containerTuple = new Tuple<K, DupsContainer<V>>();
+
+    /**
+     * A Cursor over a set of value objects for the current key held in the
+     * containerTuple.  A new Cursor will be set for each new key as we
+     * traverse.  The Cursor traverses over either a AvlTree object full
+     * of values in a multi-valued key or it traverses over a BTree which
+     * contains the values in the key field of it's Tuples.
+     */
+    private Cursor<V> dupsCursor;
+
+    /**
+     * The Tuple that is used to return values via the get() method. This
+     * same Tuple instance will be returned every time.  At different
+     * positions it may return different values for the same key.
+     */
+    private final Tuple<K,V> returnedTuple = new Tuple<K,V>();
+
+    /**
+     * Whether or not a value is available when get() is called.
+     */
+    private boolean valueAvailable;
+
+
+    public DupsCursor( JdbmTable<K,V> table ) throws Exception
+    {
+        this.table = table;
+        this.containerCursor = new DupsContainerCursor<K,V>( table );
+        LOG.debug( "Created on table {}", table );
+    }
+
+
+    public boolean available()
+    {
+        return valueAvailable;
+    }
+
+
+    public void beforeKey( K key ) throws Exception
+    {
+        beforeValue( key, null );
+    }
+
+
+    public void beforeValue( K key, V value ) throws Exception
+    {
+        checkNotClosed( "beforeValue()" );
+        containerCursor.before( new Tuple<K,DupsContainer<V>>( key, null ) );
+
+        if ( containerCursor.next() )
+        {
+            containerTuple.setBoth( containerCursor.get() );
+            DupsContainer<V> values = containerTuple.getValue();
+
+            if ( values.isArrayTree() )
+            {
+                ArrayTree<V> set = values.getArrayTree();
+                dupsCursor = new ArrayTreeCursor<V>( set );
+            }
+            else
+            {
+                BTree tree = table.getBTree( values.getBTreeRedirect() );
+                dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
+            }
+
+            if ( value == null )
+            {
+                return;
+            }
+
+            // advance the dupsCursor only if we're on same key
+            if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
+            {
+                dupsCursor.before( value );
+            }
+
+            return;
+        }
+
+        clearValue();
+        containerTuple.setKey( null );
+        containerTuple.setValue( null );
+    }
+
+
+    public void afterKey( K key ) throws Exception
+    {
+        afterValue( key, null );
+    }
+
+
+    public void afterValue( K key, V value ) throws Exception
+    {
+        checkNotClosed( "afterValue()" );
+        /*
+         * There is a subtle difference between after and before handling
+         * with duplicate key values.  Say we have the following tuples:
+         *
+         * (0, 0)
+         * (1, 1)
+         * (1, 2)
+         * (1, 3)
+         * (2, 2)
+         *
+         * If we request an after cursor on (1, 2).  We must make sure that
+         * the container cursor does not advance after the entry with key 1
+         * since this would result in us skip returning (1. 3) on the call to
+         * next which will incorrectly return (2, 2) instead.
+         *
+         * So if the value is null in the element then we don't care about
+         * this obviously since we just want to advance past the duplicate key
+         * values all together.  But when it is not null, then we want to
+         * go right before this key instead of after it.
+         */
+
+        if ( value == null )
+        {
+            containerCursor.after( new Tuple<K,DupsContainer<V>>( key, null ) );
+        }
+        else
+        {
+            containerCursor.before( new Tuple<K,DupsContainer<V>>( key, null ) );
+        }
+
+        if ( containerCursor.next() )
+        {
+            containerTuple.setBoth( containerCursor.get() );
+            DupsContainer<V> values = containerTuple.getValue();
+
+            if ( values.isArrayTree() )
+            {
+                ArrayTree<V> set = values.getArrayTree();
+                dupsCursor = new ArrayTreeCursor<V>( set );
+            }
+            else
+            {
+                BTree tree = table.getBTree( values.getBTreeRedirect() );
+                dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
+            }
+
+            if ( value == null )
+            {
+                return;
+            }
+
+            // only advance the dupsCursor if we're on same key
+            if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
+            {
+                dupsCursor.after( value );
+            }
+
+            return;
+        }
+
+        clearValue();
+        containerTuple.setKey( null );
+        containerTuple.setValue( null );
+    }
+
+
+    public void before( Tuple<K,V> element ) throws Exception
+    {
+        beforeValue( element.getKey(), element.getValue() );
+    }
+
+
+    public void after( Tuple<K,V> element ) throws Exception
+    {
+        afterValue( element.getKey(), element.getValue() );
+    }
+
+
+    public void beforeFirst() throws Exception
+    {
+        checkNotClosed( "beforeFirst()" );
+        clearValue();
+        containerCursor.beforeFirst();
+        containerTuple.setKey( null );
+        containerTuple.setValue( null );
+        dupsCursor = null;
+    }
+
+
+    public void afterLast() throws Exception
+    {
+        checkNotClosed( "afterLast()" );
+        clearValue();
+        containerCursor.afterLast();
+        containerTuple.setKey( null );
+        containerTuple.setValue( null );
+        dupsCursor = null;
+    }
+
+
+    public boolean first() throws Exception
+    {
+        checkNotClosed( "first()" );
+        clearValue();
+        dupsCursor = null;
+
+        if ( containerCursor.first() )
+        {
+            containerTuple.setBoth( containerCursor.get() );
+            DupsContainer<V> values = containerTuple.getValue();
+
+            if ( containerTuple.getValue().isArrayTree() )
+            {
+                dupsCursor = new ArrayTreeCursor<V>( values.getArrayTree() );
+            }
+            else
+            {
+                BTree bt = table.getBTree( values.getBTreeRedirect() );
+                dupsCursor = new KeyBTreeCursor<V>( bt, table.getValueComparator() );
+            }
+
+            /*
+             * Since only tables with duplicate keys enabled use this
+             * cursor, entries must have at least one value, and therefore
+             * call to last() will always return true.
+             */
+            dupsCursor.first();
+            valueAvailable =  true;
+            returnedTuple.setKey( containerTuple.getKey() );
+            returnedTuple.setValue( dupsCursor.get() );
+            return true;
+        }
+
+        return false;
+    }
+
+
+    public boolean last() throws Exception
+    {
+        checkNotClosed( "last()" );
+        clearValue();
+        dupsCursor = null;
+
+        if ( containerCursor.last() )
+        {
+            containerTuple.setBoth( containerCursor.get() );
+            DupsContainer<V> values = containerTuple.getValue();
+
+            if ( values.isArrayTree() )
+            {
+                ArrayTree<V> set = values.getArrayTree();
+                dupsCursor = new ArrayTreeCursor<V>( set );
+            }
+            else
+            {
+                BTree tree = table.getBTree( values.getBTreeRedirect() );
+                dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
+            }
+
+            /*
+             * Since only tables with duplicate keys enabled use this
+             * cursor, entries must have at least one value, and therefore
+             * call to last() will always return true.
+             */
+            dupsCursor.last();
+            valueAvailable = true;
+            returnedTuple.setKey( containerTuple.getKey() );
+            returnedTuple.setValue( dupsCursor.get() );
+            return true;
+        }
+
+        return false;
+    }
+
+
+
+    private void clearValue()
+    {
+        returnedTuple.setKey( null );
+        returnedTuple.setValue( null );
+        valueAvailable = false;
+    }
+
+
+    public boolean previous() throws Exception
+    {
+        checkNotClosed( "previous()" );
+        /*
+         * If the iterator over the values of the current key is null or is
+         * extinguished then we need to advance to the previous key.
+         */
+        if ( null == dupsCursor || ! dupsCursor.previous() )
+        {
+            /*
+             * If the wrappedCursor cursor has more elements we get the previous
+             * key/AvlTree Tuple to work with and get a cursor over it's
+             * values.
+             */
+            if ( containerCursor.previous() )
+            {
+                containerTuple.setBoth( containerCursor.get() );
+                DupsContainer<V> values = containerTuple.getValue();
+
+                if ( values.isArrayTree() )
+                {
+                    ArrayTree<V> set = values.getArrayTree();
+                    dupsCursor = new ArrayTreeCursor<V>( set );
+                }
+                else
+                {
+                    BTree tree = table.getBTree( values.getBTreeRedirect() );
+                    dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
+                }
+
+                /*
+                 * Since only tables with duplicate keys enabled use this
+                 * cursor, entries must have at least one value, and therefore
+                 * call to previous() after bringing the cursor to afterLast()
+                 * will always return true.
+                 */
+                dupsCursor.afterLast();
+                dupsCursor.previous();
+            }
+            else
+            {
+                dupsCursor = null;
+                return false;
+            }
+        }
+
+        returnedTuple.setKey( containerTuple.getKey() );
+        returnedTuple.setValue( dupsCursor.get() );
+        return valueAvailable = true;
+    }
+
+
+    public boolean next() throws Exception
+    {
+        checkNotClosed( "next()" );
+        /*
+         * If the iterator over the values of the current key is null or is
+         * extinguished then we need to advance to the next key.
+         */
+        if ( null == dupsCursor || ! dupsCursor.next() )
+        {
+            /*
+             * If the wrappedCursor cursor has more elements we get the next
+             * key/AvlTree Tuple to work with and get a cursor over it.
+             */
+            if ( containerCursor.next() )
+            {
+                containerTuple.setBoth( containerCursor.get() );
+                DupsContainer<V> values = containerTuple.getValue();
+
+                if ( values.isArrayTree() )
+                {
+                    ArrayTree<V> set = values.getArrayTree();
+                    dupsCursor = new ArrayTreeCursor<V>( set );
+                }
+                else
+                {
+                    BTree tree = table.getBTree( values.getBTreeRedirect() );
+                    dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
+                }
+
+                /*
+                 * Since only tables with duplicate keys enabled use this
+                 * cursor, entries must have at least one value, and therefore
+                 * call to next() after bringing the cursor to beforeFirst()
+                 * will always return true.
+                 */
+                dupsCursor.beforeFirst();
+                dupsCursor.next();
+            }
+            else
+            {
+                dupsCursor = null;
+                return false;
+            }
+        }
+
+        /*
+         * If we get to this point then cursor has more elements and
+         * containerTuple holds the Tuple containing the key and the btree or
+         * AvlTree of values for that key which the Cursor traverses.  All we
+         * need to do is populate our tuple object with the key and the value
+         * in the cursor.
+         */
+        returnedTuple.setKey( containerTuple.getKey() );
+        returnedTuple.setValue( dupsCursor.get() );
+        return valueAvailable = true;
+    }
+
+
+    public Tuple<K,V> get() throws Exception
+    {
+        checkNotClosed( "get()" );
+
+        if ( ! valueAvailable )
+        {
+            throw new InvalidCursorPositionException();
+        }
+
+        return returnedTuple;
+    }
+
+
+    public boolean isElementReused()
+    {
+        return true;
+    }
+}

Modified: directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java?rev=801340&r1=801339&r2=801340&view=diff
==============================================================================
--- directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java (original)
+++ directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java Wed Aug  5 17:55:15 2009
@@ -1,212 +1,212 @@
-/*
- * 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.directory.server.core.partition.impl.btree.jdbm;
-
-
-import jdbm.btree.BTree;
-import jdbm.helper.Tuple;
-import jdbm.helper.TupleBrowser;
-
-import java.util.Comparator;
-
-import org.apache.directory.shared.ldap.cursor.AbstractCursor;
-import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
-
-
-/**
- * Cursor over the keys of a JDBM BTree.  Obviously does not return duplicate
- * keys since JDBM does not natively support multiple values for the same key.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-public class KeyBTreeCursor<E> extends AbstractCursor<E>
-{
-    private final Tuple tuple = new Tuple();
-
-    private final BTree btree;
-    private final Comparator<E> comparator;
-    private boolean valueAvailable;
-    private TupleBrowser browser;
-
-
-    /**
-     * Creates a Cursor over the keys of a JDBM BTree.
-     *
-     * @param btree the JDBM BTree to build a Cursor over
-     * @param comparator the Comparator used to determine key ordering
-     * @throws Exception of there are problems accessing the BTree
-     */
-    public KeyBTreeCursor( BTree btree, Comparator<E> comparator ) throws Exception
-    {
-        this.btree = btree;
-        this.comparator = comparator;
-    }
-
-
-    private void clearValue()
-    {
-        tuple.setKey( null );
-        tuple.setValue( null );
-        valueAvailable = false;
-    }
-
-
-    public boolean available()
-    {
-        return valueAvailable;
-    }
-
-
-    public void before( E element ) throws Exception
-    {
-        checkNotClosed( "before()" );
-        browser = btree.browse( element );
-        clearValue();
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public void after( E element ) throws Exception
-    {
-        browser = btree.browse( element );
-
-        /*
-         * While the next value is less than or equal to the element keep
-         * advancing forward to the next item.  If we cannot advance any
-         * further then stop and return.  If we find a value greater than
-         * the element then we stop, backup, and return so subsequent calls
-         * to getNext() will return a value greater than the element.
-         */
-        while ( browser.getNext( tuple ) )
-        {
-            checkNotClosed( "after()" );
-            E next = ( E ) tuple.getKey();
-            int nextCompared = comparator.compare( next, element );
-
-            if ( nextCompared <= 0 )
-            {
-                // just continue
-            }
-            else 
-            {
-                /*
-                 * If we just have values greater than the element argument
-                 * then we are before the first element and must backup to
-                 * before the first element state for the JDBM browser which 
-                 * apparently the browser supports.
-                 */
-                browser.getPrevious( tuple );
-                clearValue();
-                return;
-            }
-        }
-
-        clearValue();
-        // just return
-    }
-
-
-    public void beforeFirst() throws Exception
-    {
-        checkNotClosed( "beforeFirst()" );
-        browser = btree.browse();
-        clearValue();
-    }
-
-
-    public void afterLast() throws Exception
-    {
-        checkNotClosed( "afterLast()" );
-        browser = btree.browse( null );
-    }
-
-
-    public boolean first() throws Exception
-    {
-        beforeFirst();
-        return next();
-    }
-
-
-    public boolean last() throws Exception
-    {
-        afterLast();
-        return previous();
-    }
-
-
-    public boolean previous() throws Exception
-    {
-        checkNotClosed( "previous()" );
-        if ( browser == null )
-        {
-            browser = btree.browse( null );
-        }
-
-        if ( browser.getPrevious( tuple ) )
-        {
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    public boolean next() throws Exception
-    {
-        checkNotClosed( "next()" );
-        if ( browser == null )
-        {
-            browser = btree.browse();
-        }
-
-        if ( browser.getNext( tuple ) )
-        {
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public E get() throws Exception
-    {
-        checkNotClosed( "get()" );
-        if ( valueAvailable )
-        {
-            return ( E ) tuple.getKey();
-        }
-
-        throw new InvalidCursorPositionException();
-    }
-
-
-    public boolean isElementReused()
-    {
-        return false;
-    }
-}
+/*
+ * 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.directory.server.core.partition.impl.btree.jdbm;
+
+
+import jdbm.btree.BTree;
+import jdbm.helper.Tuple;
+import jdbm.helper.TupleBrowser;
+
+import java.util.Comparator;
+
+import org.apache.directory.shared.ldap.cursor.AbstractCursor;
+import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
+
+
+/**
+ * Cursor over the keys of a JDBM BTree.  Obviously does not return duplicate
+ * keys since JDBM does not natively support multiple values for the same key.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class KeyBTreeCursor<E> extends AbstractCursor<E>
+{
+    private final Tuple tuple = new Tuple();
+
+    private final BTree btree;
+    private final Comparator<E> comparator;
+    private boolean valueAvailable;
+    private TupleBrowser browser;
+
+
+    /**
+     * Creates a Cursor over the keys of a JDBM BTree.
+     *
+     * @param btree the JDBM BTree to build a Cursor over
+     * @param comparator the Comparator used to determine key ordering
+     * @throws Exception of there are problems accessing the BTree
+     */
+    public KeyBTreeCursor( BTree btree, Comparator<E> comparator ) throws Exception
+    {
+        this.btree = btree;
+        this.comparator = comparator;
+    }
+
+
+    private void clearValue()
+    {
+        tuple.setKey( null );
+        tuple.setValue( null );
+        valueAvailable = false;
+    }
+
+
+    public boolean available()
+    {
+        return valueAvailable;
+    }
+
+
+    public void before( E element ) throws Exception
+    {
+        checkNotClosed( "before()" );
+        browser = btree.browse( element );
+        clearValue();
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public void after( E element ) throws Exception
+    {
+        browser = btree.browse( element );
+
+        /*
+         * While the next value is less than or equal to the element keep
+         * advancing forward to the next item.  If we cannot advance any
+         * further then stop and return.  If we find a value greater than
+         * the element then we stop, backup, and return so subsequent calls
+         * to getNext() will return a value greater than the element.
+         */
+        while ( browser.getNext( tuple ) )
+        {
+            checkNotClosed( "after()" );
+            E next = ( E ) tuple.getKey();
+            int nextCompared = comparator.compare( next, element );
+
+            if ( nextCompared <= 0 )
+            {
+                // just continue
+            }
+            else 
+            {
+                /*
+                 * If we just have values greater than the element argument
+                 * then we are before the first element and must backup to
+                 * before the first element state for the JDBM browser which 
+                 * apparently the browser supports.
+                 */
+                browser.getPrevious( tuple );
+                clearValue();
+                return;
+            }
+        }
+
+        clearValue();
+        // just return
+    }
+
+
+    public void beforeFirst() throws Exception
+    {
+        checkNotClosed( "beforeFirst()" );
+        browser = btree.browse();
+        clearValue();
+    }
+
+
+    public void afterLast() throws Exception
+    {
+        checkNotClosed( "afterLast()" );
+        browser = btree.browse( null );
+    }
+
+
+    public boolean first() throws Exception
+    {
+        beforeFirst();
+        return next();
+    }
+
+
+    public boolean last() throws Exception
+    {
+        afterLast();
+        return previous();
+    }
+
+
+    public boolean previous() throws Exception
+    {
+        checkNotClosed( "previous()" );
+        if ( browser == null )
+        {
+            browser = btree.browse( null );
+        }
+
+        if ( browser.getPrevious( tuple ) )
+        {
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    public boolean next() throws Exception
+    {
+        checkNotClosed( "next()" );
+        if ( browser == null )
+        {
+            browser = btree.browse();
+        }
+
+        if ( browser.getNext( tuple ) )
+        {
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public E get() throws Exception
+    {
+        checkNotClosed( "get()" );
+        if ( valueAvailable )
+        {
+            return ( E ) tuple.getKey();
+        }
+
+        throw new InvalidCursorPositionException();
+    }
+
+
+    public boolean isElementReused()
+    {
+        return false;
+    }
+}

Modified: directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleArrayCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleArrayCursor.java?rev=801340&r1=801339&r2=801340&view=diff
==============================================================================
--- directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleArrayCursor.java (original)
+++ directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleArrayCursor.java Wed Aug  5 17:55:15 2009
@@ -1,215 +1,215 @@
-/*
- * 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.directory.server.core.partition.impl.btree.jdbm;
-
-
-import org.apache.directory.server.xdbm.Tuple;
-import org.apache.directory.server.xdbm.AbstractTupleCursor;
-import org.apache.directory.server.core.avltree.ArrayTree;
-import org.apache.directory.server.core.avltree.ArrayTreeCursor;
-import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
-
-
-/**
- * Cursor over a set of values for the same key which are store in an in
- * memory ArrayTree.  This Cursor is limited to the same key and it's tuples
- * will always return the same key.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-public class KeyTupleArrayCursor<K,V> extends AbstractTupleCursor<K,V>
-{
-    private final ArrayTreeCursor<V> wrapped;
-    private final K key;
-
-    private Tuple<K,V> returnedTuple = new Tuple<K,V>();
-    private boolean valueAvailable;
-
-
-    /**
-     * Creates a Cursor over the tuples of an ArrayTree.
-     *
-     * @param avlTree the ArrayTree to build a Tuple returning Cursor over
-     * @param key the constant key for which values are returned
-     */
-    public KeyTupleArrayCursor( ArrayTree<V> arrayTree, K key )
-    {
-        this.key = key;
-        this.wrapped = new ArrayTreeCursor<V>( arrayTree );
-    }
-
-
-    private void clearValue()
-    {
-        returnedTuple.setKey( key );
-        returnedTuple.setValue( null );
-        valueAvailable = false;
-    }
-
-
-    public boolean available()
-    {
-        return valueAvailable;
-    }
-
-
-    public void beforeKey( K key ) throws Exception
-    {
-        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-    }
-
-
-    public void afterKey( K key ) throws Exception
-    {
-        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-    }
-
-
-    public void beforeValue( K key, V value ) throws Exception
-    {
-        checkNotClosed( "beforeValue()" );
-        if ( key != null && ! key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-        }
-
-        wrapped.before( value );
-        clearValue();
-    }
-
-
-    public void afterValue( K key, V value ) throws Exception
-    {
-        checkNotClosed( "afterValue()" );
-        if ( key != null && ! key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-        }
-
-        wrapped.after( value );
-        clearValue();
-    }
-
-
-    /**
-     * Positions this Cursor over the same keys before the value of the
-     * supplied element Tuple.  The supplied element Tuple's key is not
-     * considered at all.
-     *
-     * @param element the valueTuple who's value is used to position this Cursor
-     * @throws Exception if there are failures to position the Cursor
-     */
-    public void before( Tuple<K,V> element ) throws Exception
-    {
-        checkNotClosed( "before()" );
-        wrapped.before( element.getValue() );
-        clearValue();
-    }
-
-
-    public void after( Tuple<K,V> element ) throws Exception
-    {
-        checkNotClosed( "after()" );
-        wrapped.after( element.getValue() );
-        clearValue();
-    }
-
-
-    public void beforeFirst() throws Exception
-    {
-        checkNotClosed( "beforeFirst()" );
-        wrapped.beforeFirst();
-        clearValue();
-    }
-
-
-    public void afterLast() throws Exception
-    {
-        checkNotClosed( "afterLast()" );
-        wrapped.afterLast();
-        clearValue();
-    }
-
-
-    public boolean first() throws Exception
-    {
-        beforeFirst();
-        return next();
-    }
-
-
-    public boolean last() throws Exception
-    {
-        afterLast();
-        return previous();
-    }
-
-
-    public boolean previous() throws Exception
-    {
-        checkNotClosed( "previous()" );
-        if ( wrapped.previous() )
-        {
-            returnedTuple.setKey( key );
-            returnedTuple.setValue( wrapped.get() );
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    public boolean next() throws Exception
-    {
-        checkNotClosed( "next()" );
-        if ( wrapped.next() )
-        {
-            returnedTuple.setKey( key );
-            returnedTuple.setValue( wrapped.get() );
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    public Tuple<K,V> get() throws Exception
-    {
-        checkNotClosed( "get()" );
-        if ( valueAvailable )
-        {
-            return returnedTuple;
-        }
-
-        throw new InvalidCursorPositionException();
-    }
-
-
-    public boolean isElementReused()
-    {
-        return true;
-    }
-}
\ No newline at end of file
+/*
+ * 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.directory.server.core.partition.impl.btree.jdbm;
+
+
+import org.apache.directory.server.xdbm.Tuple;
+import org.apache.directory.server.xdbm.AbstractTupleCursor;
+import org.apache.directory.server.core.avltree.ArrayTree;
+import org.apache.directory.server.core.avltree.ArrayTreeCursor;
+import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
+
+
+/**
+ * Cursor over a set of values for the same key which are store in an in
+ * memory ArrayTree.  This Cursor is limited to the same key and it's tuples
+ * will always return the same key.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class KeyTupleArrayCursor<K,V> extends AbstractTupleCursor<K,V>
+{
+    private final ArrayTreeCursor<V> wrapped;
+    private final K key;
+
+    private Tuple<K,V> returnedTuple = new Tuple<K,V>();
+    private boolean valueAvailable;
+
+
+    /**
+     * Creates a Cursor over the tuples of an ArrayTree.
+     *
+     * @param avlTree the ArrayTree to build a Tuple returning Cursor over
+     * @param key the constant key for which values are returned
+     */
+    public KeyTupleArrayCursor( ArrayTree<V> arrayTree, K key )
+    {
+        this.key = key;
+        this.wrapped = new ArrayTreeCursor<V>( arrayTree );
+    }
+
+
+    private void clearValue()
+    {
+        returnedTuple.setKey( key );
+        returnedTuple.setValue( null );
+        valueAvailable = false;
+    }
+
+
+    public boolean available()
+    {
+        return valueAvailable;
+    }
+
+
+    public void beforeKey( K key ) throws Exception
+    {
+        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+    }
+
+
+    public void afterKey( K key ) throws Exception
+    {
+        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+    }
+
+
+    public void beforeValue( K key, V value ) throws Exception
+    {
+        checkNotClosed( "beforeValue()" );
+        if ( key != null && ! key.equals( this.key ) )
+        {
+            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+        }
+
+        wrapped.before( value );
+        clearValue();
+    }
+
+
+    public void afterValue( K key, V value ) throws Exception
+    {
+        checkNotClosed( "afterValue()" );
+        if ( key != null && ! key.equals( this.key ) )
+        {
+            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+        }
+
+        wrapped.after( value );
+        clearValue();
+    }
+
+
+    /**
+     * Positions this Cursor over the same keys before the value of the
+     * supplied element Tuple.  The supplied element Tuple's key is not
+     * considered at all.
+     *
+     * @param element the valueTuple who's value is used to position this Cursor
+     * @throws Exception if there are failures to position the Cursor
+     */
+    public void before( Tuple<K,V> element ) throws Exception
+    {
+        checkNotClosed( "before()" );
+        wrapped.before( element.getValue() );
+        clearValue();
+    }
+
+
+    public void after( Tuple<K,V> element ) throws Exception
+    {
+        checkNotClosed( "after()" );
+        wrapped.after( element.getValue() );
+        clearValue();
+    }
+
+
+    public void beforeFirst() throws Exception
+    {
+        checkNotClosed( "beforeFirst()" );
+        wrapped.beforeFirst();
+        clearValue();
+    }
+
+
+    public void afterLast() throws Exception
+    {
+        checkNotClosed( "afterLast()" );
+        wrapped.afterLast();
+        clearValue();
+    }
+
+
+    public boolean first() throws Exception
+    {
+        beforeFirst();
+        return next();
+    }
+
+
+    public boolean last() throws Exception
+    {
+        afterLast();
+        return previous();
+    }
+
+
+    public boolean previous() throws Exception
+    {
+        checkNotClosed( "previous()" );
+        if ( wrapped.previous() )
+        {
+            returnedTuple.setKey( key );
+            returnedTuple.setValue( wrapped.get() );
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    public boolean next() throws Exception
+    {
+        checkNotClosed( "next()" );
+        if ( wrapped.next() )
+        {
+            returnedTuple.setKey( key );
+            returnedTuple.setValue( wrapped.get() );
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    public Tuple<K,V> get() throws Exception
+    {
+        checkNotClosed( "get()" );
+        if ( valueAvailable )
+        {
+            return returnedTuple;
+        }
+
+        throw new InvalidCursorPositionException();
+    }
+
+
+    public boolean isElementReused()
+    {
+        return true;
+    }
+}

Modified: directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java?rev=801340&r1=801339&r2=801340&view=diff
==============================================================================
--- directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java (original)
+++ directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java Wed Aug  5 17:55:15 2009
@@ -1,277 +1,277 @@
-/*
- * 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.directory.server.core.partition.impl.btree.jdbm;
-
-
-import org.apache.directory.server.xdbm.Tuple;
-import org.apache.directory.server.xdbm.AbstractTupleCursor;
-import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
-
-import java.util.Comparator;
-
-import jdbm.helper.TupleBrowser;
-import jdbm.btree.BTree;
-
-
-/**
- * Cursor over a set of values for the same key which are store in another
- * BTree.  This Cursor is limited to the same key and it's tuples will always
- * return the same key.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-public class KeyTupleBTreeCursor<K,V> extends AbstractTupleCursor<K,V>
-{
-    private final Comparator<V> comparator;
-    private final BTree btree;
-    private final K key;
-
-    private jdbm.helper.Tuple valueTuple = new jdbm.helper.Tuple();
-    private Tuple<K,V> returnedTuple = new Tuple<K,V>();
-    private TupleBrowser browser;
-    private boolean valueAvailable;
-
-
-    /**
-     * Creates a Cursor over the tuples of a JDBM BTree.
-     *
-     * @param btree the JDBM BTree to build a Cursor over
-     * @param key the constant key for which values are returned
-     * @param comparator the Comparator used to determine <b>key</b> ordering
-     * @throws Exception of there are problems accessing the BTree
-     */
-    public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws Exception
-    {
-        this.key = key;
-        this.btree = btree;
-        this.comparator = comparator;
-        this.browser = btree.browse();
-    }
-
-
-    private void clearValue()
-    {
-        returnedTuple.setKey( key );
-        returnedTuple.setValue( null );
-        valueAvailable = false;
-    }
-
-
-    public boolean available()
-    {
-        return valueAvailable;
-    }
-
-
-    public void beforeKey( K key ) throws Exception
-    {
-        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-    }
-
-
-    public void afterKey( K key ) throws Exception
-    {
-        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-    }
-
-
-    public void beforeValue( K key, V value ) throws Exception
-    {
-        checkNotClosed( "beforeValue()" );
-        if ( key != null && ! key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-        }
-
-        browser = btree.browse( value );
-        clearValue();
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public void afterValue( K key, V value ) throws Exception
-    {
-        if ( key != null && ! key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
-        }
-
-        browser = btree.browse( value );
-
-        /*
-         * While the next value is less than or equal to the element keep
-         * advancing forward to the next item.  If we cannot advance any
-         * further then stop and return.  If we find a value greater than
-         * the element then we stop, backup, and return so subsequent calls
-         * to getNext() will return a value greater than the element.
-         */
-        while ( browser.getNext( valueTuple ) )
-        {
-            checkNotClosed( "afterValue" );
-
-            V next = ( V ) valueTuple.getKey();
-
-            int nextCompared = comparator.compare( next, value );
-
-            if ( nextCompared <= 0 )
-            {
-                // just continue
-            }
-            else if ( nextCompared > 0 )
-            {
-                /*
-                 * If we just have values greater than the element argument
-                 * then we are before the first element and cannot backup, and
-                 * the call below to getPrevious() will fail.  In this special
-                 * case we just reset the Cursor's browser and return.
-                 */
-                if ( browser.getPrevious( valueTuple ) )
-                {
-                }
-                else
-                {
-                    browser = btree.browse( this.key );
-                }
-
-                clearValue();
-                return;
-            }
-        }
-
-        clearValue();
-    }
-
-
-    /**
-     * Positions this Cursor over the same keys before the value of the
-     * supplied valueTuple.  The supplied element Tuple's key is not considered at
-     * all.
-     *
-     * @param element the valueTuple who's value is used to position this Cursor
-     * @throws Exception if there are failures to position the Cursor
-     */
-    public void before( Tuple<K,V> element ) throws Exception
-    {
-        checkNotClosed( "before()" );
-        browser = btree.browse( element.getValue() );
-        clearValue();
-    }
-
-
-    public void after( Tuple<K,V> element ) throws Exception
-    {
-        afterValue( key, element.getValue() );
-    }
-
-
-    public void beforeFirst() throws Exception
-    {
-        checkNotClosed( "beforeFirst()" );
-        browser = btree.browse();
-        clearValue();
-    }
-
-
-    public void afterLast() throws Exception
-    {
-        checkNotClosed( "afterLast()" );
-        browser = btree.browse( null );
-    }
-
-
-    public boolean first() throws Exception
-    {
-        beforeFirst();
-        return next();
-    }
-
-
-    public boolean last() throws Exception
-    {
-        afterLast();
-        return previous();
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public boolean previous() throws Exception
-    {
-        checkNotClosed( "previous()" );
-        if ( browser.getPrevious( valueTuple ) )
-        {
-            // work around to fix direction change problem with jdbm browser
-            if ( returnedTuple.getValue() != null &&
-                comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
-            {
-                browser.getPrevious( valueTuple ) ;
-            }
-            returnedTuple.setKey( key );
-            returnedTuple.setValue( ( V ) valueTuple.getKey() );
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public boolean next() throws Exception
-    {
-        checkNotClosed( "next()" );
-        if ( browser.getNext( valueTuple ) )
-        {
-            // work around to fix direction change problem with jdbm browser
-            if ( returnedTuple.getValue() != null &&
-                 comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
-            {
-                browser.getNext( valueTuple ) ;
-            }
-            returnedTuple.setKey( key );
-            returnedTuple.setValue( ( V ) valueTuple.getKey() );
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    public Tuple<K,V> get() throws Exception
-    {
-        checkNotClosed( "get()" );
-        if ( valueAvailable )
-        {
-            return returnedTuple;
-        }
-
-        throw new InvalidCursorPositionException();
-    }
-
-
-    public boolean isElementReused()
-    {
-        return true;
-    }
-}
\ No newline at end of file
+/*
+ * 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.directory.server.core.partition.impl.btree.jdbm;
+
+
+import org.apache.directory.server.xdbm.Tuple;
+import org.apache.directory.server.xdbm.AbstractTupleCursor;
+import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
+
+import java.util.Comparator;
+
+import jdbm.helper.TupleBrowser;
+import jdbm.btree.BTree;
+
+
+/**
+ * Cursor over a set of values for the same key which are store in another
+ * BTree.  This Cursor is limited to the same key and it's tuples will always
+ * return the same key.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class KeyTupleBTreeCursor<K,V> extends AbstractTupleCursor<K,V>
+{
+    private final Comparator<V> comparator;
+    private final BTree btree;
+    private final K key;
+
+    private jdbm.helper.Tuple valueTuple = new jdbm.helper.Tuple();
+    private Tuple<K,V> returnedTuple = new Tuple<K,V>();
+    private TupleBrowser browser;
+    private boolean valueAvailable;
+
+
+    /**
+     * Creates a Cursor over the tuples of a JDBM BTree.
+     *
+     * @param btree the JDBM BTree to build a Cursor over
+     * @param key the constant key for which values are returned
+     * @param comparator the Comparator used to determine <b>key</b> ordering
+     * @throws Exception of there are problems accessing the BTree
+     */
+    public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws Exception
+    {
+        this.key = key;
+        this.btree = btree;
+        this.comparator = comparator;
+        this.browser = btree.browse();
+    }
+
+
+    private void clearValue()
+    {
+        returnedTuple.setKey( key );
+        returnedTuple.setValue( null );
+        valueAvailable = false;
+    }
+
+
+    public boolean available()
+    {
+        return valueAvailable;
+    }
+
+
+    public void beforeKey( K key ) throws Exception
+    {
+        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+    }
+
+
+    public void afterKey( K key ) throws Exception
+    {
+        throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+    }
+
+
+    public void beforeValue( K key, V value ) throws Exception
+    {
+        checkNotClosed( "beforeValue()" );
+        if ( key != null && ! key.equals( this.key ) )
+        {
+            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+        }
+
+        browser = btree.browse( value );
+        clearValue();
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public void afterValue( K key, V value ) throws Exception
+    {
+        if ( key != null && ! key.equals( this.key ) )
+        {
+            throw new UnsupportedOperationException( "This cursor locks down the key so keywise advances are not allowed." );
+        }
+
+        browser = btree.browse( value );
+
+        /*
+         * While the next value is less than or equal to the element keep
+         * advancing forward to the next item.  If we cannot advance any
+         * further then stop and return.  If we find a value greater than
+         * the element then we stop, backup, and return so subsequent calls
+         * to getNext() will return a value greater than the element.
+         */
+        while ( browser.getNext( valueTuple ) )
+        {
+            checkNotClosed( "afterValue" );
+
+            V next = ( V ) valueTuple.getKey();
+
+            int nextCompared = comparator.compare( next, value );
+
+            if ( nextCompared <= 0 )
+            {
+                // just continue
+            }
+            else if ( nextCompared > 0 )
+            {
+                /*
+                 * If we just have values greater than the element argument
+                 * then we are before the first element and cannot backup, and
+                 * the call below to getPrevious() will fail.  In this special
+                 * case we just reset the Cursor's browser and return.
+                 */
+                if ( browser.getPrevious( valueTuple ) )
+                {
+                }
+                else
+                {
+                    browser = btree.browse( this.key );
+                }
+
+                clearValue();
+                return;
+            }
+        }
+
+        clearValue();
+    }
+
+
+    /**
+     * Positions this Cursor over the same keys before the value of the
+     * supplied valueTuple.  The supplied element Tuple's key is not considered at
+     * all.
+     *
+     * @param element the valueTuple who's value is used to position this Cursor
+     * @throws Exception if there are failures to position the Cursor
+     */
+    public void before( Tuple<K,V> element ) throws Exception
+    {
+        checkNotClosed( "before()" );
+        browser = btree.browse( element.getValue() );
+        clearValue();
+    }
+
+
+    public void after( Tuple<K,V> element ) throws Exception
+    {
+        afterValue( key, element.getValue() );
+    }
+
+
+    public void beforeFirst() throws Exception
+    {
+        checkNotClosed( "beforeFirst()" );
+        browser = btree.browse();
+        clearValue();
+    }
+
+
+    public void afterLast() throws Exception
+    {
+        checkNotClosed( "afterLast()" );
+        browser = btree.browse( null );
+    }
+
+
+    public boolean first() throws Exception
+    {
+        beforeFirst();
+        return next();
+    }
+
+
+    public boolean last() throws Exception
+    {
+        afterLast();
+        return previous();
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public boolean previous() throws Exception
+    {
+        checkNotClosed( "previous()" );
+        if ( browser.getPrevious( valueTuple ) )
+        {
+            // work around to fix direction change problem with jdbm browser
+            if ( returnedTuple.getValue() != null &&
+                comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
+            {
+                browser.getPrevious( valueTuple ) ;
+            }
+            returnedTuple.setKey( key );
+            returnedTuple.setValue( ( V ) valueTuple.getKey() );
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public boolean next() throws Exception
+    {
+        checkNotClosed( "next()" );
+        if ( browser.getNext( valueTuple ) )
+        {
+            // work around to fix direction change problem with jdbm browser
+            if ( returnedTuple.getValue() != null &&
+                 comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
+            {
+                browser.getNext( valueTuple ) ;
+            }
+            returnedTuple.setKey( key );
+            returnedTuple.setValue( ( V ) valueTuple.getKey() );
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    public Tuple<K,V> get() throws Exception
+    {
+        checkNotClosed( "get()" );
+        if ( valueAvailable )
+        {
+            return returnedTuple;
+        }
+
+        throw new InvalidCursorPositionException();
+    }
+
+
+    public boolean isElementReused()
+    {
+        return true;
+    }
+}

Modified: directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/NoDupsCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/NoDupsCursor.java?rev=801340&r1=801339&r2=801340&view=diff
==============================================================================
--- directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/NoDupsCursor.java (original)
+++ directory/apacheds/trunk/jdbm-store/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/NoDupsCursor.java Wed Aug  5 17:55:15 2009
@@ -1,257 +1,257 @@
-/*
- * 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.directory.server.core.partition.impl.btree.jdbm;
-
-
-import org.apache.directory.server.xdbm.Tuple;
-import org.apache.directory.server.xdbm.AbstractTupleCursor;
-import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
-
-import java.io.IOException;
-
-import jdbm.helper.TupleBrowser;
-
-
-/**
- * Cursor over the Tuples of a JDBM BTree.  Duplicate keys are not supported
- * by JDBM natively so you will not see duplicate keys.  For this reason as
- * well before() and after() positioning only considers the key of the Tuple
- * arguments provided.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-class NoDupsCursor<K,V> extends AbstractTupleCursor<K,V>
-{
-    private final JdbmTable<K,V> table;
-
-    private jdbm.helper.Tuple jdbmTuple = new jdbm.helper.Tuple();
-    private Tuple<K,V> returnedTuple = new Tuple<K,V>();
-    private TupleBrowser browser;
-    private boolean valueAvailable;
-
-
-    /**
-     * Creates a Cursor over the tuples of a JDBM table.
-     *
-     * @param table the JDBM Table to build a Cursor over
-     * @throws IOException of there are problems accessing the BTree
-     */
-    public NoDupsCursor( JdbmTable<K,V> table ) throws IOException
-    {
-        this.table = table;
-    }
-
-
-    private void clearValue()
-    {
-        returnedTuple.setKey( null );
-        returnedTuple.setValue( null );
-        jdbmTuple.setKey( null );
-        jdbmTuple.setValue( null );
-        valueAvailable = false;
-    }
-
-
-    public boolean available()
-    {
-        return valueAvailable;
-    }
-
-
-    public void beforeKey( K key ) throws Exception
-    {
-        checkNotClosed( "beforeKey()" );
-        browser = table.getBTree().browse( key );
-        clearValue();
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public void afterKey( K key ) throws Exception
-    {
-        browser = table.getBTree().browse( key );
-
-        /*
-         * While the next value is less than or equal to the element keep
-         * advancing forward to the next item.  If we cannot advance any
-         * further then stop and return.  If we find a value greater than
-         * the element then we stop, backup, and return so subsequent calls
-         * to getNext() will return a value greater than the element.
-         */
-        while ( browser.getNext( jdbmTuple ) )
-        {
-            checkNotClosed( "afterKey()" );
-            K next = ( K ) jdbmTuple.getKey();
-
-            int nextCompared = table.getKeyComparator().compare( next, key );
-
-            if ( nextCompared > 0 )
-            {
-                browser.getPrevious( jdbmTuple );
-                clearValue();
-                return;
-            }
-        }
-
-        clearValue();
-    }
-
-
-    public void beforeValue( K key, V value ) throws Exception
-    {
-        throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
-    }
-
-
-    public void afterValue( K key, V value ) throws Exception
-    {
-        throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
-    }
-
-
-    /**
-     * Positions this Cursor before the key of the supplied tuple.
-     *
-     * @param element the tuple who's key is used to position this Cursor
-     * @throws IOException if there are failures to position the Cursor
-     */
-    public void before( Tuple<K,V> element ) throws Exception
-    {
-        beforeKey( element.getKey() );
-    }
-
-
-    public void after( Tuple<K,V> element ) throws Exception
-    {
-        afterKey( element.getKey() );
-    }
-
-
-    public void beforeFirst() throws Exception
-    {
-        checkNotClosed( "beforeFirst()" );
-        browser = table.getBTree().browse();
-        clearValue();
-    }
-
-
-    public void afterLast() throws Exception
-    {
-        checkNotClosed( "afterLast()" );
-        browser = table.getBTree().browse( null );
-        clearValue();
-    }
-
-
-    public boolean first() throws Exception
-    {
-        beforeFirst();
-        return next();
-    }
-
-
-    public boolean last() throws Exception
-    {
-        afterLast();
-        return previous();
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public boolean previous() throws Exception
-    {
-        checkNotClosed( "previous()" );
-        if ( browser == null )
-        {
-            afterLast();
-        }
-
-        if ( browser.getPrevious( jdbmTuple ) )
-        {
-            if( returnedTuple.getKey() != null )
-            {
-                if( table.getKeyComparator().compare(
-                    ( K) jdbmTuple.getKey(), ( K) returnedTuple.getKey() ) == 0 )
-                {
-                    browser.getPrevious( jdbmTuple );
-                }
-            }
-
-            returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
-            returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public boolean next() throws Exception
-    {
-        checkNotClosed( "previous()" );
-        if ( browser == null )
-        {
-            beforeFirst();
-        }
-
-        if ( browser.getNext( jdbmTuple ) )
-        {
-            if( returnedTuple.getKey() != null )
-            {
-                if( table.getKeyComparator().compare(
-                    ( K) jdbmTuple.getKey(), ( K) returnedTuple.getKey() ) == 0 )
-                {
-                    browser.getNext( jdbmTuple );
-                }
-            }
-            
-            returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
-            returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
-            return valueAvailable = true;
-        }
-        else
-        {
-            clearValue();
-            return false;
-        }
-    }
-
-
-    public Tuple<K,V> get() throws Exception
-    {
-        checkNotClosed( "get()" );
-        if ( valueAvailable )
-        {
-            return returnedTuple;
-        }
-
-        throw new InvalidCursorPositionException();
-    }
-
-
-    public boolean isElementReused()
-    {
-        return true;
-    }
-}
+/*
+ * 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.directory.server.core.partition.impl.btree.jdbm;
+
+
+import org.apache.directory.server.xdbm.Tuple;
+import org.apache.directory.server.xdbm.AbstractTupleCursor;
+import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
+
+import java.io.IOException;
+
+import jdbm.helper.TupleBrowser;
+
+
+/**
+ * Cursor over the Tuples of a JDBM BTree.  Duplicate keys are not supported
+ * by JDBM natively so you will not see duplicate keys.  For this reason as
+ * well before() and after() positioning only considers the key of the Tuple
+ * arguments provided.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+class NoDupsCursor<K,V> extends AbstractTupleCursor<K,V>
+{
+    private final JdbmTable<K,V> table;
+
+    private jdbm.helper.Tuple jdbmTuple = new jdbm.helper.Tuple();
+    private Tuple<K,V> returnedTuple = new Tuple<K,V>();
+    private TupleBrowser browser;
+    private boolean valueAvailable;
+
+
+    /**
+     * Creates a Cursor over the tuples of a JDBM table.
+     *
+     * @param table the JDBM Table to build a Cursor over
+     * @throws IOException of there are problems accessing the BTree
+     */
+    public NoDupsCursor( JdbmTable<K,V> table ) throws IOException
+    {
+        this.table = table;
+    }
+
+
+    private void clearValue()
+    {
+        returnedTuple.setKey( null );
+        returnedTuple.setValue( null );
+        jdbmTuple.setKey( null );
+        jdbmTuple.setValue( null );
+        valueAvailable = false;
+    }
+
+
+    public boolean available()
+    {
+        return valueAvailable;
+    }
+
+
+    public void beforeKey( K key ) throws Exception
+    {
+        checkNotClosed( "beforeKey()" );
+        browser = table.getBTree().browse( key );
+        clearValue();
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public void afterKey( K key ) throws Exception
+    {
+        browser = table.getBTree().browse( key );
+
+        /*
+         * While the next value is less than or equal to the element keep
+         * advancing forward to the next item.  If we cannot advance any
+         * further then stop and return.  If we find a value greater than
+         * the element then we stop, backup, and return so subsequent calls
+         * to getNext() will return a value greater than the element.
+         */
+        while ( browser.getNext( jdbmTuple ) )
+        {
+            checkNotClosed( "afterKey()" );
+            K next = ( K ) jdbmTuple.getKey();
+
+            int nextCompared = table.getKeyComparator().compare( next, key );
+
+            if ( nextCompared > 0 )
+            {
+                browser.getPrevious( jdbmTuple );
+                clearValue();
+                return;
+            }
+        }
+
+        clearValue();
+    }
+
+
+    public void beforeValue( K key, V value ) throws Exception
+    {
+        throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
+    }
+
+
+    public void afterValue( K key, V value ) throws Exception
+    {
+        throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
+    }
+
+
+    /**
+     * Positions this Cursor before the key of the supplied tuple.
+     *
+     * @param element the tuple who's key is used to position this Cursor
+     * @throws IOException if there are failures to position the Cursor
+     */
+    public void before( Tuple<K,V> element ) throws Exception
+    {
+        beforeKey( element.getKey() );
+    }
+
+
+    public void after( Tuple<K,V> element ) throws Exception
+    {
+        afterKey( element.getKey() );
+    }
+
+
+    public void beforeFirst() throws Exception
+    {
+        checkNotClosed( "beforeFirst()" );
+        browser = table.getBTree().browse();
+        clearValue();
+    }
+
+
+    public void afterLast() throws Exception
+    {
+        checkNotClosed( "afterLast()" );
+        browser = table.getBTree().browse( null );
+        clearValue();
+    }
+
+
+    public boolean first() throws Exception
+    {
+        beforeFirst();
+        return next();
+    }
+
+
+    public boolean last() throws Exception
+    {
+        afterLast();
+        return previous();
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public boolean previous() throws Exception
+    {
+        checkNotClosed( "previous()" );
+        if ( browser == null )
+        {
+            afterLast();
+        }
+
+        if ( browser.getPrevious( jdbmTuple ) )
+        {
+            if( returnedTuple.getKey() != null )
+            {
+                if( table.getKeyComparator().compare(
+                    ( K) jdbmTuple.getKey(), ( K) returnedTuple.getKey() ) == 0 )
+                {
+                    browser.getPrevious( jdbmTuple );
+                }
+            }
+
+            returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
+            returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public boolean next() throws Exception
+    {
+        checkNotClosed( "previous()" );
+        if ( browser == null )
+        {
+            beforeFirst();
+        }
+
+        if ( browser.getNext( jdbmTuple ) )
+        {
+            if( returnedTuple.getKey() != null )
+            {
+                if( table.getKeyComparator().compare(
+                    ( K) jdbmTuple.getKey(), ( K) returnedTuple.getKey() ) == 0 )
+                {
+                    browser.getNext( jdbmTuple );
+                }
+            }
+            
+            returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
+            returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
+            return valueAvailable = true;
+        }
+        else
+        {
+            clearValue();
+            return false;
+        }
+    }
+
+
+    public Tuple<K,V> get() throws Exception
+    {
+        checkNotClosed( "get()" );
+        if ( valueAvailable )
+        {
+            return returnedTuple;
+        }
+
+        throw new InvalidCursorPositionException();
+    }
+
+
+    public boolean isElementReused()
+    {
+        return true;
+    }
+}