Annotation of java/classes/org/w3c/jigsaw/servlet/JigsawHttpServletResponse.java, revision 1.33

1.1       abaird      1: // JigsawHttpServletReponse.java
1.33    ! bmahe       2: // $Id: JigsawHttpServletResponse.java,v 1.31.4.6 2000/02/11 13:07:12 bmahe Exp $
1.1       abaird      3: // (c) COPYRIGHT MIT and INRIA, 1996.
                      4: // Please first read the full copyright statement in file COPYRIGHT.html
                      5: 
1.10      bmahe       6: package org.w3c.jigsaw.servlet;
1.1       abaird      7: 
                      8: import java.io.*;
1.6       bmahe       9: import javax.servlet.*;
                     10: import javax.servlet.http.*;
1.4       abaird     11: import java.net.*;
1.33    ! bmahe      12: import java.util.Locale;
1.1       abaird     13: 
1.10      bmahe      14: import org.w3c.www.mime.*;
                     15: import org.w3c.www.http.*;
                     16: import org.w3c.jigsaw.http.*;
1.33    ! bmahe      17: import org.w3c.www.http.HeaderValue;
1.2       abaird     18: 
                     19: /**
1.30      bmahe      20:  * @author Alexandre Rafalovitch <alex@access.com.au>
                     21:  * @author Anselm Baird-Smith <abaird@w3.org>
                     22:  * @author Benoît Mahé (bmahe@w3.org)
                     23:  * @author Roland Mainz (Roland.Mainz@informatik.med.uni-giessen.de)
1.2       abaird     24:  */
1.1       abaird     25: 
1.29      bmahe      26: public class JigsawHttpServletResponse implements HttpServletResponse {
                     27: 
1.33    ! bmahe      28:     public final static String CHARSET_PARAMETER = "charset";
        !            29: 
        !            30:     public final static int DEFAULT_BUFFER_SIZE   = 8 * 1024; // 8KB buffer
        !            31:     public final static int MIN_BUFFER_SIZE       = 4 * 1024; // 4KB buffer
        !            32: 
1.31      ylafon     33:     private final static int STATE_INITIAL        = 0;
                     34:     private final static int STATE_HEADERS_DONE   = 1;
                     35:     private final static int STATE_ALL_DONE       = 2;
1.11      bmahe      36:     private final static int STREAM_STATE_INITIAL = 0;
1.31      ylafon     37:     private final static int STREAM_WRITER_USED   = 1;
                     38:     private final static int OUTPUT_STREAM_USED   = 2;
1.11      bmahe      39: 
                     40:     private int stream_state = STREAM_STATE_INITIAL;
1.20      bmahe      41: 
                     42:     private JigsawServletOutputStream output = null;
                     43:     private PrintWriter               writer = null;
1.7       bmahe      44:  
1.30      bmahe      45:     private MimeTypeFormatException setContentTypeException = null;
                     46: 
                     47:     // servlet has set a fixed content length or not, 
                     48:     // and cut (see flushStream) any data which are too much here...
                     49:     private final static int CALC_CONTENT_LENGTH = -1; 
                     50:     private              int fixedContentLength  = CALC_CONTENT_LENGTH;
                     51: 
1.33    ! bmahe      52:     // Our Locale
        !            53:     protected Locale locale;
        !            54: 
1.29      bmahe      55:     /**
                     56:      * Our temp stream.
                     57:      */
                     58:     protected ByteArrayOutputStream out = null;
                     59: 
1.14      bmahe      60:     protected JigsawHttpServletRequest jrequest = null;
                     61: 
1.33    ! bmahe      62:     protected int buffer_size;
        !            63: 
1.14      bmahe      64:     protected void setServletRequest(JigsawHttpServletRequest jrequest) {
                     65:        this.jrequest = jrequest;
                     66:     }
                     67: 
1.7       bmahe      68:     public static final 
1.29      bmahe      69:        String INCLUDED = "org.w3c.jigsaw.servlet.included";
1.28      bmahe      70: 
1.1       abaird     71:     int   state = STATE_INITIAL;
                     72:     Reply reply = null;
                     73:     Request request = null;
                     74:     
1.18      bmahe      75:     /**
                     76:      * Sets the content length for this response. 
                     77:      * @param len - the content length 
                     78:      */
1.5       abaird     79:     public void setContentLength(int i) {
1.30      bmahe      80:        fixedContentLength = i;
1.1       abaird     81:        reply.setContentLength(i);
                     82:     }
1.18      bmahe      83: 
                     84:     /**
                     85:      * Sets the content type for this response. This type may later be 
                     86:      * implicitly modified by addition of properties such as the MIME
                     87:      * charset=<value> if the service finds it necessary, and the appropriate
                     88:      * media type property has not been set.
                     89:      * <p>This response property may only be assigned one time. If a writer 
                     90:      * is to be used to write a text response, this method must be
                     91:      * called before the method getWriter. If an output stream will be used 
                     92:      * to write a response, this method must be called before the
                     93:      * output stream is used to write response data. 
                     94:      * @param spec - the content's MIME type 
1.27      ylafon     95:      * @see JigsawHttpServletResponse#getOutputStream
                     96:      * @see JigsawHttpServletResponse#getWriter
1.18      bmahe      97:      */    
1.5       abaird     98:     public void setContentType(String spec) {
1.1       abaird     99:        try {
                    100:            MimeType type= new MimeType(spec);
                    101:            reply.setContentType(type);
1.30      bmahe     102:            setContentTypeException = null;
1.1       abaird    103:        } catch(MimeTypeFormatException ex) {
1.30      bmahe     104:            //store exception
                    105:            setContentTypeException = ex;
1.1       abaird    106:        }
                    107:     }
1.5       abaird    108: 
1.28      bmahe     109:     protected boolean isStreamObtained() {
                    110:        return (stream_state != STREAM_STATE_INITIAL);
                    111:     }
                    112: 
1.29      bmahe     113:     protected Reply getReply() {
                    114:        return reply;
                    115:     }
                    116: 
1.18      bmahe     117:     /**
                    118:      * Returns an output stream for writing binary response data.
1.24      bmahe     119:      * @return A ServletOutputStream
1.18      bmahe     120:      * @exception IOException if an I/O exception has occurred 
                    121:      * @exception IllegalStateException if getWriter has been called on this 
                    122:      * same request. 
1.27      ylafon    123:      * @see JigsawHttpServletResponse#getWriter
1.18      bmahe     124:      */    
1.5       abaird    125:     public synchronized ServletOutputStream getOutputStream()
                    126:        throws IOException
                    127:     {
1.12      bmahe     128:        if (stream_state == STREAM_WRITER_USED)
                    129:            throw new IllegalStateException("Writer used");
                    130:        stream_state = OUTPUT_STREAM_USED;
                    131:        return getJigsawOutputStream();
1.11      bmahe     132:     }
                    133: 
                    134:     protected ServletOutputStream getJigsawOutputStream()
                    135:        throws IOException
                    136:     {
1.12      bmahe     137:        if ( output != null )
                    138:            return output;
1.30      bmahe     139: 
                    140:        // any exception during setContentType ?    
                    141:        if( setContentTypeException != null ) {
                    142:            // "wrap" the exception from setContentType in an IOException
1.33    ! bmahe     143:            throw new IOException("Illegal Content Type: "+
1.30      bmahe     144:                                  setContentTypeException.toString());
                    145:        }
                    146: 
                    147:        if( request.hasState(INCLUDED) ) {
                    148:            out = new ByteArrayOutputStream();
                    149:            output = new JigsawServletOutputStream(this, 
1.33    ! bmahe     150:                                                   new DataOutputStream(out),
        !           151:                                                   buffer_size);
1.30      bmahe     152:        } else {
1.33    ! bmahe     153:            output = new JigsawServletOutputStream(this, reply, buffer_size);
1.30      bmahe     154:        }
1.5       abaird    155:        return output;
1.1       abaird    156:     }
1.29      bmahe     157: 
1.18      bmahe     158:     /**
                    159:      * Sets the status code and message for this response. If the field had
                    160:      * already been set, the new value overwrites the previous one. The message
                    161:      * is sent as the body of an HTML page, which is returned to the user to
                    162:      * describe the problem. The page is sent with a default HTML header; the
                    163:      * message is enclosed in simple body tags (<body></body>).
                    164:      * @param i - the status code 
                    165:      * @param reason - the status message
1.28      bmahe     166:      * @deprecated since jsdk2.1
1.18      bmahe     167:      */
1.5       abaird    168:     public void setStatus(int i, String reason) {
1.1       abaird    169:        reply.setStatus(i);
                    170:        reply.setReason(reason);
                    171:     }
                    172:     
1.18      bmahe     173:     /**
                    174:      * Sets the status code for this response. This method is used to set the
                    175:      * return status code when there is no error (for example, for the status
                    176:      * codes SC_OK or SC_MOVED_TEMPORARILY). If there is an error, the 
                    177:      * sendError method should be used instead.
                    178:      * @param i - the status code 
1.27      ylafon    179:      * @see JigsawHttpServletResponse#sendError
1.18      bmahe     180:      */
1.5       abaird    181:     public void setStatus(int i) {
1.1       abaird    182:        setStatus(i, reply.getStandardReason(i));
                    183:     }
                    184:     
1.18      bmahe     185:     /**
                    186:      * Adds a field to the response header with the given name and value. If
                    187:      * the field had already been set, the new value overwrites the previous
                    188:      * one. The containsHeader method can be used to test for the presence of a
                    189:      * header before setting its value.
                    190:      * @param name - the name of the header field 
                    191:      * @param value - the header field's value 
1.27      ylafon    192:      * @see JigsawHttpServletResponse#containsHeader
1.18      bmahe     193:      */
1.5       abaird    194:     public void setHeader(String name, String value) {
1.1       abaird    195:        reply.setValue(name, value);
                    196:     }
                    197:     
1.18      bmahe     198:     /**
                    199:      * Adds a field to the response header with the given name and integer
                    200:      * value. If the field had already been set, the new value overwrites the
                    201:      * previous one. The containsHeader method can be used to test for the
                    202:      * presence of a header before setting its value.
                    203:      * @param name - the name of the header field 
                    204:      * @param value - the header field's integer value 
1.27      ylafon    205:      * @see JigsawHttpServletResponse#containsHeader
1.18      bmahe     206:      */
1.5       abaird    207:     public void setIntHeader(String name, int value) {
1.1       abaird    208:        setHeader(name, String.valueOf(value));
                    209:     }
                    210:     
1.18      bmahe     211:     /**
                    212:      * Adds a field to the response header with the given name and date-valued
                    213:      * field. The date is specified in terms of milliseconds since the epoch. 
                    214:      * If the date field had already been set, the new value overwrites the
                    215:      * previous one. The containsHeader method can be used to test for the
                    216:      * presence of a header before setting its value.
                    217:      * @param name - the name of the header field 
                    218:      * @param value - the header field's date value 
1.27      ylafon    219:      * @see JigsawHttpServletResponse#containsHeader 
1.18      bmahe     220:      */
1.5       abaird    221:     public void setDateHeader(String name, long date) {
1.32      bmahe     222:        setHeader(name, HttpFactory.makeDate(date).toExternalForm());
1.1       abaird    223:     }
                    224:     
1.5       abaird    225:     public void unsetHeader(String name) {
1.1       abaird    226:        setHeader(name, null);
                    227:     }
                    228:     
1.18      bmahe     229:     /**
                    230:      * Sends an error response to the client using the specified status code
                    231:      * and descriptive message. If setStatus has previously been called, it is
                    232:      * reset to the error status code. The message is sent as the body of an
                    233:      * HTML page, which is returned to the user to describe the problem. The
                    234:      * page is sent with a default HTML header; the message is enclosed in
                    235:      * simple body tags (<body></body>).
                    236:      * @param sc - the status code 
                    237:      * @param msg - the detail message 
                    238:      * @exception IOException If an I/O error has occurred.
                    239:      */
1.5       abaird    240:     public void sendError(int i, String msg) 
                    241:        throws IOException
1.1       abaird    242:     {
                    243:        setStatus(i);
                    244:        reply.setContent(msg);
                    245:        state = STATE_ALL_DONE;
                    246:     }
1.18      bmahe     247: 
                    248:     /**
                    249:      * Sends an error response to the client using the specified status 
                    250:      * code and a default message. 
                    251:      * @param sc - the status code 
                    252:      * @exception IOException If an I/O error has occurred.
                    253:      */
1.1       abaird    254:     public void sendError(int i)
                    255:         throws IOException
                    256:     {
                    257:        setStatus(i);
                    258:        reply.setContent(reply.getStandardReason(i));
                    259:        state = STATE_ALL_DONE;
                    260:     }
                    261:     
1.18      bmahe     262:     /**
                    263:      * Sends a temporary redirect response to the client using the specified
                    264:      *  redirect location URL. The URL must be absolute (for example, 
                    265:      * https://hostname/path/file.html). Relative URLs are not permitted here. 
                    266:      * @param url - the redirect location URL 
                    267:      * @exception IOException If an I/O error has occurred. 
                    268:      */    
1.1       abaird    269:     public void sendRedirect(String url)
                    270:         throws IOException
                    271:     {
1.4       abaird    272:        URL loc = null;
                    273:        try {
                    274:            loc = new URL(request.getURL(), url);
                    275:            setStatus(SC_MOVED_TEMPORARILY);
                    276:            reply.setLocation(loc);
                    277:            state = STATE_ALL_DONE;
                    278:        } catch (Exception ex) {
                    279:            ex.printStackTrace();
                    280:        }
1.1       abaird    281:     }
1.6       bmahe     282: 
1.18      bmahe     283:     /**
                    284:      * Checks whether the response message header has a field with the
                    285:      * specified name. 
                    286:      * @param name - the header field name 
                    287:      * @return true if the response message header has a field with the 
                    288:      * specified name; false otherwise
                    289:      */
1.12      bmahe     290:     public boolean containsHeader(String header) {
                    291:        return reply.hasHeader(header);
                    292:     }
                    293: 
1.18      bmahe     294:     /**
                    295:      * Adds the specified cookie to the response. It can be called multiple 
                    296:      * times to set more than one cookie. 
                    297:      * @param cookie - the Cookie to return to the client 
                    298:      */
1.12      bmahe     299:     public void addCookie(Cookie cookie) {
1.13      bmahe     300:        HttpSetCookieList clist = reply.getSetCookie();
                    301:        if (clist == null) {
                    302:            HttpSetCookie cookies [] = new HttpSetCookie[1];
                    303:            cookies[0] = convertCookie(cookie);
                    304:            clist = new HttpSetCookieList(cookies);
                    305:        } else {
                    306:            clist.addSetCookie(convertCookie(cookie));
                    307:        }
                    308:        reply.setSetCookie(clist);
                    309:     }
1.12      bmahe     310: 
1.31      ylafon    311:     private HttpSetCookie convertCookie(Cookie cookie) {
1.13      bmahe     312:        HttpSetCookie scookie = new HttpSetCookie(true, 
                    313:                                                  cookie.getName(),
                    314:                                                  cookie.getValue());
                    315:        scookie.setComment(cookie.getComment());
                    316:        scookie.setDomain(cookie.getDomain());
                    317:        scookie.setMaxAge(cookie.getMaxAge());
                    318:        scookie.setPath(cookie.getPath());
                    319:        scookie.setSecurity(cookie.getSecure());
                    320:        scookie.setVersion(cookie.getVersion());
                    321:        return scookie;
1.12      bmahe     322:     }
                    323: 
1.18      bmahe     324:     /**
                    325:      * Encodes the specified URL for use in the sendRedirect method or, if 
                    326:      * encoding is not needed, returns the URL unchanged. The implementation 
                    327:      * of this method should include the logic to determine whether the 
                    328:      * session ID needs to be encoded in the URL.
                    329:      * Because the rules for making this determination differ from those used
                    330:      * to decide whether to encode a normal link, this method is seperate from
                    331:      * the encodeUrl method.
                    332:      * <p>All URLs sent to the HttpServletResponse.sendRedirect method should
                    333:      * be run through this method. Otherwise, URL rewriting canont be used 
                    334:      * with browsers which do not support cookies. 
                    335:      * @param url - the url to be encoded. 
                    336:      * @return the encoded URL if encoding is needed; the unchanged URL 
                    337:      * otherwise. 
1.28      bmahe     338:      * @deprecated since jsdk2.1
1.27      ylafon    339:      * @see JigsawHttpServletResponse#sendRedirect
                    340:      * @see JigsawHttpServletResponse#encodeUrl
1.18      bmahe     341:      */
1.12      bmahe     342:     public String encodeRedirectUrl(String url) {
1.19      bmahe     343:        try {
                    344:            URL redirect = new URL(url);
                    345:            URL requested = new URL(jrequest.getRequestURI());
                    346:            if ( redirect.getHost().equals(requested.getHost()) &&
                    347:                 redirect.getPort() == requested.getPort())
                    348:                return encodeUrl(url);
                    349:        } catch (MalformedURLException ex) {
                    350:            //error so return url.
                    351:            return url;
                    352:        }
                    353:        return url;
1.12      bmahe     354:     }
                    355: 
1.28      bmahe     356:         /**
                    357:      * Encodes the specified URL for use in the sendRedirect method or, if 
                    358:      * encoding is not needed, returns the URL unchanged. The implementation 
                    359:      * of this method should include the logic to determine whether the 
                    360:      * session ID needs to be encoded in the URL.
                    361:      * Because the rules for making this determination differ from those used
                    362:      * to decide whether to encode a normal link, this method is seperate from
                    363:      * the encodeUrl method.
                    364:      * <p>All URLs sent to the HttpServletResponse.sendRedirect method should
                    365:      * be run through this method. Otherwise, URL rewriting canont be used 
                    366:      * with browsers which do not support cookies. 
                    367:      * @param url - the url to be encoded. 
                    368:      * @return the encoded URL if encoding is needed; the unchanged URL 
                    369:      * otherwise. 
                    370:      * @see JigsawHttpServletResponse#sendRedirect
                    371:      * @see JigsawHttpServletResponse#encodeUrl
                    372:      */
                    373:     public String encodeRedirectURL(String url) {
                    374:        return encodeRedirectUrl(url);
                    375:     }
                    376: 
1.18      bmahe     377:     /**
                    378:      * Encodes the specified URL by including the session ID in it, or, if 
                    379:      * encoding is not needed, returns the URL unchanged. The implementation of
                    380:      * this method should include the logic to determine whether the session ID
                    381:      * needs to be encoded in the URL. For example, if the browser supports
                    382:      * cookies, or session tracking is turned off, URL encoding is unnecessary.
                    383:      * <p>All URLs emitted by a Servlet should be run through this method. 
                    384:      * Otherwise, URL rewriting cannot be used with browsers which do not 
                    385:      * support cookies.
                    386:      * @param url - the url to be encoded. 
                    387:      * @return the encoded URL if encoding is needed; the unchanged URL 
                    388:      * otherwise. 
1.28      bmahe     389:      * @deprecated since jsdk2.1
1.18      bmahe     390:      */
1.12      bmahe     391:     public String encodeUrl(String url) {
1.15      bmahe     392:        if (! jrequest.isRequestedSessionIdFromCookie()) {
1.25      bmahe     393:            url = url + ((url.indexOf("?") != -1) ? "&" : "?")+
                    394:                jrequest.getCookieName()+"="+
1.15      bmahe     395:                jrequest.getSession(true).getId();
                    396:        }
1.12      bmahe     397:        return url;
1.28      bmahe     398:     }
                    399: 
                    400:     /**
                    401:      * Encodes the specified URL by including the session ID in it, or, if 
                    402:      * encoding is not needed, returns the URL unchanged. The implementation of
                    403:      * this method should include the logic to determine whether the session ID
                    404:      * needs to be encoded in the URL. For example, if the browser supports
                    405:      * cookies, or session tracking is turned off, URL encoding is unnecessary.
                    406:      * <p>All URLs emitted by a Servlet should be run through this method. 
                    407:      * Otherwise, URL rewriting cannot be used with browsers which do not 
                    408:      * support cookies.
                    409:      * @param url - the url to be encoded. 
                    410:      * @return the encoded URL if encoding is needed; the unchanged URL 
                    411:      * otherwise. 
                    412:      */
                    413:     public String encodeURL(String url) {
                    414:        return encodeUrl(url);
1.12      bmahe     415:     }
                    416: 
                    417:     /**
                    418:      * Return the Charset parameter of content type
                    419:      * @return A String instance
                    420:      */
                    421:     public String getCharacterEncoding() {
                    422:        org.w3c.www.mime.MimeType type = reply.getContentType();
1.33    ! bmahe     423:        if ((type != null) && (type.hasParameter(CHARSET_PARAMETER))) {
        !           424:            return type.getParameterValue(CHARSET_PARAMETER);
1.12      bmahe     425:        }
1.30      bmahe     426:        return System.getProperty("file.encoding");
1.12      bmahe     427:     }
                    428: 
1.18      bmahe     429:     /**
                    430:      * Returns a print writer for writing formatted text responses. 
                    431:      * The MIME type of the response will be modified, if necessary, to
                    432:      * reflect the character encoding used, through the charset=... property. 
                    433:      * This means that the content type must be set before calling this 
                    434:      * method. 
                    435:      * @exception UnsupportedEncodingException if no such encoding can be 
                    436:      * provided 
                    437:      * @exception IllegalStateException if getOutputStream has been called 
                    438:      * on this same request.
                    439:      * @exception IOException on other errors. 
1.27      ylafon    440:      * @see JigsawHttpServletResponse#getOutputStream
                    441:      * @see JigsawHttpServletResponse#setContentType 
1.18      bmahe     442:      */    
1.12      bmahe     443:     public synchronized PrintWriter getWriter() 
                    444:        throws IOException, UnsupportedEncodingException
                    445:     {
                    446:        if (stream_state == OUTPUT_STREAM_USED)
                    447:            throw new IllegalStateException("Output stream used");
                    448:        stream_state = STREAM_WRITER_USED;
1.11      bmahe     449:       
1.12      bmahe     450:        if (writer == null) {
                    451:            writer = new PrintWriter(
1.29      bmahe     452:                         new OutputStreamWriter(getJigsawOutputStream(), 
                    453:                                                getCharacterEncoding()));
1.12      bmahe     454:        }
                    455:        return writer;
1.20      bmahe     456:     }
                    457: 
1.31      ylafon    458:     /**
                    459:      * Flush the output stream.
                    460:      * @param close Close the stream if true.
                    461:      * @exception IOException if an IO error occurs.
                    462:      */
1.30      bmahe     463:     protected synchronized void flushStream(boolean close) 
                    464:        throws IOException
                    465:     {
                    466:        int writeLength;
1.29      bmahe     467: 
1.30      bmahe     468:        if (stream_state == OUTPUT_STREAM_USED) {
                    469:            output.flush();
                    470:        } else if (stream_state == STREAM_WRITER_USED) {
                    471:            writer.flush();
                    472:        }
1.29      bmahe     473: 
1.30      bmahe     474:        if (request.hasState(INCLUDED)) {
                    475:            if (out == null)
                    476:                return;
                    477: 
                    478:            if( fixedContentLength != CALC_CONTENT_LENGTH ) {
                    479:                writeLength = (out.size() < fixedContentLength) 
                    480:                    ? (out.size())
                    481:                    : (fixedContentLength);
1.29      bmahe     482:            } else {
1.30      bmahe     483:                writeLength = out.size();
1.29      bmahe     484:            }
1.30      bmahe     485:            reply.setContentLength(writeLength);
                    486:            
                    487:            OutputStream rout = reply.getOutputStream(false);
                    488:            byte content[] = out.toByteArray();
                    489:            if (close)
                    490:                out.close();
                    491:            else 
                    492:                out.reset();
                    493:            rout.write(content);
                    494:            rout.flush();
1.29      bmahe     495:        }
1.13      bmahe     496:     }
                    497: 
1.33    ! bmahe     498:     // 2.2
        !           499: 
        !           500:     /**
        !           501:      * Sets the preferred buffer size for the body of the response.  
        !           502:      * The servlet container will use a buffer at least as large as 
        !           503:      * the size requested.  The actual buffer size used can be found
        !           504:      * using <code>getBufferSize</code>.
        !           505:      *
        !           506:      * <p>A larger buffer allows more content to be written before anything is
        !           507:      * actually sent, thus providing the servlet with more time to set
        !           508:      * appropriate status codes and headers.  A smaller buffer decreases 
        !           509:      * server memory load and allows the client to start receiving data more
        !           510:      * quickly.
        !           511:      *
        !           512:      * <p>This method must be called before any response body content is
        !           513:      * written; if content has been written, this method throws an 
        !           514:      * <code>IllegalStateException</code>.
        !           515:      * @param size the preferred buffer size
        !           516:      * @exception IllegalStateException        if this method is called after
        !           517:      * content has been written
        !           518:      * @see #getBufferSize
        !           519:      * @see #flushBuffer
        !           520:      * @see #isCommitted
        !           521:      * @see #reset
        !           522:      */
        !           523:     public void setBufferSize(int size) {
        !           524:        if (stream_state != STREAM_STATE_INITIAL) {
        !           525:            throw new IllegalStateException("Stream already initialized");
        !           526:        }
        !           527:        if (size < MIN_BUFFER_SIZE) {
        !           528:            buffer_size = MIN_BUFFER_SIZE;
        !           529:        } else {
        !           530:            buffer_size = size;
        !           531:        }
        !           532:     }
        !           533: 
        !           534:     /**
        !           535:      * Returns the actual buffer size used for the response.  If no buffering
        !           536:      * is used, this method returns 0.
        !           537:      * @return the actual buffer size used
        !           538:      * @see #setBufferSize
        !           539:      * @see #flushBuffer
        !           540:      * @see #isCommitted
        !           541:      * @see #reset
        !           542:      */
        !           543:     public int getBufferSize() {
        !           544:        return buffer_size;
        !           545:     }
        !           546: 
        !           547:     /**
        !           548:      * Forces any content in the buffer to be written to the client.  A call
        !           549:      * to this method automatically commits the response, meaning the status 
        !           550:      * code and headers will be written.
        !           551:      * @see #setBufferSize
        !           552:      * @see #getBufferSize
        !           553:      * @see #isCommitted
        !           554:      * @see #reset
        !           555:      */
        !           556:     public void flushBuffer() 
        !           557:        throws IOException
        !           558:     {
        !           559:        if (output != null) {
        !           560:            output.flush();
        !           561:        }
        !           562:     }
        !           563: 
        !           564:     /**
        !           565:      * Returns a boolean indicating if the response has been
        !           566:      * committed.  A commited response has already had its status 
        !           567:      * code and headers written.
        !           568:      * @return a boolean indicating if the response has been
        !           569:      * committed
        !           570:      * @see #setBufferSize
        !           571:      * @see #getBufferSize
        !           572:      * @see #flushBuffer
        !           573:      * @see #reset
        !           574:      */
        !           575:     public boolean isCommitted() {
        !           576:        if (output != null) {
        !           577:            return output.isCommitted();
        !           578:        } else {
        !           579:            return false;
        !           580:        }
        !           581:     }
        !           582: 
        !           583:     /**
        !           584:      * Clears any data that exists in the buffer as well as the status code and
        !           585:      * headers.  If the response has been committed, this method throws an 
        !           586:      * <code>IllegalStateException</code>.
        !           587:      * @exception IllegalStateException  if the response has already been
        !           588:      *                                   committed
        !           589:      * @see #setBufferSize
        !           590:      * @see #getBufferSize
        !           591:      * @see #flushBuffer
        !           592:      * @see #isCommitted
        !           593:      */
        !           594:     public void reset() {
        !           595:        if (output != null) {
        !           596:            output.reset();
        !           597:        }
        !           598:     }
        !           599: 
        !           600:     /**
        !           601:      * Sets the locale of the response, setting the headers (including the
        !           602:      * Content-Type's charset) as appropriate.  This method should be called
        !           603:      * before a call to {@link #getWriter}.  By default, the response locale
        !           604:      * is the default locale for the server.
        !           605:      * @param loc  the locale of the response
        !           606:      * @see #getLocale
        !           607:      */
        !           608:     public void setLocale(Locale locale) {
        !           609:        if (locale == null) {
        !           610:            return;
        !           611:        }
        !           612:        this.locale = locale;
        !           613: 
        !           614:        // content language
        !           615:        String lang = locale.getLanguage();
        !           616:        if (lang.length() > 0) {
        !           617:            String array[] = new String[1];
        !           618:            array[0] = lang;
        !           619:            reply.setContentLanguage(array);
        !           620:        }
        !           621:        
        !           622:        // content type (charset)
        !           623:        String charset = org.w3c.www.mime.Utils.getCharset(locale);
        !           624:        if (charset != null) {
        !           625:            MimeType contentType = reply.getContentType();
        !           626:            // override charset
        !           627:            contentType.setParameter(CHARSET_PARAMETER, charset);
        !           628:        }
        !           629:     }
        !           630: 
        !           631:     /**
        !           632:      * Returns the locale assigned to the response.
        !           633:      * @see #setLocale
        !           634:      */
        !           635:     public Locale getLocale() {
        !           636:        return locale;
        !           637:     }
        !           638: 
        !           639:     public void addHeader(String name, String value) {
        !           640:        String      lname = name.toLowerCase();
        !           641:        HeaderValue hvalue = reply.getHeaderValue(lname);
        !           642:        //
        !           643:        // Horrible, Shame on us, I hate that
        !           644:        //
        !           645:        if (hvalue == null) {
        !           646:            setHeader(name, value);
        !           647:        } else if (hvalue instanceof HttpAcceptCharsetList) {
        !           648:            HttpAcceptCharsetList acl = (HttpAcceptCharsetList) hvalue;
        !           649:            acl.addCharset(HttpFactory.parseAcceptCharset(value));
        !           650:        } else if (hvalue instanceof HttpAcceptEncodingList) {
        !           651:            HttpAcceptEncodingList ael = (HttpAcceptEncodingList) hvalue;
        !           652:            ael.addEncoding(HttpFactory.parseAcceptEncoding(value));
        !           653:        } else if (hvalue instanceof HttpAcceptLanguageList) {
        !           654:            HttpAcceptLanguageList all = (HttpAcceptLanguageList) hvalue;
        !           655:            all.addLanguage(HttpFactory.parseAcceptLanguage(value));
        !           656:        } else if (hvalue instanceof HttpAcceptList) {
        !           657:            HttpAcceptList al = (HttpAcceptList) hvalue;
        !           658:            al.addAccept(HttpFactory.parseAccept(value));
        !           659:        } else if (hvalue instanceof HttpEntityTagList) {
        !           660:            HttpEntityTagList etl = (HttpEntityTagList) hvalue;
        !           661:            etl.addTag(HttpFactory.parseETag(value));
        !           662:        } else if (hvalue instanceof HttpExtList) {
        !           663:            HttpExtList el = (HttpExtList) hvalue;
        !           664:            el.addHttpExt(new HttpExt(value, false));
        !           665:        } else if (hvalue instanceof HttpCookieList) {
        !           666:            // shouldn't be used, but who knows?
        !           667:            HttpCookieList cl  = (HttpCookieList) hvalue;
        !           668:            HttpCookieList ncl = HttpFactory.parseCookieList(value);
        !           669:            HttpCookie scookies[] = ncl.getCookies();
        !           670:            for (int i = 0 ; i < scookies.length ; i++) {
        !           671:                HttpCookie cookie = scookies[i];
        !           672:                cl.addCookie(cookie.getName(), cookie.getValue());
        !           673:            }
        !           674:        } else if (hvalue instanceof HttpParamList) {
        !           675:            int idx = value.indexOf('=');
        !           676:            if (idx != -1) {
        !           677:                String pname  = value.substring(0, idx);
        !           678:                String pvalue = value.substring(idx+1);
        !           679:                HttpParamList pl = (HttpParamList) hvalue;
        !           680:                pl.setParameter(pname, pvalue);
        !           681:            }
        !           682:        } else if (hvalue instanceof HttpRangeList) {
        !           683:            HttpRangeList rl = (HttpRangeList) hvalue;
        !           684:            rl.addRange(HttpFactory.parseRange(value));
        !           685:        } else if (hvalue instanceof HttpSetCookieList) {
        !           686:            HttpSetCookieList scl = (HttpSetCookieList) hvalue;
        !           687:            HttpSetCookieList nscl = HttpFactory.parseSetCookieList(value);
        !           688:            HttpSetCookie scookies[] = nscl.getSetCookies();
        !           689:            for (int i = 0 ; i < scookies.length ; i++) {
        !           690:                scl.addSetCookie(scookies[i]);
        !           691:            }
        !           692:        } else if (hvalue instanceof HttpTokenList) {
        !           693:            ((HttpTokenList) hvalue).addToken(value, true);
        !           694:        } else if (hvalue instanceof HttpWarningList) {
        !           695:            HttpWarningList wl = (HttpWarningList) hvalue;
        !           696:            wl.addWarning(HttpFactory.parseWarning(value));
        !           697:        } else if (hvalue instanceof HttpString) {
        !           698:            // this is the default type for unkown header
        !           699:            // we don't know what it is, so just append
        !           700:            HttpString s = (HttpString) hvalue;
        !           701:            String string = (String) s.getValue();
        !           702:            s.setValue(string+", "+value);
        !           703:        } else {
        !           704:            // not compliant with HTTP/1.1, override
        !           705:            setHeader(name, value);
        !           706:        }
        !           707:     }
        !           708: 
        !           709:     public void addDateHeader(String name, long date) {
        !           710:        addHeader(name, HttpFactory.makeDate(date).toExternalForm());
        !           711:     }
        !           712: 
        !           713:     public void addIntHeader(String name, int value) {
        !           714:        addHeader(name, String.valueOf(value));
        !           715:     }
        !           716: 
1.13      bmahe     717:     JigsawHttpServletResponse(Request request, Reply reply) {
1.33    ! bmahe     718:        this.request     = request;
        !           719:        this.reply       = reply;
        !           720:        this.buffer_size = DEFAULT_BUFFER_SIZE;
1.11      bmahe     721:     }
1.6       bmahe     722: 
1.1       abaird    723: }

Webmaster