All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gc.iotools.stream.store.ThresholdStore Maven / Gradle / Ivy

package com.gc.iotools.stream.store;

/*
 * Copyright (c) 2008,2009 Davide Simonetti.
 * This source code is released under the BSD Software License.
 */

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Store that puts data in memory until threshold size is reach. At that point
 * data is written to the disk.
 * @author dvd.smnt
 * @since 1.2.0
 */
public class ThresholdStore implements SeekableStore {
	private static final int BUF_SIZE = 8192;

	private static final Logger LOG = LoggerFactory
			.getLogger(ThresholdStore.class);

	private RandomAccessFile fileAccess;
	private File fileStorage;
	private final MemoryStore ms = new MemoryStore();
	private long position = 0;
	private long size = 0;

	private final int treshold;

	public ThresholdStore(final int treshold) {
		this.treshold = treshold;
	}

	public ThresholdStore(final int treshold, final File file) {
		this.treshold = treshold;
		this.fileStorage = file;
	}

	public void cleanup() {
		this.size = 0;
		this.position = 0;
		this.ms.cleanup();
		if (this.fileAccess != null) {
			try {
				this.fileAccess.close();
			} catch (final IOException e) {
				ThresholdStore.LOG.warn("Exception in closing the temporary "
						+ "stream associated to file ["
						+ this.fileStorage.getName() + "] it "
						+ "is possible to continue but some"
						+ " resources are not released.", e);
			}
			this.fileAccess = null;
		}
		if (this.fileStorage != null) {
			final boolean deleted = this.fileStorage.delete();
			if (deleted) {
				this.fileStorage = null;
			} else {
				this.fileStorage.deleteOnExit();
				ThresholdStore.LOG.warn("Temporary file ["
						+ this.fileStorage.getName()
						+ "] was not deleted. It "
						+ "is possible to continue but some"
						+ " resources are not released.");
			}
		}
	}

	public int get(final byte[] bytes, final int offset, final int length)
			throws IOException {
		int result;
		if (this.size < this.treshold) {
			result = this.ms.get(bytes, offset, length);
		} else {
			if (this.position != this.fileAccess.getFilePointer()) {
				this.fileAccess.seek(this.position);
			}
			result = this.fileAccess.read(bytes, offset, length);
		}
		this.position += Math.max(result, 0);
		return result;
	}

	public long getSize() {
		return this.size;
	}

	public int getTreshold() {
		return this.treshold;
	}

	public void put(final byte[] bytes, final int offset, final int length)
			throws IOException {
		if (length <= 0) {
			throw new IllegalArgumentException("lenght = [" + length + "]");
		}
		if (this.size + length < this.treshold) {
			this.ms.put(bytes, offset, length);
		} else {
			if (this.size < this.treshold) {
				// empty the memory buffer and init the file buffer
				if (this.fileStorage == null) {
					this.fileStorage = File.createTempFile("iotools-storage",
							".tmp");
				}
				this.fileAccess = new RandomAccessFile(this.fileStorage, "rw");
				final byte[] buffer = new byte[ThresholdStore.BUF_SIZE];
				this.ms.seek(0);
				int len;
				while ((len = this.ms.get(buffer, 0, buffer.length)) > 0) {
					this.fileAccess.write(buffer, 0, len);
				}
				this.ms.cleanup();
			} else {
				final long fp = this.fileAccess.getFilePointer();
				if (fp != this.size) {
					this.fileAccess.seek(this.size);
				}
			}
			this.fileAccess.write(bytes, offset, length);
		}
		this.size += length;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws IOException
	 *             is thrown if some (disk) error happens or a seek over the
	 *             buffer length is requested.
	 */
	public void seek(final long position) throws IOException {
		// if already in place do nothing.
		if (this.position != position) {
			this.position = position;
			if (position <= this.size) {
				if (this.size < this.treshold) {
					this.ms.seek(position);
				} else {
					final long fp = this.fileAccess.getFilePointer();
					if (fp != position) {
						this.fileAccess.seek(position);
					}
				}
			} else {
				// seek outside the buffer
				throw new IOException("Seek at posiotion [" + position
						+ "]outside buffer size[" + this.size + "]");
			}
		}
	}

	public void setPosition(final long position) {
		this.position = position;
	}

	/**
	 * Provides a String representation of the state of the Store for debugging
	 * purposes.
	 */
	@Override
	public String toString() {
		String str = this.getClass().getSimpleName() + "[pos="
				+ this.position + ",size=" + this.size;
		if (this.fileStorage != null) {
			str += ",file=" + this.fileStorage;
		} else {
			str += ",ms=" + this.ms;
		}
		if (this.fileAccess != null) {
			try {
				str += ",fp=" + this.fileAccess.getFilePointer();
			} catch (final IOException e) {
				// do nothing... here for debugging.
			}
		}
		return str + "]";
	}

	/**
	 * Clean up the temporary files eventually open.
	 */
	@Override
	protected void finalize() throws Throwable {
		cleanup();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy