001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.catalina.ssi;
019:
020: import java.io.IOException;
021: import java.io.OutputStreamWriter;
022: import java.io.PrintWriter;
023:
024: import javax.servlet.ServletContext;
025: import javax.servlet.ServletOutputStream;
026: import javax.servlet.http.HttpServletRequest;
027: import javax.servlet.http.HttpServletResponse;
028: import javax.servlet.http.HttpServletResponseWrapper;
029:
030: import org.apache.catalina.util.DateTool;
031:
032: /**
033: * A HttpServletResponseWrapper, used from
034: * <code>SSIServletExternalResolver</code>
035: *
036: * @author Bip Thelin
037: * @author David Becker
038: * @version $Revision: 467222 $, $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
039: */
040: public class ResponseIncludeWrapper extends HttpServletResponseWrapper {
041: /**
042: * The names of some headers we want to capture.
043: */
044: private static final String CONTENT_TYPE = "content-type";
045: private static final String LAST_MODIFIED = "last-modified";
046: protected long lastModified = -1;
047: private String contentType = null;
048:
049: /**
050: * Our ServletOutputStream
051: */
052: protected ServletOutputStream captureServletOutputStream;
053: protected ServletOutputStream servletOutputStream;
054: protected PrintWriter printWriter;
055:
056: private ServletContext context;
057: private HttpServletRequest request;
058:
059: /**
060: * Initialize our wrapper with the current HttpServletResponse and
061: * ServletOutputStream.
062: *
063: * @param context The servlet context
064: * @param request The HttpServletResponse to use
065: * @param response The response to use
066: * @param captureServletOutputStream The ServletOutputStream to use
067: */
068: public ResponseIncludeWrapper(ServletContext context,
069: HttpServletRequest request, HttpServletResponse response,
070: ServletOutputStream captureServletOutputStream) {
071: super (response);
072: this .context = context;
073: this .request = request;
074: this .captureServletOutputStream = captureServletOutputStream;
075: }
076:
077: /**
078: * Flush the servletOutputStream or printWriter ( only one will be non-null )
079: * This must be called after a requestDispatcher.include, since we can't
080: * assume that the included servlet flushed its stream.
081: */
082: public void flushOutputStreamOrWriter() throws IOException {
083: if (servletOutputStream != null) {
084: servletOutputStream.flush();
085: }
086: if (printWriter != null) {
087: printWriter.flush();
088: }
089: }
090:
091: /**
092: * Return a printwriter, throws and exception if a OutputStream already
093: * been returned.
094: *
095: * @return a PrintWriter object
096: * @exception java.io.IOException
097: * if the outputstream already been called
098: */
099: public PrintWriter getWriter() throws java.io.IOException {
100: if (servletOutputStream == null) {
101: if (printWriter == null) {
102: setCharacterEncoding(getCharacterEncoding());
103: printWriter = new PrintWriter(new OutputStreamWriter(
104: captureServletOutputStream,
105: getCharacterEncoding()));
106: }
107: return printWriter;
108: }
109: throw new IllegalStateException();
110: }
111:
112: /**
113: * Return a OutputStream, throws and exception if a printwriter already
114: * been returned.
115: *
116: * @return a OutputStream object
117: * @exception java.io.IOException
118: * if the printwriter already been called
119: */
120: public ServletOutputStream getOutputStream()
121: throws java.io.IOException {
122: if (printWriter == null) {
123: if (servletOutputStream == null) {
124: servletOutputStream = captureServletOutputStream;
125: }
126: return servletOutputStream;
127: }
128: throw new IllegalStateException();
129: }
130:
131: /**
132: * Returns the value of the <code>last-modified</code> header field. The
133: * result is the number of milliseconds since January 1, 1970 GMT.
134: *
135: * @return the date the resource referenced by this
136: * <code>ResponseIncludeWrapper</code> was last modified, or -1 if not
137: * known.
138: */
139: public long getLastModified() {
140: if (lastModified == -1) {
141: // javadocs say to return -1 if date not known, if you want another
142: // default, put it here
143: return -1;
144: }
145: return lastModified;
146: }
147:
148: /**
149: * Sets the value of the <code>last-modified</code> header field.
150: *
151: * @param lastModified The number of milliseconds since January 1, 1970 GMT.
152: */
153: public void setLastModified(long lastModified) {
154: this .lastModified = lastModified;
155: ((HttpServletResponse) getResponse()).setDateHeader(
156: LAST_MODIFIED, lastModified);
157: }
158:
159: /**
160: * Returns the value of the <code>content-type</code> header field.
161: *
162: * @return the content type of the resource referenced by this
163: * <code>ResponseIncludeWrapper</code>, or <code>null</code> if not known.
164: */
165: public String getContentType() {
166: if (contentType == null) {
167: String url = request.getRequestURI();
168: String mime = context.getMimeType(url);
169: if (mime != null) {
170: setContentType(mime);
171: } else {
172: // return a safe value
173: setContentType("application/x-octet-stream");
174: }
175: }
176: return contentType;
177: }
178:
179: /**
180: * Sets the value of the <code>content-type</code> header field.
181: *
182: * @param mime a mime type
183: */
184: public void setContentType(String mime) {
185: contentType = mime;
186: if (contentType != null) {
187: getResponse().setContentType(contentType);
188: }
189: }
190:
191: public void addDateHeader(String name, long value) {
192: super .addDateHeader(name, value);
193: String lname = name.toLowerCase();
194: if (lname.equals(LAST_MODIFIED)) {
195: lastModified = value;
196: }
197: }
198:
199: public void addHeader(String name, String value) {
200: super .addHeader(name, value);
201: String lname = name.toLowerCase();
202: if (lname.equals(LAST_MODIFIED)) {
203: try {
204: lastModified = DateTool.rfc1123Format.parse(value)
205: .getTime();
206: } catch (Throwable ignore) {
207: }
208: } else if (lname.equals(CONTENT_TYPE)) {
209: contentType = value;
210: }
211: }
212:
213: public void setDateHeader(String name, long value) {
214: super .setDateHeader(name, value);
215: String lname = name.toLowerCase();
216: if (lname.equals(LAST_MODIFIED)) {
217: lastModified = value;
218: }
219: }
220:
221: public void setHeader(String name, String value) {
222: super .setHeader(name, value);
223: String lname = name.toLowerCase();
224: if (lname.equals(LAST_MODIFIED)) {
225: try {
226: lastModified = DateTool.rfc1123Format.parse(value)
227: .getTime();
228: } catch (Throwable ignore) {
229: }
230: } else if (lname.equals(CONTENT_TYPE)) {
231: contentType = value;
232: }
233: }
234: }
|