KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > util > LengthMarkedBufferedInputStream


1 /**
2  * com.mckoi.util.LengthMarkedBufferedInputStream 22 Jul 2000
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.util;
26
27 import java.io.FilterInputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.EOFException JavaDoc;
30 import java.io.InputStream JavaDoc;
31
32 /**
33  * Reads a command block on the underlying stream that is constrained by
34  * a length marker preceeding the command. This can be used as a hack
35  * work around for non-blocking IO because we know ahead of time how much data
36  * makes up the next block of information over the stream.
37  *
38  * @author Tobias Downer
39  */

40
41 public final class LengthMarkedBufferedInputStream extends FilterInputStream JavaDoc {
42
43   /**
44    * The initial buffer size of the internal input buffer.
45    */

46   private static int INITIAL_BUFFER_SIZE = 512;
47
48   /**
49    * The chained InputStream that is underneath this object.
50    */

51   private InputStream JavaDoc in;
52
53   /**
54    * The buffer that is used to read in whatever is on the stream.
55    */

56   private byte[] buf;
57
58   /**
59    * The number of valid bytes in the buffer.
60    */

61   private int count;
62
63   /**
64    * The area of the buffer that is marked as being an available command.
65    * If it's -1 then there is no area marked.
66    */

67   private int marked_length;
68
69   /**
70    * The current index of the marked area that is being read.
71    */

72   private int marked_index;
73
74   /**
75    * The Constructor.
76    */

77   public LengthMarkedBufferedInputStream(InputStream JavaDoc in) {
78     super(in);
79     this.in = in;
80     buf = new byte[INITIAL_BUFFER_SIZE];
81     count = 0;
82     marked_length = -1;
83     marked_index = -1;
84   }
85
86   /**
87    * Ensures that the buffer is large enough to store the given value. If
88    * it's not then it grows the buffer so it is big enough.
89    */

90   private void ensureCapacity(int new_size) {
91     int old_size = buf.length;
92     if (new_size > old_size) {
93       int cap = (old_size * 3)/2 + 1;
94       if (cap < new_size)
95         cap = new_size;
96       byte[] old_buf = buf;
97       buf = new byte[cap];
98 // // Copy all the contents except the first 4 bytes (the size marker)
99
// System.arraycopy(old_buf, 4, buf, 4, count - 4);
100
System.arraycopy(old_buf, 0, buf, 0, count - 0);
101     }
102   }
103
104   /**
105    * Private method, it is called when the end of the marked length is reached.
106    * It performs various maintenance operations to ensure the buffer
107    * consistency is maintained.
108    * Assumes we are calling from a synchronized method.
109    */

110   private void handleEndReached() {
111 // System.out.println();
112
// System.out.println("Shifting Buffer: ");
113
// System.out.println(" Index: " + marked_index +
114
// ", Length: " + (count - marked_length));
115
// Move anything from the end of the buffer to the start.
116
System.arraycopy(buf, marked_index, buf, 0, count - marked_length);
117     count -= marked_length;
118
119     // Reset the state
120
marked_length = -1;
121     marked_index = -1;
122   }
123
124   // ---------- Overwritten from FilterInputStream ----------
125

126   public synchronized int read() throws IOException JavaDoc {
127     if (marked_index == -1) {
128       throw new IOException JavaDoc("No mark has been read yet.");
129     }
130     if (marked_index >= marked_length) {
131       String JavaDoc debug_msg = "Read over end of length marked buffer. ";
132       debug_msg += "(marked_index=" + marked_index;
133       debug_msg += ",marked_length=" + marked_length + ")";
134       debug_msg += ")";
135       throw new IOException JavaDoc(debug_msg);
136     }
137     int n = buf[marked_index++] & 0x0FF;
138     if (marked_index >= marked_length) {
139       handleEndReached();
140     }
141     return n;
142   }
143
144   public synchronized int read(byte[] b, int off, int len) throws IOException JavaDoc {
145     if (marked_index == -1) {
146       throw new IOException JavaDoc("No mark has been read yet.");
147     }
148     int read_upto = marked_index + len;
149     if (read_upto > marked_length) {
150       String JavaDoc debug_msg = "Read over end of length marked buffer. ";
151       debug_msg += "(marked_index=" + marked_index;
152       debug_msg += ",len=" + len;
153       debug_msg += ",marked_length=" + marked_length + ")";
154       throw new IOException JavaDoc(debug_msg);
155     }
156     System.arraycopy(buf, marked_index, b, off, len);
157     marked_index = read_upto;
158     if (marked_index >= marked_length) {
159       handleEndReached();
160     }
161     return len;
162   }
163
164   public synchronized int available() throws IOException JavaDoc {
165     // This method only returns a non 0 value if there is a complete command
166
// waiting on the stream.
167
if (marked_length >= 0) {
168       return (marked_length - marked_index);
169     }
170     return 0;
171   }
172
173   public boolean markSupported() {
174     return false;
175   }
176
177   // ---------- These methods aid in reading state from the stream ----------
178

179   /**
180    * Checks to see if there is a complete command waiting on the input stream.
181    * Returns true if there is. If this method returns true then it is safe
182    * to go ahead and process a single command from this stream.
183    * This will return true only once while there is a command pending until
184    * that command is completely read in.
185    * <p>
186    * 'max_size' is the maximum number of bytes we are allowing before an
187    * IOException is thrown.
188    */

189   public synchronized boolean pollForCommand(int max_size) throws IOException JavaDoc {
190     if (marked_length == -1) {
191       int available = in.available();
192 // System.out.print(available);
193
// System.out.print(", ");
194
if (count > 0 || available > 0) {
195         if ((count + available) > max_size) {
196           throw new IOException JavaDoc("Marked length is greater than max size ( " +
197                                 (count + available) + " > " + max_size + " )");
198         }
199
200         ensureCapacity(count + available);
201         int read_in = in.read(buf, count, available);
202
203 // System.out.println("-----");
204
// for (int i = 0; i < available; ++i) {
205
// System.out.print((char) buf[count + i] +
206
// "(" + (int) buf[count + i] + "),");
207
// }
208
// System.out.println("-----");
209

210
211         if (read_in == -1) {
212           throw new EOFException JavaDoc();
213         }
214         count = count + read_in;
215
216 // else if (read_in != available) {
217
// throw new IOException("Read in size mismatch: " +
218
// "read_in: " + read_in + " available: " + available);
219
// }
220

221         // Check: Is a complete command available?
222
if (count >= 4) {
223           int length_marker = (((buf[0] & 0x0FF) << 24) +
224                                ((buf[1] & 0x0FF) << 16) +
225                                ((buf[2] & 0x0FF) << 8) +
226                                ((buf[3] & 0x0FF) << 0));
227           if (count >= length_marker + 4) {
228             // Yes, complete command available.
229
// mark this area up.
230
marked_length = length_marker + 4;
231             marked_index = 4;
232 // System.out.println("Complete command available: ");
233
// System.out.println("Length: " + marked_length +
234
// ", Index: " + marked_index);
235
return true;
236           }
237         }
238       }
239     }
240     return false;
241   }
242
243   /**
244    * Blocks until a complete command has been read in.
245    */

246   public synchronized void blockForCommand() throws IOException JavaDoc {
247     while (true) {
248
249       // Is there a command available?
250
if (count >= 4) {
251         int length_marker = (((buf[0] & 0x0FF) << 24) +
252                              ((buf[1] & 0x0FF) << 16) +
253                              ((buf[2] & 0x0FF) << 8) +
254                              ((buf[3] & 0x0FF) << 0));
255         if (count >= length_marker + 4) {
256           // Yes, complete command available.
257
// mark this area up.
258
marked_length = length_marker + 4;
259           marked_index = 4;
260 // System.out.println("marked_length = " + marked_length);
261
// System.out.println("marked_index = " + marked_index);
262
return;
263         }
264       }
265
266       // If the buffer is full grow it larger.
267
if (count >= buf.length) {
268         ensureCapacity(count + INITIAL_BUFFER_SIZE);
269       }
270       // Read in a block of data, block if nothing there
271
int read_in = in.read(buf, count, buf.length - count);
272       if (read_in == -1) {
273         throw new EOFException JavaDoc();
274       }
275       count += read_in;
276     }
277   }
278
279 }
280
Popular Tags