1 package com.fasterxml.jackson.core.io; 2 3 import com.fasterxml.jackson.core.JsonEncoding; 4 import com.fasterxml.jackson.core.util.BufferRecycler; 5 import com.fasterxml.jackson.core.util.TextBuffer; 6 7 /** 8 * To limit number of configuration and state objects to pass, all 9 * contextual objects that need to be passed by the factory to 10 * readers and writers are combined under this object. One instance 11 * is created for each reader and writer. 12 *<p> 13 * NOTE: non-final since 2.4, to allow sub-classing. 14 */ 15 public class IOContext 16 { 17 /* 18 /********************************************************** 19 /* Configuration 20 /********************************************************** 21 */ 22 23 /** 24 * Reference to the source object, which can be used for displaying 25 * location information 26 */ 27 protected final Object _sourceRef; 28 29 /** 30 * Encoding used by the underlying stream, if known. 31 */ 32 protected JsonEncoding _encoding; 33 34 /** 35 * Flag that indicates whether underlying input/output source/target 36 * object is fully managed by the owner of this context (parser or 37 * generator). If true, it is, and is to be closed by parser/generator; 38 * if false, calling application has to do closing (unless auto-closing 39 * feature is enabled for the parser/generator in question; in which 40 * case it acts like the owner). 41 */ 42 protected final boolean _managedResource; 43 44 /* 45 /********************************************************** 46 /* Buffer handling, recycling 47 /********************************************************** 48 */ 49 50 /** 51 * Recycler used for actual allocation/deallocation/reuse 52 */ 53 protected final BufferRecycler _bufferRecycler; 54 55 /** 56 * Reference to the allocated I/O buffer for low-level input reading, 57 * if any allocated. 58 */ 59 protected byte[] _readIOBuffer; 60 61 /** 62 * Reference to the allocated I/O buffer used for low-level 63 * encoding-related buffering. 64 */ 65 protected byte[] _writeEncodingBuffer; 66 67 /** 68 * Reference to the buffer allocated for temporary use with 69 * base64 encoding or decoding. 70 */ 71 protected byte[] _base64Buffer; 72 73 /** 74 * Reference to the buffer allocated for tokenization purposes, 75 * in which character input is read, and from which it can be 76 * further returned. 77 */ 78 protected char[] _tokenCBuffer; 79 80 /** 81 * Reference to the buffer allocated for buffering it for 82 * output, before being encoded: generally this means concatenating 83 * output, then encoding when buffer fills up. 84 */ 85 protected char[] _concatCBuffer; 86 87 /** 88 * Reference temporary buffer Parser instances need if calling 89 * app decides it wants to access name via 'getTextCharacters' method. 90 * Regular text buffer can not be used as it may contain textual 91 * representation of the value token. 92 */ 93 protected char[] _nameCopyBuffer; 94 95 /* 96 /********************************************************** 97 /* Life-cycle 98 /********************************************************** 99 */ 100 IOContext(BufferRecycler br, Object sourceRef, boolean managedResource)101 public IOContext(BufferRecycler br, Object sourceRef, boolean managedResource) 102 { 103 _bufferRecycler = br; 104 _sourceRef = sourceRef; 105 _managedResource = managedResource; 106 } 107 setEncoding(JsonEncoding enc)108 public void setEncoding(JsonEncoding enc) { 109 _encoding = enc; 110 } 111 112 /** 113 * @since 1.6 114 */ withEncoding(JsonEncoding enc)115 public IOContext withEncoding(JsonEncoding enc) { 116 _encoding = enc; 117 return this; 118 } 119 120 /* 121 /********************************************************** 122 /* Public API, accessors 123 /********************************************************** 124 */ 125 getSourceReference()126 public Object getSourceReference() { return _sourceRef; } getEncoding()127 public JsonEncoding getEncoding() { return _encoding; } isResourceManaged()128 public boolean isResourceManaged() { return _managedResource; } 129 130 /* 131 /********************************************************** 132 /* Public API, buffer management 133 /********************************************************** 134 */ 135 constructTextBuffer()136 public TextBuffer constructTextBuffer() { 137 return new TextBuffer(_bufferRecycler); 138 } 139 140 /** 141 *<p> 142 * Note: the method can only be called once during its life cycle. 143 * This is to protect against accidental sharing. 144 */ allocReadIOBuffer()145 public byte[] allocReadIOBuffer() { 146 _verifyAlloc(_readIOBuffer); 147 return (_readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_READ_IO_BUFFER)); 148 } 149 150 /** 151 * @since 2.4 152 */ allocReadIOBuffer(int minSize)153 public byte[] allocReadIOBuffer(int minSize) { 154 _verifyAlloc(_readIOBuffer); 155 return (_readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_READ_IO_BUFFER, minSize)); 156 } 157 allocWriteEncodingBuffer()158 public byte[] allocWriteEncodingBuffer() { 159 _verifyAlloc(_writeEncodingBuffer); 160 return (_writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER)); 161 } 162 163 /** 164 * @since 2.4 165 */ allocWriteEncodingBuffer(int minSize)166 public byte[] allocWriteEncodingBuffer(int minSize) { 167 _verifyAlloc(_writeEncodingBuffer); 168 return (_writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER, minSize)); 169 } 170 171 /** 172 * @since 2.1 173 */ allocBase64Buffer()174 public byte[] allocBase64Buffer() { 175 _verifyAlloc(_base64Buffer); 176 return (_base64Buffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_BASE64_CODEC_BUFFER)); 177 } 178 179 /** 180 * @since 2.9 181 */ allocBase64Buffer(int minSize)182 public byte[] allocBase64Buffer(int minSize) { 183 _verifyAlloc(_base64Buffer); 184 return (_base64Buffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_BASE64_CODEC_BUFFER, minSize)); 185 } 186 allocTokenBuffer()187 public char[] allocTokenBuffer() { 188 _verifyAlloc(_tokenCBuffer); 189 return (_tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER)); 190 } 191 192 /** 193 * @since 2.4 194 */ allocTokenBuffer(int minSize)195 public char[] allocTokenBuffer(int minSize) { 196 _verifyAlloc(_tokenCBuffer); 197 return (_tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER, minSize)); 198 } 199 allocConcatBuffer()200 public char[] allocConcatBuffer() { 201 _verifyAlloc(_concatCBuffer); 202 return (_concatCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_CONCAT_BUFFER)); 203 } 204 allocNameCopyBuffer(int minSize)205 public char[] allocNameCopyBuffer(int minSize) { 206 _verifyAlloc(_nameCopyBuffer); 207 return (_nameCopyBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_NAME_COPY_BUFFER, minSize)); 208 } 209 210 /** 211 * Method to call when all the processing buffers can be safely 212 * recycled. 213 */ releaseReadIOBuffer(byte[] buf)214 public void releaseReadIOBuffer(byte[] buf) { 215 if (buf != null) { 216 /* Let's do sanity checks to ensure once-and-only-once release, 217 * as well as avoiding trying to release buffers not owned 218 */ 219 _verifyRelease(buf, _readIOBuffer); 220 _readIOBuffer = null; 221 _bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_READ_IO_BUFFER, buf); 222 } 223 } 224 releaseWriteEncodingBuffer(byte[] buf)225 public void releaseWriteEncodingBuffer(byte[] buf) { 226 if (buf != null) { 227 /* Let's do sanity checks to ensure once-and-only-once release, 228 * as well as avoiding trying to release buffers not owned 229 */ 230 _verifyRelease(buf, _writeEncodingBuffer); 231 _writeEncodingBuffer = null; 232 _bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER, buf); 233 } 234 } 235 releaseBase64Buffer(byte[] buf)236 public void releaseBase64Buffer(byte[] buf) { 237 if (buf != null) { // sanity checks, release once-and-only-once, must be one owned 238 _verifyRelease(buf, _base64Buffer); 239 _base64Buffer = null; 240 _bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_BASE64_CODEC_BUFFER, buf); 241 } 242 } 243 releaseTokenBuffer(char[] buf)244 public void releaseTokenBuffer(char[] buf) { 245 if (buf != null) { 246 _verifyRelease(buf, _tokenCBuffer); 247 _tokenCBuffer = null; 248 _bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER, buf); 249 } 250 } 251 releaseConcatBuffer(char[] buf)252 public void releaseConcatBuffer(char[] buf) { 253 if (buf != null) { 254 // 14-Jan-2014, tatu: Let's actually allow upgrade of the original buffer. 255 _verifyRelease(buf, _concatCBuffer); 256 _concatCBuffer = null; 257 _bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_CONCAT_BUFFER, buf); 258 } 259 } 260 releaseNameCopyBuffer(char[] buf)261 public void releaseNameCopyBuffer(char[] buf) { 262 if (buf != null) { 263 // 14-Jan-2014, tatu: Let's actually allow upgrade of the original buffer. 264 _verifyRelease(buf, _nameCopyBuffer); 265 _nameCopyBuffer = null; 266 _bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_NAME_COPY_BUFFER, buf); 267 } 268 } 269 270 /* 271 /********************************************************** 272 /* Internal helpers 273 /********************************************************** 274 */ 275 _verifyAlloc(Object buffer)276 protected final void _verifyAlloc(Object buffer) { 277 if (buffer != null) { throw new IllegalStateException("Trying to call same allocXxx() method second time"); } 278 } 279 _verifyRelease(byte[] toRelease, byte[] src)280 protected final void _verifyRelease(byte[] toRelease, byte[] src) { 281 // 07-Mar-2016, tatu: As per [core#255], only prevent shrinking of buffer 282 if ((toRelease != src) && (toRelease.length < src.length)) { throw wrongBuf(); } 283 } 284 _verifyRelease(char[] toRelease, char[] src)285 protected final void _verifyRelease(char[] toRelease, char[] src) { 286 // 07-Mar-2016, tatu: As per [core#255], only prevent shrinking of buffer 287 if ((toRelease != src) && (toRelease.length < src.length)) { throw wrongBuf(); } 288 } 289 wrongBuf()290 private IllegalArgumentException wrongBuf() { 291 // sanity check failed; trying to return different, smaller buffer. 292 return new IllegalArgumentException("Trying to release buffer smaller than original"); 293 } 294 } 295