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: package org.apache.cocoon.environment.http;
018:
019: import java.io.IOException;
020: import java.io.OutputStream;
021: import java.net.MalformedURLException;
022:
023: import javax.servlet.ServletContext;
024: import javax.servlet.http.HttpServletRequest;
025: import javax.servlet.http.HttpServletResponse;
026:
027: import org.apache.cocoon.environment.AbstractEnvironment;
028: import org.apache.cocoon.environment.ObjectModelHelper;
029: import org.apache.cocoon.environment.PermanentRedirector;
030: import org.apache.cocoon.environment.Redirector;
031: import org.apache.cocoon.environment.Session;
032: import org.apache.cocoon.util.NetUtils;
033:
034: /**
035: * HTTP Servlet environment.
036: *
037: * @author <a herf="mailto:dev@cocoon.apache.org">Apache Cocoon Team</a>
038: * @version $Id: HttpEnvironment.java 433543 2006-08-22 06:22:54Z crossley $
039: */
040: public class HttpEnvironment extends AbstractEnvironment implements
041: Redirector, PermanentRedirector {
042:
043: public static final String HTTP_REQUEST_OBJECT = "httprequest";
044: public static final String HTTP_RESPONSE_OBJECT = "httpresponse";
045: public static final String HTTP_SERVLET_CONTEXT = "httpservletcontext";
046:
047: /** The HttpRequest */
048: private HttpRequest request;
049:
050: /** The HttpResponse */
051: private HttpResponse response;
052:
053: /** The HttpContext */
054: private HttpContext webcontext;
055:
056: /** Cache content type as there is no getContentType() in reponse object */
057: private String contentType;
058:
059: /** Did we redirect ? */
060: private boolean hasRedirected = false;
061:
062: /**
063: * Constructs a HttpEnvironment object from a HttpServletRequest
064: * and HttpServletResponse objects
065: */
066: public HttpEnvironment(String uri, String root,
067: HttpServletRequest req, HttpServletResponse res,
068: ServletContext servletContext, HttpContext context,
069: String containerEncoding, String defaultFormEncoding)
070: throws MalformedURLException, IOException {
071: super (uri, null, root, null);
072:
073: this .request = new HttpRequest(req, this );
074: this .request.setCharacterEncoding(defaultFormEncoding);
075: this .request.setContainerEncoding(containerEncoding);
076: this .response = new HttpResponse(res);
077: this .webcontext = context;
078:
079: setView(extractView(this .request));
080: setAction(extractAction(this .request));
081:
082: this .objectModel.put(ObjectModelHelper.REQUEST_OBJECT,
083: this .request);
084: this .objectModel.put(ObjectModelHelper.RESPONSE_OBJECT,
085: this .response);
086: this .objectModel.put(ObjectModelHelper.CONTEXT_OBJECT,
087: this .webcontext);
088:
089: // This is a kind of a hack for the components that need
090: // the real servlet objects to pass them along to other
091: // libraries.
092: this .objectModel.put(HTTP_REQUEST_OBJECT, req);
093: this .objectModel.put(HTTP_RESPONSE_OBJECT, res);
094: this .objectModel.put(HTTP_SERVLET_CONTEXT, servletContext);
095: }
096:
097: public void redirect(boolean sessionmode, String newURL)
098: throws IOException {
099: doRedirect(sessionmode, newURL, false);
100: }
101:
102: public void permanentRedirect(boolean sessionmode, String newURL)
103: throws IOException {
104: doRedirect(sessionmode, newURL, true);
105: }
106:
107: public void sendStatus(int sc) {
108: setStatus(sc);
109: this .hasRedirected = true;
110: }
111:
112: /**
113: * Redirect the client to new URL with session mode
114: */
115: private void doRedirect(boolean sessionmode, String newURL,
116: boolean permanent) throws IOException {
117: this .hasRedirected = true;
118:
119: // check if session mode shall be activated
120: if (sessionmode) {
121: String s = request.getRequestedSessionId();
122: if (getLogger().isDebugEnabled()) {
123: if (s != null) {
124: getLogger()
125: .debug(
126: "Redirect: Requested session ID <"
127: + s
128: + "> is "
129: + (request
130: .isRequestedSessionIdValid() ? "valid"
131: : "invalid"));
132: } else {
133: getLogger().debug(
134: "Redirect: No session found in request");
135: }
136: }
137:
138: // Get session from request, or create new session
139: Session session = request.getSession();
140: if (getLogger().isDebugEnabled()) {
141: getLogger().debug(
142: "Redirect: Obtained session <"
143: + session.getId() + ">");
144: }
145: }
146:
147: // Redirect
148: String redirect = this .response.encodeRedirectURL(newURL);
149:
150: // FIXME (VG): WebSphere 4.0/4.0.1 bug
151: if (!newURL.startsWith("/") && newURL.indexOf(':') == -1
152: && redirect.indexOf(':') != -1) {
153: if (getLogger().isDebugEnabled()) {
154: getLogger().debug("Redirect: WebSphere Bug Detected!");
155: }
156: String base = NetUtils.getPath(request.getRequestURI());
157: if (base.startsWith("/")) {
158: base = base.substring(1);
159: }
160: redirect = response.encodeRedirectURL(base + '/' + newURL);
161: }
162:
163: if (getLogger().isDebugEnabled()) {
164: getLogger().debug("Sending redirect to '" + redirect + "'");
165: }
166:
167: if (permanent) {
168: this .response.sendPermanentRedirect(redirect);
169: } else {
170: this .response.sendRedirect(redirect);
171: }
172: }
173:
174: public boolean hasRedirected() {
175: return this .hasRedirected;
176: }
177:
178: /**
179: * Set the StatusCode
180: */
181: public void setStatus(int statusCode) {
182: this .response.setStatus(statusCode);
183: }
184:
185: /**
186: * Set the ContentType
187: */
188: public void setContentType(String contentType) {
189: this .response.setContentType(contentType);
190: this .contentType = contentType;
191: }
192:
193: /**
194: * Get the ContentType
195: */
196: public String getContentType() {
197: return this .contentType;
198: }
199:
200: /**
201: * Set the length of the generated content
202: */
203: public void setContentLength(int length) {
204: this .response.setContentLength(length);
205: }
206:
207: /**
208: * Check if the response has been modified since the same
209: * "resource" was requested.
210: * The caller has to test if it is really the same "resource"
211: * which is requested.
212: * @return true if the response is modified or if the
213: * environment is not able to test it
214: */
215: public boolean isResponseModified(long lastModified) {
216: if (lastModified != 0) {
217: long if_modified_since = this .request
218: .getDateHeader("If-Modified-Since");
219: this .response.setDateHeader("Last-Modified", lastModified);
220: return (if_modified_since / 1000 < lastModified / 1000);
221: }
222: return true;
223: }
224:
225: /**
226: * Mark the response as not modified.
227: */
228: public void setResponseIsNotModified() {
229: this .response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
230: }
231:
232: /**
233: * Reset the response if possible. This allows error handlers to have
234: * a higher chance to produce clean output if the pipeline that raised
235: * the error has already output some data.
236: *
237: * @return true if the response was successfully reset
238: */
239: public boolean tryResetResponse() throws IOException {
240: if (!super .tryResetResponse()) {
241: try {
242: if (!this .response.isCommitted()) {
243: this .response.reset();
244: if (getLogger().isDebugEnabled()) {
245: getLogger()
246: .debug("Response successfully reset");
247: }
248: return true;
249: }
250: } catch (Exception e) {
251: // Log the error, but don't transmit it
252: getLogger().warn("Problem resetting response", e);
253: }
254: if (getLogger().isDebugEnabled()) {
255: getLogger().debug("Response wasn't reset");
256: }
257: return false;
258: }
259: return true;
260: }
261:
262: /**
263: * Get the output stream where to write the generated resource.
264: * The returned stream is buffered by the environment. If the
265: * buffer size is -1 then the complete output is buffered.
266: * If the buffer size is 0, no buffering takes place.
267: * This method replaces {@link #getOutputStream()}.
268: */
269: public OutputStream getOutputStream(final int bufferSize)
270: throws IOException {
271: if (this .outputStream == null) {
272: this .outputStream = this .response.getOutputStream();
273: }
274: return super .getOutputStream(bufferSize);
275: }
276:
277: /**
278: * Always return <code>true</code>.
279: */
280: public boolean isExternal() {
281: return true;
282: }
283: }
|