001: /*
002: * $Id: WebResponse.java 5231 2006-04-01 15:34:49 -0800 (Sat, 01 Apr 2006)
003: * joco01 $ $Revision: 462386 $ $Date: 2006-04-01 15:34:49 -0800 (Sat, 01 Apr
004: * 2006) $
005: *
006: * ==============================================================================
007: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
008: * use this file except in compliance with the License. You may obtain a copy of
009: * the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016: * License for the specific language governing permissions and limitations under
017: * the License.
018: */
019: package wicket.protocol.http;
020:
021: import java.io.IOException;
022: import java.io.OutputStream;
023: import java.util.Locale;
024:
025: import javax.servlet.http.Cookie;
026: import javax.servlet.http.HttpServletResponse;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import wicket.Response;
032: import wicket.WicketRuntimeException;
033: import wicket.util.string.AppendingStringBuffer;
034: import wicket.util.string.Strings;
035: import wicket.util.time.Time;
036:
037: /**
038: * Implements responses over the HTTP protocol by holding an underlying
039: * HttpServletResponse object and providing convenience methods for using that
040: * object. Convenience methods include methods which: add a cookie, close the
041: * stream, encode a URL, redirect a request to another resource, determine if a
042: * redirect has been issued, set the content type, set the locale and, most
043: * importantly, write a String to the response output.
044: *
045: * @author Jonathan Locke
046: */
047: public class WebResponse extends Response {
048: /** Log. */
049: private static final Log log = LogFactory.getLog(WebResponse.class);
050:
051: /** True if response is a redirect. */
052: protected boolean redirect;
053:
054: /** The underlying response object. */
055: private final HttpServletResponse httpServletResponse;
056:
057: /** */
058: private boolean ajax;
059:
060: /**
061: * Constructor for testing harness.
062: */
063: public WebResponse() {
064: this .httpServletResponse = null;
065: }
066:
067: /**
068: * Package private constructor.
069: *
070: * @param httpServletResponse
071: * The servlet response object
072: */
073: public WebResponse(final HttpServletResponse httpServletResponse) {
074: this .httpServletResponse = httpServletResponse;
075: }
076:
077: /**
078: * Add a cookie to the web response
079: *
080: * @param cookie
081: */
082: public void addCookie(final Cookie cookie) {
083: getHttpServletResponse().addCookie(cookie);
084: }
085:
086: /**
087: * Convenience method for clearing a cookie.
088: *
089: * @param cookie
090: * The cookie to set
091: * @see WebResponse#addCookie(Cookie)
092: */
093: public void clearCookie(final Cookie cookie) {
094: cookie.setMaxAge(0);
095: cookie.setValue(null);
096: addCookie(cookie);
097: }
098:
099: /**
100: * Closes response output.
101: */
102: public void close() {
103: // NOTE: Servlet container will close the response output stream
104: // automatically, so we do nothing here.
105: }
106:
107: /**
108: * Returns the given url encoded.
109: *
110: * @param url
111: * The URL to encode
112: * @return The encoded url
113: */
114: public CharSequence encodeURL(CharSequence url) {
115: if (httpServletResponse != null && url != null) {
116: return httpServletResponse.encodeURL(url.toString());
117: }
118: return url;
119: }
120:
121: /**
122: * Gets the wrapped http servlet response object.
123: *
124: * @return The wrapped http servlet response object
125: */
126: public final HttpServletResponse getHttpServletResponse() {
127: return httpServletResponse;
128: }
129:
130: /**
131: * @see wicket.Response#getOutputStream()
132: */
133: public OutputStream getOutputStream() {
134: try {
135: return httpServletResponse.getOutputStream();
136: } catch (IOException e) {
137: throw new WicketRuntimeException(
138: "Error while getting output stream.", e);
139: }
140: }
141:
142: /**
143: * Whether this response is going to redirect the user agent.
144: *
145: * @return True if this response is going to redirect the user agent
146: */
147: public final boolean isRedirect() {
148: return redirect;
149: }
150:
151: /**
152: * CLIENTS SHOULD NEVER CALL THIS METHOD FOR DAY TO DAY USE!
153: * <p>
154: * Redirects to the given url. Implementations should encode the URL to make
155: * sure cookie-less operation is supported in case clients forgot.
156: * </p>
157: *
158: * @param url
159: * The URL to redirect to
160: */
161: public void redirect(String url) {
162: if (!redirect) {
163: if (httpServletResponse != null) {
164: // encode to make sure no caller forgot this
165: url = encodeURL(url).toString();
166: try {
167: if (httpServletResponse.isCommitted()) {
168: log
169: .error("Unable to redirect to: "
170: + url
171: + ", HTTP Response has already been committed.");
172: }
173:
174: if (log.isDebugEnabled()) {
175: log.debug("Redirecting to " + url);
176: }
177:
178: if (isAjax()) {
179: httpServletResponse.addHeader("Ajax-Location",
180: url);
181:
182: // safari chokes on empty response. but perhaps this is not the best place?
183: httpServletResponse.getWriter().write(" ");
184: } else {
185: httpServletResponse.sendRedirect(url);
186: }
187: redirect = true;
188: } catch (IOException e) {
189: throw new WicketRuntimeException("Redirect failed",
190: e);
191: }
192: }
193: } else {
194: log
195: .info("Already redirecting to an url current one ignored: "
196: + url);
197: }
198: }
199:
200: /**
201: * Set the content type on the response.
202: *
203: * @param mimeType
204: * The mime type
205: */
206: public final void setContentType(final String mimeType) {
207: httpServletResponse.setContentType(mimeType);
208: }
209:
210: /**
211: * @see wicket.Response#setContentLength(long)
212: */
213: public void setContentLength(long length) {
214: httpServletResponse.setContentLength((int) length);
215: }
216:
217: /**
218: * @see wicket.Response#setLastModifiedTime(wicket.util.time.Time)
219: */
220: public void setLastModifiedTime(Time time) {
221: if (time != null && time.getMilliseconds() != -1) {
222: httpServletResponse.setDateHeader("Last-Modified", time
223: .getMilliseconds());
224: }
225: }
226:
227: /**
228: * Output stream encoding. If the deployment descriptor contains a
229: * locale-encoding-mapping-list element, and that element provides a mapping
230: * for the given locale, that mapping is used. Otherwise, the mapping from
231: * locale to character encoding is container dependent. Default is
232: * ISO-8859-1.
233: *
234: * @see javax.servlet.ServletResponse#setLocale(java.util.Locale)
235: *
236: * @param locale
237: * The locale use for mapping the character encoding
238: */
239: public final void setLocale(final Locale locale) {
240: httpServletResponse.setLocale(locale);
241: }
242:
243: /**
244: * Writes string to response output.
245: *
246: * @param string
247: * The string to write
248: */
249: public void write(final CharSequence string) {
250: if (string instanceof AppendingStringBuffer) {
251: write((AppendingStringBuffer) string);
252: } else if (string instanceof StringBuffer) {
253: try {
254: StringBuffer sb = (StringBuffer) string;
255: char[] array = new char[sb.length()];
256: sb.getChars(0, sb.length(), array, 0);
257: httpServletResponse.getWriter().write(array, 0,
258: array.length);
259: } catch (IOException e) {
260: throw new WicketRuntimeException(
261: "Error while writing to servlet output writer.",
262: e);
263: }
264: } else {
265: try {
266: httpServletResponse.getWriter()
267: .write(string.toString());
268: } catch (IOException e) {
269: throw new WicketRuntimeException(
270: "Error while writing to servlet output writer.",
271: e);
272: }
273: }
274: }
275:
276: /**
277: * Writes AppendingStringBuffer to response output.
278: *
279: * @param asb
280: * The AppendingStringBuffer to write to the stream
281: */
282: public void write(AppendingStringBuffer asb) {
283: try {
284: httpServletResponse.getWriter().write(asb.getValue(), 0,
285: asb.length());
286: } catch (IOException e) {
287: throw new WicketRuntimeException(
288: "Error while writing to servlet output writer.", e);
289: }
290: }
291:
292: /**
293: * Set a header to the date value in the servlet response stream.
294: *
295: * @param header
296: * @param date
297: */
298: public void setDateHeader(String header, long date) {
299: httpServletResponse.setDateHeader(header, date);
300: }
301:
302: /**
303: * Set a header to the string value in the servlet response stream.
304: *
305: * @param header
306: * @param value
307: */
308: public void setHeader(String header, String value) {
309: httpServletResponse.setHeader(header, value);
310: }
311:
312: /**
313: * Convinience method for setting the content-disposition:attachment header.
314: * This header is used if the response should prompt the user to download it
315: * as a file instead of opening in a browser.
316: *
317: * @param filename
318: * file name of the attachment
319: */
320: public void setAttachmentHeader(String filename) {
321: setHeader("Content-Disposition", "attachment"
322: + ((!Strings.isEmpty(filename)) ? ("; filename=\""
323: + filename + "\"") : ""));
324: }
325:
326: /**
327: * Is the request, which matches this response an ajax request.
328: *
329: * @return True if the request is an ajax request.
330: */
331: public boolean isAjax() {
332: return ajax;
333: }
334:
335: /**
336: * Set that the request which matches this response is an ajax request.
337: *
338: * @param ajax True if the request is an ajax request.
339: */
340: public void setAjax(boolean ajax) {
341: this.ajax = ajax;
342: }
343: }
|