// 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; } } }