// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.core.store;
import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openstreetmap.osmosis.core.OsmosisRuntimeException;
import org.openstreetmap.osmosis.core.lifecycle.Closeable;
/**
* Provides read-only access to a random access object store. Each thread
* accessing the object store must create its own reader. The reader maintains
* all references to heavyweight resources such as file handles used to access
* the store eliminating the need for objects such as object iterators to be
* cleaned up explicitly.
*
* @param <T>
* The object type being stored.
* @author Brett Henderson
*/
public class RandomAccessObjectStoreReader<T> implements Closeable {
private static final Logger LOG = Logger.getLogger(RandomAccessObjectStoreReader.class.getName());
private BufferedRandomAccessFileInputStream randomFile;
private ObjectReader objectReader;
/**
* Creates a new instance.
*
* @param randomFile
* A read-only random access file opened on the store file.
* @param objectReader
* The reader containing the objects to be deserialized.
*/
public RandomAccessObjectStoreReader(BufferedRandomAccessFileInputStream randomFile, ObjectReader objectReader) {
this.randomFile = randomFile;
this.objectReader = objectReader;
}
/**
* Seeks to the specified location in the storage file.
*
* @param offset
* The file offset to seek to.
*/
private void seek(long offset) {
try {
randomFile.seek(offset);
} catch (IOException e) {
throw new OsmosisRuntimeException("Unable to seek to position " + offset + " in the storage file.", e);
}
}
/**
* Reads the object at the specified file offset.
*
* @param offset
* The file offset to read an object from.
* @return The requested object.
*/
@SuppressWarnings("unchecked")
public T get(long offset) {
seek(offset);
return (T) objectReader.readObject();
}
/**
* Returns the length of data.
*
* @return The data length in bytes.
*/
public long length() {
try {
return randomFile.length();
} catch (IOException e) {
throw new OsmosisRuntimeException("Unable to obtain the length of the storage file.", e);
}
}
/**
* Returns the current read position.
*
* @return The current offset offset in bytes.
*/
public long position() {
try {
return randomFile.position();
} catch (IOException e) {
throw new OsmosisRuntimeException("Unable to obtain the current position in the storage file.", e);
}
}
/**
* Iterates over the entire stream of data.
*
* @param offset
* The location in the storage file to begin reading.
* @return An iterator for reading objects from the data store. This
* iterator must be released after use.
*/
public Iterator<T> iterate(long offset) {
seek(offset);
return new ObjectDataInputIterator<T>(objectReader);
}
/**
* Iterates over the entire stream of data.
*
* @return An iterator for reading objects from the data store. This
* iterator must be released after use.
*/
public Iterator<T> iterate() {
return iterate(0);
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
if (randomFile != null) {
try {
randomFile.close();
} catch (IOException e) {
// We cannot throw an exception within a release statement.
LOG.log(Level.WARNING, "Unable to close random access file.", e);
}
randomFile = null;
}
}
}