Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

StoredIterator.java

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2000-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: StoredIterator.java,v 12.1 2005/01/31 19:27:32 mark Exp $
00008  */
00009 
00010 package com.sleepycat.collections;
00011 
00012 import java.util.Iterator;
00013 import java.util.ListIterator;
00014 import java.util.NoSuchElementException;
00015 
00016 import com.sleepycat.db.DatabaseException;
00017 import com.sleepycat.db.OperationStatus;
00018 
00051 public class StoredIterator implements ListIterator, Cloneable {
00052 
00062     public static void close(Iterator i) {
00063 
00064         if (i instanceof StoredIterator) {
00065             ((StoredIterator) i).close();
00066         }
00067     }
00068 
00069     private static final int MOVE_NEXT = 1;
00070     private static final int MOVE_PREV = 2;
00071     private static final int MOVE_FIRST = 3;
00072 
00073     private boolean lockForWrite;
00074     private StoredCollection coll;
00075     private DataCursor cursor;
00076     private int toNext;
00077     private int toPrevious;
00078     private int toCurrent;
00079     private boolean writeAllowed;
00080     private boolean setAndRemoveAllowed;
00081     private Object currentData;
00082     private final boolean recNumAccess;
00083 
00084     StoredIterator(StoredCollection coll, boolean writeAllowed,
00085                    DataCursor joinCursor) {
00086         try {
00087             this.coll = coll;
00088             this.writeAllowed = writeAllowed;
00089             if (joinCursor == null)
00090                 this.cursor = new DataCursor(coll.view, writeAllowed);
00091             else
00092                 this.cursor = joinCursor;
00093             this.recNumAccess = cursor.hasRecNumAccess();
00094             reset();
00095         } catch (Exception e) {
00096             try {
00097                 /* Ensure that the cursor is closed.  [#10516] */
00098                 close();
00099             } catch (Exception ignored) {}
00100             throw StoredContainer.convertException(e);
00101         }
00102     }
00103 
00110     protected Object clone() {
00111 
00112         try {
00113             StoredIterator o = (StoredIterator) super.clone();
00114             o.cursor = cursor.cloneCursor();
00115             return o;
00116         } catch (Exception e) {
00117             throw StoredContainer.convertException(e);
00118         }
00119     }
00120 
00129     public final boolean isReadModifyWrite() {
00130 
00131         return lockForWrite;
00132     }
00133 
00142     public void setReadModifyWrite(boolean lockForWrite) {
00143 
00144         this.lockForWrite = lockForWrite;
00145     }
00146 
00147     // --- begin Iterator/ListIterator methods ---
00148 
00158     public boolean hasNext() {
00159 
00160         if (cursor == null) {
00161             return false;
00162         }
00163         try {
00164             if (toNext != 0) {
00165                 OperationStatus status = move(toNext);
00166                 if (status == OperationStatus.SUCCESS) {
00167                     toNext = 0;
00168                     toPrevious = MOVE_PREV;
00169                     toCurrent = MOVE_PREV;
00170                 }
00171             }
00172             return (toNext == 0);
00173         }
00174         catch (Exception e) {
00175             throw StoredContainer.convertException(e);
00176         }
00177     }
00178 
00188     public boolean hasPrevious() {
00189 
00190         if (cursor == null) {
00191             return false;
00192         }
00193         try {
00194             if (toPrevious != 0) {
00195                 OperationStatus status = move(toPrevious);
00196                 if (status == OperationStatus.SUCCESS) {
00197                     toPrevious = 0;
00198                     toNext = MOVE_NEXT;
00199                     toCurrent = MOVE_NEXT;
00200                 }
00201             }
00202             return (toPrevious == 0);
00203         } catch (Exception e) {
00204             throw StoredContainer.convertException(e);
00205         }
00206     }
00207 
00217     public Object next() {
00218 
00219         try {
00220             if (toNext != 0) {
00221                 OperationStatus status = move(toNext);
00222                 if (status == OperationStatus.SUCCESS) {
00223                     toNext = 0;
00224                 }
00225             }
00226             if (toNext == 0) {
00227                 currentData = coll.makeIteratorData(this, cursor);
00228                 toNext = MOVE_NEXT;
00229                 toPrevious = 0;
00230                 toCurrent = 0;
00231                 setAndRemoveAllowed = true;
00232                 return currentData;
00233             }
00234             // else throw NoSuchElementException below
00235         } catch (Exception e) {
00236             throw StoredContainer.convertException(e);
00237         }
00238         throw new NoSuchElementException();
00239     }
00240 
00250     public Object previous() {
00251 
00252         try {
00253             if (toPrevious != 0) {
00254                 OperationStatus status = move(toPrevious);
00255                 if (status == OperationStatus.SUCCESS) {
00256                     toPrevious = 0;
00257                 }
00258             }
00259             if (toPrevious == 0) {
00260                 currentData = coll.makeIteratorData(this, cursor);
00261                 toPrevious = MOVE_PREV;
00262                 toNext = 0;
00263                 toCurrent = 0;
00264                 setAndRemoveAllowed = true;
00265                 return currentData;
00266             }
00267             // else throw NoSuchElementException below
00268         } catch (Exception e) {
00269             throw StoredContainer.convertException(e);
00270         }
00271         throw new NoSuchElementException();
00272     }
00273 
00291     public int nextIndex() {
00292 
00293         if (!recNumAccess) {
00294             throw new UnsupportedOperationException(
00295                 "Record number access not supported");
00296         }
00297         try {
00298             return hasNext() ? (cursor.getCurrentRecordNumber() -
00299                                 coll.getIndexOffset())
00300                              : Integer.MAX_VALUE;
00301         } catch (Exception e) {
00302             throw StoredContainer.convertException(e);
00303         }
00304     }
00305 
00320     public int previousIndex() {
00321 
00322         if (!recNumAccess) {
00323             throw new UnsupportedOperationException(
00324                 "Record number access not supported");
00325         }
00326         try {
00327             return hasPrevious() ? (cursor.getCurrentRecordNumber() -
00328                                     coll.getIndexOffset())
00329                                  : -1;
00330         } catch (Exception e) {
00331             throw StoredContainer.convertException(e);
00332         }
00333     }
00334 
00354     public void set(Object value) {
00355 
00356         if (!coll.hasValues()) throw new UnsupportedOperationException();
00357         if (!setAndRemoveAllowed) throw new IllegalStateException();
00358         try {
00359             moveToCurrent();
00360             cursor.putCurrent(value);
00361         } catch (Exception e) {
00362             throw StoredContainer.convertException(e);
00363         }
00364     }
00365 
00383     public void remove() {
00384 
00385         if (!setAndRemoveAllowed) throw new IllegalStateException();
00386         try {
00387             moveToCurrent();
00388             cursor.delete();
00389             setAndRemoveAllowed = false;
00390         } catch (Exception e) {
00391             throw StoredContainer.convertException(e);
00392         }
00393     }
00394 
00425     public void add(Object value) {
00426 
00427         coll.checkIterAddAllowed();
00428         try {
00429             OperationStatus status = OperationStatus.SUCCESS;
00430             if (toNext != 0 && toPrevious != 0) { // database is empty
00431                 if (coll.view.keysRenumbered) { // recno-renumber database
00432                     /*
00433                      * Close cursor during append and then reopen to support
00434                      * CDB restriction that append may not be called with a
00435                      * cursor open; note the append will still fail if the
00436                      * application has another cursor open.
00437                      */
00438                     close();
00439                     status = coll.view.append(value, null, null);
00440                     cursor = new DataCursor(coll.view, writeAllowed);
00441                     reset();
00442                     next(); // move past new record
00443                 } else { // hash/btree with duplicates
00444                     throw new IllegalStateException(
00445                         "Collection is empty, cannot add() duplicate");
00446                 }
00447             } else { // database is not empty
00448                 boolean putBefore = false;
00449                 if (coll.view.keysRenumbered) { // recno-renumber database
00450                     moveToCurrent();
00451                     if (hasNext()) {
00452                         status = cursor.putBefore(value);
00453                         putBefore = true;
00454                     } else {
00455                         status = cursor.putAfter(value);
00456                     }
00457                 } else { // hash/btree with duplicates
00458                     if (coll.areDuplicatesOrdered()) {
00459                         status = cursor.putNoDupData(null, value, null, true);
00460                     } else if (toNext == 0) {
00461                         status = cursor.putBefore(value);
00462                         putBefore = true;
00463                     } else {
00464                         status = cursor.putAfter(value);
00465                     }
00466                 }
00467                 if (putBefore) {
00468                     toPrevious = 0;
00469                     toNext = MOVE_NEXT;
00470                 }
00471             }
00472             if (status == OperationStatus.KEYEXIST) {
00473                 throw new IllegalArgumentException("Duplicate value");
00474             } else if (status != OperationStatus.SUCCESS) {
00475                 throw new IllegalArgumentException("Could not insert: " +
00476                                                     status);
00477             }
00478             setAndRemoveAllowed = false;
00479         } catch (Exception e) {
00480             throw StoredContainer.convertException(e);
00481         }
00482     }
00483 
00484     // --- end Iterator/ListIterator methods ---
00485 
00489     private void reset() {
00490 
00491         toNext = MOVE_FIRST;
00492         toPrevious = MOVE_PREV;
00493         toCurrent = 0;
00494         currentData = null;
00495         /* 
00496          * Initialize cursor at beginning to avoid "initial previous == last"
00497          * behavior when cursor is uninitialized.
00498          *
00499          * FindBugs whines about us ignoring the return value from hasNext().
00500          */
00501         hasNext();
00502     }
00503 
00515     public int count() {
00516 
00517         if (!setAndRemoveAllowed) throw new IllegalStateException();
00518         try {
00519             moveToCurrent();
00520             return cursor.count();
00521         } catch (Exception e) {
00522             throw StoredContainer.convertException(e);
00523         }
00524     }
00525 
00540     public void close() {
00541 
00542         if (cursor != null) {
00543             coll.closeCursor(cursor);
00544             cursor = null;
00545         }
00546     }
00547 
00555     public final StoredCollection getCollection() {
00556 
00557         return coll;
00558     }
00559 
00560     final boolean isCurrentData(Object currentData) {
00561 
00562         return (this.currentData == currentData);
00563     }
00564 
00565     final boolean moveToIndex(int index) {
00566 
00567         try {
00568             OperationStatus status =
00569                 cursor.getSearchKey(new Integer(index), null, lockForWrite);
00570             setAndRemoveAllowed = (status == OperationStatus.SUCCESS);
00571             return setAndRemoveAllowed;
00572         } catch (Exception e) {
00573             throw StoredContainer.convertException(e);
00574         }
00575     }
00576 
00577     private void moveToCurrent()
00578         throws DatabaseException {
00579 
00580         if (toCurrent != 0) {
00581             move(toCurrent);
00582             toCurrent = 0;
00583         }
00584     }
00585 
00586     private OperationStatus move(int direction)
00587         throws DatabaseException {
00588 
00589         switch (direction) {
00590             case MOVE_NEXT:
00591                 if (coll.iterateDuplicates()) {
00592                     return cursor.getNext(lockForWrite);
00593                 } else {
00594                     return cursor.getNextNoDup(lockForWrite);
00595                 }
00596             case MOVE_PREV:
00597                 if (coll.iterateDuplicates()) {
00598                     return cursor.getPrev(lockForWrite);
00599                 } else {
00600                     return cursor.getPrevNoDup(lockForWrite);
00601                 }
00602             case MOVE_FIRST:
00603                 return cursor.getFirst(lockForWrite);
00604             default:
00605                 throw new IllegalArgumentException(String.valueOf(direction));
00606         }
00607     }
00608 }

Generated on Sun Dec 25 12:14:31 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2