001: /*
002: * $Id: ResourceStreamRequestTarget.java 462313 2006-09-19 18:12:11Z ehillenius $
003: * $Revision: 462313 $ $Date: 2006-09-19 20:12:11 +0200 (Tue, 19 Sep 2006) $
004: *
005: * ==============================================================================
006: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
007: * use this file except in compliance with the License. You may obtain a copy of
008: * the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations under
016: * the License.
017: */
018: package wicket.request.target.resource;
019:
020: import java.io.OutputStream;
021: import java.net.SocketException;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import wicket.IRequestTarget;
027: import wicket.RequestCycle;
028: import wicket.Response;
029: import wicket.WicketRuntimeException;
030: import wicket.protocol.http.WebResponse;
031: import wicket.util.io.Streams;
032: import wicket.util.resource.IResourceStream;
033:
034: /**
035: * Request target that responds by sending it's resources stream.
036: *
037: * @author Eelco Hillenius
038: */
039: public class ResourceStreamRequestTarget implements IRequestTarget {
040: /** Logger */
041: private static final Log log = LogFactory
042: .getLog(ResourceStreamRequestTarget.class);
043:
044: /**
045: * Optional filename, used to set the content disposition header. Only
046: * meaningful when using with web requests.
047: */
048: private String fileName;
049:
050: /** the resource stream for the response. */
051: private final IResourceStream resourceStream;
052:
053: /**
054: * the response type, eg 'text/html'.
055: *
056: * @deprecated Removed in 2.0
057: */
058: private final String responseType;
059:
060: /**
061: * Construct.
062: *
063: * @param resourceStream
064: * the resource stream for the response
065: */
066: public ResourceStreamRequestTarget(IResourceStream resourceStream) {
067: this (resourceStream, null);
068: }
069:
070: /**
071: * Construct.
072: *
073: * @param resourceStream
074: * the resource stream for the response
075: * @param responseType
076: * the response type, eg 'text/html'
077: * @deprecated Will be removed in 2.0. Response type can be determined from
078: * resource stream
079: */
080: public ResourceStreamRequestTarget(IResourceStream resourceStream,
081: String responseType) {
082: if (resourceStream == null) {
083: throw new IllegalArgumentException(
084: "Argument resourceStream must be not null");
085: }
086:
087: this .resourceStream = resourceStream;
088: this .responseType = responseType;
089: }
090:
091: /**
092: * @see wicket.IRequestTarget#detach(wicket.RequestCycle)
093: */
094: public void detach(RequestCycle requestCycle) {
095: }
096:
097: /**
098: * @see java.lang.Object#equals(java.lang.Object)
099: */
100: public boolean equals(Object obj) {
101: if (obj instanceof ResourceStreamRequestTarget) {
102: ResourceStreamRequestTarget that = (ResourceStreamRequestTarget) obj;
103: return resourceStream.equals(that.resourceStream)
104: && ((fileName != null) ? fileName
105: .equals(this .fileName) : true);
106: }
107: return false;
108: }
109:
110: /**
111: * @return Optional filename, used to set the content disposition header.
112: * Only meaningful when using with web requests.
113: */
114: public String getFileName() {
115: return fileName;
116: }
117:
118: /**
119: * @see wicket.IRequestTarget#getLock(RequestCycle)
120: */
121: public Object getLock(RequestCycle requestCycle) {
122: return null;
123: }
124:
125: /**
126: * Gets the resource stream for the response.
127: *
128: * @return the resource stream for the response
129: */
130: public final IResourceStream getResourceStream() {
131: return resourceStream;
132: }
133:
134: /**
135: * Gets the response type, eg 'text/html'.
136: *
137: * @return the response type, eg 'text/html'
138: * @deprecated Will be removed in 2.0. Response type can be determined by
139: * looking at the resource stream
140: */
141: public final String getResponseType() {
142: return responseType;
143: }
144:
145: /**
146: * @see java.lang.Object#hashCode()
147: */
148: public int hashCode() {
149: int result = "ResourceStreamRequestTarget".hashCode();
150: result += resourceStream.hashCode();
151: result += (fileName != null) ? fileName.hashCode() : 0;
152: return 17 * result;
153: }
154:
155: /**
156: * Responds by sending the contents of the resource stream.
157: *
158: * @see wicket.IRequestTarget#respond(wicket.RequestCycle)
159: */
160: public void respond(RequestCycle requestCycle) {
161: // Get servlet response to use when responding with resource
162: final Response response = requestCycle.getResponse();
163:
164: configure(response, resourceStream);
165:
166: // Respond with resource
167: try {
168: final OutputStream out = response.getOutputStream();
169: try {
170: Streams.copy(resourceStream.getInputStream(), out);
171: } finally {
172: resourceStream.close();
173: out.flush();
174: }
175: } catch (Exception e) {
176: Throwable throwable = e;
177: boolean ignoreException = false;
178: while (throwable != null) {
179: if (throwable instanceof SocketException) {
180: String message = throwable.getMessage();
181: ignoreException = message != null
182: && (message
183: .indexOf("Connection reset by peer") != -1 || message
184: .indexOf("Software caused connection abort") != -1);
185: } else {
186: ignoreException = throwable.getClass().getName()
187: .indexOf("ClientAbortException") >= 0;
188: if (ignoreException) {
189: if (log.isDebugEnabled()) {
190: log
191: .debug(
192: "Socket exception ignored for sending Resource "
193: + "response to client (ClientAbort)",
194: e);
195: }
196: break;
197: }
198: }
199: throwable = throwable.getCause();
200: }
201: if (!ignoreException) {
202: throw new WicketRuntimeException(
203: "Unable to render resource stream "
204: + resourceStream, e);
205: }
206: }
207: }
208:
209: /**
210: * @param fileName
211: * Optional filename, used to set the content disposition header.
212: * Only meaningful when using with web requests.
213: */
214: public void setFileName(String fileName) {
215: this .fileName = fileName;
216: }
217:
218: /**
219: * @see java.lang.Object#toString()
220: */
221: public String toString() {
222: return "[ResourceStreamRequestTarget[resourceStream="
223: + resourceStream + ",fileName=" + fileName + "]";
224: }
225:
226: /**
227: * Configures the response, default by setting the content type and length
228: * and content disposition (in case the fileName property was set).
229: *
230: * @param response
231: * the response
232: * @param resourceStream
233: * the resource stream that will be rendered
234: */
235: protected void configure(final Response response,
236: final IResourceStream resourceStream) {
237: // Configure response with content type of resource
238: String responseType = resourceStream.getContentType();
239: if (responseType == null) {
240: responseType = this .responseType;
241: }
242: response.setContentType(responseType + ";charset="
243: + response.getCharacterEncoding());
244:
245: // and the content length
246: response.setContentLength((int) resourceStream.length());
247:
248: // and content disposition if any
249: String file = getFileName();
250: if (file != null && (response instanceof WebResponse)) {
251: ((WebResponse) response).setAttachmentHeader(file);
252: }
253: }
254: }
|