KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > oreilly > servlet > multipart > BufferedServletInputStream


1 // Copyright (C) 1999-2001 by Jason Hunter <jhunter_AT_acm_DOT_org>.
2
// All rights reserved. Use of this class is limited.
3
// Please see the LICENSE for more information.
4

5 package com.oreilly.servlet.multipart;
6
7 import java.io.IOException JavaDoc;
8
9 import javax.servlet.ServletInputStream JavaDoc;
10
11 /**
12  * A <code>BufferedServletInputStream</code> wraps a
13  * <code>ServletInputStream</code> in order to provide input buffering and to
14  * avoid calling the the <code>readLine</code> method of the wrapped
15  * <code>ServletInputStream</code>.
16  * <p>
17  * This is necessary because some servlet containers rely on the default
18  * implementation of the <code>readLine</code> method provided by the Servlet
19  * API classes, which is very slow. Tomcat 3.2, Tomcat 3.1, the JSWDK 1.0 web
20  * server and the JSDK2.1 web server are all known to need this class for
21  * performance reasons.
22  * <p>
23  * Also, it may be used to work around a bug in the Servlet API 2.0
24  * implementation of <code>readLine</code> which contains a bug that causes
25  * <code>ArrayIndexOutOfBoundsExceptions</code> under certain conditions.
26  * Apache JServ is known to suffer from this bug.
27  *
28  * @author Geoff Soutter
29  * @version 1.1, 2001/05/21, removed block of commented out code
30  * @version 1.0, 2000/10/27, initial revision
31  */

32 public class BufferedServletInputStream extends ServletInputStream JavaDoc {
33   
34   /** input stream we are filtering */
35   private ServletInputStream JavaDoc in;
36   
37   /** our buffer */
38   private byte[] buf = new byte[64*1024]; // 64k
39

40   /** number of bytes we've read into the buffer */
41   private int count;
42   
43   /** current position in the buffer */
44   private int pos;
45   
46   /**
47    * Creates a <code>BufferedServletInputStream</code> that wraps the provided
48    * <code>ServletInputStream</code>.
49    *
50    * @param in a servlet input stream.
51    */

52   public BufferedServletInputStream(ServletInputStream JavaDoc in) {
53     this.in = in;
54   }
55
56   /**
57    * Fill up our buffer from the underlying input stream. Users of this
58    * method must ensure that they use all characters in the buffer before
59    * calling this method.
60    *
61    * @exception IOException if an I/O error occurs.
62    */

63   private void fill() throws IOException JavaDoc {
64     int i = in.read(buf, 0, buf.length);
65     if (i > 0) {
66       pos = 0;
67       count = i;
68     }
69   }
70     
71   /**
72    * Implement buffering on top of the <code>readLine</code> method of
73    * the wrapped <code>ServletInputStream</code>.
74    *
75    * @param b an array of bytes into which data is read.
76    * @param off an integer specifying the character at which
77    * this method begins reading.
78    * @param len an integer specifying the maximum number of
79    * bytes to read.
80    * @return an integer specifying the actual number of bytes
81    * read, or -1 if the end of the stream is reached.
82    * @exception IOException if an I/O error occurs.
83    */

84   public int readLine(byte b[], int off, int len) throws IOException JavaDoc {
85     int total = 0;
86     if (len == 0) {
87       return 0;
88     }
89     
90     int avail = count - pos;
91     if (avail <= 0) {
92       fill();
93       avail = count - pos;
94       if (avail <= 0) {
95         return -1;
96       }
97     }
98     int copy = Math.min(len, avail);
99     int eol = findeol(buf, pos, copy);
100     if (eol != -1) {
101       copy = eol;
102     }
103     System.arraycopy(buf, pos, b, off, copy);
104     pos += copy;
105     total += copy;
106     
107     while (total < len && eol == -1) {
108       fill();
109       avail = count - pos;
110       if(avail <= 0) {
111         return total;
112       }
113       copy = Math.min(len - total, avail);
114       eol = findeol(buf, pos, copy);
115       if (eol != -1) {
116         copy = eol;
117       }
118       System.arraycopy(buf, pos, b, off + total, copy);
119       pos += copy;
120       total += copy;
121     }
122     return total;
123   }
124
125   /**
126    * Attempt to find the '\n' end of line marker as defined in the comment of
127    * the <code>readLine</code> method of <code>ServletInputStream</code>.
128    *
129    * @param b byte array to search.
130    * @param pos position in byte array to search from.
131    * @param len maximum number of bytes to search.
132    *
133    * @return the number of bytes including the \n, or -1 if none found.
134    */

135   private static int findeol(byte b[], int pos, int len) {
136     int end = pos + len;
137     int i = pos;
138     while (i < end) {
139       if (b[i++] == '\n') {
140         return i - pos;
141       }
142     }
143     return -1;
144   }
145   
146   /**
147    * Implement buffering on top of the <code>read</code> method of
148    * the wrapped <code>ServletInputStream</code>.
149    *
150    * @return the next byte of data, or <code>-1</code> if the end of the
151    * stream is reached.
152    * @exception IOException if an I/O error occurs.
153    */

154   public int read() throws IOException JavaDoc {
155     if (count <= pos) {
156       fill();
157       if (count <= pos) {
158         return -1;
159       }
160     }
161     return buf[pos++] & 0xff;
162   }
163
164   /**
165    * Implement buffering on top of the <code>read</code> method of
166    * the wrapped <code>ServletInputStream</code>.
167    *
168    * @param b the buffer into which the data is read.
169    * @param off the start offset of the data.
170    * @param len the maximum number of bytes read.
171    * @return the total number of bytes read into the buffer, or
172    * <code>-1</code> if there is no more data because the end
173    * of the stream has been reached.
174    * @exception IOException if an I/O error occurs.
175    */

176   public int read(byte b[], int off, int len) throws IOException JavaDoc
177   {
178     int total = 0;
179     while (total < len) {
180       int avail = count - pos;
181       if (avail <= 0) {
182         fill();
183         avail = count - pos;
184         if(avail <= 0) {
185           if (total > 0)
186             return total;
187           else
188             return -1;
189         }
190       }
191       int copy = Math.min(len - total, avail);
192       System.arraycopy(buf, pos, b, off + total, copy);
193       pos += copy;
194       total += copy;
195     }
196     return total;
197   }
198 }
199
Popular Tags