00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 package com.sleepycat.collections;
00011
00012 import java.util.Collection;
00013 import java.util.Iterator;
00014 import java.util.List;
00015 import java.util.ListIterator;
00016
00017 import com.sleepycat.bind.EntityBinding;
00018 import com.sleepycat.bind.EntryBinding;
00019 import com.sleepycat.bind.RecordNumberBinding;
00020 import com.sleepycat.db.Database;
00021 import com.sleepycat.db.DatabaseEntry;
00022 import com.sleepycat.db.DatabaseException;
00023 import com.sleepycat.db.OperationStatus;
00024
00057 public class StoredList extends StoredCollection implements List {
00058
00059 private static final EntryBinding DEFAULT_KEY_BINDING =
00060 new IndexKeyBinding(1);
00061
00062 private int baseIndex = 1;
00063 private boolean isSubList;
00064
00082 public StoredList(Database database, EntryBinding valueBinding,
00083 boolean writeAllowed) {
00084
00085 super(new DataView(database, DEFAULT_KEY_BINDING, valueBinding, null,
00086 writeAllowed, null));
00087 }
00088
00106 public StoredList(Database database, EntityBinding valueEntityBinding,
00107 boolean writeAllowed) {
00108
00109 super(new DataView(database, DEFAULT_KEY_BINDING, null,
00110 valueEntityBinding, writeAllowed, null));
00111 }
00112
00131 public StoredList(Database database, EntryBinding valueBinding,
00132 PrimaryKeyAssigner keyAssigner) {
00133
00134 super(new DataView(database, DEFAULT_KEY_BINDING, valueBinding,
00135 null, true, keyAssigner));
00136 }
00137
00156 public StoredList(Database database, EntityBinding valueEntityBinding,
00157 PrimaryKeyAssigner keyAssigner) {
00158
00159 super(new DataView(database, DEFAULT_KEY_BINDING, null,
00160 valueEntityBinding, true, keyAssigner));
00161 }
00162
00163 private StoredList(DataView view, int baseIndex) {
00164
00165 super(view);
00166 this.baseIndex = baseIndex;
00167 this.isSubList = true;
00168 }
00169
00182 public void add(int index, Object value) {
00183
00184 checkIterAddAllowed();
00185 DataCursor cursor = null;
00186 boolean doAutoCommit = beginAutoCommit();
00187 try {
00188 cursor = new DataCursor(view, true);
00189 OperationStatus status =
00190 cursor.getSearchKey(new Long(index), null, false);
00191 if (status == OperationStatus.SUCCESS) {
00192 cursor.putBefore(value);
00193 closeCursor(cursor);
00194 } else {
00195 closeCursor(cursor);
00196 cursor = null;
00197 view.append(value, null, null);
00198 }
00199 commitAutoCommit(doAutoCommit);
00200 } catch (Exception e) {
00201 closeCursor(cursor);
00202 throw handleException(e, doAutoCommit);
00203 }
00204 }
00205
00218 public boolean add(Object value) {
00219
00220 checkIterAddAllowed();
00221 boolean doAutoCommit = beginAutoCommit();
00222 try {
00223 view.append(value, null, null);
00224 commitAutoCommit(doAutoCommit);
00225 return true;
00226 } catch (Exception e) {
00227 throw handleException(e, doAutoCommit);
00228 }
00229 }
00230
00251 public int append(Object value) {
00252
00253 boolean doAutoCommit = beginAutoCommit();
00254 try {
00255 Object[] key = new Object[1];
00256 view.append(value, key, null);
00257 commitAutoCommit(doAutoCommit);
00258 return ((Number) key[0]).intValue();
00259 } catch (Exception e) {
00260 throw handleException(e, doAutoCommit);
00261 }
00262 }
00263
00264 void checkIterAddAllowed()
00265 throws UnsupportedOperationException {
00266
00267 if (isSubList) {
00268 throw new UnsupportedOperationException("cannot add to subList");
00269 }
00270 if (!view.keysRenumbered) {
00271 throw new UnsupportedOperationException(
00272 "requires renumbered keys");
00273 }
00274 }
00275
00289 public boolean addAll(int index, Collection coll) {
00290
00291 checkIterAddAllowed();
00292 DataCursor cursor = null;
00293 Iterator i = null;
00294 boolean doAutoCommit = beginAutoCommit();
00295 try {
00296 i = coll.iterator();
00297 if (!i.hasNext()) {
00298 return false;
00299 }
00300 cursor = new DataCursor(view, true);
00301 OperationStatus status =
00302 cursor.getSearchKey(new Long(index), null, false);
00303 if (status == OperationStatus.SUCCESS) {
00304 while (i.hasNext()) {
00305 cursor.putBefore(i.next());
00306 }
00307 closeCursor(cursor);
00308 } else {
00309 closeCursor(cursor);
00310 cursor = null;
00311 while (i.hasNext()) {
00312 view.append(i.next(), null, null);
00313 }
00314 }
00315 StoredIterator.close(i);
00316 commitAutoCommit(doAutoCommit);
00317 return true;
00318 } catch (Exception e) {
00319 closeCursor(cursor);
00320 StoredIterator.close(i);
00321 throw handleException(e, doAutoCommit);
00322 }
00323 }
00324
00332 public boolean contains(Object value) {
00333
00334 return containsValue(value);
00335 }
00336
00344 public Object get(int index) {
00345
00346 return super.get(new Long(index));
00347 }
00348
00357 public int indexOf(Object value) {
00358
00359 return indexOf(value, true);
00360 }
00361
00370 public int lastIndexOf(Object value) {
00371
00372 return indexOf(value, false);
00373 }
00374
00375 private int indexOf(Object value, boolean findFirst) {
00376
00377 DataCursor cursor = null;
00378 try {
00379 cursor = new DataCursor(view, false);
00380 OperationStatus status = cursor.find(value, findFirst);
00381 return (status == OperationStatus.SUCCESS)
00382 ? (cursor.getCurrentRecordNumber() - baseIndex)
00383 : (-1);
00384 } catch (Exception e) {
00385 throw StoredContainer.convertException(e);
00386 } finally {
00387 closeCursor(cursor);
00388 }
00389 }
00390
00391 int getIndexOffset() {
00392
00393 return baseIndex;
00394 }
00395
00409 public ListIterator listIterator() {
00410
00411 return iterator(isWriteAllowed());
00412 }
00413
00427 public ListIterator listIterator(int index) {
00428
00429 StoredIterator i = iterator(isWriteAllowed());
00430 if (i.moveToIndex(index)) {
00431 return i;
00432 } else {
00433 i.close();
00434 throw new IndexOutOfBoundsException(String.valueOf(index));
00435 }
00436 }
00437
00449 public Object remove(int index) {
00450
00451 try {
00452 Object[] oldVal = new Object[1];
00453 removeKey(new Long(index), oldVal);
00454 return oldVal[0];
00455 } catch (IllegalArgumentException e) {
00456 throw new IndexOutOfBoundsException(e.getMessage());
00457 }
00458 }
00459
00471 public boolean remove(Object value) {
00472
00473 return removeValue(value);
00474 }
00475
00491 public Object set(int index, Object value) {
00492
00493 try {
00494 return put(new Long(index), value);
00495 } catch (IllegalArgumentException e) {
00496 throw new IndexOutOfBoundsException(e.getMessage());
00497 }
00498 }
00499
00509 public List subList(int fromIndex, int toIndex) {
00510
00511 if (fromIndex < 0 || fromIndex > toIndex) {
00512 throw new IndexOutOfBoundsException(String.valueOf(fromIndex));
00513 }
00514 try {
00515 int newBaseIndex = baseIndex + fromIndex;
00516 return new StoredList(
00517 view.subView(new Long(fromIndex), true,
00518 new Long(toIndex), false,
00519 new IndexKeyBinding(newBaseIndex)),
00520 newBaseIndex);
00521 } catch (KeyRangeException e) {
00522 throw new IndexOutOfBoundsException(e.getMessage());
00523 } catch (Exception e) {
00524 throw StoredContainer.convertException(e);
00525 }
00526 }
00527
00537 public boolean equals(Object other) {
00538
00539 if (!(other instanceof List)) return false;
00540 List otherList = (List) other;
00541 ListIterator i1 = null;
00542 ListIterator i2 = null;
00543 try {
00544 i1 = listIterator();
00545 i2 = otherList.listIterator();
00546 while (i1.hasNext()) {
00547 if (!i2.hasNext()) return false;
00548 if (i1.nextIndex() != i2.nextIndex()) return false;
00549 Object o1 = i1.next();
00550 Object o2 = i2.next();
00551 if (o1 == null) {
00552 if (o2 != null) return false;
00553 } else {
00554 if (!o1.equals(o2)) return false;
00555 }
00556 }
00557 if (i2.hasNext()) return false;
00558 return true;
00559 } finally {
00560 StoredIterator.close(i1);
00561 StoredIterator.close(i2);
00562 }
00563 }
00564
00565
00566
00567
00568
00569 public int hashCode() {
00570 return super.hashCode();
00571 }
00572
00573 Object makeIteratorData(StoredIterator iterator, DataCursor cursor)
00574 throws DatabaseException {
00575
00576 return cursor.getCurrentValue();
00577 }
00578
00579 boolean hasValues() {
00580
00581 return true;
00582 }
00583
00584 private static class IndexKeyBinding extends RecordNumberBinding {
00585
00586 private int baseIndex;
00587
00588 private IndexKeyBinding(int baseIndex) {
00589
00590 this.baseIndex = baseIndex;
00591 }
00592
00593 public Object entryToObject(DatabaseEntry data) {
00594
00595 return new Long(entryToRecordNumber(data) - baseIndex);
00596 }
00597
00598 public void objectToEntry(Object object, DatabaseEntry data) {
00599
00600 recordNumberToEntry(((Number) object).intValue() + baseIndex,
00601 data);
00602 }
00603 }
00604 }