001: package servletunit;
002:
003: // ServletUnit Library v1.2 - A java-based testing framework for servlets
004: // Copyright (C) June 1, 2001 Somik Raha
005: //
006: // This library is free software; you can redistribute it and/or
007: // modify it under the terms of the GNU Lesser General Public
008: // License as published by the Free Software Foundation; either
009: // version 2.1 of the License, or (at your option) any later version.
010: //
011: // This library is distributed in the hope that it will be useful,
012: // but WITHOUT ANY WARRANTY; without even the implied warranty of
013: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: // Lesser General Public License for more details.
015: //
016: // You should have received a copy of the GNU Lesser General Public
017: // License along with this library; if not, write to the Free Software
018: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: //
020: // For any questions or suggestions, you can write to me at :
021: // Email : somik@kizna.com
022: //
023: // Postal Address :
024: // Somik Raha
025: // R&D Team
026: // Kizna Corporation
027: // 2-1-17-6F, Sakamoto Bldg., Moto Azabu, Minato ku, Tokyo, 106 0046, JAPAN
028: //
029: // Additions by:
030: //
031: // Dane S. Foster
032: // Equity Technology Group, Inc
033: // http://www.equitytg.com.
034: // 954.360.9800
035: // dfoster@equitytg.com
036: //
037: // Additions by:
038: // Sean Pritchard
039: // smpritchard@yahoo.com
040: //
041: import junit.framework.AssertionFailedError;
042:
043: import javax.servlet.ServletOutputStream;
044: import javax.servlet.http.Cookie;
045: import javax.servlet.http.HttpServletResponse;
046: import java.io.*;
047: import java.util.HashMap;
048: import java.util.Locale;
049: import java.util.Date;
050: import java.text.SimpleDateFormat;
051:
052: // StrutsTestCase - a JUnit extension for testing Struts actions
053: // within the context of the ActionServlet.
054: // Copyright (C) 2002 Deryl Seale
055: //
056: // This library is free software; you can redistribute it and/or
057: // modify it under the terms of the Apache Software License as
058: // published by the Apache Software Foundation; either version 1.1
059: // of the License, or (at your option) any later version.
060: //
061: // This library is distributed in the hope that it will be useful,
062: // but WITHOUT ANY WARRANTY; without even the implied warranty of
063: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
064: // Apache Software Foundation Licens for more details.
065: //
066: // You may view the full text here: http://www.apache.org/LICENSE.txt
067:
068: public class HttpServletResponseSimulator implements
069: HttpServletResponse {
070: private OutputStream servOStream; // The non-default javax.servlet.ServletOutputStream
071:
072: private boolean calledGetWriter, calledGetOutputStream;
073: private StringWriter stringWriter = null;
074: private PrintWriter printWriter = null;
075: private Locale locale = null;
076: private int contentLength;
077: private String contentType = null;
078: private int status = 200;
079: private String message = null;
080: private HashMap headers = new HashMap();
081: private HashMap cookies = new HashMap();
082:
083: String charEncoding;
084:
085: private boolean isCommitted = false;
086:
087: public static final int SC_CONTINUE = 100;
088:
089: public static final int SC_SWITCHING_PROTOCOLS = 101;
090:
091: public static final int SC_OK = 200;
092:
093: public static final int SC_CREATED = 201;
094:
095: public static final int SC_ACCEPTED = 202;
096:
097: public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
098:
099: public static final int SC_NO_CONTENT = 204;
100:
101: public static final int SC_RESET_CONTENT = 205;
102:
103: public static final int SC_PARTIAL_CONTENT = 206;
104:
105: public static final int SC_MULTIPLE_CHOICES = 300;
106:
107: public static final int SC_MOVED_PERMANENTLY = 301;
108:
109: public static final int SC_MOVED_TEMPORARILY = 302;
110:
111: public static final int SC_SEE_OTHER = 303;
112:
113: public static final int SC_NOT_MODIFIED = 304;
114:
115: public static final int SC_USE_PROXY = 305;
116:
117: public static final int SC_BAD_REQUEST = 400;
118:
119: public static final int SC_UNAUTHORIZED = 401;
120:
121: public static final int SC_PAYMENT_REQUIRED = 402;
122:
123: public static final int SC_FORBIDDEN = 403;
124:
125: public static final int SC_NOT_FOUND = 404;
126:
127: public static final int SC_METHOD_NOT_ALLOWED = 405;
128:
129: public static final int SC_NOT_ACCEPTABLE = 406;
130:
131: public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
132:
133: public static final int SC_REQUEST_TIMEOUT = 408;
134:
135: public static final int SC_CONFLICT = 409;
136:
137: public static final int SC_GONE = 410;
138:
139: public static final int SC_LENGTH_REQUIRED = 411;
140:
141: public static final int SC_PRECONDITION_FAILED = 412;
142:
143: public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
144:
145: public static final int SC_REQUEST_URI_TOO_LONG = 414;
146:
147: public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
148:
149: public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
150:
151: public static final int SC_EXPECTATION_FAILED = 417;
152:
153: public static final int SC_INTERNAL_SERVER_ERROR = 500;
154:
155: public static final int SC_NOT_IMPLEMENTED = 501;
156:
157: public static final int SC_BAD_GATEWAY = 502;
158:
159: public static final int SC_SERVICE_UNAVAILABLE = 503;
160:
161: public static final int SC_GATEWAY_TIMEOUT = 504;
162:
163: public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
164:
165: /**
166: * Add a cookie to this response, which will then be stored in the browser.
167: */
168: public void addCookie(Cookie cookie) {
169: cookies.put(cookie.getName(), cookie);
170: }
171:
172: /**
173: * Returns a cookie with a given, or null if this cookie has
174: * not been added to the repsonse.
175: */
176: public Cookie findCookie(String name) {
177: return (Cookie) cookies.get(name);
178: }
179:
180: /**
181: * This method is not supported.
182: */
183: public void addDateHeader(String name, long date) {
184: this .headers.put(name, new SimpleDateFormat(
185: "EEE, d MMM yyyy HH:mm:ss z").format(new Date(date)));
186: }
187:
188: /**
189: * Adds a response header with the given name and value.
190: */
191: public void addHeader(String name, String value) {
192: this .setHeader(name, value);
193: }
194:
195: /**
196: * Returns a given header field, or null if this header
197: * has not been set.
198: */
199: public String getHeader(String name) {
200: if (headers.containsKey(name))
201: return (String) headers.get(name);
202: else
203: return null;
204: }
205:
206: /**
207: * Adds a response header with the given name and integer value.
208: */
209: public void addIntHeader(String name, int value) {
210: this .setIntHeader(name, value);
211: }
212:
213: /**
214: * returns true if a header with the given name
215: * has already been set
216: */
217: public boolean containsHeader(String name) {
218: return headers.containsKey(name);
219: }
220:
221: /**
222: * Returns the given URL unmodified
223: */
224: public String encodeRedirectUrl(String url) {
225: return url;
226: }
227:
228: /**
229: * Returns the given URL unmodified.
230: */
231: public String encodeRedirectURL(String url) {
232: return url;
233: }
234:
235: /**
236: * Returns the given URL unmodified.
237: */
238: public String encodeUrl(String url) {
239: return url;
240: }
241:
242: /**
243: * Returns the given URL unmodified
244: */
245: public String encodeURL(String url) {
246: return url;
247: }
248:
249: /**
250: * This method is not supported.
251: */
252: public void flushBuffer() throws IOException {
253: throw new UnsupportedOperationException(
254: "flushBuffer operation is not supported!");
255: }
256:
257: /**
258: * This method is not supported.
259: */
260: public int getBufferSize() {
261: throw new UnsupportedOperationException(
262: "getBufferSize operation is not supported!");
263: }
264:
265: /**
266: * This method is not supported.
267: */
268: public String getCharacterEncoding() {
269: return charEncoding;
270: }
271:
272: /**
273: * Returns the locale assigned to the response.
274: *
275: *
276: * @see #setLocale
277: *
278: */
279: public Locale getLocale() {
280: if (locale == null)
281: return Locale.US;
282: else
283: return locale;
284: }
285:
286: /**
287: * Returns a {@link ServletOutputStream} suitable for writing binary
288: * data in the response. The servlet container does not encode the
289: * binary data.
290:
291: * <p> Calling flush() on the ServletOutputStream commits the response.
292:
293: * Either this method or {@link #getWriter} may
294: * be called to write the body, not both.
295: *
296: * @return a {@link ServletOutputStream} for writing binary data
297: *
298: * @exception IllegalStateException if the <code>getWriter</code> method
299: * has been called on this response
300: *
301: * @exception IOException if an input or output exception occurred
302: *
303: * @see #getWriter
304: *
305: */
306: public ServletOutputStream getOutputStream() throws IOException {
307: if (this .calledGetWriter)
308: throw new IllegalStateException(
309: "The getWriter method has already been called");
310:
311: ServletOutputStream oStream = null;
312: if (null == this .servOStream)
313: oStream = new ServletOutputStreamSimulator();
314: else
315: oStream = new ServletOutputStreamSimulator(this .servOStream);
316: // resets the status of servOStream to prevent us from possible using a closed stream
317: this .servOStream = null;
318: this .calledGetOutputStream = true;
319: return oStream;
320: }
321:
322: /**
323: * Returns a <code>PrintWriter</code> object that
324: * can send character text to the client.
325: * The character encoding used is the one specified
326: * in the <code>charset=</code> property of the
327: * {@link #setContentType} method, which must be called
328: * <i>before</i> calling this method for the charset to take effect.
329: *
330: * <p>If necessary, the MIME type of the response is
331: * modified to reflect the character encoding used.
332: *
333: * <p> Calling flush() on the PrintWriter commits the response.
334: *
335: * <p>Either this method or {@link #getOutputStream} may be called
336: * to write the body, not both.
337: *
338: *
339: * @return a <code>PrintWriter</code> object that
340: * can return character data to the client
341: *
342: * @exception UnsupportedEncodingException if the charset specified in
343: * <code>setContentType</code> cannot be
344: * used
345: *
346: * @exception IllegalStateException if the <code>getOutputStream</code>
347: * method has already been called for this
348: * response object
349: *
350: * @exception IOException if an input or output exception occurred
351: *
352: * @see #getOutputStream
353: * @see #setContentType
354: *
355: */
356: public PrintWriter getWriter() throws IOException {
357: if (this .calledGetOutputStream)
358: throw new IllegalStateException(
359: "The getOutputStream method has already been called");
360:
361: if (stringWriter == null)
362: stringWriter = new StringWriter();
363: if (printWriter == null)
364: printWriter = new PrintWriter(stringWriter);
365:
366: this .calledGetWriter = true;
367: return printWriter;
368: }
369:
370: /**
371: * Use this method to pick up the string buffer which will hold
372: * the contents of the string buffer. You can then
373: * write your test case to examine the contents of this
374: * buffer and match it against an expected output.
375: */
376: public StringBuffer getWriterBuffer() {
377: if (stringWriter == null)
378: return null;
379: return stringWriter.getBuffer();
380: }
381:
382: //TODO: better documentation
383: public boolean isCommitted() {
384: return isCommitted;
385: }
386:
387: public void setIsCommitted(boolean isCommitted) {
388: this .isCommitted = isCommitted;
389: }
390:
391: /**
392: * Reinitializes all local variables.
393: * Note, in most servlet containers, you may get an
394: * IllegalStateException if you call this method
395: * after committing the response.
396: * That behavior is not replicated here.
397: */
398: public void reset() {
399: this .calledGetOutputStream = false;
400: this .calledGetWriter = false;
401: this .contentLength = 0;
402: this .contentType = null;
403: this .stringWriter = null;
404: this .printWriter = null;
405: headers = new HashMap();
406: }
407:
408: /**
409: * This method is not supported.
410: */
411: public void resetBuffer() {
412: throw new UnsupportedOperationException(
413: "resetBuffer operation is not supported.");
414: }
415:
416: /**
417: * Sends an error response to the client using the specified
418: * status clearing the buffer. This method always throws
419: * an AssertionFailedError with the corresponding error
420: * number.
421: *
422: * @param sc the error status code
423: */
424: public void sendError(int sc) throws IOException {
425: setStatus(sc);
426: throw new AssertionFailedError("received error: " + sc);
427: }
428:
429: /**
430: * Sends an error response to the client using the specified
431: * status clearing the buffer. This method always throws
432: * an AssertionFailedError with the corresponding error
433: * number and descriptive text.
434: *
435: * @param sc the error status code
436: * @param msg the descriptive message
437: */
438: public void sendError(int sc, String msg) throws IOException {
439: setStatus(sc, msg);
440: throw new AssertionFailedError("received error " + sc + " : "
441: + msg);
442: }
443:
444: /**
445: * Resets the response and sets the appropriate redirect headers.
446: */
447: public void sendRedirect(String location) throws IOException {
448: reset();
449: setStatus(SC_MOVED_TEMPORARILY);
450: setHeader("Location", location);
451: }
452:
453: /**
454: * This method is not supported.
455: */
456: public void setBufferSize(int size) {
457: throw new UnsupportedOperationException(
458: "setBufferSize operation not supported.");
459: }
460:
461: /**
462: * Sets the length of the content body in the response
463: * In HTTP servlets, this method sets the HTTP Content-Length header.
464: *
465: *
466: * @param len an integer specifying the length of the
467: * content being returned to the client; sets
468: * the Content-Length header
469: *
470: */
471: public void setContentLength(int len) {
472: this .contentLength = len;
473: }
474:
475: /**
476: * returns the content length previously set in setContentLength()
477: * @return the content length
478: */
479: public int getContentLength() {
480: return this .contentLength;
481: }
482:
483: /**
484: * Sets the content type of the response being sent to
485: * the client. The content type may include the type of character
486: * encoding used, for example, <code>text/html; charset=ISO-8859-4</code>.
487: *
488: * <p>If obtaining a <code>PrintWriter</code>, this method should be
489: * called first.
490: *
491: *
492: * @param type a <code>String</code> specifying the MIME
493: * type of the content
494: *
495: * @see #getOutputStream
496: * @see #getWriter
497: *
498: */
499: public void setContentType(String type) {
500: this .contentType = type;
501: }
502:
503: /**
504: * returns the content type previously set in setContentType()
505: * @return the content type
506: */
507: public String getContentType() {
508: return this .contentType;
509: }
510:
511: /**
512: * This method is not supported.
513: */
514: public void setDateHeader(String name, long date) {
515: this .addDateHeader(name, date);
516: }
517:
518: /**
519: * adds the name/value pair to the headers
520: */
521: public void setHeader(String name, String value) {
522: if (name.equalsIgnoreCase("content-type")) {
523: setContentType(value);
524: return;
525: } else if (name.equalsIgnoreCase("content-length")) {
526: this .setContentLength(Integer.parseInt(value));
527: return;
528: }
529:
530: headers.put(name, value);
531: }
532:
533: /**
534: * Removes a given header
535: */
536: public void removeHeader(String name) {
537: if (headers.containsKey(name))
538: headers.remove(name);
539: }
540:
541: /**
542: * Adds the given name/value pair to the headers collection.
543: */
544: public void setIntHeader(String name, int value) {
545: setHeader(name, String.valueOf(value));
546: }
547:
548: /**
549: * Sets the locale of the response, setting the headers (including the
550: * Content-Type's charset) as appropriate. This method should be called
551: * before a call to {@link #getWriter}. By default, the response locale
552: * is the default locale for the server.
553: *
554: * @param loc the locale of the response
555: *
556: * @see #getLocale
557: *
558: */
559: public void setLocale(Locale loc) {
560: this .locale = loc;
561: }
562:
563: /**
564: * The default action of calling the <code>getOutputStream</code> method
565: * is to return a <code>javax.servlet.ServletOutputStream</code> object
566: * that sends the data to <code> System.out</code>. If you don't want
567: * the output sent to <code>System.out</code> you can use this method to
568: * set where the output will go. Please note, subsequent calls to
569: * <code>getOutputStream</code> will reset the output path to
570: * <code>System.out</code>. This prevents the OutputStream returned by
571: * calling getOutputStream from writing to a closed stream
572: *
573: * @param out The <code>java.io.OutputStream</code> that represents
574: * the real path of the output.
575: */
576: public void setOutputStream(OutputStream out) {
577: this .servOStream = out;
578: }
579:
580: /**
581: * Sets the given status code.
582: */
583: public void setStatus(int sc) {
584: setStatus(sc, null);
585: }
586:
587: /**
588: * Sets the given status and an associated message.
589: */
590: public void setStatus(int sc, String sm) {
591: this .status = sc;
592: this .message = sm;
593: }
594:
595: /**
596: * Returns the status code for this response, which is useful for testing expected errors.
597: * @return the status code for this response.
598: */
599: public int getStatusCode() {
600: return this .status;
601: }
602:
603: public void setCharacterEncoding(String charEncoding) {
604: this .charEncoding = charEncoding;
605: }
606:
607: public String getMessage() {
608: return message;
609: }
610:
611: }
|