KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > coyote > tomcat5 > InputBuffer


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  *
21  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
22  *
23  * Portions Copyright Apache Software Foundation.
24  */

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

50 public class InputBuffer extends Reader JavaDoc
51     implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
52                CharChunk.CharOutputChannel {
53
54     private static com.sun.org.apache.commons.logging.Log log=
55         com.sun.org.apache.commons.logging.LogFactory.getLog( InputBuffer.class );
56
57     // -------------------------------------------------------------- Constants
58

59
60     public static final String JavaDoc DEFAULT_ENCODING =
61         org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
62     public static final int DEFAULT_BUFFER_SIZE = 8*1024;
63     static final int debug = 0;
64
65
66     // The buffer can be used for byte[] and char[] reading
67
// ( this is needed to support ServletInputStream and BufferedReader )
68
public final int INITIAL_STATE = 0;
69     public final int CHAR_STATE = 1;
70     public final int BYTE_STATE = 2;
71
72
73     // ----------------------------------------------------- Instance Variables
74

75
76     /**
77      * The byte buffer.
78      */

79     private ByteChunk bb;
80
81
82     /**
83      * The chunk buffer.
84      */

85     private CharChunk cb;
86
87
88     /**
89      * State of the output buffer.
90      */

91     private int state = 0;
92
93
94     /**
95      * Number of bytes read.
96      */

97     private int bytesRead = 0;
98
99
100     /**
101      * Number of chars read.
102      */

103     private int charsRead = 0;
104
105
106     /**
107      * Flag which indicates if the input buffer is closed.
108      */

109     private boolean closed = false;
110
111
112     /**
113      * Byte chunk used to input bytes.
114      */

115     private ByteChunk inputChunk = new ByteChunk();
116
117
118     /**
119      * Encoding to use.
120      */

121     private String JavaDoc enc;
122
123
124     /**
125      * Encoder is set.
126      */

127     private boolean gotEnc = false;
128
129
130     /**
131      * List of encoders.
132      */

133     protected HashMap JavaDoc encoders = new HashMap JavaDoc();
134
135
136     /**
137      * Current byte to char converter.
138      */

139     protected B2CConverter conv;
140
141
142     /**
143      * Associated Coyote request.
144      */

145     private Request coyoteRequest;
146
147
148     /**
149      * Buffer position.
150      */

151     private int markPos = -1;
152
153
154     /**
155      * Buffer size.
156      */

157     private int size = -1;
158
159
160     // ----------------------------------------------------------- Constructors
161

162
163     /**
164      * Default constructor. Allocate the buffer with the default buffer size.
165      */

166     public InputBuffer() {
167
168         this(DEFAULT_BUFFER_SIZE);
169
170     }
171
172
173     /**
174      * Alternate constructor which allows specifying the initial buffer size.
175      *
176      * @param size Buffer size to use
177      */

178     public InputBuffer(int size) {
179         
180         this.size = size;
181         bb = new ByteChunk(size);
182         bb.setLimit(size);
183         bb.setByteInputChannel(this);
184     }
185     
186     
187     // START OF SJSAS 6231069
188
private void initChar() {
189         if (cb != null)
190             return;
191         cb = new CharChunk(size);
192         cb.setLimit(size);
193         cb.setOptimizedWrite(false);
194         cb.setCharInputChannel(this);
195         cb.setCharOutputChannel(this);
196     }
197     // END OF SJSAS 6231069
198
// ------------------------------------------------------------- Properties
199

200
201     /**
202      * Associated Coyote request.
203      *
204      * @param coyoteRequest Associated Coyote request
205      */

206     public void setRequest(Request coyoteRequest) {
207     this.coyoteRequest = coyoteRequest;
208     }
209
210
211     /**
212      * Get associated Coyote request.
213      *
214      * @return the associated Coyote request
215      */

216     public Request getRequest() {
217         return this.coyoteRequest;
218     }
219
220
221     // --------------------------------------------------------- Public Methods
222

223
224     /**
225      * Recycle the output buffer.
226      */

227     public void recycle() {
228
229         if (log.isTraceEnabled())
230             log.trace("recycle()");
231
232         state = INITIAL_STATE;
233         bytesRead = 0;
234         charsRead = 0;
235
236         // START OF SJSAS 6231069
237
/*
238         // If usage of mark made the buffer too big, reallocate it
239         if (cb.getChars().length > size) {
240             cb = new CharChunk(size);
241             cb.setLimit(size);
242             cb.setCharInputChannel(this);
243             cb.setCharOutputChannel(this);
244         } else {
245             cb.recycle();
246         }
247         */

248         cb = null;
249         // END OF SJSAS 6231069
250

251         bb.recycle();
252         markPos = -1;
253         closed = false;
254
255         if (conv != null) {
256             conv.recycle();
257         }
258
259         gotEnc = false;
260         enc = null;
261
262     }
263
264
265     /**
266      * Close the input buffer.
267      *
268      * @throws IOException An underlying IOException occurred
269      */

270     public void close()
271         throws IOException JavaDoc {
272         closed = true;
273     }
274
275
276     public int available()
277         throws IOException JavaDoc {
278         if (state == BYTE_STATE) {
279             return bb.getLength();
280         } else if (state == CHAR_STATE) {
281             return cb.getLength();
282         } else {
283             return 0;
284         }
285     }
286
287
288     // ------------------------------------------------- Bytes Handling Methods
289

290
291     /**
292      * Reads new bytes in the byte chunk.
293      *
294      * @param buf Byte buffer to be written to the response
295      * @param off Offset
296      * @param cnt Length
297      *
298      * @throws IOException An underlying IOException occurred
299      */

300     public int realReadBytes(byte cbuf[], int off, int len)
301     throws IOException JavaDoc {
302
303         if (log.isDebugEnabled())
304             log.debug("realRead() " + coyoteRequest);
305
306         if (closed)
307             return -1;
308         if (coyoteRequest == null)
309             return -1;
310
311         state = BYTE_STATE;
312
313         int result = coyoteRequest.doRead(bb);
314
315         return result;
316
317     }
318
319
320     public int readByte()
321         throws IOException JavaDoc {
322         return bb.substract();
323     }
324
325
326     public int read(byte[] b, int off, int len)
327         throws IOException JavaDoc {
328         return bb.substract(b, off, len);
329     }
330
331
332     // ------------------------------------------------- Chars Handling Methods
333

334
335     /**
336      * Since the converter will use append, it is possible to get chars to
337      * be removed from the buffer for "writing". Since the chars have already
338      * been read before, they are ignored. If a mark was set, then the
339      * mark is lost.
340      */

341     public void realWriteChars(char c[], int off, int len)
342         throws IOException JavaDoc {
343         // START OF SJSAS 6231069
344
initChar();
345         // END OF SJSAS 6231069
346
markPos = -1;
347     }
348
349
350     public void setEncoding(String JavaDoc s) {
351         enc = s;
352     }
353
354
355     public int realReadChars(char cbuf[], int off, int len)
356         throws IOException JavaDoc {
357
358         // START OF SJSAS 6231069
359
initChar();
360         // END OF SJSAS 6231069
361
if (log.isDebugEnabled())
362             log.debug("realRead() " + cb.getOffset() + " " + len);
363
364         if (!gotEnc)
365             setConverter();
366
367         if (log.isDebugEnabled())
368             log.debug("encoder: " + conv + " " + gotEnc);
369
370         if (bb.getLength() <= 0) {
371             int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
372             if (nRead < 0) {
373                 return -1;
374             }
375         }
376
377         int limit = bb.getLength()+cb.getStart();
378         if ( cb.getLimit() < limit )
379             cb.setLimit(limit);
380
381         if (markPos == -1) {
382             cb.setOffset(0);
383             cb.setEnd(0);
384         }
385
386         conv.convert(bb, cb);
387         bb.setOffset(bb.getEnd());
388         state = CHAR_STATE;
389
390         return cb.getLength();
391
392     }
393
394
395     public int read()
396         throws IOException JavaDoc {
397         // START OF SJSAS 6231069
398
initChar();
399         // END OF SJSAS 6231069
400
return cb.substract();
401     }
402
403
404     public int read(char[] cbuf)
405         throws IOException JavaDoc {
406         // START OF SJSAS 6231069
407
initChar();
408         // END OF SJSAS 6231069
409
return read(cbuf, 0, cbuf.length);
410     }
411
412
413     public int read(char[] cbuf, int off, int len)
414         throws IOException JavaDoc {
415         // START OF SJSAS 6231069
416
initChar();
417         // END OF SJSAS 6231069
418
return cb.substract(cbuf, off, len);
419     }
420
421
422     public long skip(long n)
423         throws IOException JavaDoc {
424
425         if (n < 0) {
426             throw new IllegalArgumentException JavaDoc();
427         }
428
429         // START OF SJSAS 6231069
430
initChar();
431         // END OF SJSAS 6231069
432
long nRead = 0;
433         while (nRead < n) {
434             if (cb.getLength() >= n) {
435                 cb.setOffset(cb.getStart() + (int) n);
436                 nRead = n;
437             } else {
438                 nRead += cb.getLength();
439                 cb.setOffset(cb.getEnd());
440                 int toRead = 0;
441                 if (cb.getChars().length < (n - nRead)) {
442                     toRead = cb.getChars().length;
443                 } else {
444                     toRead = (int) (n - nRead);
445                 }
446                 int nb = realReadChars(cb.getChars(), 0, toRead);
447                 if (nb < 0)
448                     break;
449             }
450         }
451
452         return nRead;
453
454     }
455
456
457     public boolean ready()
458         throws IOException JavaDoc {
459         // START OF SJSAS 6231069
460
initChar();
461         // END OF SJSAS 6231069
462
return (cb.getLength() > 0);
463     }
464
465
466     public boolean markSupported() {
467         return true;
468     }
469
470
471     public void mark(int readAheadLimit)
472         throws IOException JavaDoc {
473         // START OF SJSAS 6231069
474
initChar();
475         // END OF SJSAS 6231069
476
if (cb.getLength() <= 0) {
477             cb.setOffset(0);
478             cb.setEnd(0);
479         } else {
480             if ((cb.getBuffer().length > (2 * size))
481                 && (cb.getLength()) < (cb.getStart())) {
482                 System.arraycopy(cb.getBuffer(), cb.getStart(),
483                                  cb.getBuffer(), 0, cb.getLength());
484                 cb.setEnd(cb.getLength());
485                 cb.setOffset(0);
486             }
487         }
488         int offset = readAheadLimit;
489         if (offset < size) {
490             offset = size;
491         }
492         cb.setLimit(cb.getStart() + offset);
493         markPos = cb.getStart();
494     }
495
496
497     public void reset()
498         throws IOException JavaDoc {
499         if (state == CHAR_STATE) {
500             if (markPos < 0) {
501                 cb.recycle();
502                 markPos = -1;
503                 throw new IOException JavaDoc();
504             } else {
505                 cb.setOffset(markPos);
506             }
507         } else {
508             bb.recycle();
509         }
510     }
511
512
513     public void checkConverter()
514         throws IOException JavaDoc {
515
516         if (!gotEnc)
517             setConverter();
518
519     }
520
521
522     protected void setConverter()
523         throws IOException JavaDoc {
524
525         if (coyoteRequest != null)
526             enc = coyoteRequest.getCharacterEncoding();
527
528         if (log.isDebugEnabled())
529             log.debug("Got encoding: " + enc);
530
531         gotEnc = true;
532         if (enc == null)
533             enc = DEFAULT_ENCODING;
534         conv = (B2CConverter) encoders.get(enc);
535         if (conv == null) {
536             if (SecurityUtil.isPackageProtectionEnabled()){
537                 try{
538                     conv = (B2CConverter)AccessController.doPrivileged(
539                             new PrivilegedExceptionAction JavaDoc(){
540
541                                 public Object JavaDoc run() throws IOException JavaDoc{
542                                     return new B2CConverter(enc);
543                                 }
544
545                             }
546                     );
547                 }catch(PrivilegedActionException JavaDoc ex){
548                     Exception JavaDoc e = ex.getException();
549                     if (e instanceof IOException JavaDoc)
550                         throw (IOException JavaDoc)e;
551                     
552                     if (log.isDebugEnabled())
553                         log.debug("setConverter: " + ex.getMessage());
554                 }
555             } else {
556                 conv = new B2CConverter(enc);
557             }
558             encoders.put(enc, conv);
559         }
560
561     }
562 }
563
Popular Tags