text: 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);
          }
      }
  }
  