001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.io.buffer; 018 019import java.io.InputStream; 020import java.io.OutputStream; 021import java.nio.ByteBuffer; 022import java.nio.CharBuffer; 023import java.nio.charset.Charset; 024import java.nio.charset.CharsetEncoder; 025import java.nio.charset.CoderResult; 026import java.nio.charset.CodingErrorAction; 027import java.util.function.IntPredicate; 028 029import org.springframework.util.Assert; 030 031/** 032 * Basic abstraction over byte buffers. 033 * 034 * <p>{@code DataBuffer}s has a separate {@linkplain #readPosition() read} and 035 * {@linkplain #writePosition() write} position, as opposed to {@code ByteBuffer}'s 036 * single {@linkplain ByteBuffer#position() position}. As such, the {@code DataBuffer} 037 * does not require a {@linkplain ByteBuffer#flip() flip} to read after writing. In general, 038 * the following invariant holds for the read and write positions, and the capacity: 039 * 040 * <blockquote> 041 * <tt>0</tt> <tt><=</tt> 042 * <i>readPosition</i> <tt><=</tt> 043 * <i>writePosition</i> <tt><=</tt> 044 * <i>capacity</i> 045 * </blockquote> 046 * 047 * <p>The {@linkplain #capacity() capacity} of a {@code DataBuffer} is expanded on demand, 048 * similar to {@code StringBuilder}. 049 * 050 * <p>The main purpose of the {@code DataBuffer} abstraction is to provide a convenient wrapper 051 * around {@link ByteBuffer} which is similar to Netty's {@link io.netty.buffer.ByteBuf} but 052 * can also be used on non-Netty platforms (i.e. Servlet containers). 053 * 054 * @author Arjen Poutsma 055 * @author Brian Clozel 056 * @since 5.0 057 * @see DataBufferFactory 058 */ 059public interface DataBuffer { 060 061 /** 062 * Return the {@link DataBufferFactory} that created this buffer. 063 * @return the creating buffer factory 064 */ 065 DataBufferFactory factory(); 066 067 /** 068 * Return the index of the first byte in this buffer that matches 069 * the given predicate. 070 * @param predicate the predicate to match 071 * @param fromIndex the index to start the search from 072 * @return the index of the first byte that matches {@code predicate}; 073 * or {@code -1} if none match 074 */ 075 int indexOf(IntPredicate predicate, int fromIndex); 076 077 /** 078 * Return the index of the last byte in this buffer that matches 079 * the given predicate. 080 * @param predicate the predicate to match 081 * @param fromIndex the index to start the search from 082 * @return the index of the last byte that matches {@code predicate}; 083 * or {@code -1} if none match 084 */ 085 int lastIndexOf(IntPredicate predicate, int fromIndex); 086 087 /** 088 * Return the number of bytes that can be read from this data buffer. 089 * @return the readable byte count 090 */ 091 int readableByteCount(); 092 093 /** 094 * Return the number of bytes that can be written to this data buffer. 095 * @return the writable byte count 096 * @since 5.0.1 097 */ 098 int writableByteCount(); 099 100 /** 101 * Return the number of bytes that this buffer can contain. 102 * @return the capacity 103 * @since 5.0.1 104 */ 105 int capacity(); 106 107 /** 108 * Set the number of bytes that this buffer can contain. 109 * <p>If the new capacity is lower than the current capacity, the contents 110 * of this buffer will be truncated. If the new capacity is higher than 111 * the current capacity, it will be expanded. 112 * @param capacity the new capacity 113 * @return this buffer 114 */ 115 DataBuffer capacity(int capacity); 116 117 /** 118 * Ensure that the current buffer has enough {@link #writableByteCount()} 119 * to write the amount of data given as an argument. If not, the missing 120 * capacity will be added to the buffer. 121 * @param capacity the writable capacity to check for 122 * @return this buffer 123 * @since 5.1.4 124 */ 125 default DataBuffer ensureCapacity(int capacity) { 126 return this; 127 } 128 129 /** 130 * Return the position from which this buffer will read. 131 * @return the read position 132 * @since 5.0.1 133 */ 134 int readPosition(); 135 136 /** 137 * Set the position from which this buffer will read. 138 * @param readPosition the new read position 139 * @return this buffer 140 * @throws IndexOutOfBoundsException if {@code readPosition} is smaller than 0 141 * or greater than {@link #writePosition()} 142 * @since 5.0.1 143 */ 144 DataBuffer readPosition(int readPosition); 145 146 /** 147 * Return the position to which this buffer will write. 148 * @return the write position 149 * @since 5.0.1 150 */ 151 int writePosition(); 152 153 /** 154 * Set the position to which this buffer will write. 155 * @param writePosition the new write position 156 * @return this buffer 157 * @throws IndexOutOfBoundsException if {@code writePosition} is smaller than 158 * {@link #readPosition()} or greater than {@link #capacity()} 159 * @since 5.0.1 160 */ 161 DataBuffer writePosition(int writePosition); 162 163 /** 164 * Read a single byte at the given index from this data buffer. 165 * @param index the index at which the byte will be read 166 * @return the byte at the given index 167 * @throws IndexOutOfBoundsException when {@code index} is out of bounds 168 * @since 5.0.4 169 */ 170 byte getByte(int index); 171 172 /** 173 * Read a single byte from the current reading position from this data buffer. 174 * @return the byte at this buffer's current reading position 175 */ 176 byte read(); 177 178 /** 179 * Read this buffer's data into the specified destination, starting at the current 180 * reading position of this buffer. 181 * @param destination the array into which the bytes are to be written 182 * @return this buffer 183 */ 184 DataBuffer read(byte[] destination); 185 186 /** 187 * Read at most {@code length} bytes of this buffer into the specified destination, 188 * starting at the current reading position of this buffer. 189 * @param destination the array into which the bytes are to be written 190 * @param offset the index within {@code destination} of the first byte to be written 191 * @param length the maximum number of bytes to be written in {@code destination} 192 * @return this buffer 193 */ 194 DataBuffer read(byte[] destination, int offset, int length); 195 196 /** 197 * Write a single byte into this buffer at the current writing position. 198 * @param b the byte to be written 199 * @return this buffer 200 */ 201 DataBuffer write(byte b); 202 203 /** 204 * Write the given source into this buffer, starting at the current writing position 205 * of this buffer. 206 * @param source the bytes to be written into this buffer 207 * @return this buffer 208 */ 209 DataBuffer write(byte[] source); 210 211 /** 212 * Write at most {@code length} bytes of the given source into this buffer, starting 213 * at the current writing position of this buffer. 214 * @param source the bytes to be written into this buffer 215 * @param offset the index within {@code source} to start writing from 216 * @param length the maximum number of bytes to be written from {@code source} 217 * @return this buffer 218 */ 219 DataBuffer write(byte[] source, int offset, int length); 220 221 /** 222 * Write one or more {@code DataBuffer}s to this buffer, starting at the current 223 * writing position. It is the responsibility of the caller to 224 * {@linkplain DataBufferUtils#release(DataBuffer) release} the given data buffers. 225 * @param buffers the byte buffers to write into this buffer 226 * @return this buffer 227 */ 228 DataBuffer write(DataBuffer... buffers); 229 230 /** 231 * Write one or more {@link ByteBuffer} to this buffer, starting at the current 232 * writing position. 233 * @param buffers the byte buffers to write into this buffer 234 * @return this buffer 235 */ 236 DataBuffer write(ByteBuffer... buffers); 237 238 /** 239 * Write the given {@code CharSequence} using the given {@code Charset}, 240 * starting at the current writing position. 241 * @param charSequence the char sequence to write into this buffer 242 * @param charset the charset to encode the char sequence with 243 * @return this buffer 244 * @since 5.1.4 245 */ 246 default DataBuffer write(CharSequence charSequence, Charset charset) { 247 Assert.notNull(charSequence, "CharSequence must not be null"); 248 Assert.notNull(charset, "Charset must not be null"); 249 if (charSequence.length() != 0) { 250 CharsetEncoder charsetEncoder = charset.newEncoder() 251 .onMalformedInput(CodingErrorAction.REPLACE) 252 .onUnmappableCharacter(CodingErrorAction.REPLACE); 253 CharBuffer inBuffer = CharBuffer.wrap(charSequence); 254 int estimatedSize = (int) (inBuffer.remaining() * charsetEncoder.averageBytesPerChar()); 255 ByteBuffer outBuffer = ensureCapacity(estimatedSize) 256 .asByteBuffer(writePosition(), writableByteCount()); 257 while (true) { 258 CoderResult cr = (inBuffer.hasRemaining() ? 259 charsetEncoder.encode(inBuffer, outBuffer, true) : CoderResult.UNDERFLOW); 260 if (cr.isUnderflow()) { 261 cr = charsetEncoder.flush(outBuffer); 262 } 263 if (cr.isUnderflow()) { 264 break; 265 } 266 if (cr.isOverflow()) { 267 writePosition(writePosition() + outBuffer.position()); 268 int maximumSize = (int) (inBuffer.remaining() * charsetEncoder.maxBytesPerChar()); 269 ensureCapacity(maximumSize); 270 outBuffer = asByteBuffer(writePosition(), writableByteCount()); 271 } 272 } 273 writePosition(writePosition() + outBuffer.position()); 274 } 275 return this; 276 } 277 278 /** 279 * Create a new {@code DataBuffer} whose contents is a shared subsequence of this 280 * data buffer's content. Data between this data buffer and the returned buffer is 281 * shared; though changes in the returned buffer's position will not be reflected 282 * in the reading nor writing position of this data buffer. 283 * <p><strong>Note</strong> that this method will <strong>not</strong> call 284 * {@link DataBufferUtils#retain(DataBuffer)} on the resulting slice: the reference 285 * count will not be increased. 286 * @param index the index at which to start the slice 287 * @param length the length of the slice 288 * @return the specified slice of this data buffer 289 */ 290 DataBuffer slice(int index, int length); 291 292 /** 293 * Create a new {@code DataBuffer} whose contents is a shared, retained subsequence of this 294 * data buffer's content. Data between this data buffer and the returned buffer is 295 * shared; though changes in the returned buffer's position will not be reflected 296 * in the reading nor writing position of this data buffer. 297 * <p><strong>Note</strong> that unlike {@link #slice(int, int)}, this method 298 * <strong>will</strong> call {@link DataBufferUtils#retain(DataBuffer)} (or equivalent) on the 299 * resulting slice. 300 * @param index the index at which to start the slice 301 * @param length the length of the slice 302 * @return the specified, retained slice of this data buffer 303 * @since 5.2 304 */ 305 default DataBuffer retainedSlice(int index, int length) { 306 return DataBufferUtils.retain(slice(index, length)); 307 } 308 309 /** 310 * Expose this buffer's bytes as a {@link ByteBuffer}. Data between this 311 * {@code DataBuffer} and the returned {@code ByteBuffer} is shared; though 312 * changes in the returned buffer's {@linkplain ByteBuffer#position() position} 313 * will not be reflected in the reading nor writing position of this data buffer. 314 * @return this data buffer as a byte buffer 315 */ 316 ByteBuffer asByteBuffer(); 317 318 /** 319 * Expose a subsequence of this buffer's bytes as a {@link ByteBuffer}. Data between 320 * this {@code DataBuffer} and the returned {@code ByteBuffer} is shared; though 321 * changes in the returned buffer's {@linkplain ByteBuffer#position() position} 322 * will not be reflected in the reading nor writing position of this data buffer. 323 * @param index the index at which to start the byte buffer 324 * @param length the length of the returned byte buffer 325 * @return this data buffer as a byte buffer 326 * @since 5.0.1 327 */ 328 ByteBuffer asByteBuffer(int index, int length); 329 330 /** 331 * Expose this buffer's data as an {@link InputStream}. Both data and read position are 332 * shared between the returned stream and this data buffer. The underlying buffer will 333 * <strong>not</strong> be {@linkplain DataBufferUtils#release(DataBuffer) released} 334 * when the input stream is {@linkplain InputStream#close() closed}. 335 * @return this data buffer as an input stream 336 * @see #asInputStream(boolean) 337 */ 338 InputStream asInputStream(); 339 340 /** 341 * Expose this buffer's data as an {@link InputStream}. Both data and read position are 342 * shared between the returned stream and this data buffer. 343 * @param releaseOnClose whether the underlying buffer will be 344 * {@linkplain DataBufferUtils#release(DataBuffer) released} when the input stream is 345 * {@linkplain InputStream#close() closed}. 346 * @return this data buffer as an input stream 347 * @since 5.0.4 348 */ 349 InputStream asInputStream(boolean releaseOnClose); 350 351 /** 352 * Expose this buffer's data as an {@link OutputStream}. Both data and write position are 353 * shared between the returned stream and this data buffer. 354 * @return this data buffer as an output stream 355 */ 356 OutputStream asOutputStream(); 357 358 /** 359 * Return this buffer's data a String using the specified charset. Default implementation 360 * delegates to {@code toString(readPosition(), readableByteCount(), charset)}. 361 * @param charset the character set to use 362 * @return a string representation of all this buffers data 363 * @since 5.2 364 */ 365 default String toString(Charset charset) { 366 Assert.notNull(charset, "Charset must not be null"); 367 return toString(readPosition(), readableByteCount(), charset); 368 } 369 370 /** 371 * Return a part of this buffer's data as a String using the specified charset. 372 * @param index the index at which to start the string 373 * @param length the number of bytes to use for the string 374 * @param charset the charset to use 375 * @return a string representation of a part of this buffers data 376 * @since 5.2 377 */ 378 String toString(int index, int length, Charset charset); 379 380}