# Class DeferrableOutputStream

java.lang.Object
java.io.OutputStream
org.apache.commons.fileupload2.core.DeferrableOutputStream

All Implemented Interfaces:
  `Closeable, Flushable, AutoCloseable`

public class DeferrableOutputStream extends OutputStream
An `OutputStream`, which keeps its data in memory, until a configured threshold is reached. If that is the case, a temporary file is being created, and the in-memory data is transferred to that file. All following data will be written to that file, too. In other words: If an uploaded file is small, then it will be kept completely in memory. On the other hand, if the uploaded file's size exceeds the configured threshold, it it considered a large file, and the data is kept in a temporary file. More precisely, this output stream supports three modes of operation:

1. `threshold=-1`: Always create a temporary file, even if the uploaded file is empty.
2. `threshold=0`: Don't create empty, temporary files. (Create a temporary file, as soon as the first byte is written.)
3. `threshold>0`: Create a temporary file, if the size exceeds the threshold, otherwise keep the file in memory.

Technically, this is similar to `DeferredFileOutputStream`, which has been used in the past, except that this implementation observes a precisely specified behavior, and semantics, that match the needs of the `DiskFileItem`. Background: Over the various versions of commons-io, the `DeferredFileOutputStream` has changed semantics, and behavior more than once. (For details, see FILEUPLOAD-295)

## Nested Class Summary

Nested Classes
Modifier and Type
Class
Description
`static interface`
`DeferrableOutputStream.Listener`
Interface of a listener object, that wishes to be notified about state changes.
`static enum`
`DeferrableOutputStream.State`
This enumeration represents the possible states of the `DeferrableOutputStream`.

## Constructor Summary

Constructors
Constructor
Description
`DeferrableOutputStream(int threshold, Supplier<Path> pathSupplier, DeferrableOutputStream.Listener listener)`
Creates a new instance with the given threshold, and the given supplier for a temporary files path.

## Method Summary

Modifier and Type
Method
Description
`protected OutputStream`
`checkThreshold(int numberOfIncomingBytes)`
Called to check, whether the threshold will be exceeded, if the given number of bytes are written to the stream.
`void`
`close()`
`byte[]`
`getBytes()`
Returns the data, that has been written, if the stream has been closed, and the stream is still in memory (`isInMemory()` returns true).
`InputStream`
`getInputStream()`
If the stream is closed: Returns an `InputStream` on the data, that has been written to this stream.
`Path`
`getPath()`
Returns the output file, that has been created, if any, or null.
`long`
`getSize()`
Returns the number of bytes, that have been written to this stream.
`DeferrableOutputStream.State`
`getState()`
Returns the streams current state.
`int`
`getThreshold()`
Returns the streams configured threshold.
`boolean`
`isInMemory()`
Returns true, if this stream was never persisted, and no output file has been created.
`protected OutputStream`
`persist()`
Create the output file, change the state to `persisted`, and return an `OutputStream`, which is writing to that file.
`void`
`write(byte[] buffer)`
`void`
`write(byte[] buffer, int offset, int len)`
`void`
`write(int b)`

### Methods inherited from class OutputStream

`flush, nullOutputStream`

### Methods inherited from class Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

## Constructor Details

### DeferrableOutputStream

public DeferrableOutputStream(int threshold, Supplier<Path> pathSupplier, DeferrableOutputStream.Listener listener) throws IOException
Creates a new instance with the given threshold, and the given supplier for a temporary files path. If the threshold is -1, then the temporary file will be created immediately, and no in-memory data will be kept, at all. If the threshold is 0, then the temporary file will be created, as soon as the first byte will be written, but no in-memory data will be kept. If the threshold is > 0, then the temporary file will be created, as soon as that number of bytes have been written. Up to that point, data will be kept in an in-memory buffer.

Parameters:
  `threshold` - Either of -1 (Create the temporary file immediately), 0 (Create the temporary file, as soon as data is being written for the first time), or >0 (Keep data in memory, as long as the given number of bytes is reached, then create a temporary file, and continue using that).
  `pathSupplier` - A supplier for the temporary files path. This supplier must not return null. The file's directory will be created, if necessary, by invoking `Files.createDirectories(Path, java.nio.file.attribute.FileAttribute...)`.
  `listener` - An optional listener, which is being notified about important state changes.
Throws:
  `IOException` - Creating the temporary file (in the case of threshold -1) has failed.

## Method Details

### checkThreshold

protected OutputStream checkThreshold(int numberOfIncomingBytes) throws IOException
Called to check, whether the threshold will be exceeded, if the given number of bytes are written to the stream. If so, persists the in-memory data by creating a new, temporary file, and writing the in-memory data to the file.

Parameters:
  `numberOfIncomingBytes` - The number of bytes, which are about to be written.
Returns:
  The actual output stream, to which the incoming data may be written. If the threshold is not yet exceeded, then this will be an internal `ByteArrayOutputStream`, otherwise a stream, which is writing to the temporary output file.
Throws:
  `IOException` - Persisting the in-memory data to a temporary file has failed.

### close

public void close() throws IOException

Specified by:
  `close` in interface `AutoCloseable`
Specified by:
  `close` in interface `Closeable`
Overrides:
  `close` in class `OutputStream`
Throws:
  `IOException`

### getBytes

public byte[] getBytes()
Returns the data, that has been written, if the stream has been closed, and the stream is still in memory (`isInMemory()` returns true). Otherwise, returns null.

Returns:
  If the stream is closed (no more data can be written), and the data is still in memory (no temporary file has been created), returns the data, that has been written. Otherwise, returns null.

### getInputStream

public InputStream getInputStream() throws IOException
If the stream is closed: Returns an `InputStream` on the data, that has been written to this stream. Otherwise, throws an `IllegalStateException`.

Returns:
  An `InputStream` on the data, that has been written. Never null.
Throws:
  `IllegalStateException` - The stream has not yet been closed.
  `IOException` - Creating the `InputStream` has failed.

### getPath

public Path getPath()
Returns the output file, that has been created, if any, or null. The latter is the case, if `isInMemory()` returns true.

Returns:
  The output file, that has been created, if any, or null.

### getSize

public long getSize()
Returns the number of bytes, that have been written to this stream.

Returns:
  The number of bytes, that have been written to this stream.

### getState

public DeferrableOutputStream.State getState()
Returns the streams current state.

Returns:
  The streams current state.

### getThreshold

public int getThreshold()
Returns the streams configured threshold.

Returns:
  The streams configured threshold.

### isInMemory

public boolean isInMemory()
Returns true, if this stream was never persisted, and no output file has been created.

Returns:
  True, if the stream was never in state `DeferrableOutputStream.State.persisted`, otherwise false.

### persist

protected OutputStream persist() throws IOException
Create the output file, change the state to `persisted`, and return an `OutputStream`, which is writing to that file.

Returns:
  The `OutputStream`, which is writing to the created, temporary file.
Throws:
  `IOException` - Creating the temporary file has failed.

### write

public void write(byte[] buffer) throws IOException

Overrides:
  `write` in class `OutputStream`
Throws:
  `IOException`

### write

public void write(byte[] buffer, int offset, int len) throws IOException

Overrides:
  `write` in class `OutputStream`
Throws:
  `IOException`

### write

public void write(int b) throws IOException

Specified by:
  `write` in class `OutputStream`
Throws:
  `IOException`