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

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

Webmaster