001/*
002 * Copyright 2002-2018 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.nio.ByteBuffer;
020import java.util.List;
021
022import io.netty.buffer.ByteBuf;
023import io.netty.buffer.ByteBufAllocator;
024import io.netty.buffer.CompositeByteBuf;
025import io.netty.buffer.Unpooled;
026
027import org.springframework.util.Assert;
028
029/**
030 * Implementation of the {@code DataBufferFactory} interface based on a
031 * Netty {@link ByteBufAllocator}.
032 *
033 * @author Arjen Poutsma
034 * @author Juergen Hoeller
035 * @since 5.0
036 * @see io.netty.buffer.PooledByteBufAllocator
037 * @see io.netty.buffer.UnpooledByteBufAllocator
038 */
039public class NettyDataBufferFactory implements DataBufferFactory {
040
041        private final ByteBufAllocator byteBufAllocator;
042
043
044        /**
045         * Create a new {@code NettyDataBufferFactory} based on the given factory.
046         * @param byteBufAllocator the factory to use
047         * @see io.netty.buffer.PooledByteBufAllocator
048         * @see io.netty.buffer.UnpooledByteBufAllocator
049         */
050        public NettyDataBufferFactory(ByteBufAllocator byteBufAllocator) {
051                Assert.notNull(byteBufAllocator, "ByteBufAllocator must not be null");
052                this.byteBufAllocator = byteBufAllocator;
053        }
054
055
056        /**
057         * Return the {@code ByteBufAllocator} used by this factory.
058         */
059        public ByteBufAllocator getByteBufAllocator() {
060                return this.byteBufAllocator;
061        }
062
063        @Override
064        public NettyDataBuffer allocateBuffer() {
065                ByteBuf byteBuf = this.byteBufAllocator.buffer();
066                return new NettyDataBuffer(byteBuf, this);
067        }
068
069        @Override
070        public NettyDataBuffer allocateBuffer(int initialCapacity) {
071                ByteBuf byteBuf = this.byteBufAllocator.buffer(initialCapacity);
072                return new NettyDataBuffer(byteBuf, this);
073        }
074
075        @Override
076        public NettyDataBuffer wrap(ByteBuffer byteBuffer) {
077                ByteBuf byteBuf = Unpooled.wrappedBuffer(byteBuffer);
078                return new NettyDataBuffer(byteBuf, this);
079        }
080
081        @Override
082        public DataBuffer wrap(byte[] bytes) {
083                ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
084                return new NettyDataBuffer(byteBuf, this);
085        }
086
087        /**
088         * Wrap the given Netty {@link ByteBuf} in a {@code NettyDataBuffer}.
089         * @param byteBuf the Netty byte buffer to wrap
090         * @return the wrapped buffer
091         */
092        public NettyDataBuffer wrap(ByteBuf byteBuf) {
093                byteBuf.touch();
094                return new NettyDataBuffer(byteBuf, this);
095        }
096
097        /**
098         * {@inheritDoc}
099         * <p>This implementation uses Netty's {@link CompositeByteBuf}.
100         */
101        @Override
102        public DataBuffer join(List<? extends DataBuffer> dataBuffers) {
103                Assert.notEmpty(dataBuffers, "DataBuffer List must not be empty");
104                int bufferCount = dataBuffers.size();
105                if (bufferCount == 1) {
106                        return dataBuffers.get(0);
107                }
108                CompositeByteBuf composite = this.byteBufAllocator.compositeBuffer(bufferCount);
109                for (DataBuffer dataBuffer : dataBuffers) {
110                        Assert.isInstanceOf(NettyDataBuffer.class, dataBuffer);
111                        composite.addComponent(true, ((NettyDataBuffer) dataBuffer).getNativeBuffer());
112                }
113                return new NettyDataBuffer(composite, this);
114        }
115
116        /**
117         * Return the given Netty {@link DataBuffer} as a {@link ByteBuf}.
118         * <p>Returns the {@linkplain NettyDataBuffer#getNativeBuffer() native buffer}
119         * if {@code buffer} is a {@link NettyDataBuffer}; returns
120         * {@link Unpooled#wrappedBuffer(ByteBuffer)} otherwise.
121         * @param buffer the {@code DataBuffer} to return a {@code ByteBuf} for
122         * @return the netty {@code ByteBuf}
123         */
124        public static ByteBuf toByteBuf(DataBuffer buffer) {
125                if (buffer instanceof NettyDataBuffer) {
126                        return ((NettyDataBuffer) buffer).getNativeBuffer();
127                }
128                else {
129                        return Unpooled.wrappedBuffer(buffer.asByteBuffer());
130                }
131        }
132
133
134        @Override
135        public String toString() {
136                return "NettyDataBufferFactory (" + this.byteBufAllocator + ")";
137        }
138
139}