001    /*
002     * Copyright (C) 2008  Trustin Heuiseung Lee
003     *
004     * This library is free software; you can redistribute it and/or
005     * modify it under the terms of the GNU Lesser General Public
006     * License as published by the Free Software Foundation; either
007     * version 2.1 of the License, or (at your option) any later version.
008     *
009     * This library is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this library; if not, write to the Free Software
016     * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA
017     */
018    package net.gleamynode.netty.buffer;
019    
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.io.OutputStream;
023    import java.nio.ByteBuffer;
024    import java.nio.ByteOrder;
025    import java.nio.channels.GatheringByteChannel;
026    import java.nio.channels.ScatteringByteChannel;
027    
028    
029    /**
030     * @author The Netty Project (netty@googlegroups.com)
031     * @author Trustin Lee (trustin@gmail.com)
032     *
033     * @version $Rev$, $Date$
034     *
035     */
036    public class DynamicChannelBuffer extends AbstractChannelBuffer {
037    
038        private final int initialCapacity;
039        private final ByteOrder endianness;
040        private ChannelBuffer buffer = ChannelBuffer.EMPTY_BUFFER;
041    
042        public DynamicChannelBuffer(int estimatedLength) {
043            this(ByteOrder.BIG_ENDIAN, estimatedLength);
044        }
045    
046        public DynamicChannelBuffer(ByteOrder endianness, int estimatedLength) {
047            if (estimatedLength <= 0) {
048                throw new IllegalArgumentException("estimatedLength");
049            }
050            if (endianness == null) {
051                throw new NullPointerException("endianness");
052            }
053    
054            initialCapacity = estimatedLength;
055            this.endianness = endianness;
056        }
057    
058        public ByteOrder order() {
059            return endianness;
060        }
061    
062        public int capacity() {
063            return buffer.capacity();
064        }
065    
066        public byte getByte(int index) {
067            return buffer.getByte(index);
068        }
069    
070        public short getShort(int index) {
071            return buffer.getShort(index);
072        }
073    
074        public int getMedium(int index) {
075            return buffer.getMedium(index);
076        }
077    
078        public int getInt(int index) {
079            return buffer.getInt(index);
080        }
081    
082        public long getLong(int index) {
083            return buffer.getLong(index);
084        }
085    
086        public void getBytes(int index, byte[] dst, int dstIndex, int length) {
087            buffer.getBytes(index, dst, dstIndex, length);
088        }
089    
090        public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
091            buffer.getBytes(index, dst, dstIndex, length);
092        }
093    
094        public void getBytes(int index, ByteBuffer dst) {
095            buffer.getBytes(index, dst);
096        }
097    
098        public int getBytes(int index, GatheringByteChannel out, int length)
099                throws IOException {
100            return buffer.getBytes(index, out, length);
101        }
102    
103        public void getBytes(int index, OutputStream out, int length)
104                throws IOException {
105            buffer.getBytes(index, out, length);
106        }
107    
108        public void setByte(int index, byte value) {
109            buffer.setByte(index, value);
110        }
111    
112        public void setShort(int index, short value) {
113            buffer.setShort(index, value);
114        }
115    
116        public void setMedium(int index, int value) {
117            buffer.setMedium(index, value);
118        }
119    
120        public void setInt(int index, int value) {
121            buffer.setInt(index, value);
122        }
123    
124        public void setLong(int index, long value) {
125            buffer.setLong(index, value);
126        }
127    
128        public void setBytes(int index, byte[] src, int srcIndex, int length) {
129            buffer.setBytes(index, src, srcIndex, length);
130        }
131    
132        public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
133            buffer.setBytes(index, src, srcIndex, length);
134        }
135    
136        public void setBytes(int index, ByteBuffer src) {
137            buffer.setBytes(index, src);
138        }
139    
140        public void setBytes(int index, InputStream in, int length)
141                throws IOException {
142            buffer.setBytes(index, in, length);
143        }
144    
145        public int setBytes(int index, ScatteringByteChannel in, int length)
146                throws IOException {
147            return buffer.setBytes(index, in, length);
148        }
149    
150        @Override
151        public void writeByte(byte value) {
152            ensureWritableBytes(1);
153            super.writeByte(value);
154        }
155    
156        @Override
157        public void writeShort(short value) {
158            ensureWritableBytes(2);
159            super.writeShort(value);
160        }
161    
162        @Override
163        public void writeMedium(int value) {
164            ensureWritableBytes(3);
165            super.writeMedium(value);
166        }
167    
168        @Override
169        public void writeInt(int value) {
170            ensureWritableBytes(4);
171            super.writeInt(value);
172        }
173    
174        @Override
175        public void writeLong(long value) {
176            ensureWritableBytes(8);
177            super.writeLong(value);
178        }
179    
180        @Override
181        public void writeBytes(byte[] src, int srcIndex, int length) {
182            ensureWritableBytes(length);
183            super.writeBytes(src, srcIndex, length);
184        }
185    
186        @Override
187        public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
188            ensureWritableBytes(length);
189            super.writeBytes(src, srcIndex, length);
190        }
191    
192        @Override
193        public void writeBytes(ByteBuffer src) {
194            ensureWritableBytes(src.remaining());
195            super.writeBytes(src);
196        }
197    
198        @Override
199        public void writePlaceholder(int length) {
200            ensureWritableBytes(length);
201            super.writePlaceholder(length);
202        }
203    
204        public ChannelBuffer duplicate() {
205            return new DuplicatedChannelBuffer(this);
206        }
207    
208        public ChannelBuffer copy(int index, int length) {
209            DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(endianness, Math.max(length, 64));
210            copiedBuffer.buffer = buffer.copy();
211            if (copiedBuffer.buffer.capacity() == 0) {
212                copiedBuffer.buffer = ChannelBuffer.EMPTY_BUFFER;
213            }
214            return copiedBuffer;
215        }
216    
217        public ChannelBuffer slice(int index, int length) {
218            if (index == 0) {
219                return new TruncatedChannelBuffer(this, length);
220            } else {
221                return new SlicedChannelBuffer(this, index, length);
222            }
223        }
224    
225        public ByteBuffer toByteBuffer(int index, int length) {
226            return buffer.toByteBuffer(index, length);
227        }
228    
229        private void ensureWritableBytes(int requestedBytes) {
230            if (requestedBytes <= writableBytes()) {
231                return;
232            }
233    
234            int newCapacity;
235            if (capacity() == 0) {
236                newCapacity = initialCapacity;
237            } else {
238                newCapacity = capacity();
239            }
240            int minNewCapacity = writerIndex() + requestedBytes;
241            while (newCapacity < minNewCapacity) {
242                newCapacity <<= 1;
243            }
244    
245            ChannelBuffer newBuffer = ChannelBuffers.buffer(endianness, newCapacity);
246            newBuffer.writeBytes(buffer, readerIndex(), readableBytes());
247            buffer = newBuffer;
248        }
249    }