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

1.1       abaird      1: // JigsawHttpServletReponse.java
1.26    ! bmahe       2: // $Id: JigsawHttpServletResponse.java,v 1.25 1998/09/24 15:48:05 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.1       abaird     12: 
1.10      bmahe      13: import org.w3c.www.mime.*;
                     14: import org.w3c.www.http.*;
                     15: import org.w3c.jigsaw.http.*;
1.2       abaird     16: 
                     17: /**
                     18:  *  @author Alexandre Rafalovitch <alex@access.com.au>
                     19:  *  @author Anselm Baird-Smith <abaird@w3.org>
1.17      bmahe      20:  *  @author  Benoît Mahé (bmahe@w3.org)
1.2       abaird     21:  */
1.1       abaird     22: 
                     23: public class JigsawHttpServletResponse implements HttpServletResponse 
                     24: {
                     25:     private final static int STATE_INITIAL = 0;
                     26:     private final static int STATE_HEADERS_DONE = 1;
                     27:     private final static int STATE_ALL_DONE = 2;
1.11      bmahe      28: 
                     29:     private final static int STREAM_STATE_INITIAL = 0;
                     30:     private final static int STREAM_WRITER_USED = 1;
                     31:     private final static int OUTPUT_STREAM_USED = 2;
                     32: 
                     33:     private int stream_state = STREAM_STATE_INITIAL;
1.20      bmahe      34: 
                     35:     private JigsawServletOutputStream output = null;
                     36:     private PrintWriter               writer = null;
1.7       bmahe      37:  
1.14      bmahe      38:     protected JigsawHttpServletRequest jrequest = null;
                     39: 
                     40:     protected void setServletRequest(JigsawHttpServletRequest jrequest) {
                     41:        this.jrequest = jrequest;
                     42:     }
                     43: 
1.7       bmahe      44:     public static final 
1.12      bmahe      45:        String REMOVE_HEADER = "org.w3c.jigsaw.servlet.removeHeader";
1.7       bmahe      46:    
1.1       abaird     47:     int   state = STATE_INITIAL;
                     48:     Reply reply = null;
                     49:     Request request = null;
                     50:     
1.18      bmahe      51:     /**
                     52:      * Sets the content length for this response. 
                     53:      * @param len - the content length 
                     54:      */
1.5       abaird     55:     public void setContentLength(int i) {
1.1       abaird     56:        reply.setContentLength(i);
                     57:     }
1.18      bmahe      58: 
                     59:     /**
                     60:      * Sets the content type for this response. This type may later be 
                     61:      * implicitly modified by addition of properties such as the MIME
                     62:      * charset=<value> if the service finds it necessary, and the appropriate
                     63:      * media type property has not been set.
                     64:      * <p>This response property may only be assigned one time. If a writer 
                     65:      * is to be used to write a text response, this method must be
                     66:      * called before the method getWriter. If an output stream will be used 
                     67:      * to write a response, this method must be called before the
                     68:      * output stream is used to write response data. 
                     69:      * @param spec - the content's MIME type 
1.24      bmahe      70:      * @see getOutputStream
                     71:      * @see getWriter
1.18      bmahe      72:      */    
1.5       abaird     73:     public void setContentType(String spec) {
1.1       abaird     74:        try {
                     75:            MimeType type= new MimeType(spec);
                     76:            reply.setContentType(type);
                     77:        } catch(MimeTypeFormatException ex) {
                     78:            // FIXME what should I do?
                     79:        }
                     80:     }
1.5       abaird     81: 
1.18      bmahe      82:     /**
                     83:      * Returns an output stream for writing binary response data.
1.24      bmahe      84:      * @return A ServletOutputStream
1.18      bmahe      85:      * @exception IOException if an I/O exception has occurred 
                     86:      * @exception IllegalStateException if getWriter has been called on this 
                     87:      * same request. 
                     88:      * @see getWriter
                     89:      */    
1.5       abaird     90:     public synchronized ServletOutputStream getOutputStream()
                     91:        throws IOException
                     92:     {
1.12      bmahe      93:        if (stream_state == STREAM_WRITER_USED)
                     94:            throw new IllegalStateException("Writer used");
                     95:        stream_state = OUTPUT_STREAM_USED;
                     96:        return getJigsawOutputStream();
1.11      bmahe      97:     }
                     98: 
                     99:     protected ServletOutputStream getJigsawOutputStream()
                    100:        throws IOException
                    101:     {
1.12      bmahe     102:        if ( output != null )
                    103:            return output;
                    104:       
1.26    ! bmahe     105:        if ( request.hasState(REMOVE_HEADER) ) //included so no close
        !           106:            output = 
        !           107:                (new JigsawServletOutputStream
        !           108:                 (this,
        !           109:                  new IncludedDataOutputStream(reply.getOutputStream(false))));
1.12      bmahe     110:        else
                    111:            output = (new JigsawServletOutputStream
                    112:                      (this
                    113:                       , new DataOutputStream(reply.getOutputStream())));
1.5       abaird    114:        return output;
1.1       abaird    115:     }
                    116:     
1.18      bmahe     117:     /**
                    118:      * Sets the status code and message for this response. If the field had
                    119:      * already been set, the new value overwrites the previous one. The message
                    120:      * is sent as the body of an HTML page, which is returned to the user to
                    121:      * describe the problem. The page is sent with a default HTML header; the
                    122:      * message is enclosed in simple body tags (<body></body>).
                    123:      * @param i - the status code 
                    124:      * @param reason - the status message
                    125:      */
1.5       abaird    126:     public void setStatus(int i, String reason) {
1.1       abaird    127:        reply.setStatus(i);
                    128:        reply.setReason(reason);
                    129:     }
                    130:     
1.18      bmahe     131:     /**
                    132:      * Sets the status code for this response. This method is used to set the
                    133:      * return status code when there is no error (for example, for the status
                    134:      * codes SC_OK or SC_MOVED_TEMPORARILY). If there is an error, the 
                    135:      * sendError method should be used instead.
                    136:      * @param i - the status code 
                    137:      * @see sendError
                    138:      */
1.5       abaird    139:     public void setStatus(int i) {
1.1       abaird    140:        setStatus(i, reply.getStandardReason(i));
                    141:     }
                    142:     
1.18      bmahe     143:     /**
                    144:      * Adds a field to the response header with the given name and value. If
                    145:      * the field had already been set, the new value overwrites the previous
                    146:      * one. The containsHeader method can be used to test for the presence of a
                    147:      * header before setting its value.
                    148:      * @param name - the name of the header field 
                    149:      * @param value - the header field's value 
                    150:      * @see containsHeader
                    151:      */
1.5       abaird    152:     public void setHeader(String name, String value) {
1.1       abaird    153:        reply.setValue(name, value);
                    154:     }
                    155:     
1.18      bmahe     156:     /**
                    157:      * Adds a field to the response header with the given name and integer
                    158:      * value. If the field had already been set, the new value overwrites the
                    159:      * previous one. The containsHeader method can be used to test for the
                    160:      * presence of a header before setting its value.
                    161:      * @param name - the name of the header field 
                    162:      * @param value - the header field's integer value 
                    163:      * @see containsHeader
                    164:      */
1.5       abaird    165:     public void setIntHeader(String name, int value) {
1.1       abaird    166:        setHeader(name, String.valueOf(value));
                    167:     }
                    168:     
1.18      bmahe     169:     /**
                    170:      * Adds a field to the response header with the given name and date-valued
                    171:      * field. The date is specified in terms of milliseconds since the epoch. 
                    172:      * If the date field had already been set, the new value overwrites the
                    173:      * previous one. The containsHeader method can be used to test for the
                    174:      * presence of a header before setting its value.
                    175:      * @param name - the name of the header field 
                    176:      * @param value - the header field's date value 
                    177:      * @see containsHeader 
                    178:      */
1.5       abaird    179:     public void setDateHeader(String name, long date) {
1.1       abaird    180:        setHeader(name, String.valueOf(date));
                    181:     }
                    182:     
1.5       abaird    183:     public void unsetHeader(String name) {
1.1       abaird    184:        setHeader(name, null);
                    185:     }
                    186:     
1.18      bmahe     187:     /**
                    188:      * Sends an error response to the client using the specified status code
                    189:      * and descriptive message. If setStatus has previously been called, it is
                    190:      * reset to the error status code. The message is sent as the body of an
                    191:      * HTML page, which is returned to the user to describe the problem. The
                    192:      * page is sent with a default HTML header; the message is enclosed in
                    193:      * simple body tags (<body></body>).
                    194:      * @param sc - the status code 
                    195:      * @param msg - the detail message 
                    196:      * @exception IOException If an I/O error has occurred.
                    197:      */
1.5       abaird    198:     public void sendError(int i, String msg) 
                    199:        throws IOException
1.1       abaird    200:     {
                    201:        setStatus(i);
                    202:        reply.setContent(msg);
                    203:        state = STATE_ALL_DONE;
                    204:     }
1.18      bmahe     205: 
                    206:     /**
                    207:      * Sends an error response to the client using the specified status 
                    208:      * code and a default message. 
                    209:      * @param sc - the status code 
                    210:      * @exception IOException If an I/O error has occurred.
                    211:      */
1.1       abaird    212:     public void sendError(int i)
                    213:         throws IOException
                    214:     {
                    215:        setStatus(i);
                    216:        reply.setContent(reply.getStandardReason(i));
                    217:        state = STATE_ALL_DONE;
                    218:     }
                    219:     
1.18      bmahe     220:     /**
                    221:      * Sends a temporary redirect response to the client using the specified
                    222:      *  redirect location URL. The URL must be absolute (for example, 
                    223:      * https://hostname/path/file.html). Relative URLs are not permitted here. 
                    224:      * @param url - the redirect location URL 
                    225:      * @exception IOException If an I/O error has occurred. 
                    226:      */    
1.1       abaird    227:     public void sendRedirect(String url)
                    228:         throws IOException
                    229:     {
1.4       abaird    230:        URL loc = null;
                    231:        try {
                    232:            loc = new URL(request.getURL(), url);
                    233:            setStatus(SC_MOVED_TEMPORARILY);
                    234:            reply.setLocation(loc);
                    235:            state = STATE_ALL_DONE;
                    236:        } catch (Exception ex) {
                    237:            ex.printStackTrace();
                    238:        }
1.1       abaird    239:     }
1.6       bmahe     240: 
1.18      bmahe     241:     /**
                    242:      * Checks whether the response message header has a field with the
                    243:      * specified name. 
                    244:      * @param name - the header field name 
                    245:      * @return true if the response message header has a field with the 
                    246:      * specified name; false otherwise
                    247:      */
1.12      bmahe     248:     public boolean containsHeader(String header) {
                    249:        return reply.hasHeader(header);
                    250:     }
                    251: 
1.18      bmahe     252:     /**
                    253:      * Adds the specified cookie to the response. It can be called multiple 
                    254:      * times to set more than one cookie. 
                    255:      * @param cookie - the Cookie to return to the client 
                    256:      */
1.12      bmahe     257:     public void addCookie(Cookie cookie) {
1.13      bmahe     258:        HttpSetCookieList clist = reply.getSetCookie();
                    259:        if (clist == null) {
                    260:            HttpSetCookie cookies [] = new HttpSetCookie[1];
                    261:            cookies[0] = convertCookie(cookie);
                    262:            clist = new HttpSetCookieList(cookies);
                    263:        } else {
                    264:            clist.addSetCookie(convertCookie(cookie));
                    265:        }
                    266:        reply.setSetCookie(clist);
                    267:     }
1.12      bmahe     268: 
1.13      bmahe     269:     public HttpSetCookie convertCookie(Cookie cookie) {
                    270:        HttpSetCookie scookie = new HttpSetCookie(true, 
                    271:                                                  cookie.getName(),
                    272:                                                  cookie.getValue());
                    273:        scookie.setComment(cookie.getComment());
                    274:        scookie.setDomain(cookie.getDomain());
                    275:        scookie.setMaxAge(cookie.getMaxAge());
                    276:        scookie.setPath(cookie.getPath());
                    277:        scookie.setSecurity(cookie.getSecure());
                    278:        scookie.setVersion(cookie.getVersion());
                    279:        return scookie;
1.12      bmahe     280:     }
                    281: 
1.18      bmahe     282:     /**
                    283:      * Encodes the specified URL for use in the sendRedirect method or, if 
                    284:      * encoding is not needed, returns the URL unchanged. The implementation 
                    285:      * of this method should include the logic to determine whether the 
                    286:      * session ID needs to be encoded in the URL.
                    287:      * Because the rules for making this determination differ from those used
                    288:      * to decide whether to encode a normal link, this method is seperate from
                    289:      * the encodeUrl method.
                    290:      * <p>All URLs sent to the HttpServletResponse.sendRedirect method should
                    291:      * be run through this method. Otherwise, URL rewriting canont be used 
                    292:      * with browsers which do not support cookies. 
                    293:      * @param url - the url to be encoded. 
                    294:      * @return the encoded URL if encoding is needed; the unchanged URL 
                    295:      * otherwise. 
1.24      bmahe     296:      * @see sendRedirect
                    297:      * @see encodeUrl
1.18      bmahe     298:      */
1.12      bmahe     299:     public String encodeRedirectUrl(String url) {
1.19      bmahe     300:        try {
                    301:            URL redirect = new URL(url);
                    302:            URL requested = new URL(jrequest.getRequestURI());
                    303:            if ( redirect.getHost().equals(requested.getHost()) &&
                    304:                 redirect.getPort() == requested.getPort())
                    305:                return encodeUrl(url);
                    306:        } catch (MalformedURLException ex) {
                    307:            //error so return url.
                    308:            return url;
                    309:        }
                    310:        return url;
1.12      bmahe     311:     }
                    312: 
1.18      bmahe     313:     /**
                    314:      * Encodes the specified URL by including the session ID in it, or, if 
                    315:      * encoding is not needed, returns the URL unchanged. The implementation of
                    316:      * this method should include the logic to determine whether the session ID
                    317:      * needs to be encoded in the URL. For example, if the browser supports
                    318:      * cookies, or session tracking is turned off, URL encoding is unnecessary.
                    319:      * <p>All URLs emitted by a Servlet should be run through this method. 
                    320:      * Otherwise, URL rewriting cannot be used with browsers which do not 
                    321:      * support cookies.
                    322:      * @param url - the url to be encoded. 
                    323:      * @return the encoded URL if encoding is needed; the unchanged URL 
                    324:      * otherwise. 
                    325:      */
1.12      bmahe     326:     public String encodeUrl(String url) {
1.15      bmahe     327:        if (! jrequest.isRequestedSessionIdFromCookie()) {
1.25      bmahe     328:            url = url + ((url.indexOf("?") != -1) ? "&" : "?")+
                    329:                jrequest.getCookieName()+"="+
1.15      bmahe     330:                jrequest.getSession(true).getId();
                    331:        }
1.12      bmahe     332:        return url;
                    333:     }
                    334: 
                    335:     /**
                    336:      * Return the Charset parameter of content type
                    337:      * @return A String instance
                    338:      */
                    339:     public String getCharacterEncoding() {
                    340:        org.w3c.www.mime.MimeType type = reply.getContentType();
                    341:        if ((type != null) && (type.hasParameter("charset"))) {
                    342:            return type.getParameterValue("charset");
                    343:        }
1.13      bmahe     344:        return "ISO-8859-1";
1.12      bmahe     345:     }
                    346: 
1.18      bmahe     347:     /**
                    348:      * Returns a print writer for writing formatted text responses. 
                    349:      * The MIME type of the response will be modified, if necessary, to
                    350:      * reflect the character encoding used, through the charset=... property. 
                    351:      * This means that the content type must be set before calling this 
                    352:      * method. 
                    353:      * @exception UnsupportedEncodingException if no such encoding can be 
                    354:      * provided 
                    355:      * @exception IllegalStateException if getOutputStream has been called 
                    356:      * on this same request.
                    357:      * @exception IOException on other errors. 
1.24      bmahe     358:      * @see getOutputStream
                    359:      * @see setContentType 
1.18      bmahe     360:      */    
1.12      bmahe     361:     public synchronized PrintWriter getWriter() 
                    362:        throws IOException, UnsupportedEncodingException
                    363:     {
                    364:        if (stream_state == OUTPUT_STREAM_USED)
                    365:            throw new IllegalStateException("Output stream used");
                    366:        stream_state = STREAM_WRITER_USED;
1.11      bmahe     367:       
1.12      bmahe     368:        if (writer == null) {
                    369:            writer = new PrintWriter(
                    370:                         new OutputStreamWriter( getJigsawOutputStream(), 
                    371:                                                 getCharacterEncoding()));
                    372:        }
                    373:        return writer;
1.20      bmahe     374:     }
                    375: 
1.22      bmahe     376:     protected synchronized void flushStream() {
1.20      bmahe     377:        try {
                    378:            if (stream_state == OUTPUT_STREAM_USED) {
                    379:                output.flush();
1.21      bmahe     380:            } else if (stream_state == STREAM_WRITER_USED) {
1.20      bmahe     381:                writer.flush();
                    382:            }
                    383:        } catch (IOException ex) {}
1.13      bmahe     384:     }
                    385: 
                    386:     JigsawHttpServletResponse(Request request, Reply reply) {
                    387:        this.request = request;
                    388:        this.reply   = reply;
1.11      bmahe     389:     }
1.6       bmahe     390: 
1.1       abaird    391: }

Webmaster