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 org.springframework.util.Assert;
023
024/**
025 * Default implementation of the {@code DataBufferFactory} interface. Allows for
026 * specification of the default initial capacity at construction time, as well
027 * as whether heap-based or direct buffers are to be preferred.
028 *
029 * @author Arjen Poutsma
030 * @since 5.0
031 */
032public class DefaultDataBufferFactory implements DataBufferFactory {
033
034        /**
035         * The default capacity when none is specified.
036         * @see #DefaultDataBufferFactory()
037         * @see #DefaultDataBufferFactory(boolean)
038         */
039        public static final int DEFAULT_INITIAL_CAPACITY = 256;
040
041
042        private final boolean preferDirect;
043
044        private final int defaultInitialCapacity;
045
046
047        /**
048         * Creates a new {@code DefaultDataBufferFactory} with default settings.
049         */
050        public DefaultDataBufferFactory() {
051                this(false);
052        }
053
054        /**
055         * Creates a new {@code DefaultDataBufferFactory}, indicating whether direct
056         * buffers should be created by {@link #allocateBuffer()} and
057         * {@link #allocateBuffer(int)}.
058         * @param preferDirect {@code true} if direct buffers are to be preferred;
059         * {@code false} otherwise
060         */
061        public DefaultDataBufferFactory(boolean preferDirect) {
062                this(preferDirect, DEFAULT_INITIAL_CAPACITY);
063        }
064
065        /**
066         * Creates a new {@code DefaultDataBufferFactory}, indicating whether direct
067         * buffers should be created by {@link #allocateBuffer()} and
068         * {@link #allocateBuffer(int)}, and what the capacity is to be used for
069         * {@link #allocateBuffer()}.
070         * @param preferDirect {@code true} if direct buffers are to be preferred;
071         * {@code false} otherwise
072         */
073        public DefaultDataBufferFactory(boolean preferDirect, int defaultInitialCapacity) {
074                Assert.isTrue(defaultInitialCapacity > 0, "'defaultInitialCapacity' should be larger than 0");
075                this.preferDirect = preferDirect;
076                this.defaultInitialCapacity = defaultInitialCapacity;
077        }
078
079
080        @Override
081        public DefaultDataBuffer allocateBuffer() {
082                return allocateBuffer(this.defaultInitialCapacity);
083        }
084
085        @Override
086        public DefaultDataBuffer allocateBuffer(int initialCapacity) {
087                ByteBuffer byteBuffer = (this.preferDirect ?
088                                ByteBuffer.allocateDirect(initialCapacity) :
089                                ByteBuffer.allocate(initialCapacity));
090                return DefaultDataBuffer.fromEmptyByteBuffer(this, byteBuffer);
091        }
092
093        @Override
094        public DefaultDataBuffer wrap(ByteBuffer byteBuffer) {
095                return DefaultDataBuffer.fromFilledByteBuffer(this, byteBuffer.slice());
096        }
097
098        @Override
099        public DefaultDataBuffer wrap(byte[] bytes) {
100                return DefaultDataBuffer.fromFilledByteBuffer(this, ByteBuffer.wrap(bytes));
101        }
102
103        /**
104         * {@inheritDoc}
105         * <p>This implementation creates a single {@link DefaultDataBuffer}
106         * to contain the data in {@code dataBuffers}.
107         */
108        @Override
109        public DefaultDataBuffer join(List<? extends DataBuffer> dataBuffers) {
110                Assert.notEmpty(dataBuffers, "DataBuffer List must not be empty");
111                int capacity = dataBuffers.stream().mapToInt(DataBuffer::readableByteCount).sum();
112                DefaultDataBuffer result = allocateBuffer(capacity);
113                dataBuffers.forEach(result::write);
114                dataBuffers.forEach(DataBufferUtils::release);
115                return result;
116        }
117
118
119        @Override
120        public String toString() {
121                return "DefaultDataBufferFactory (preferDirect=" + this.preferDirect + ")";
122        }
123
124}