LazyFileOutputStream.java

package de.japrost.jabudget.serialization;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.FileChannel;

/**
 * An {@link OutputStream} that uses a {@link FileOutputStream} internally, which is created when first access is done.
 * On {@link OutputStream#close()} the internal {@link FileOutputStream} will be closed and unset that next writing will
 * get a new stream.
 */
//TODO move to a io project
public class LazyFileOutputStream extends OutputStream {

	private final File file;
	private FileOutputStream delegate;

	/**
	 * Create an instance based on the given File.
	 *
	 * @param file the file to use in the internal delegate.
	 */
	public LazyFileOutputStream(final File file) {
		// TODO require non null
		this.file = file;
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * <strong>This implementation</strong> calls {@link FileOutputStream#close()} on the delegate and unassigns the
	 * delegate.
	 */
	@Override
	public void close() throws IOException {
		if (delegate != null) {
			delegate.close();
			delegate = null;
		}
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * <strong>This implementation</strong> calls {@link FileOutputStream#flush()} on the delegate if it is initalized.
	 */
	@Override
	public void flush() throws IOException {
		if (delegate != null) {
			delegate.flush();
		}
	}

	/**
	 * Initializes the delegate if not already done and delegates to {@link FileOutputStream#getChannel()}.
	 *
	 * @return {@link FileOutputStream#getChannel()}
	 * @throws FileNotFoundException if initialization of delegate fails. see
	 *         {@link FileOutputStream#FileOutputStream(File)}.
	 */
	public FileChannel getChannel() throws FileNotFoundException {
		if (delegate == null) {
			initDelegate();
		}
		return delegate.getChannel();
	}

	/**
	 * Initializes the delegate if not already done and delegates to {@link FileOutputStream#getFD()}.
	 *
	 * @return {@link FileOutputStream#getFD()}
	 * @throws IOException see {@link FileOutputStream#getFD()}.
	 * @throws FileNotFoundException if initialization of delegate fails. see
	 *         {@link FileOutputStream#FileOutputStream(File)}.
	 */
	public FileDescriptor getFD() throws IOException {
		if (delegate == null) {
			initDelegate();
		}
		return delegate.getFD();
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * <strong>This implementation</strong> innitializes the delegate if not already done and delegates to
	 * {@link FileOutputStream#write(byte[])}.
	 *
	 * @throws FileNotFoundException if initialization of delegate fails. see
	 *         {@link FileOutputStream#FileOutputStream(File)}.
	 */
	@Override
	public void write(final byte[] b) throws IOException {
		if (delegate == null) {
			initDelegate();
		}
		delegate.write(b);
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * <strong>This implementation</strong> innitializes the delegate if not already done and delegates to
	 * {@link FileOutputStream#write(byte[], int, int)}.
	 *
	 * @throws FileNotFoundException if initialization of delegate fails. see
	 *         {@link FileOutputStream#FileOutputStream(File)}.
	 */
	@Override
	public void write(final byte[] b, final int off, final int len) throws IOException {
		if (delegate == null) {
			initDelegate();
		}
		delegate.write(b, off, len);
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * <strong>This implementation</strong> innitializes the delegate if not already done and delegates to
	 * {@link FileOutputStream#write(int)}.
	 *
	 * @throws FileNotFoundException if initialization of delegate fails. see
	 *         {@link FileOutputStream#FileOutputStream(File)}.
	 */
	@Override
	public void write(final int b) throws IOException {
		if (delegate == null) {
			initDelegate();
		}
		delegate.write(b);
	}

	/**
	 * Tell if the delegate is initialized.
	 *
	 * @return {@code true} if there is a delegate.
	 */
	public boolean isOpen() {
		return delegate != null;
	}

	private void initDelegate() throws FileNotFoundException {
		delegate = new FileOutputStream(file);
	}

}