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.charset.Charset; 023import java.nio.charset.StandardCharsets; 024import java.util.function.IntPredicate; 025 026import io.netty.buffer.ByteBuf; 027import io.netty.buffer.ByteBufInputStream; 028import io.netty.buffer.ByteBufOutputStream; 029import io.netty.buffer.ByteBufUtil; 030 031import org.springframework.lang.Nullable; 032import org.springframework.util.Assert; 033import org.springframework.util.ObjectUtils; 034 035/** 036 * Implementation of the {@code DataBuffer} interface that wraps a Netty 037 * {@link ByteBuf}. Typically constructed with {@link NettyDataBufferFactory}. 038 * 039 * @author Arjen Poutsma 040 * @author Brian Clozel 041 * @since 5.0 042 */ 043public class NettyDataBuffer implements PooledDataBuffer { 044 045 private final ByteBuf byteBuf; 046 047 private final NettyDataBufferFactory dataBufferFactory; 048 049 050 /** 051 * Create a new {@code NettyDataBuffer} based on the given {@code ByteBuff}. 052 * @param byteBuf the buffer to base this buffer on 053 */ 054 NettyDataBuffer(ByteBuf byteBuf, NettyDataBufferFactory dataBufferFactory) { 055 Assert.notNull(byteBuf, "ByteBuf must not be null"); 056 Assert.notNull(dataBufferFactory, "NettyDataBufferFactory must not be null"); 057 this.byteBuf = byteBuf; 058 this.dataBufferFactory = dataBufferFactory; 059 } 060 061 062 /** 063 * Directly exposes the native {@code ByteBuf} that this buffer is based on. 064 * @return the wrapped byte buffer 065 */ 066 public ByteBuf getNativeBuffer() { 067 return this.byteBuf; 068 } 069 070 @Override 071 public NettyDataBufferFactory factory() { 072 return this.dataBufferFactory; 073 } 074 075 @Override 076 public int indexOf(IntPredicate predicate, int fromIndex) { 077 Assert.notNull(predicate, "IntPredicate must not be null"); 078 if (fromIndex < 0) { 079 fromIndex = 0; 080 } 081 else if (fromIndex >= this.byteBuf.writerIndex()) { 082 return -1; 083 } 084 int length = this.byteBuf.writerIndex() - fromIndex; 085 return this.byteBuf.forEachByte(fromIndex, length, predicate.negate()::test); 086 } 087 088 @Override 089 public int lastIndexOf(IntPredicate predicate, int fromIndex) { 090 Assert.notNull(predicate, "IntPredicate must not be null"); 091 if (fromIndex < 0) { 092 return -1; 093 } 094 fromIndex = Math.min(fromIndex, this.byteBuf.writerIndex() - 1); 095 return this.byteBuf.forEachByteDesc(0, fromIndex + 1, predicate.negate()::test); 096 } 097 098 @Override 099 public int readableByteCount() { 100 return this.byteBuf.readableBytes(); 101 } 102 103 @Override 104 public int writableByteCount() { 105 return this.byteBuf.writableBytes(); 106 } 107 108 @Override 109 public int readPosition() { 110 return this.byteBuf.readerIndex(); 111 } 112 113 @Override 114 public NettyDataBuffer readPosition(int readPosition) { 115 this.byteBuf.readerIndex(readPosition); 116 return this; 117 } 118 119 @Override 120 public int writePosition() { 121 return this.byteBuf.writerIndex(); 122 } 123 124 @Override 125 public NettyDataBuffer writePosition(int writePosition) { 126 this.byteBuf.writerIndex(writePosition); 127 return this; 128 } 129 130 @Override 131 public byte getByte(int index) { 132 return this.byteBuf.getByte(index); 133 } 134 135 @Override 136 public int capacity() { 137 return this.byteBuf.capacity(); 138 } 139 140 @Override 141 public NettyDataBuffer capacity(int capacity) { 142 this.byteBuf.capacity(capacity); 143 return this; 144 } 145 146 @Override 147 public DataBuffer ensureCapacity(int capacity) { 148 this.byteBuf.ensureWritable(capacity); 149 return this; 150 } 151 152 @Override 153 public byte read() { 154 return this.byteBuf.readByte(); 155 } 156 157 @Override 158 public NettyDataBuffer read(byte[] destination) { 159 this.byteBuf.readBytes(destination); 160 return this; 161 } 162 163 @Override 164 public NettyDataBuffer read(byte[] destination, int offset, int length) { 165 this.byteBuf.readBytes(destination, offset, length); 166 return this; 167 } 168 169 @Override 170 public NettyDataBuffer write(byte b) { 171 this.byteBuf.writeByte(b); 172 return this; 173 } 174 175 @Override 176 public NettyDataBuffer write(byte[] source) { 177 this.byteBuf.writeBytes(source); 178 return this; 179 } 180 181 @Override 182 public NettyDataBuffer write(byte[] source, int offset, int length) { 183 this.byteBuf.writeBytes(source, offset, length); 184 return this; 185 } 186 187 @Override 188 public NettyDataBuffer write(DataBuffer... buffers) { 189 if (!ObjectUtils.isEmpty(buffers)) { 190 if (hasNettyDataBuffers(buffers)) { 191 ByteBuf[] nativeBuffers = new ByteBuf[buffers.length]; 192 for (int i = 0; i < buffers.length; i++) { 193 nativeBuffers[i] = ((NettyDataBuffer) buffers[i]).getNativeBuffer(); 194 } 195 write(nativeBuffers); 196 } 197 else { 198 ByteBuffer[] byteBuffers = new ByteBuffer[buffers.length]; 199 for (int i = 0; i < buffers.length; i++) { 200 byteBuffers[i] = buffers[i].asByteBuffer(); 201 202 } 203 write(byteBuffers); 204 } 205 } 206 return this; 207 } 208 209 private static boolean hasNettyDataBuffers(DataBuffer[] buffers) { 210 for (DataBuffer buffer : buffers) { 211 if (!(buffer instanceof NettyDataBuffer)) { 212 return false; 213 } 214 } 215 return true; 216 } 217 218 @Override 219 public NettyDataBuffer write(ByteBuffer... buffers) { 220 if (!ObjectUtils.isEmpty(buffers)) { 221 for (ByteBuffer buffer : buffers) { 222 this.byteBuf.writeBytes(buffer); 223 } 224 } 225 return this; 226 } 227 228 /** 229 * Writes one or more Netty {@link ByteBuf ByteBufs} to this buffer, 230 * starting at the current writing position. 231 * @param byteBufs the buffers to write into this buffer 232 * @return this buffer 233 */ 234 public NettyDataBuffer write(ByteBuf... byteBufs) { 235 if (!ObjectUtils.isEmpty(byteBufs)) { 236 for (ByteBuf byteBuf : byteBufs) { 237 this.byteBuf.writeBytes(byteBuf); 238 } 239 } 240 return this; 241 } 242 243 @Override 244 public DataBuffer write(CharSequence charSequence, Charset charset) { 245 Assert.notNull(charSequence, "CharSequence must not be null"); 246 Assert.notNull(charset, "Charset must not be null"); 247 if (StandardCharsets.UTF_8.equals(charset)) { 248 ByteBufUtil.writeUtf8(this.byteBuf, charSequence); 249 } 250 else if (StandardCharsets.US_ASCII.equals(charset)) { 251 ByteBufUtil.writeAscii(this.byteBuf, charSequence); 252 } 253 else { 254 return PooledDataBuffer.super.write(charSequence, charset); 255 } 256 return this; 257 } 258 259 @Override 260 public NettyDataBuffer slice(int index, int length) { 261 ByteBuf slice = this.byteBuf.slice(index, length); 262 return new NettyDataBuffer(slice, this.dataBufferFactory); 263 } 264 265 @Override 266 public NettyDataBuffer retainedSlice(int index, int length) { 267 ByteBuf slice = this.byteBuf.retainedSlice(index, length); 268 return new NettyDataBuffer(slice, this.dataBufferFactory); 269 } 270 271 @Override 272 public ByteBuffer asByteBuffer() { 273 return this.byteBuf.nioBuffer(); 274 } 275 276 @Override 277 public ByteBuffer asByteBuffer(int index, int length) { 278 return this.byteBuf.nioBuffer(index, length); 279 } 280 281 @Override 282 public InputStream asInputStream() { 283 return new ByteBufInputStream(this.byteBuf); 284 } 285 286 @Override 287 public InputStream asInputStream(boolean releaseOnClose) { 288 return new ByteBufInputStream(this.byteBuf, releaseOnClose); 289 } 290 291 @Override 292 public OutputStream asOutputStream() { 293 return new ByteBufOutputStream(this.byteBuf); 294 } 295 296 @Override 297 public String toString(Charset charset) { 298 Assert.notNull(charset, "Charset must not be null"); 299 return this.byteBuf.toString(charset); 300 } 301 302 @Override 303 public String toString(int index, int length, Charset charset) { 304 Assert.notNull(charset, "Charset must not be null"); 305 return this.byteBuf.toString(index, length, charset); 306 } 307 308 @Override 309 public boolean isAllocated() { 310 return this.byteBuf.refCnt() > 0; 311 } 312 313 @Override 314 public PooledDataBuffer retain() { 315 return new NettyDataBuffer(this.byteBuf.retain(), this.dataBufferFactory); 316 } 317 318 @Override 319 public boolean release() { 320 return this.byteBuf.release(); 321 } 322 323 324 @Override 325 public boolean equals(@Nullable Object other) { 326 return (this == other || (other instanceof NettyDataBuffer && 327 this.byteBuf.equals(((NettyDataBuffer) other).byteBuf))); 328 } 329 330 @Override 331 public int hashCode() { 332 return this.byteBuf.hashCode(); 333 } 334 335 @Override 336 public String toString() { 337 return this.byteBuf.toString(); 338 } 339 340}