| package org.codehaus.jackson.io; |
| |
| import org.codehaus.jackson.JsonEncoding; |
| import org.codehaus.jackson.util.BufferRecycler; |
| import org.codehaus.jackson.util.TextBuffer; |
| |
| /** |
| * To limit number of configuration and state objects to pass, all |
| * contextual objects that need to be passed by the factory to |
| * readers and writers are combined under this object. One instance |
| * is created for each reader and writer. |
| */ |
| public final class IOContext |
| { |
| /* |
| /********************************************************** |
| /* Configuration |
| /********************************************************** |
| */ |
| |
| /** |
| * Reference to the source object, which can be used for displaying |
| * location information |
| */ |
| protected final Object _sourceRef; |
| |
| /** |
| * Encoding used by the underlying stream, if known. |
| */ |
| protected JsonEncoding _encoding; |
| |
| /** |
| * Flag that indicates whether underlying input/output source/target |
| * object is fully managed by the owner of this context (parser or |
| * generator). If true, it is, and is to be closed by parser/generator; |
| * if false, calling application has to do closing (unless auto-closing |
| * feature is enabled for the parser/generator in question; in which |
| * case it acts like the owner). |
| */ |
| protected final boolean _managedResource; |
| |
| /* |
| /********************************************************** |
| /* Buffer handling, recycling |
| /********************************************************** |
| */ |
| |
| /** |
| * Recycler used for actual allocation/deallocation/reuse |
| */ |
| protected final BufferRecycler _bufferRecycler; |
| |
| /** |
| * Reference to the allocated I/O buffer for low-level input reading, |
| * if any allocated. |
| */ |
| protected byte[] _readIOBuffer = null; |
| |
| /** |
| * Reference to the allocated I/O buffer used for low-level |
| * encoding-related buffering. |
| */ |
| protected byte[] _writeEncodingBuffer = null; |
| |
| /** |
| * Reference to the buffer allocated for tokenization purposes, |
| * in which character input is read, and from which it can be |
| * further returned. |
| */ |
| protected char[] _tokenCBuffer = null; |
| |
| /** |
| * Reference to the buffer allocated for buffering it for |
| * output, before being encoded: generally this means concatenating |
| * output, then encoding when buffer fills up. |
| */ |
| protected char[] _concatCBuffer = null; |
| |
| /** |
| * Reference temporary buffer Parser instances need if calling |
| * app decides it wants to access name via 'getTextCharacters' method. |
| * Regular text buffer can not be used as it may contain textual |
| * representation of the value token. |
| */ |
| protected char[] _nameCopyBuffer = null; |
| |
| /* |
| /********************************************************** |
| /* Life-cycle |
| /********************************************************** |
| */ |
| |
| public IOContext(BufferRecycler br, Object sourceRef, boolean managedResource) |
| { |
| _bufferRecycler = br; |
| _sourceRef = sourceRef; |
| _managedResource = managedResource; |
| } |
| |
| public void setEncoding(JsonEncoding enc) |
| { |
| _encoding = enc; |
| } |
| |
| /* |
| /********************************************************** |
| /* Public API, accessors |
| /********************************************************** |
| */ |
| |
| public final Object getSourceReference() { return _sourceRef; } |
| public final JsonEncoding getEncoding() { return _encoding; } |
| public final boolean isResourceManaged() { return _managedResource; } |
| |
| /* |
| /********************************************************** |
| /* Public API, buffer management |
| /********************************************************** |
| */ |
| |
| public final TextBuffer constructTextBuffer() { |
| return new TextBuffer(_bufferRecycler); |
| } |
| |
| /** |
| *<p> |
| * Note: the method can only be called once during its life cycle. |
| * This is to protect against accidental sharing. |
| */ |
| public final byte[] allocReadIOBuffer() |
| { |
| if (_readIOBuffer != null) { |
| throw new IllegalStateException("Trying to call allocReadIOBuffer() second time"); |
| } |
| _readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.READ_IO_BUFFER); |
| return _readIOBuffer; |
| } |
| |
| public final byte[] allocWriteEncodingBuffer() |
| { |
| if (_writeEncodingBuffer != null) { |
| throw new IllegalStateException("Trying to call allocWriteEncodingBuffer() second time"); |
| } |
| _writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER); |
| return _writeEncodingBuffer; |
| } |
| |
| public final char[] allocTokenBuffer() |
| { |
| if (_tokenCBuffer != null) { |
| throw new IllegalStateException("Trying to call allocTokenBuffer() second time"); |
| } |
| _tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER); |
| return _tokenCBuffer; |
| } |
| |
| public final char[] allocConcatBuffer() |
| { |
| if (_concatCBuffer != null) { |
| throw new IllegalStateException("Trying to call allocConcatBuffer() second time"); |
| } |
| _concatCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER); |
| return _concatCBuffer; |
| } |
| |
| public final char[] allocNameCopyBuffer(int minSize) |
| { |
| if (_nameCopyBuffer != null) { |
| throw new IllegalStateException("Trying to call allocNameCopyBuffer() second time"); |
| } |
| _nameCopyBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.NAME_COPY_BUFFER, minSize); |
| return _nameCopyBuffer; |
| } |
| |
| /** |
| * Method to call when all the processing buffers can be safely |
| * recycled. |
| */ |
| public final void releaseReadIOBuffer(byte[] buf) |
| { |
| if (buf != null) { |
| /* Let's do sanity checks to ensure once-and-only-once release, |
| * as well as avoiding trying to release buffers not owned |
| */ |
| if (buf != _readIOBuffer) { |
| throw new IllegalArgumentException("Trying to release buffer not owned by the context"); |
| } |
| _readIOBuffer = null; |
| _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.READ_IO_BUFFER, buf); |
| } |
| } |
| |
| public final void releaseWriteEncodingBuffer(byte[] buf) |
| { |
| if (buf != null) { |
| /* Let's do sanity checks to ensure once-and-only-once release, |
| * as well as avoiding trying to release buffers not owned |
| */ |
| if (buf != _writeEncodingBuffer) { |
| throw new IllegalArgumentException("Trying to release buffer not owned by the context"); |
| } |
| _writeEncodingBuffer = null; |
| _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER, buf); |
| } |
| } |
| |
| public final void releaseTokenBuffer(char[] buf) |
| { |
| if (buf != null) { |
| if (buf != _tokenCBuffer) { |
| throw new IllegalArgumentException("Trying to release buffer not owned by the context"); |
| } |
| _tokenCBuffer = null; |
| _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER, buf); |
| } |
| } |
| |
| public final void releaseConcatBuffer(char[] buf) |
| { |
| if (buf != null) { |
| if (buf != _concatCBuffer) { |
| throw new IllegalArgumentException("Trying to release buffer not owned by the context"); |
| } |
| _concatCBuffer = null; |
| _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER, buf); |
| } |
| } |
| |
| public final void releaseNameCopyBuffer(char[] buf) |
| { |
| if (buf != null) { |
| if (buf != _nameCopyBuffer) { |
| throw new IllegalArgumentException("Trying to release buffer not owned by the context"); |
| } |
| _nameCopyBuffer = null; |
| _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.NAME_COPY_BUFFER, buf); |
| } |
| } |
| } |