package com.fsck.k9.mailstore.util; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.apache.commons.io.output.ThresholdingOutputStream; /** * This OutputStream is modelled after apache commons' {@link org.apache.commons.io.output.DeferredFileOutputStream}, * but uses a {@link FileFactory} instead of directly generating temporary files itself. */ public class DeferredFileOutputStream extends ThresholdingOutputStream { private final FileFactory fileFactory; private OutputStream currentOutputStream; private File outputFile; public DeferredFileOutputStream(int threshold, FileFactory fileFactory) { super(threshold); this.fileFactory = fileFactory; // scale it so we expand the ByteArrayOutputStream at most three times (assuming quadratic growth) int size = threshold < 1024 ? 256 : threshold / 4; currentOutputStream = new ByteArrayOutputStream(size); } @Override protected OutputStream getStream() throws IOException { return currentOutputStream; } private boolean isMemoryBacked() { return currentOutputStream instanceof ByteArrayOutputStream; } @Override protected void thresholdReached() throws IOException { if (outputFile != null) { throw new IllegalStateException("thresholdReached must not be called if we already have an output file!"); } if (!isMemoryBacked()) { throw new IllegalStateException("currentOutputStream must be memory-based at this point!"); } ByteArrayOutputStream memoryOutputStream = (ByteArrayOutputStream) currentOutputStream; outputFile = fileFactory.createFile(); currentOutputStream = new FileOutputStream(outputFile); memoryOutputStream.writeTo(currentOutputStream); } public byte[] getData() { if (!isMemoryBacked()) { throw new IllegalStateException("getData must only be called in memory-backed state!"); } return ((ByteArrayOutputStream) currentOutputStream).toByteArray(); } public File getFile() { if (isMemoryBacked()) { throw new IllegalStateException("getFile must only be called in file-backed state!"); } return outputFile; } }