KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > portal > setup > util > GrowableByteBuffer


1 /*****************************************
2  * *
3  * JBoss Portal: The OpenSource Portal *
4  * *
5  * Distributable under LGPL license. *
6  * See terms of license at gnu.org. *
7  * *
8  *****************************************/

9 package org.jboss.portal.setup.util;
10
11 import java.io.IOException JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.io.OutputStream JavaDoc;
14 import java.io.UnsupportedEncodingException JavaDoc;
15 import java.nio.ByteBuffer JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.List JavaDoc;
18
19 /**
20  * @author <a HREF="mailto:palber@novell.com">Polina Alber</a>
21  * Date: May 4, 2005; Time: 2:26:17 PM
22  * @since JBoss portal 2.0
23  * Class org.jboss.portal.setup.util.GrowableByteBuffer
24  * A class that implements a growable byte buffer. It also provides an
25  * <code>InputStream</code> for accessing the data. The aim here is to write a
26  * very fast implementation that never copies the data. It assumes that it can
27  * consume all the memory it wants. The caller can limit the maximum number of
28  * bytes used in this buffer through a constructor argument.
29  * <p/>
30  * This implementation is not thread safe. Callers who want to use this buffer
31  * from multiple threads must synchronize around all calls.
32  */

33 public class GrowableByteBuffer
34 {
35
36    /**
37     * The List of ByteBuffers we maintain
38     */

39    private List JavaDoc m_bufferList = null;
40
41    /**
42     * The current buffer we are writing to / reading from
43     */

44    private int m_bufferIndex = 0;
45
46    /**
47     * A flag indicating if we have been flipped from write mode to read mode
48     */

49    private boolean m_isReadable = false;
50
51    /**
52     * A flag indicating if the InputStream has been closed
53     */

54    private boolean m_closed = false;
55
56    /**
57     * The number of written bytes to all buffers
58     */

59    private int m_bytesWritten = 0;
60
61    /**
62     * The maximum number of bytes allowed to be written to this buffer
63     */

64    private int m_maximumBytes = -1;
65
66    /**
67     * The size of each buffer
68     */

69    private int m_bufferSize = DEFAULT_BUFFER_SIZE;
70
71    /**
72     * The default size of each buffer
73     */

74    private static final int DEFAULT_BUFFER_SIZE = 32 * 1000;
75
76
77    /**
78     * Create a new <code>GrowableByteBuffer</code> instance. Use the default
79     * buffer size and set no limit on the total number of bytes allowed.
80     */

81    public GrowableByteBuffer()
82    {
83       m_bufferList = new ArrayList JavaDoc();
84
85       addBuffer();
86    }
87
88    /**
89     * Create a new <code>GrowableByteBuffer</code> instance. Use the supplied
90     * buffer size and set no limit on the total number of bytes allowed.
91     *
92     * @param bufferSize an <code>int</code> containing the size to use for each
93     * buffer in the chain
94     */

95    public GrowableByteBuffer(int bufferSize)
96    {
97       m_bufferList = new ArrayList JavaDoc();
98       m_bufferSize = bufferSize;
99
100       addBuffer();
101    }
102
103    /**
104     * Create a new <code>GrowableByteBuffer</code> instance. Use the supplied
105     * buffer size and the supplied limit on the total number of bytes allowed.
106     *
107     * @param bufferSize an <code>int</code> containing the size to use for each
108     * buffer in the chain
109     * @param maximumBytes an <code>int</code> containing the maximum number of
110     * bytes allowed to be written
111     */

112    public GrowableByteBuffer(int bufferSize, int maximumBytes)
113    {
114       m_bufferList = new ArrayList JavaDoc();
115       m_bufferSize = bufferSize;
116       m_maximumBytes = maximumBytes;
117
118       addBuffer();
119    }
120
121    /**
122     * A method to get current content of buffer as byte array
123     */

124    public byte[] getBytes() throws IOException JavaDoc
125    {
126       if (!m_isReadable)
127       {
128          throw new IOException JavaDoc("The buffer is not in a readable state");
129       }
130
131       if (m_bytesWritten == 0)
132       {
133          return new byte[0];
134       }
135
136       // Build a byte[] to hold the whole contents
137
byte[] allBytes = new byte[m_bytesWritten];
138       read(allBytes, 0, m_bytesWritten);
139
140       return allBytes;
141    }
142
143
144    /**
145     * A method to get the current contents of all buffers as a String. This requires
146     * that the object be in the "readable" state (the output stream has been closed).
147     *
148     * @param encoding a <code>String</code> containing the encoding to use when
149     * creating the <code>String</code>
150     * @return a <code>String</code> containing the contents of this buffer as a
151     * <code>String</code>
152     * @throws IOException if an error occurs reading the buffer to create the
153     * <code>String</code>
154     * @throws UnsupportedEncodingException if an error occurs if the encoding
155     * supplied is invalid
156     */

157    public String JavaDoc toString(String JavaDoc encoding)
158       throws IOException JavaDoc, UnsupportedEncodingException JavaDoc
159    {
160       if (encoding == null)
161       {
162          throw new IllegalArgumentException JavaDoc("Encoding cannot be null");
163       }
164
165       // Build a byte[] to hold the whole contents
166
byte[] allBytes = getBytes();
167
168       return new String JavaDoc(allBytes, encoding);
169
170    }
171
172    public void write(byte b) throws IOException JavaDoc
173    {
174       if (m_isReadable || m_closed)
175       {
176          throw new IOException JavaDoc("The OutputStream has already been closed");
177       }
178       if (m_maximumBytes != -1 && (m_bytesWritten >= m_maximumBytes))
179       {
180          throw new IOException JavaDoc("The buffer is full");
181       }
182       ByteBuffer JavaDoc currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
183       if (!currentBuffer.hasRemaining())
184       {
185          currentBuffer = addBuffer();
186          m_bufferIndex++;
187       }
188       m_bytesWritten++;
189    }
190
191    /**
192     * Write a byte (supplied as an int) to the buffer. Note that per the
193     * OutputStream.write(int) contract, only the 8 low-order bits of the int
194     * are honored.
195     *
196     * @see OutputStream#write(int)
197     */

198    public void write(int b)
199       throws IOException JavaDoc
200    {
201       write((byte)(0xff & b));
202    }
203
204    /**
205     * Write the supplied byte[] to the buffer.
206     *
207     * @see OutputStream#write(byte[], int, int)
208     * @see ByteBuffer#put(byte[], int, int)
209     */

210    public void write(byte b[], int off, int len)
211       throws IOException JavaDoc
212    {
213       if (m_isReadable || m_closed)
214       {
215          throw new IOException JavaDoc("The OutputStream has already been closed");
216       }
217
218       if (m_maximumBytes != -1 && (m_bytesWritten + len >= m_maximumBytes))
219       {
220          throw new IOException JavaDoc("The buffer is full");
221       }
222
223       ByteBuffer JavaDoc currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
224
225       int writeCount = 0;
226       int bOffset = off;
227       while (writeCount < len)
228       {
229          // Get the number of bytes left in the current buffer
230
int remaining = currentBuffer.remaining();
231          if (remaining > 0)
232          {
233             // We have some space left, write as much as we can
234
int currentLen = Math.min(remaining, len - writeCount);
235             currentBuffer.put(b, bOffset, currentLen);
236             writeCount += currentLen;
237             bOffset += currentLen;
238
239             continue;
240          }
241
242          // We need a new buffer, create it
243
currentBuffer = addBuffer();
244          m_bufferIndex++;
245       }
246
247       m_bytesWritten += writeCount;
248    }
249
250    /**
251     * Read a byte byte (and convert it to an int) from the buffer. Note that
252     * per the InputStream.read() contract, only the 8 low-order bits of the int
253     * are ever set.
254     *
255     * @see InputStream#read()
256     */

257    public int read()
258       throws IOException JavaDoc
259    {
260       if (m_closed)
261       {
262          throw new IOException JavaDoc("The InputStream has already been closed");
263       }
264
265       if (!m_isReadable)
266       {
267          throw new IOException JavaDoc("The buffer is not in a readable state; close the OutputStream first");
268       }
269
270       ByteBuffer JavaDoc currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
271
272       // Check if we are at the end of this buffer
273
if (!currentBuffer.hasRemaining())
274       {
275          // Check if there are any more buffers
276
if (m_bufferIndex == m_bufferList.size() - 1)
277          {
278             return -1;
279          }
280
281          m_bufferIndex++;
282          currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
283          currentBuffer.flip();
284       }
285
286       // We only create additional buffers when we have data to write
287
if (currentBuffer.position() > currentBuffer.limit())
288       {
289          throw new IOException JavaDoc("position exceeded limit");
290       }
291
292       return (int)currentBuffer.get();
293    }
294
295    /**
296     * Read from the buffer and fill the supplied array of bytes.
297     *
298     * @see InputStream#read(byte[], int, int)
299     */

300    public int read(byte b[], int off, int len)
301       throws IOException JavaDoc
302    {
303       if (b == null)
304       {
305          throw new NullPointerException JavaDoc("b argument is null");
306       }
307
308       if (m_closed)
309       {
310          throw new IOException JavaDoc("The InputStream has already been closed");
311       }
312
313       if (!m_isReadable)
314       {
315          throw new IOException JavaDoc("The buffer is not in a readable state; close the OutputStream first");
316       }
317
318       ByteBuffer JavaDoc currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
319
320       int readCount = 0;
321       int bOffset = off;
322       while (readCount < len)
323       {
324          // Get the number of bytes left in the current buffer
325
int remaining = currentBuffer.remaining();
326          if (remaining > 0)
327          {
328             // We have some data, get as much as we can
329
int currentLen = Math.min(remaining, len - readCount);
330             currentBuffer.get(b, bOffset, currentLen);
331             readCount += currentLen;
332             bOffset += currentLen;
333
334             continue;
335          }
336
337          // Check if there are any more buffers
338
if (m_bufferIndex == m_bufferList.size() - 1)
339          {
340             return (readCount == 0) ? -1 : readCount;
341          }
342
343          // We have more buffers, move to the next buffer and loop
344
m_bufferIndex++;
345          currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
346          currentBuffer.flip();
347       }
348
349       return (readCount == 0) ? -1 : readCount;
350    }
351
352
353    /**
354     * Indicate that the <code>InputStream</code> has closed.
355     */

356    public void inputStreamClose()
357    {
358       m_closed = true;
359    }
360    /**
361     * Flipps buffer to a read mode
362     */

363    public void flip()
364      {
365         if (m_isReadable)
366         {
367            throw new IllegalStateException JavaDoc("The buffer has already been flipped into read mode");
368         }
369
370         m_isReadable = true;
371         m_bufferIndex = 0;
372
373         ByteBuffer JavaDoc currentBuffer = (ByteBuffer JavaDoc)m_bufferList.get(m_bufferIndex);
374         currentBuffer.flip();
375      }
376
377
378
379    /**
380     * Internal implementation methods
381     */

382
383    /**
384     */

385    private ByteBuffer JavaDoc addBuffer()
386    {
387       ByteBuffer JavaDoc buf = ByteBuffer.allocate(m_bufferSize);
388       m_bufferList.add(buf);
389
390       return buf;
391    }
392
393
394
395 }
396
Popular Tags