You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2007/11/11 00:54:36 UTC
svn commit: r593826 - in
/directory/apacheds/branches/bigbang/core-shared/src:
main/java/org/apache/directory/server/core/
main/java/org/apache/directory/server/core/cursor/
test/java/org/apache/directory/server/core/cursor/
Author: akarasulu
Date: Sat Nov 10 15:54:34 2007
New Revision: 593826
URL: http://svn.apache.org/viewvc?rev=593826&view=rev
Log:
introducing (yet again - did this before in 2002) the concept of a Cursor to replace the use of NamingEnumerations
Added:
directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/
directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/
directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/Cursor.java
directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/ListCursor.java
directory/apacheds/branches/bigbang/core-shared/src/test/java/org/apache/directory/server/core/cursor/ListCursorTest.java (with props)
Added: directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/Cursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/Cursor.java?rev=593826&view=auto
==============================================================================
--- directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/Cursor.java (added)
+++ directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/Cursor.java Sat Nov 10 15:54:34 2007
@@ -0,0 +1,236 @@
+/*
+ * 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.cursor;
+
+import java.io.IOException;
+
+
+/**
+ * A simple cursor concept for bidirectionally enumerating over elements.
+ * Cursors unlike iterators request to advance to an element by calling next()
+ * or previous() which returns true or false if the request succeeds. Other
+ * operations for relative and absolute advances are provided. If the cursor
+ * does not advance, then the Cursor is either positioned before the first
+ * element or after the last element in which case the user of the Cursor must
+ * stop advancing in the respective direction. If an advance succeeds a get()
+ * operation retreives the current object at the Cursors position.
+ *
+ * Although this interface presumes Cursors can advance bidirectionally, one
+ * or more either direction may not be supported. In this case
+ * implementations should throw UnsupportedOperationExceptions.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface Cursor<E>
+{
+ /**
+ * Positions this Curser before the first element.
+ *
+ * @throws IOException if there are problems positioning this cursor or if
+ * this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ void beforeFirst() throws IOException;
+
+
+ /**
+ * Positions this Curser after the last element.
+ *
+ * @throws IOException if there are problems positioning this Cursor or if
+ * this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ void afterLast() throws IOException;
+
+
+ /**
+ * Positions this Curser at the nth element. Zero based indexing is used.
+ *
+ * If the specified position is past the first or last element, the Cursor
+ * is positioned before the first or after the last element respectively.
+ *
+ * @param absolutePosition the absolute position to move this Cursor to
+ * @return true if the position has been successfully changed to the
+ * element at the specified position, false otherwise
+ * @throws IOException if there are problems positioning this Cursor or if
+ * this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean absolute( int absolutePosition ) throws IOException;
+
+
+ /**
+ * Positions this Curser n places relative to the present position. Zero
+ * based indexing is used and negative index values may be provided for
+ * representing the direction.
+ *
+ * If the specified position is past the first or last element, the Cursor
+ * is positioned before the first or after the last element respectively.
+ *
+ * @param relativePosition the relative position to move this Cursor to
+ * @return true if the position has been successfully changed to the
+ * element relative to the current position, false otherwise
+ * @throws IOException if there are problems positioning this Cursor or if
+ * this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean relative( int relativePosition ) throws IOException;
+
+
+ /**
+ * Positions this Curser at the first element.
+ *
+ * @return true if the position has been successfully changed to the first
+ * element, false otherwise
+ * @throws IOException if there are problems positioning this Cursor or if
+ * this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean first() throws IOException;
+
+
+ /**
+ * Positions this Curser at the last element.
+ *
+ * @return true if the position has been successfully changed to the last
+ * element, false otherwise
+ * @throws IOException if there are problems positioning this Cursor or if
+ * this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean last() throws IOException;
+
+
+ /**
+ * Checks if this Curser is positioned at the first element.
+ *
+ * @return true if the current position is at the first element, false
+ * otherwise
+ * @throws IOException if there are problems determining this Cursor's
+ * position, or if this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean isFirst() throws IOException;
+
+
+ /**
+ * Checks if this Curser is positioned at the last element.
+ *
+ * @return true if the current position is at the last element, false
+ * otherwise
+ * @throws IOException if there are problems determining this Cursor's
+ * position, or if this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean isLast() throws IOException;
+
+
+ /**
+ * Checks if this Curser is positioned after the last element.
+ *
+ * @return true if the current position is after the last element, false
+ * otherwise
+ * @throws IOException if there are problems determining this Cursor's
+ * position, or if this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean isAfterLast() throws IOException;
+
+
+ /**
+ * Checks if this Curser is positioned before the first element.
+ *
+ * @return true if the current position is before the first element, false
+ * otherwise
+ * @throws IOException if there are problems determining this Cursor's
+ * position, or if this Cursor is closed
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean isBeforeFirst() throws IOException;
+
+
+ /**
+ * Checks if this Curser is closed. Calls to this operation should not
+ * fail with exceptions if and only if the cursor is in the closed state.
+ *
+ * @return true if this Cursor is closed, false otherwise
+ * @throws IOException if there are problems determining the cursor's closed state
+ * @throws UnsupportedOperationException if this operation is not supported
+ */
+ boolean isClosed() throws IOException;
+
+
+ /**
+ * Advances this Cursor to the previous position.
+ *
+ * @return true if the advance succeeded, false otherwise
+ * @throws IOException if there are problems advancing to the next position
+ * @throws UnsupportedOperationException if advances in this direction are not supported
+ */
+ boolean previous() throws IOException;
+
+
+ /**
+ * Advances this Cursor to the next position.
+ *
+ * @return true if the advance succeeded, false otherwise
+ * @throws IOException if there are problems advancing to this Cursor to
+ * the next position, or if this Cursor is closed
+ * @throws UnsupportedOperationException if advances in this direction are not supported
+ */
+ boolean next() throws IOException;
+
+
+ /**
+ * Gets the object at the current position. Cursor implementations may
+ * choose to reuse element objects by re-populating them on advances
+ * instead of creating new objects on each advance.
+ *
+ * @return the object at the current position
+ * @throws IOException if the object at this Cursor's current position
+ * cannot be retrieved, or if this Cursor is closed
+ */
+ E get() throws IOException;
+
+
+ /**
+ * Gets whether or not this Cursor will return the same element object
+ * instance on get() operations for any position of this Cursor. Some
+ * Cursor implementations may reuse the same element copying values into
+ * it for every position rather than creating and emiting new element
+ * objects on each advance. Some Cursor implementations may return
+ * different elements for each position yet the same element instance
+ * is returned for the same position. In these cases this method should
+ * return true.
+ *
+ * @return true if elements are reused by this Cursor
+ */
+ boolean isElementReused();
+
+
+ /**
+ * Closes this Cursor and frees any resources it my have allocated.
+ * Repeated calls to this method after this Cursor has already been
+ * called should not fail with exceptions.
+ *
+ * @throws IOException if this Cursor cannot be closed
+ */
+ void close() throws IOException;
+}
Added: directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/ListCursor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/ListCursor.java?rev=593826&view=auto
==============================================================================
--- directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/ListCursor.java (added)
+++ directory/apacheds/branches/bigbang/core-shared/src/main/java/org/apache/directory/server/core/cursor/ListCursor.java Sat Nov 10 15:54:34 2007
@@ -0,0 +1,358 @@
+/*
+ * 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.cursor;
+
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * A simple implementation of a Cursor on a {@link List}. Optionally, the
+ * Cursor may be limited to a specific range within the list.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ListCursor<E> implements Cursor<E>
+{
+ private final List<E> list;
+ private final int start;
+ private final int end;
+ private boolean closed;
+ private int index = -1;
+
+
+ /**
+ * Creates a new ListCursor with lower (inclusive) and upper (exclusive)
+ * bounds.
+ *
+ * As with all Cursors, this ListCursor requires a successful return from
+ * advance operations (next() or previous()) to properly return values
+ * using the get() operation.
+ *
+ * @param start the lower bound index
+ * @param list the list this ListCursor operates on
+ * @param end the upper bound index
+ */
+ public ListCursor( int start, List<E> list, int end )
+ {
+ if ( start < 0 || start > list.size() )
+ {
+ throw new IllegalArgumentException( "start index '" + start + "' out of range" );
+ }
+
+ if ( end < 0 || end > list.size() )
+ {
+ throw new IllegalArgumentException( "end index '" + end + "' out of range" );
+ }
+
+ // check list is not empty list since the empty list is the only situation
+ // where we allow for start to equal the end: in other cases it makes no sense
+ if ( list.size() > 0 && start >= end )
+ {
+ throw new IllegalArgumentException( "start index '" + start + "' greater than or equal to end index '"
+ + end + "' just does not make sense" );
+ }
+
+ //noinspection ConstantConditions
+ if ( list != null )
+ {
+ this.list = list;
+ }
+ else
+ {
+ //noinspection unchecked
+ this.list = Collections.EMPTY_LIST;
+ }
+
+ this.start = start;
+ this.end = end;
+ }
+
+
+ /**
+ * Creates a new ListCursor with a specific upper (exclusive) bound: the
+ * lower (inclusive) bound defaults to 0.
+ *
+ * @param list the backing for this ListCursor
+ * @param end the upper bound index representing the position after the
+ * last element
+ */
+ public ListCursor( List<E> list, int end )
+ {
+ this( 0, list, end );
+ }
+
+
+ /**
+ * Creates a new ListCursor with a lower (inclusive) bound: the upper
+ * (exclusive) bound is the size of the list.
+ *
+ * @param start the lower (inclusive) bound index: the position of the
+ * first entry
+ * @param list the backing for this ListCursor
+ */
+ public ListCursor( int start, List<E> list )
+ {
+ this( start, list, list.size() );
+ }
+
+
+ /**
+ * Creates a new ListCursor without specific bounds: the bounds are
+ * acquired from the size of the list.
+ *
+ * @param list the backing for this ListCursor
+ */
+ public ListCursor( List<E> list )
+ {
+ this( 0, list, list.size() );
+ }
+
+
+ /**
+ * Creates a new ListCursor without any elements.
+ */
+ public ListCursor()
+ {
+ //noinspection unchecked
+ this( 0, Collections.EMPTY_LIST, 0 );
+ }
+
+
+ protected void checkClosed( String operation ) throws IOException
+ {
+ if ( closed )
+ {
+ throw new IOException( "Attempting " + operation + " operation on a closed Cursor." );
+ }
+ }
+
+
+ public void beforeFirst() throws IOException
+ {
+ checkClosed( "beforeFirst()" );
+ this.index = -1;
+ }
+
+
+ public void afterLast() throws IOException
+ {
+ checkClosed( "afterLast()" );
+ this.index = end;
+ }
+
+
+ public boolean absolute( int index ) throws IOException
+ {
+ checkClosed( "absolute()" );
+
+ if ( index < start )
+ {
+ this.index = -1;
+ return false;
+ }
+
+ if ( index >= end )
+ {
+ this.index = end;
+ return false;
+ }
+
+ this.index = index;
+ return true;
+ }
+
+
+ public boolean relative( int index ) throws IOException
+ {
+ checkClosed( "relative()" );
+
+ if ( this.index + index < start )
+ {
+ this.index = -1;
+ return false;
+ }
+
+ if ( this.index + index >= end )
+ {
+ this.index = end;
+ return false;
+ }
+
+ this.index += index;
+ return true;
+ }
+
+
+ public boolean first() throws IOException
+ {
+ checkClosed( "first()" );
+
+ if ( list.size() > 0 )
+ {
+ index = start;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ public boolean last() throws IOException
+ {
+ checkClosed( "last()" );
+
+ if ( list.size() > 0 )
+ {
+ index = end - 1;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ public boolean isFirst() throws IOException
+ {
+ checkClosed( "isFirst()" );
+ return list.size() > 0 && index == start;
+ }
+
+
+ public boolean isLast() throws IOException
+ {
+ checkClosed( "isLast()" );
+ return list.size() > 0 && index == end - 1;
+
+ }
+
+
+ public boolean isAfterLast() throws IOException
+ {
+ checkClosed( "isAfterLast()" );
+ return index == end;
+ }
+
+
+ public boolean isBeforeFirst() throws IOException
+ {
+ checkClosed( "isBeforeFirst()" );
+ return index == -1;
+ }
+
+
+ public boolean isClosed()
+ {
+ return closed;
+ }
+
+
+ public boolean previous() throws IOException
+ {
+ checkClosed( "previous()" );
+
+ // if parked at -1 we cannot go backwards
+ if ( index == -1 )
+ {
+ return false;
+ }
+
+ // if the index moved back is still greater than or eq to start then OK
+ if ( index - 1 >= start )
+ {
+ index--;
+ return true;
+ }
+
+ // if the index currently less than or equal to start we need to park it at -1 and return false
+ if ( index <= start )
+ {
+ index = -1;
+ return false;
+ }
+
+ if ( list.size() <= 0 )
+ {
+ index = -1;
+ }
+
+ return false;
+ }
+
+
+ public boolean next() throws IOException
+ {
+ checkClosed( "next()" );
+
+ // if parked at -1 we advance to the start index and return true
+ if ( list.size() > 0 && index == -1 )
+ {
+ index = start;
+ return true;
+ }
+
+ // if the index plus one is less than the end then increment and return true
+ if ( list.size() > 0 && index + 1 < end )
+ {
+ index++;
+ return true;
+ }
+
+ // if the index plus one is equal to the end then increment and return false
+ if ( list.size() > 0 && index + 1 == end )
+ {
+ index++;
+ return false;
+ }
+
+ if ( list.size() <= 0 )
+ {
+ index = end;
+ }
+
+ return false;
+ }
+
+
+ public E get() throws IOException
+ {
+ checkClosed( "get()" );
+ if ( index < start || index >= end )
+ {
+ throw new IOException( "Cursor not positioned at an element" );
+ }
+
+ return list.get( index );
+ }
+
+
+ public boolean isElementReused()
+ {
+ return true;
+ }
+
+
+ public void close()
+ {
+ closed = true;
+ }
+}
Added: directory/apacheds/branches/bigbang/core-shared/src/test/java/org/apache/directory/server/core/cursor/ListCursorTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-shared/src/test/java/org/apache/directory/server/core/cursor/ListCursorTest.java?rev=593826&view=auto
==============================================================================
--- directory/apacheds/branches/bigbang/core-shared/src/test/java/org/apache/directory/server/core/cursor/ListCursorTest.java (added)
+++ directory/apacheds/branches/bigbang/core-shared/src/test/java/org/apache/directory/server/core/cursor/ListCursorTest.java Sat Nov 10 15:54:34 2007
@@ -0,0 +1,589 @@
+/*
+ * 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.cursor;
+
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * Tests the ListCursor class. The assertXxxx() methods defined in this class
+ * can be collected in an abstract test case class that can be used to test
+ * the behavior of any Cursor implementation down the line.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ListCursorTest extends TestCase
+{
+ public void testEmptyList() throws IOException
+ {
+ ListCursor<String> cursor = new ListCursor<String>();
+
+ assertFirstLastOnNewCursor( cursor, 0, 0, 0 );
+ assertAbsolute( cursor, 0, 0, 0 );
+ assertRelative( cursor, 0, 0, 0 );
+
+ // close test
+ cursor.close();
+ assertClosed( cursor, "cursor.isCloased() should return true after closing the cursor", true );
+ }
+
+
+ public void testSingleElementList() throws IOException
+ {
+ ListCursor<String> cursor = new ListCursor<String>( Collections.singletonList( "singleton" ) );
+ assertFirstLastOnNewCursor( cursor, 1, 0, 1 );
+ assertAbsolute( cursor, 1, 0, 1 );
+ assertRelative( cursor, 1, 0, 1 );
+ cursor.close();
+
+ // close test
+ cursor.close();
+ assertClosed( cursor, "cursor.isCloased() should return true after closing the cursor", true );
+
+ // bad bounds: start = end is senseless
+ try
+ {
+ cursor = new ListCursor<String>( Collections.singletonList( "singleton" ), 0 );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: start = end is senseless
+ try
+ {
+ cursor = new ListCursor<String>( 1, Collections.singletonList( "singleton" ) );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: start > end is senseless
+ try
+ {
+ cursor = new ListCursor<String>( 5, Collections.singletonList( "singleton" ) );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: end < start is senseless too in another way :)
+ try
+ {
+ cursor = new ListCursor<String>( Collections.singletonList( "singleton" ), -5 );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: start out of range
+ try
+ {
+ cursor = new ListCursor<String>( -5, Collections.singletonList( "singleton" ) );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: end out of range
+ try
+ {
+ cursor = new ListCursor<String>( Collections.singletonList( "singleton" ), 5 );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+ }
+
+
+ public void testManyElementList() throws IOException
+ {
+ List<String> list = new ArrayList<String>();
+ list.add( "item 1" );
+ list.add( "item 2" );
+ list.add( "item 3" );
+ list.add( "item 4" );
+ list.add( "item 5" );
+
+ // test with bounds of the list itself
+ ListCursor<String> cursor = new ListCursor<String>( list );
+ assertFirstLastOnNewCursor( cursor, 5, 0, 5 );
+ assertAbsolute( cursor, 5, 0, 5 );
+ assertRelative( cursor, 5, 0, 5 );
+ cursor.close();
+
+ // test with nonzero lower bound
+ cursor = new ListCursor<String>( 1, list );
+ assertFirstLastOnNewCursor( cursor, 5, 1, 5 );
+ assertAbsolute( cursor, 5, 1, 5 );
+ assertRelative( cursor, 5, 1, 5 );
+ cursor.close();
+
+ // test with nonzero lower bound and upper bound
+ cursor = new ListCursor<String>( 1, list, 4 );
+ assertFirstLastOnNewCursor( cursor, 5, 1, 4 );
+ assertAbsolute( cursor, 5, 1, 4 );
+ assertRelative( cursor, 5, 1, 4 );
+
+ // close test
+ cursor.close();
+ assertClosed( cursor, "cursor.isCloased() should return true after closing the cursor", true );
+
+ // bad bounds: start = end is senseless
+ try
+ {
+ cursor = new ListCursor<String>( list, 0 );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: start = end is senseless
+ try
+ {
+ cursor = new ListCursor<String>( 5, list );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: start > end is senseless
+ try
+ {
+ cursor = new ListCursor<String>( 10, list );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: end < start is senseless too in another way :)
+ try
+ {
+ cursor = new ListCursor<String>( list, -5 );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: start out of range
+ try
+ {
+ cursor = new ListCursor<String>( -5, list );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+
+ // bad bounds: end out of range
+ try
+ {
+ cursor = new ListCursor<String>( list, 10 );
+ cursor.close();
+ fail( "when the start = end bounds this is senseless and should complain" );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ assertNotNull( e );
+ }
+ }
+
+
+ @SuppressWarnings ( { "ConstantConditions" } )
+ protected void assertFirstLastOnNewCursor( Cursor cursor, int listSize, int lowerBound, int upperBound )
+ throws IOException
+ {
+ assertNotNull( cursor );
+
+ String prefix = "[size, " + listSize + "] [lower, " + lowerBound + "] [upper, " + upperBound + "]: ";
+
+ assertFalse( prefix + "new cursor should not be positioned after last", cursor.isAfterLast() );
+ assertTrue( prefix + "new cursor should be positioned before first", cursor.isBeforeFirst() );
+ assertFalse( prefix + "new cursor should not be closed", cursor.isClosed() );
+ assertFalse( prefix + "new cursor should not be positioned at first", cursor.isFirst() );
+ assertFalse( prefix + "new cursor should not be positioned at last", cursor.isLast() );
+
+ // beforeFirst and afterLast tests
+ cursor.afterLast();
+ assertTrue( prefix + "cursor.afterLast() should return true on isAfterLast()", cursor.isAfterLast() );
+ assertFalse( prefix + "cursor.afterLast() should return false on isBeforeFirst()", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.afterLast() should return false on isFirst()", cursor.isFirst() );
+ assertFalse( prefix + "cursor.afterLast() should return false on isLast()", cursor.isLast() );
+
+ cursor.beforeFirst();
+ assertTrue( prefix + "cursor.beforeFirst() should return true on isBeforeFirst()", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.beforeFirst() should return false on isAfterLast()", cursor.isAfterLast() );
+ assertFalse( prefix + "cursor.beforeFirst() should return false on isFirst()", cursor.isFirst() );
+ assertFalse( prefix + "cursor.beforeFirst() should return false on isLast()", cursor.isLast() );
+
+ // first() tests
+ cursor.afterLast();
+ if ( listSize <= 0 )
+ {
+ assertFalse( "cursor.first() on empty cursor should return false", cursor.first() );
+ assertFalse( "cursor.first() on empty cursor should return false on isFirst()", cursor.isFirst() );
+ assertFalse( "cursor.first() on empty cursor should should change position state", cursor.isBeforeFirst() );
+ assertTrue( "cursor.first() on empty cursor should should change position state", cursor.isAfterLast() );
+ }
+ else
+ {
+ assertTrue( prefix + "cursor.first() should return true", cursor.first() );
+ assertTrue( prefix + "cursor.first() should return true on isFirst()", cursor.isFirst() );
+ assertFalse( prefix + "cursor.first() should change position", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.first() should change position", cursor.isAfterLast() );
+ }
+
+ // last() tests
+ cursor.beforeFirst();
+ if ( listSize <= 0 )
+ {
+ assertFalse( "cursor.last() on empty cursor should return false", cursor.last() );
+ assertFalse( "cursor.last() on empty cursor should return false on isLast()", cursor.isLast() );
+ assertFalse( "cursor.last() on empty cursor should should change position state", cursor.isAfterLast() );
+ assertTrue( "cursor.last() on empty cursor should should change position state", cursor.isBeforeFirst() );
+ }
+ else
+ {
+ assertTrue( prefix + "cursor.last() should return true", cursor.last() );
+ assertTrue( prefix + "cursor.last() should return true on isLast()", cursor.isLast() );
+ assertFalse( prefix + "cursor.last() should not park position after last", cursor.isAfterLast() );
+ assertFalse( prefix + "cursor.last() should not park position before first", cursor.isBeforeFirst() );
+ }
+
+ // next() tests
+ cursor.beforeFirst();
+ if ( listSize <= 0 )
+ {
+ assertFalse( "empty cursor.next() should return false", cursor.next() );
+ assertTrue( "empty cursor.next() should change pos to after last", cursor.isAfterLast() );
+ assertFalse( "empty cursor.next() should change pos to after last", cursor.isBeforeFirst() );
+ }
+ else
+ {
+ assertTrue( prefix + "cursor.next() should return true", cursor.next() );
+ assertTrue( prefix + "cursor.next() should change pos to first element", cursor.isFirst() );
+ assertFalse( prefix + "cursor.next() should not change pos to after last", cursor.isAfterLast() );
+ assertFalse( prefix + "cursor.next() should not change pos to before first", cursor.isBeforeFirst() );
+
+ while( cursor.next() )
+ {
+ assertFalse( prefix + "cursor.next() should not change pos to before first", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.next() should not change pos to first after first advance forward",
+ cursor.isFirst() );
+ }
+
+ assertTrue( prefix + "cursor.next() failure should put pos to after last", cursor.isAfterLast() );
+ }
+
+ // previous() tests
+ cursor.afterLast();
+ if ( listSize <= 0 )
+ {
+ assertFalse( "empty cursor.previous() should return false", cursor.previous() );
+ assertTrue( "empty cursor.previous() should change pos to before first", cursor.isBeforeFirst() );
+ assertFalse( "empty cursor.previous() should change pos to before first", cursor.isAfterLast() );
+ }
+ else
+ {
+ assertTrue( prefix + "cursor.previous() should return true", cursor.previous() );
+ assertTrue( prefix + "cursor.previous() should change pos to last element", cursor.isLast() );
+ assertFalse( prefix + "cursor.previous() should not change pos to before first", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.previous() should not change pos to after last", cursor.isAfterLast() );
+
+ while( cursor.previous() )
+ {
+ assertFalse( prefix + "cursor.previous() should not change pos to after last", cursor.isAfterLast() );
+ assertFalse( prefix + "cursor.previous() should not change pos to last after first advance backward",
+ cursor.isLast() );
+ }
+
+ assertTrue( prefix + "cursor.previous() failure should put pos to before first", cursor.isBeforeFirst() );
+ }
+ }
+
+
+ protected void assertAbsolute( Cursor cursor, int listSize, int lowerBound, int upperBound )
+ throws IOException
+ {
+ String prefix = "[size, " + listSize + "] [lower, " + lowerBound + "] [upper, " + upperBound + "]: ";
+
+ // test absolute() advance with change of position below lower bound
+ cursor.afterLast();
+ assertFalse( prefix + "cursor.absolute(" + ( lowerBound - 1 ) +
+ ") should return false and change state to before first", cursor.absolute( lowerBound - 1 ) );
+ assertTrue( prefix + "cursor.relative(" + ( lowerBound - 1 ) +
+ ") should change pos to before first", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.relative(" + ( lowerBound - 1 ) +
+ ") should --NOT-- change pos to after last", cursor.isAfterLast() );
+
+ if ( listSize == 0 )
+ {
+ // Corner case!!! Technically the 0th index is the 1st element
+ // which is greater than 0 elements which is the size of the list
+ // so technically the observed state change for index = 0 should be
+ // the same as when index > 0.
+ cursor.beforeFirst();
+ assertFalse( "empty cursor.absolute(0) should fail but change state to after last", cursor.absolute( 0 ) );
+ assertFalse( "empty cursor.absolute(0) should change pos to after last", cursor.isBeforeFirst() );
+ assertTrue( "empty cursor.absolute(0) should change pos to after last", cursor.isAfterLast() );
+ }
+
+ // test absolute() advance with change of position above upper bound
+ cursor.beforeFirst();
+ assertFalse( prefix + "cursor.absolute(" + ( upperBound + 1 )
+ + ") should return false but change state to after last", cursor.absolute( upperBound + 1 ) );
+ assertFalse( prefix + "cursor.absolute(" + ( upperBound + 1 ) + ") should change pos to after last",
+ cursor.isBeforeFirst() );
+ assertTrue( prefix + "cursor.absolute(" + ( upperBound + 1 ) + ") should change pos to after last",
+ cursor.isAfterLast() );
+ }
+
+
+ protected void assertRelative( Cursor cursor, int listSize, int lowerBound, int upperBound )
+ throws IOException
+ {
+ String prefix = "[size, " + listSize + "] [lower, " + lowerBound + "] [upper, " + upperBound + "]: ";
+
+ // test relative() advance which changes position below lower bound
+ cursor.afterLast();
+ int relativePos = - ( upperBound - lowerBound + 1 );
+
+ assertFalse( prefix + "cursor.relative(" + relativePos +
+ ") should return false and change state to before first", cursor.relative( - ( upperBound + 1 ) ) );
+ assertTrue( prefix + "cursor.relative(" + relativePos +
+ ") should change pos to before first", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.relative(" + relativePos +
+ ") should --NOT-- change pos to after last", cursor.isAfterLast() );
+
+ // make sure relative(0) does not change pos if begin state is after last
+ cursor.afterLast();
+ assertFalse( prefix + "cursor.relative(0) should return false and have no effect on pos",
+ cursor.relative( 0 ) );
+ assertFalse( prefix + "cursor.relative(0) should have no effect on changing state", cursor.isBeforeFirst() );
+ assertTrue( prefix + "cursor.relative(0) should have no effect on changing state", cursor.isAfterLast() );
+
+ // make sure relative(0) does not change pos if begin state is before first
+ cursor.beforeFirst();
+ assertFalse( prefix + "cursor.relative(0) should return false and have no effect on pos",
+ cursor.relative( 0 ) );
+ assertTrue( prefix + "cursor.relative(0) should have no effect on changing state", cursor.isBeforeFirst() );
+ assertFalse( prefix + "cursor.relative(0) should have no effect on changing state", cursor.isAfterLast() );
+
+ // make relative() advance which changes position above upper bound
+ cursor.beforeFirst();
+ assertFalse( prefix + "cursor.relative(" + ( upperBound + 1 )
+ + ") should return false but change state to after last", cursor.relative( upperBound + 1 ) );
+ assertFalse( prefix + "cursor.relative(" + ( upperBound + 1 ) + ") should change pos to after last",
+ cursor.isBeforeFirst() );
+ assertTrue( prefix + "cursor.relative(" + ( upperBound + 1 ) + ") should change pos to after last",
+ cursor.isAfterLast() );
+ }
+
+
+ protected void assertClosed( Cursor cursor, String msg, boolean expected )
+ {
+ try
+ {
+ assertEquals( msg, expected, cursor.isClosed() );
+ }
+ catch ( IOException e )
+ {
+ fail( "cursor.isClosed() test should not fail after closing the cursor" );
+ }
+
+ try
+ {
+ cursor.close();
+ }
+ catch ( IOException e )
+ {
+ fail( "cursor.close() after closing the cursor should not fail with exceptions" );
+ }
+
+
+ try
+ {
+ cursor.absolute( 1 );
+ fail( "cursor.absolute() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.afterLast();
+ fail( "cursor.afterLast() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.beforeFirst();
+ fail( "cursor.beforeFirst() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.first();
+ fail( "cursor.first() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.get();
+ fail( "cursor.get() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.isAfterLast();
+ fail( "cursor.isAfterLast() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.isBeforeFirst();
+ fail( "cursor.isBeforeFirst() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.isFirst();
+ fail( "cursor.isFirst() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.isLast();
+ fail( "cursor.isLast() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.last();
+ fail( "cursor.last() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.next();
+ fail( "cursor.next() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.previous();
+ fail( "cursor.previous() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+
+ try
+ {
+ cursor.relative( 1 );
+ fail( "cursor.relative() after closing the cursor should fail with an IOException" );
+ }
+ catch ( IOException e )
+ {
+ assertNotNull( e );
+ }
+ }
+}
\ No newline at end of file
Propchange: directory/apacheds/branches/bigbang/core-shared/src/test/java/org/apache/directory/server/core/cursor/ListCursorTest.java
------------------------------------------------------------------------------
svn:executable = *