KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > connector > InputBuffer


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.catalina.connector;
19
20 import java.io.IOException JavaDoc;
21 import java.io.Reader JavaDoc;
22 import java.security.AccessController JavaDoc;
23 import java.security.PrivilegedActionException JavaDoc;
24 import java.security.PrivilegedExceptionAction JavaDoc;
25 import java.util.HashMap JavaDoc;
26
27 import org.apache.catalina.security.SecurityUtil;
28 import org.apache.coyote.Request;
29 import org.apache.tomcat.util.buf.B2CConverter;
30 import org.apache.tomcat.util.buf.ByteChunk;
31 import org.apache.tomcat.util.buf.CharChunk;
32
33
34 /**
35  * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3
36  * OutputBuffer, adapted to handle input instead of output. This allows
37  * complete recycling of the facade objects (the ServletInputStream and the
38  * BufferedReader).
39  *
40  * @author Remy Maucherat
41  */

42 public class InputBuffer extends Reader JavaDoc
43     implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
44                CharChunk.CharOutputChannel {
45
46
47     // -------------------------------------------------------------- Constants
48

49
50     public static final String JavaDoc DEFAULT_ENCODING =
51         org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
52     public static final int DEFAULT_BUFFER_SIZE = 8*1024;
53
54     // The buffer can be used for byte[] and char[] reading
55
// ( this is needed to support ServletInputStream and BufferedReader )
56
public final int INITIAL_STATE = 0;
57     public final int CHAR_STATE = 1;
58     public final int BYTE_STATE = 2;
59
60
61     // ----------------------------------------------------- Instance Variables
62

63
64     /**
65      * The byte buffer.
66      */

67     private ByteChunk bb;
68
69
70     /**
71      * The chunk buffer.
72      */

73     private CharChunk cb;
74
75
76     /**
77      * State of the output buffer.
78      */

79     private int state = 0;
80
81
82     /**
83      * Number of bytes read.
84      */

85     private int bytesRead = 0;
86
87
88     /**
89      * Number of chars read.
90      */

91     private int charsRead = 0;
92
93
94     /**
95      * Flag which indicates if the input buffer is closed.
96      */

97     private boolean closed = false;
98
99
100     /**
101      * Byte chunk used to input bytes.
102      */

103     private ByteChunk inputChunk = new ByteChunk();
104
105
106     /**
107      * Encoding to use.
108      */

109     private String JavaDoc enc;
110
111
112     /**
113      * Encoder is set.
114      */

115     private boolean gotEnc = false;
116
117
118     /**
119      * List of encoders.
120      */

121     protected HashMap JavaDoc encoders = new HashMap JavaDoc();
122
123
124     /**
125      * Current byte to char converter.
126      */

127     protected B2CConverter conv;
128
129
130     /**
131      * Associated Coyote request.
132      */

133     private Request coyoteRequest;
134
135
136     /**
137      * Buffer position.
138      */

139     private int markPos = -1;
140
141
142     /**
143      * Buffer size.
144      */

145     private int size = -1;
146
147
148     // ----------------------------------------------------------- Constructors
149

150
151     /**
152      * Default constructor. Allocate the buffer with the default buffer size.
153      */

154     public InputBuffer() {
155
156         this(DEFAULT_BUFFER_SIZE);
157
158     }
159
160
161     /**
162      * Alternate constructor which allows specifying the initial buffer size.
163      *
164      * @param size Buffer size to use
165      */

166     public InputBuffer(int size) {
167
168         this.size = size;
169         bb = new ByteChunk(size);
170         bb.setLimit(size);
171         bb.setByteInputChannel(this);
172         cb = new CharChunk(size);
173         cb.setLimit(size);
174         cb.setOptimizedWrite(false);
175         cb.setCharInputChannel(this);
176         cb.setCharOutputChannel(this);
177
178     }
179
180
181     // ------------------------------------------------------------- Properties
182

183
184     /**
185      * Associated Coyote request.
186      *
187      * @param coyoteRequest Associated Coyote request
188      */

189     public void setRequest(Request coyoteRequest) {
190     this.coyoteRequest = coyoteRequest;
191     }
192
193
194     /**
195      * Get associated Coyote request.
196      *
197      * @return the associated Coyote request
198      */

199     public Request getRequest() {
200         return this.coyoteRequest;
201     }
202
203
204     // --------------------------------------------------------- Public Methods
205

206
207     /**
208      * Recycle the output buffer.
209      */

210     public void recycle() {
211         
212         state = INITIAL_STATE;
213         bytesRead = 0;
214         charsRead = 0;
215         
216         // If usage of mark made the buffer too big, reallocate it
217
if (cb.getChars().length > size) {
218             cb = new CharChunk(size);
219             cb.setLimit(size);
220             cb.setOptimizedWrite(false);
221             cb.setCharInputChannel(this);
222             cb.setCharOutputChannel(this);
223         } else {
224             cb.recycle();
225         }
226         markPos = -1;
227         bb.recycle();
228         closed = false;
229         
230         if (conv != null) {
231             conv.recycle();
232         }
233         
234         gotEnc = false;
235         enc = null;
236         
237     }
238
239
240     /**
241      * Clear cached encoders (to save memory for Comet requests).
242      */

243     public void clearEncoders() {
244         encoders.clear();
245     }
246     
247     
248     /**
249      * Close the input buffer.
250      *
251      * @throws IOException An underlying IOException occurred
252      */

253     public void close()
254         throws IOException JavaDoc {
255         closed = true;
256     }
257
258
259     public int available()
260         throws IOException JavaDoc {
261         if (state == BYTE_STATE) {
262             return bb.getLength();
263         } else if (state == CHAR_STATE) {
264             return cb.getLength();
265         } else {
266             return 0;
267         }
268     }
269
270
271     // ------------------------------------------------- Bytes Handling Methods
272

273
274     /**
275      * Reads new bytes in the byte chunk.
276      *
277      * @param cbuf Byte buffer to be written to the response
278      * @param off Offset
279      * @param len Length
280      *
281      * @throws IOException An underlying IOException occurred
282      */

283     public int realReadBytes(byte cbuf[], int off, int len)
284     throws IOException JavaDoc {
285
286         if (closed)
287             return -1;
288         if (coyoteRequest == null)
289             return -1;
290
291         state = BYTE_STATE;
292
293         int result = coyoteRequest.doRead(bb);
294
295         return result;
296
297     }
298
299
300     public int readByte()
301         throws IOException JavaDoc {
302         return bb.substract();
303     }
304
305
306     public int read(byte[] b, int off, int len)
307         throws IOException JavaDoc {
308         return bb.substract(b, off, len);
309     }
310
311
312     // ------------------------------------------------- Chars Handling Methods
313

314
315     /**
316      * Since the converter will use append, it is possible to get chars to
317      * be removed from the buffer for "writing". Since the chars have already
318      * been read before, they are ignored. If a mark was set, then the
319      * mark is lost.
320      */

321     public void realWriteChars(char c[], int off, int len)
322         throws IOException JavaDoc {
323         markPos = -1;
324     }
325
326
327     public void setEncoding(String JavaDoc s) {
328         enc = s;
329     }
330
331
332     public int realReadChars(char cbuf[], int off, int len)
333         throws IOException JavaDoc {
334
335         if (!gotEnc)
336             setConverter();
337
338         if (bb.getLength() <= 0) {
339             int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
340             if (nRead < 0) {
341                 return -1;
342             }
343         }
344
345         if (markPos == -1) {
346             cb.setOffset(0);
347             cb.setEnd(0);
348         }
349
350         int limit = bb.getLength()+cb.getStart();
351         if( cb.getLimit() < limit )
352         cb.setLimit(limit);
353         conv.convert(bb, cb);
354         bb.setOffset(bb.getEnd());
355         state = CHAR_STATE;
356
357         return cb.getLength();
358
359     }
360
361
362     public int read()
363         throws IOException JavaDoc {
364         return cb.substract();
365     }
366
367
368     public int read(char[] cbuf)
369         throws IOException JavaDoc {
370         return read(cbuf, 0, cbuf.length);
371     }
372
373
374     public int read(char[] cbuf, int off, int len)
375         throws IOException JavaDoc {
376         return cb.substract(cbuf, off, len);
377     }
378
379
380     public long skip(long n)
381         throws IOException JavaDoc {
382
383         if (n < 0) {
384             throw new IllegalArgumentException JavaDoc();
385         }
386
387         long nRead = 0;
388         while (nRead < n) {
389             if (cb.getLength() >= n) {
390                 cb.setOffset(cb.getStart() + (int) n);
391                 nRead = n;
392             } else {
393                 nRead += cb.getLength();
394                 cb.setOffset(cb.getEnd());
395                 int toRead = 0;
396                 if (cb.getChars().length < (n - nRead)) {
397                     toRead = cb.getChars().length;
398                 } else {
399                     toRead = (int) (n - nRead);
400                 }
401                 int nb = realReadChars(cb.getChars(), 0, toRead);
402                 if (nb < 0)
403                     break;
404             }
405         }
406
407         return nRead;
408
409     }
410
411
412     public boolean ready()
413         throws IOException JavaDoc {
414         return (cb.getLength() > 0);
415     }
416
417
418     public boolean markSupported() {
419         return true;
420     }
421
422
423     public void mark(int readAheadLimit)
424         throws IOException JavaDoc {
425         if (cb.getLength() <= 0) {
426             cb.setOffset(0);
427             cb.setEnd(0);
428         } else {
429             if ((cb.getBuffer().length > (2 * size))
430                 && (cb.getLength()) < (cb.getStart())) {
431                 System.arraycopy(cb.getBuffer(), cb.getStart(),
432                                  cb.getBuffer(), 0, cb.getLength());
433                 cb.setEnd(cb.getLength());
434                 cb.setOffset(0);
435             }
436         }
437         int offset = readAheadLimit;
438         if (offset < size) {
439             offset = size;
440         }
441         cb.setLimit(cb.getStart() + offset);
442         markPos = cb.getStart();
443     }
444
445
446     public void reset()
447         throws IOException JavaDoc {
448         if (state == CHAR_STATE) {
449             if (markPos < 0) {
450                 cb.recycle();
451                 markPos = -1;
452                 throw new IOException JavaDoc();
453             } else {
454                 cb.setOffset(markPos);
455             }
456         } else {
457             bb.recycle();
458         }
459     }
460
461
462     public void checkConverter()
463         throws IOException JavaDoc {
464
465         if (!gotEnc)
466             setConverter();
467
468     }
469
470
471     protected void setConverter()
472         throws IOException JavaDoc {
473
474         if (coyoteRequest != null)
475             enc = coyoteRequest.getCharacterEncoding();
476
477         gotEnc = true;
478         if (enc == null)
479             enc = DEFAULT_ENCODING;
480         conv = (B2CConverter) encoders.get(enc);
481         if (conv == null) {
482             if (SecurityUtil.isPackageProtectionEnabled()){
483                 try{
484                     conv = (B2CConverter)AccessController.doPrivileged(
485                             new PrivilegedExceptionAction JavaDoc(){
486
487                                 public Object JavaDoc run() throws IOException JavaDoc{
488                                     return new B2CConverter(enc);
489                                 }
490
491                             }
492                     );
493                 }catch(PrivilegedActionException JavaDoc ex){
494                     Exception JavaDoc e = ex.getException();
495                     if (e instanceof IOException JavaDoc)
496                         throw (IOException JavaDoc)e;
497                 }
498             } else {
499                 conv = new B2CConverter(enc);
500             }
501             encoders.put(enc, conv);
502         }
503
504     }
505
506 }
507
Popular Tags