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>&lt;=</tt>
042 *     <i>readPosition</i> <tt>&lt;=</tt>
043 *     <i>writePosition</i> <tt>&lt;=</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}