package gov.nih.nci.cagrid.common;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.UUID;
public class DiskByteBuffer implements ByteBuffer {
public static final long DEFAULT_BYTES_PER_FILE = Integer.MAX_VALUE;
public static final String DEFAULT_BUFFER_DIR_NAME = "DiskByteBuffer";
public static final File DEFAULT_BUFFER_DIR = new File(Utils.getCaGridUserHome(), DEFAULT_BUFFER_DIR_NAME);
private long maxBytesPerFile;
private File bufferDir;
private long uniqueFileIndex;
private LinkedList<File> bufferFiles = null;
private long currentReadIndex;
private long currentWriteIndex;
private FileOutputStream bufferOutput = null;
private FileInputStream bufferInput = null;
public DiskByteBuffer() {
this(DEFAULT_BUFFER_DIR, DEFAULT_BYTES_PER_FILE);
}
public DiskByteBuffer(File bufferStorageDir, long maxBytesPerFile) {
String uniqueFilePart = UUID.randomUUID().toString();
this.bufferDir = new File(bufferStorageDir, uniqueFilePart);
if (!bufferDir.exists()) {
this.bufferDir.mkdirs();
}
this.maxBytesPerFile = maxBytesPerFile;
this.bufferFiles = new LinkedList<File>();
this.currentReadIndex = maxBytesPerFile;
this.uniqueFileIndex = 0;
}
public void appendData(byte[] data, int length) throws IOException {
int totalWritten = 0;
while (totalWritten < length) {
if (currentWriteIndex == maxBytesPerFile || bufferOutput == null) {
initNextBuffer();
}
long canWrite = maxBytesPerFile - currentWriteIndex;
long tryToWrite = Math.min(length, canWrite);
bufferOutput.write(data, totalWritten, (int) tryToWrite);
totalWritten += tryToWrite;
currentWriteIndex += tryToWrite;
}
}
public synchronized void cleanUp() {
if (bufferInput != null) {
try {
bufferInput.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (bufferOutput != null) {
try {
bufferOutput.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
Utils.deleteDir(bufferDir);
}
public byte[] extractData(int length) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
while (out.size() < length && bufferFiles.size() != 0) {
if (currentReadIndex == maxBytesPerFile) {
advanceBufferReader();
}
if (bufferInput == null) {
// no more buffer files to read
break;
}
// a temporary place to stuff bytes into from the file system
byte[] temp = new byte[2048];
int bytesRead = bufferInput.read(temp);
if (bytesRead != -1) {
currentReadIndex += bytesRead;
out.write(temp, 0, bytesRead);
} else {
break;
}
}
return out.toByteArray();
}
private void initNextBuffer() throws IOException {
synchronized (bufferFiles) {
// close out the previous writer, if any
if (bufferOutput != null) {
bufferOutput.flush();
bufferOutput.close();
}
// create the next buffer file
File bufferFile = new File(bufferDir, String.valueOf(uniqueFileIndex));
uniqueFileIndex++;
// reset the write index
currentWriteIndex = 0;
// start up the next buffer writer
bufferOutput = new FileOutputStream(bufferFile);
// keep a reference to the buffer
bufferFiles.addLast(bufferFile);
}
}
private void advanceBufferReader() throws IOException {
synchronized (bufferFiles) {
// close the current reader, if any
if (bufferInput != null) {
bufferInput.close();
// if we were reading, we were reading from the head file
// in the bufferFiles list... that can be deleted
File removeme = bufferFiles.removeFirst();
System.out.flush();
removeme.delete();
}
currentReadIndex = 0;
if (bufferFiles.size() != 0) {
bufferInput = new FileInputStream(bufferFiles.getFirst());
} else {
bufferInput = null;
}
}
}
}