/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
*
*/
package com.sleepycat.collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.CursorConfig;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.JoinConfig;
import com.sleepycat.db.OperationStatus;
import com.sleepycat.util.RuntimeExceptionWrapper;
/**
* A abstract base class for all stored collections. This class, and its
* base class {@link StoredContainer}, provide implementations of most methods
* in the {@link Collection} interface. Other methods, such as {@link #add}
* and {@link #remove}, are provided by concrete classes that extend this
* class.
*
*
In addition, this class provides the following methods for stored
* collections only. Note that the use of these methods is not compatible with
* the standard Java collections interface.
*
*
{@link #getIteratorBlockSize}
*
{@link #setIteratorBlockSize}
*
{@link #storedIterator()}
*
{@link #storedIterator(boolean)}
*
{@link #join}
*
{@link #toList()}
*
*
* @author Mark Hayes
*/
public abstract class StoredCollection extends StoredContainer
implements Collection {
/**
* The default number of records read at one time by iterators.
* @see #setIteratorBlockSize
*/
public static final int DEFAULT_ITERATOR_BLOCK_SIZE = 10;
private int iteratorBlockSize = DEFAULT_ITERATOR_BLOCK_SIZE;
StoredCollection(DataView view) {
super(view);
}
/**
* Returns the number of records read at one time by iterators returned by
* the {@link #iterator} method. By default this value is {@link
* #DEFAULT_ITERATOR_BLOCK_SIZE}.
*/
public int getIteratorBlockSize() {
return iteratorBlockSize;
}
/**
* Changes the number of records read at one time by iterators returned by
* the {@link #iterator} method. By default this value is {@link
* #DEFAULT_ITERATOR_BLOCK_SIZE}.
*
* @throws IllegalArgumentException if the blockSize is less than two.
*/
public void setIteratorBlockSize(int blockSize) {
if (blockSize < 2) {
throw new IllegalArgumentException
("blockSize is less than two: " + blockSize);
}
iteratorBlockSize = blockSize;
}
final boolean add(Object key, Object value) {
DataCursor cursor = null;
boolean doAutoCommit = beginAutoCommit();
try {
cursor = new DataCursor(view, true);
OperationStatus status =
cursor.putNoDupData(key, value, null, false);
closeCursor(cursor);
commitAutoCommit(doAutoCommit);
return (status == OperationStatus.SUCCESS);
} catch (Exception e) {
closeCursor(cursor);
throw handleException(e, doAutoCommit);
}
}
BlockIterator blockIterator() {
return new BlockIterator(this, isWriteAllowed(), iteratorBlockSize);
}
/**
* Returns an iterator over the elements in this collection.
* The iterator will be read-only if the collection is read-only.
* This method conforms to the {@link Collection#iterator} interface.
*
*
The iterator returned by this method does not keep a database cursor
* open and therefore it does not need to be closed. It reads blocks of
* records as needed, opening and closing a cursor to read each block of
* records. The number of records per block is 10 by default and can be
* changed with {@link #setIteratorBlockSize}.
*
*
Because this iterator does not keep a cursor open, if it is used
* without transactions, the iterator does not have cursor
* stability characteristics. In other words, the record at the
* current iterator position can be changed or deleted by another thread.
* To prevent this from happening, call this method within a transaction or
* use the {@link #storedIterator()} method instead.
*
* @return a standard {@link Iterator} for this collection.
*
* @see #isWriteAllowed
*/
public Iterator iterator() {
return blockIterator();
}
/**
* Returns an iterator over the elements in this collection.
* The iterator will be read-only if the collection is read-only.
* This method does not exist in the standard {@link Collection} interface.
*
*
If {@code Iterator.set} or {@code Iterator.remove} will be called
* and the underlying Database is transactional, then a transaction must be
* active when calling this method and must remain active while using the
* iterator.
*
*
Warning: The iterator returned must be explicitly
* closed using {@link StoredIterator#close()} or {@link
* StoredIterator#close(java.util.Iterator)} to release the underlying
* database cursor resources.
*
* @return a {@link StoredIterator} for this collection.
*
* @see #isWriteAllowed
*/
public StoredIterator storedIterator() {
return storedIterator(isWriteAllowed());
}
/**
* Returns a read or read-write iterator over the elements in this
* collection.
* This method does not exist in the standard {@link Collection} interface.
*
*
If {@code Iterator.set} or {@code Iterator.remove} will be called
* and the underlying Database is transactional, then a transaction must be
* active when calling this method and must remain active while using the
* iterator.
*
*
Warning: The iterator returned must be explicitly
* closed using {@link StoredIterator#close()} or {@link
* StoredIterator#close(java.util.Iterator)} to release the underlying
* database cursor resources.
*
* @param writeAllowed is true to open a read-write iterator or false to
* open a read-only iterator. If the collection is read-only the iterator
* will always be read-only.
*
* @return a {@link StoredIterator} for this collection.
*
* @throws IllegalStateException if writeAllowed is true but the collection
* is read-only.
*
* @throws RuntimeExceptionWrapper if a checked exception is thrown,
* including a {@code DatabaseException} on BDB (C Edition).
*
* @see #isWriteAllowed
*/
public StoredIterator storedIterator(boolean writeAllowed) {
try {
return new StoredIterator(this, writeAllowed && isWriteAllowed(),
null);
} catch (Exception e) {
throw StoredContainer.convertException(e);
}
}
/**
* @deprecated Please use {@link #storedIterator()} or {@link
* #storedIterator(boolean)} instead. Because the iterator returned must
* be closed, the method name {@code iterator} is confusing since standard
* Java iterators do not need to be closed.
*/
public StoredIterator iterator(boolean writeAllowed) {
return storedIterator(writeAllowed);
}
/**
* Returns an array of all the elements in this collection.
* This method conforms to the {@link Collection#toArray()} interface.
*
*
* @throws RuntimeExceptionWrapper if a checked exception is thrown,
* including a {@code DatabaseException} on BDB (C Edition).
*/
public Object[] toArray() {
ArrayList