package servletunit; // ServletUnit Library v1.2 - A java-based testing framework for servlets // Copyright (C) June 1, 2001 Somik Raha // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // For any questions or suggestions, you can write to me at : // Email : somik@kizna.com // // Postal Address : // Somik Raha // R&D Team // Kizna Corporation // 2-1-17-6F, Sakamoto Bldg., Moto Azabu, Minato ku, Tokyo, 106 0046, JAPAN // // Additions by: // // Dane S. Foster // Equity Technology Group, Inc // http://www.equitytg.com. // 954.360.9800 // dfoster@equitytg.com // // Additions by: // Sean Pritchard // smpritchard@yahoo.com // import junit.framework.AssertionFailedError; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.HashMap; import java.util.Locale; import java.util.Date; import java.text.SimpleDateFormat; // StrutsTestCase - a JUnit extension for testing Struts actions // within the context of the ActionServlet. // Copyright (C) 2002 Deryl Seale // // This library is free software; you can redistribute it and/or // modify it under the terms of the Apache Software License as // published by the Apache Software Foundation; either version 1.1 // of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // Apache Software Foundation Licens for more details. // // You may view the full text here: http://www.apache.org/LICENSE.txt public class HttpServletResponseSimulator implements HttpServletResponse { private OutputStream servOStream; // The non-default javax.servlet.ServletOutputStream private boolean calledGetWriter, calledGetOutputStream; private StringWriter stringWriter=null; private PrintWriter printWriter=null; private Locale locale = null; private int contentLength; private String contentType = null; private int status = 200; private String message = null; private HashMap headers = new HashMap(); private HashMap cookies = new HashMap(); String charEncoding; private boolean isCommitted = false; public static final int SC_CONTINUE = 100; public static final int SC_SWITCHING_PROTOCOLS = 101; public static final int SC_OK = 200; public static final int SC_CREATED = 201; public static final int SC_ACCEPTED = 202; public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; public static final int SC_NO_CONTENT = 204; public static final int SC_RESET_CONTENT = 205; public static final int SC_PARTIAL_CONTENT = 206; public static final int SC_MULTIPLE_CHOICES = 300; public static final int SC_MOVED_PERMANENTLY = 301; public static final int SC_MOVED_TEMPORARILY = 302; public static final int SC_SEE_OTHER = 303; public static final int SC_NOT_MODIFIED = 304; public static final int SC_USE_PROXY = 305; public static final int SC_BAD_REQUEST = 400; public static final int SC_UNAUTHORIZED = 401; public static final int SC_PAYMENT_REQUIRED = 402; public static final int SC_FORBIDDEN = 403; public static final int SC_NOT_FOUND = 404; public static final int SC_METHOD_NOT_ALLOWED = 405; public static final int SC_NOT_ACCEPTABLE = 406; public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; public static final int SC_REQUEST_TIMEOUT = 408; public static final int SC_CONFLICT = 409; public static final int SC_GONE = 410; public static final int SC_LENGTH_REQUIRED = 411; public static final int SC_PRECONDITION_FAILED = 412; public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; public static final int SC_REQUEST_URI_TOO_LONG = 414; public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; public static final int SC_EXPECTATION_FAILED = 417; public static final int SC_INTERNAL_SERVER_ERROR = 500; public static final int SC_NOT_IMPLEMENTED = 501; public static final int SC_BAD_GATEWAY = 502; public static final int SC_SERVICE_UNAVAILABLE = 503; public static final int SC_GATEWAY_TIMEOUT = 504; public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; /** * Add a cookie to this response, which will then be stored in the browser. */ public void addCookie(Cookie cookie) { cookies.put( cookie.getName(), cookie ); } /** * Returns a cookie with a given, or null if this cookie has * not been added to the repsonse. */ public Cookie findCookie( String name ) { return (Cookie) cookies.get( name ); } /** * This method is not supported. */ public void addDateHeader(String name, long date) { this.headers.put(name,new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z").format(new Date(date))); } /** * Adds a response header with the given name and value. */ public void addHeader(String name, String value) { this.setHeader(name,value); } /** * Returns a given header field, or null if this header * has not been set. */ public String getHeader(String name) { if (headers.containsKey(name)) return (String) headers.get(name); else return null; } /** * Adds a response header with the given name and integer value. */ public void addIntHeader(String name, int value) { this.setIntHeader(name,value); } /** * returns true if a header with the given name * has already been set */ public boolean containsHeader(String name) { return headers.containsKey(name); } /** * Returns the given URL unmodified */ public String encodeRedirectUrl(String url) { return url; } /** * Returns the given URL unmodified. */ public String encodeRedirectURL(String url) { return url; } /** * Returns the given URL unmodified. */ public String encodeUrl(String url) { return url; } /** * Returns the given URL unmodified */ public String encodeURL(String url) { return url; } /** * This method is not supported. */ public void flushBuffer() throws IOException { throw new UnsupportedOperationException("flushBuffer operation is not supported!"); } /** * This method is not supported. */ public int getBufferSize() { throw new UnsupportedOperationException("getBufferSize operation is not supported!"); } /** * This method is not supported. */ public String getCharacterEncoding() { return charEncoding; } /** * Returns the locale assigned to the response. * * * @see #setLocale * */ public Locale getLocale() { if (locale == null) return Locale.US; else return locale; } /** * Returns a {@link ServletOutputStream} suitable for writing binary * data in the response. The servlet container does not encode the * binary data. *

