00001
00002
00003
00004
00005
00006
00007
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
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
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
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
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) {
00431 if (coll.view.keysRenumbered) {
00432
00433
00434
00435
00436
00437
00438 close();
00439 status = coll.view.append(value, null, null);
00440 cursor = new DataCursor(coll.view, writeAllowed);
00441 reset();
00442 next();
00443 } else {
00444 throw new IllegalStateException(
00445 "Collection is empty, cannot add() duplicate");
00446 }
00447 } else {
00448 boolean putBefore = false;
00449 if (coll.view.keysRenumbered) {
00450 moveToCurrent();
00451 if (hasNext()) {
00452 status = cursor.putBefore(value);
00453 putBefore = true;
00454 } else {
00455 status = cursor.putAfter(value);
00456 }
00457 } else {
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
00485
00489 private void reset() {
00490
00491 toNext = MOVE_FIRST;
00492 toPrevious = MOVE_PREV;
00493 toCurrent = 0;
00494 currentData = null;
00495
00496
00497
00498
00499
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 }