--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2016 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * Semantum Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.util.binary;
+
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.ByteBuffer;\r
+\r
+/**\r
+ * This class is a custom write-only wrapper for {@link BinaryFile} and\r
+ * {@link BinaryMemory} that implements a {@link RandomAccessBinary} which is\r
+ * contained fully in memory until its size reaches a user-specified threshold.\r
+ * When that size threshold is exceeded, the {@link BinaryMemory} contents are\r
+ * flushed into a BinaryFile and from there on this implementation will continue\r
+ * to write to the BinaryFile.\r
+ * <p>\r
+ * Since it is based {@link BinaryFile} and {@link BinaryMemory}, this\r
+ * implementation is also buffered and <em>not</em> thread-safe.\r
+ * <p>\r
+ * The {@link SeekableBinaryReadable} part of the {@link RandomAccessBinary}\r
+ * interface is not implemented and will throw\r
+ * {@link UnsupportedOperationException}.\r
+ *\r
+ * @author Tuukka Lehtonen\r
+ * @since 1.22.1 & 1.24.0\r
+ * @see BinaryFile\r
+ * @see BinaryMemory\r
+ */
+public class DeferredBinaryFile implements RandomAccessBinary {
+\r
+ File file;\r
+ int threshold;\r
+ int fileBufferSize;\r
+\r
+ BinaryMemory memory;\r
+ RandomAccessBinary backend;
+
+ public DeferredBinaryFile(File file, int threshold, int fileBufferSize) throws IOException {\r
+ this.memory = new BinaryMemory(threshold+10000);\r
+ this.backend = memory;\r
+ this.threshold = threshold;\r
+ this.file = file;\r
+ this.fileBufferSize = fileBufferSize;\r
+ }\r
+\r
+ /**
+ * Closes the object. Note, this will close the input random access file.\r
+ * This method may be called several times.
+ *
+ * @throws IOException
+ */
+ @Override\r
+ public synchronized void close() throws IOException {\r
+ if (backend == null)\r
+ return;\r
+ backend.close();
+ backend = null;
+ }
+\r
+ @Override\r
+ public synchronized boolean isOpen() {\r
+ return backend != null;\r
+ }\r
+
+ @Override
+ public byte readByte() throws IOException {
+ throw new UnsupportedOperationException();\r
+ }\r
+\r
+ @Override\r
+ public char readChar() throws IOException {\r
+ throw new UnsupportedOperationException();\r
+ }\r
+\r
+ @Override\r
+ public int readUnsignedByte() throws IOException {\r
+ throw new UnsupportedOperationException();\r
+ }
+\r
+ @Override\r
+ public boolean readBoolean() throws IOException {\r
+ throw new UnsupportedOperationException();\r
+ }\r
+
+ @Override
+ public void readFully(byte[] dst, int offset, int length) throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public void readFully(byte[] dst) throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public void readFully(ByteBuffer buf) throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public void readFully(ByteBuffer buf, int length) throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public double readDouble() throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public float readFloat() throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public int readInt() throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public long readLong() throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public short readShort() throws IOException {
+ throw new UnsupportedOperationException();\r
+ }\r
+\r
+ @Override\r
+ public int readUnsignedShort() throws IOException {\r
+ throw new UnsupportedOperationException();\r
+ }
+\r
+ @Override\r
+ public String readUTF() throws IOException {\r
+ throw new UnsupportedOperationException();\r
+ }\r
+\r
+ public final String readLine() throws IOException {\r
+ throw new UnsupportedOperationException();\r
+ }\r
+\r
+ @Override
+ public long position() throws IOException {
+ return backend.position();\r
+ }
+
+ @Override\r
+ public void position(long newPosition) throws IOException {
+ backend.position(newPosition);\r
+ }
+
+ /**
+ * Flushes internal buffer
+ */
+ @Override\r
+ public void flush() throws IOException {
+ backend.flush();\r
+ }
+
+ /**
+ * Clears read&write buffer. The file can be modified elsewhere after this.
+ *
+ * @throws IOException
+ */
+ @Override\r
+ public void reset() throws IOException {
+ backend.reset();\r
+ }
+\r
+ @Override\r
+ public long skipBytes(long bytes) throws IOException {\r
+ return backend.skipBytes(bytes);\r
+ }\r
+
+ @Override\r
+ public int skipBytes(int bytes) throws IOException {\r
+ return backend.skipBytes(bytes);\r
+ }\r
+\r
+\r
+ // WRITE
+
+ @Override
+ public void write(int b) throws IOException {
+ backend.write(b);\r
+ if (memory != null)\r
+ threshold();\r
+ }\r
+\r
+ @Override\r
+ public void writeByte(int b) throws IOException {\r
+ backend.writeByte(b);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+\r
+ @Override\r
+ public void writeBoolean(boolean v) throws IOException {\r
+ backend.writeBoolean(v);\r
+ if (memory != null)\r
+ threshold();\r
+ }\r
+
+ @Override
+ public void writeFully(ByteBuffer src) throws IOException {
+ backend.writeFully(src);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void writeFully(ByteBuffer src, int length) throws IOException {
+ backend.writeFully(src, length);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void write(byte[] src, int offset, int length) throws IOException {
+ backend.write(src, offset, length);\r
+ }
+
+ @Override
+ public void write(byte[] src) throws IOException {
+ backend.write(src);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void writeDouble(double value) throws IOException {
+ backend.writeDouble(value);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void writeFloat(float value) throws IOException {
+ backend.writeFloat(value);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void writeInt(int value) throws IOException {
+ backend.writeInt(value);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void writeLong(long value) throws IOException {
+ backend.writeLong(value);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+
+ @Override
+ public void writeShort(int value) throws IOException {
+ backend.writeShort(value);\r
+ if (memory != null)\r
+ threshold();\r
+ }\r
+\r
+ @Override\r
+ public void writeChar(int value) throws IOException {\r
+ backend.writeChar(value);\r
+ if (memory != null)\r
+ threshold();\r
+ }\r
+\r
+ @Override\r
+ public void writeBytes(String s) throws IOException {\r
+ backend.writeBytes(s);\r
+ if (memory != null)\r
+ threshold();\r
+ }\r
+\r
+ @Override\r
+ public void writeChars(String s) throws IOException {\r
+ backend.writeChars(s);\r
+ if (memory != null)\r
+ threshold();\r
+ }
+\r
+ @Override\r
+ public void writeUTF(String s) throws IOException {\r
+ backend.writeUTF(s);\r
+ if (memory != null)\r
+ threshold();\r
+ }\r
+
+ @Override
+ public void insertBytes(long bytes, ByteSide side) throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public void removeBytes(long bytes, ByteSide side) throws IOException {
+ throw new UnsupportedOperationException();\r
+ }
+
+ @Override
+ public long length() throws IOException {
+ return backend.length();
+ }
+
+ @Override
+ public void setLength(long newLength) throws IOException {\r
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return "DeferredBinaryFile(file="+file.getName()+", size="+length()+")";
+ } catch (IOException e) {
+ return "DeferredBinaryFile()";
+ }
+ }\r
+\r
+ private void threshold() throws IOException {\r
+ if (backend.position() >= threshold) {\r
+ backend = new BinaryFile(file, fileBufferSize);\r
+ long length = memory.position();\r
+ memory.position(0);\r
+ memory.toByteBuffer().position(0);\r
+ backend.writeFully(memory.toByteBuffer(), (int) length);\r
+ memory = null;\r
+ }\r
+ }\r
+\r
+ public boolean isInMemory() {\r
+ return memory != null;\r
+ }\r
+\r
+ public RandomAccessBinary getMemory() {\r
+ return memory;\r
+ }\r
+\r
+ public RandomAccessBinary getBackend() {\r
+ return backend;\r
+ }\r
+\r
+}
\ No newline at end of file