package com.fasterxml.jackson.core.io;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.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 temporary use with
* base64 encoding or decoding.
*/
protected byte[] _base64Buffer = 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 Object getSourceReference() { return _sourceRef; }
public JsonEncoding getEncoding() { return _encoding; }
public boolean isResourceManaged() { return _managedResource; }
/*
/**********************************************************
/* Public API, buffer management
/**********************************************************
*/
public 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 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 byte[] allocWriteEncodingBuffer()
{
if (_writeEncodingBuffer != null) {
throw new IllegalStateException("Trying to call allocWriteEncodingBuffer() second time");
}
_writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER);
return _writeEncodingBuffer;
}
/**
* @since 2.1
*/
public byte[] allocBase64Buffer()
{
if (_base64Buffer != null) {
throw new IllegalStateException("Trying to call allocBase64Buffer() second time");
}
_base64Buffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.BASE64_CODEC_BUFFER);
return _base64Buffer;
}
public char[] allocTokenBuffer()
{
if (_tokenCBuffer != null) {
throw new IllegalStateException("Trying to call allocTokenBuffer() second time");
}
_tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER);
return _tokenCBuffer;
}
public char[] allocConcatBuffer()
{
if (_concatCBuffer != null) {
throw new IllegalStateException("Trying to call allocConcatBuffer() second time");
}
_concatCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER);
return _concatCBuffer;
}
public 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 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 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 void releaseBase64Buffer(byte[] buf)
{
if (buf != null) { // sanity checks, release once-and-only-once, must be one owned
if (buf != _base64Buffer) {
throw new IllegalArgumentException("Trying to release buffer not owned by the context");
}
_base64Buffer = null;
_bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.BASE64_CODEC_BUFFER, buf);
}
}
public 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 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 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);
}
}
}