Calling flush() on the ServletOutputStream commits the response. * Either this method or {@link #getWriter} may * be called to write the body, not both. * * @return a {@link ServletOutputStream} for writing binary data * * @exception IllegalStateException if the getWriter method * has been called on this response * * @exception IOException if an input or output exception occurred * * @see #getWriter * */ public ServletOutputStream getOutputStream() throws IOException { if( this.calledGetWriter ) throw new IllegalStateException( "The getWriter method has already been called" ); ServletOutputStream oStream = null; if( null == this.servOStream ) oStream = new ServletOutputStreamSimulator(); else oStream = new ServletOutputStreamSimulator( this.servOStream ); // resets the status of servOStream to prevent us from possible using a closed stream this.servOStream = null; this.calledGetOutputStream = true; return oStream; } /** * Returns a PrintWriter object that * can send character text to the client. * The character encoding used is the one specified * in the charset= property of the * {@link #setContentType} method, which must be called * before calling this method for the charset to take effect. * *

If necessary, the MIME type of the response is * modified to reflect the character encoding used. * *

Calling flush() on the PrintWriter commits the response. * *

Either this method or {@link #getOutputStream} may be called * to write the body, not both. * * * @return a PrintWriter object that * can return character data to the client * * @exception UnsupportedEncodingException if the charset specified in * setContentType cannot be * used * * @exception IllegalStateException if the getOutputStream * method has already been called for this * response object * * @exception IOException if an input or output exception occurred * * @see #getOutputStream * @see #setContentType * */ public PrintWriter getWriter() throws IOException { if( this.calledGetOutputStream ) throw new IllegalStateException( "The getOutputStream method has already been called" ); if( stringWriter == null ) stringWriter = new StringWriter(); if( printWriter == null ) printWriter = new PrintWriter( stringWriter ); this.calledGetWriter = true; return printWriter; } /** * Use this method to pick up the string buffer which will hold * the contents of the string buffer. You can then * write your test case to examine the contents of this * buffer and match it against an expected output. */ public StringBuffer getWriterBuffer() { if (stringWriter==null) return null; return stringWriter.getBuffer(); } //TODO: better documentation public boolean isCommitted() { return isCommitted; } public void setIsCommitted(boolean isCommitted) { this.isCommitted = isCommitted; } /** * Reinitializes all local variables. * Note, in most servlet containers, you may get an * IllegalStateException if you call this method * after committing the response. * That behavior is not replicated here. */ public void reset() { this.calledGetOutputStream = false; this.calledGetWriter = false; this.contentLength = 0; this.contentType = null; this.stringWriter = null; this.printWriter = null; headers = new HashMap(); } /** * This method is not supported. */ public void resetBuffer() { throw new UnsupportedOperationException("resetBuffer operation is not supported."); } /** * Sends an error response to the client using the specified * status clearing the buffer. This method always throws * an AssertionFailedError with the corresponding error * number. * * @param sc the error status code */ public void sendError(int sc) throws IOException { setStatus(sc); throw new AssertionFailedError("received error: " + sc); } /** * Sends an error response to the client using the specified * status clearing the buffer. This method always throws * an AssertionFailedError with the corresponding error * number and descriptive text. * * @param sc the error status code * @param msg the descriptive message */ public void sendError(int sc, String msg) throws IOException { setStatus(sc,msg); throw new AssertionFailedError("received error " + sc + " : " + msg); } /** * Resets the response and sets the appropriate redirect headers. */ public void sendRedirect(String location) throws IOException { reset(); setStatus(SC_MOVED_TEMPORARILY); setHeader("Location", location); } /** * This method is not supported. */ public void setBufferSize(int size) { throw new UnsupportedOperationException("setBufferSize operation not supported."); } /** * Sets the length of the content body in the response * In HTTP servlets, this method sets the HTTP Content-Length header. * * * @param len an integer specifying the length of the * content being returned to the client; sets * the Content-Length header * */ public void setContentLength(int len) { this.contentLength = len; } /** * returns the content length previously set in setContentLength() * @return the content length */ public int getContentLength(){ return this.contentLength; } /** * Sets the content type of the response being sent to * the client. The content type may include the type of character * encoding used, for example, text/html; charset=ISO-8859-4. * *

If obtaining a PrintWriter, this method should be * called first. * * * @param type a String specifying the MIME * type of the content * * @see #getOutputStream * @see #getWriter * */ public void setContentType(String type) { this.contentType = type; } /** * returns the content type previously set in setContentType() * @return the content type */ public String getContentType(){ return this.contentType; } /** * This method is not supported. */ public void setDateHeader(String name, long date) { this.addDateHeader(name,date); } /** * adds the name/value pair to the headers */ public void setHeader(String name, String value) { if (name.equalsIgnoreCase("content-type")) { setContentType(value); return; } else if (name.equalsIgnoreCase("content-length")) { this.setContentLength(Integer.parseInt(value)); return; } headers.put(name, value); } /** * Removes a given header */ public void removeHeader(String name) { if (headers.containsKey(name)) headers.remove(name); } /** * Adds the given name/value pair to the headers collection. */ public void setIntHeader(String name, int value) { setHeader(name, String.valueOf(value)); } /** * Sets the locale of the response, setting the headers (including the * Content-Type's charset) as appropriate. This method should be called * before a call to {@link #getWriter}. By default, the response locale * is the default locale for the server. * * @param loc the locale of the response * * @see #getLocale * */ public void setLocale(Locale loc) { this.locale = loc; } /** * The default action of calling the getOutputStream method * is to return a javax.servlet.ServletOutputStream object * that sends the data to System.out. If you don't want * the output sent to System.out you can use this method to * set where the output will go. Please note, subsequent calls to * getOutputStream will reset the output path to * System.out. This prevents the OutputStream returned by * calling getOutputStream from writing to a closed stream * * @param out The java.io.OutputStream that represents * the real path of the output. */ public void setOutputStream( OutputStream out ) { this.servOStream = out; } /** * Sets the given status code. */ public void setStatus(int sc) { setStatus(sc, null); } /** * Sets the given status and an associated message. */ public void setStatus(int sc, String sm) { this.status = sc; this.message = sm; } /** * Returns the status code for this response, which is useful for testing expected errors. * @return the status code for this response. */ public int getStatusCode() { return this.status; } public void setCharacterEncoding(String charEncoding) { this.charEncoding = charEncoding; } public String getMessage() { return message; } }