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.wicket.protocol.http;
018:
019: import org.apache.wicket.AbortException;
020: import org.apache.wicket.IRedirectListener;
021: import org.apache.wicket.MetaDataKey;
022: import org.apache.wicket.Page;
023: import org.apache.wicket.RequestCycle;
024: import org.apache.wicket.Response;
025: import org.apache.wicket.RestartResponseAtInterceptPageException;
026: import org.apache.wicket.Session;
027: import org.apache.wicket.markup.html.pages.BrowserInfoPage;
028: import org.apache.wicket.protocol.http.request.WebClientInfo;
029: import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
030: import org.apache.wicket.request.ClientInfo;
031: import org.apache.wicket.request.IRequestCycleProcessor;
032: import org.apache.wicket.settings.IRequestCycleSettings;
033: import org.apache.wicket.util.string.Strings;
034: import org.slf4j.Logger;
035: import org.slf4j.LoggerFactory;
036:
037: /**
038: * RequestCycle implementation for HTTP protocol. Holds the application,
039: * session, request and response objects for a given HTTP request. Contains
040: * methods (urlFor*) which yield a URL for bookmarkable pages as well as
041: * non-bookmarkable component interfaces. The protected handleRender method is
042: * the internal entrypoint which takes care of the details of rendering a
043: * response to an HTTP request.
044: *
045: * @see RequestCycle
046: * @author Jonathan Locke
047: * @author Johan Compagner
048: * @author Gili Tzabari
049: * @author Eelco Hillenius
050: */
051: public class WebRequestCycle extends RequestCycle {
052: /** Logging object */
053: private static final Logger log = LoggerFactory
054: .getLogger(WebRequestCycle.class);
055:
056: private static final MetaDataKey BROWSER_WAS_POLLED_KEY = new MetaDataKey(
057: Boolean.class) {
058: private static final long serialVersionUID = 1L;
059: };
060:
061: /**
062: * Constructor which simply passes arguments to superclass for storage
063: * there. This instance will be set as the current one for this thread.
064: *
065: * @param application
066: * The applicaiton
067: * @param request
068: * The request
069: * @param response
070: * The response
071: */
072: public WebRequestCycle(final WebApplication application,
073: final WebRequest request, final Response response) {
074: super (application, request, response);
075: }
076:
077: /**
078: * By default returns the WebApplication's default request cycle processor.
079: * Typically, you don't override this method but instead override
080: * {@link WebApplication#getRequestCycleProcessor()}.
081: * <p>
082: * <strong>if you decide to override this method to provide a custom
083: * processor per request cycle, any mounts done via WebApplication will not
084: * work and and {@link #onRuntimeException(Page, RuntimeException)} is not
085: * called unless you deliberately put effort in it to make it work.</strong>
086: * </p>
087: *
088: * @see org.apache.wicket.RequestCycle#getProcessor()
089: */
090: public IRequestCycleProcessor getProcessor() {
091: return ((WebApplication) getApplication())
092: .getRequestCycleProcessor();
093: }
094:
095: /**
096: * @return Request as a WebRequest
097: */
098: public WebRequest getWebRequest() {
099: return (WebRequest) request;
100: }
101:
102: /**
103: * @return Response as a WebResponse
104: */
105: public WebResponse getWebResponse() {
106: return (WebResponse) response;
107: }
108:
109: /**
110: * @return Session as a WebSession
111: */
112: public WebSession getWebSession() {
113: return (WebSession) getSession();
114: }
115:
116: /**
117: * Redirects browser to the given page. NOTE: Usually, you should never call
118: * this method directly, but work with setResponsePage instead. This method
119: * is part of Wicket's internal behavior and should only be used when you
120: * want to circumvent the normal framework behavior and issue the redirect
121: * directly.
122: *
123: * @param page
124: * The page to redirect to
125: */
126: public final void redirectTo(final Page page) {
127: String redirectUrl = null;
128:
129: // Check if use serverside response for client side redirects
130: IRequestCycleSettings settings = application
131: .getRequestCycleSettings();
132: if ((settings.getRenderStrategy() == IRequestCycleSettings.REDIRECT_TO_BUFFER)
133: && (application instanceof WebApplication)) {
134: // remember the current response
135: final WebResponse currentResponse = getWebResponse();
136: try {
137: if (getWebRequest() instanceof ServletWebRequest) {
138: // Get the redirect url and set it in the ServletWebRequest
139: // so that it can be used for relative url calculation.
140: ((ServletWebRequest) getWebRequest())
141: .setWicketRedirectUrl(Strings
142: .replaceAll(
143: page
144: .urlFor(
145: IRedirectListener.INTERFACE)
146: .toString(), "../",
147: "").toString());
148: }
149: // create the redirect response.
150: final BufferedHttpServletResponse servletResponse = new BufferedHttpServletResponse(
151: currentResponse.getHttpServletResponse());
152: final WebResponse redirectResponse = new WebResponse(
153: servletResponse) {
154: public CharSequence encodeURL(CharSequence url) {
155: return currentResponse.encodeURL(url);
156: }
157: };
158: redirectResponse.setCharacterEncoding(currentResponse
159: .getCharacterEncoding());
160:
161: // redirect the response to the buffer
162: setResponse(redirectResponse);
163:
164: // render the page into the buffer
165: page.renderPage();
166:
167: // re-assign the original response
168: setResponse(currentResponse);
169:
170: final String responseRedirect = servletResponse
171: .getRedirectUrl();
172: if (responseRedirect != null) {
173: // if the redirectResponse has another redirect url set
174: // then the rendering of this page caused a redirect to
175: // something else.
176: // set this redirect then.
177: redirectUrl = responseRedirect;
178: } else if (servletResponse.getContentLength() > 0) {
179: // call filter() so that any filters can process the
180: // response
181: servletResponse.filter(currentResponse);
182:
183: // Set the final character encoding before calling close
184: servletResponse
185: .setCharacterEncoding(currentResponse
186: .getCharacterEncoding());
187: // close it so that the reponse is fixed and encoded from
188: // here on.
189: servletResponse.close();
190:
191: if (getWebRequest() instanceof ServletWebRequest) {
192: // Get the redirect url and set it in the ServletWebRequest
193: // so that it can be used for relative url calculation.
194: ((ServletWebRequest) getWebRequest())
195: .setWicketRedirectUrl(null);
196: }
197:
198: redirectUrl = page.urlFor(
199: IRedirectListener.INTERFACE).toString();
200: String stripped = Strings.replaceAll(redirectUrl,
201: "../", "").toString();
202: int index = stripped.indexOf("?");
203: String sessionId = getApplication()
204: .getSessionStore().getSessionId(request,
205: true);
206: ((WebApplication) application).addBufferedResponse(
207: sessionId, stripped.substring(index + 1),
208: servletResponse);
209: }
210: } catch (RuntimeException ex) {
211: // re-assign the original response
212: setResponse(currentResponse);
213: if (ex instanceof AbortException) {
214: throw ex;
215: }
216:
217: if (!(ex instanceof PageExpiredException)) {
218: logRuntimeException(ex);
219: }
220:
221: IRequestCycleProcessor processor = getProcessor();
222: processor.respond(ex, this );
223: return;
224: }
225: } else {
226: redirectUrl = page.urlFor(IRedirectListener.INTERFACE)
227: .toString();
228:
229: // Redirect page can touch its models already (via for example the
230: // constructors)
231: // this can be removed i guess because this page will be detached in
232: // the page target
233: // page.internalDetach();
234: }
235:
236: if (redirectUrl == null) {
237: redirectUrl = page.urlFor(IRedirectListener.INTERFACE)
238: .toString();
239: }
240:
241: // Always touch the page again so that a redirect listener makes a page
242: // stateful and adds it to the pagemap
243: getSession().touch(page);
244:
245: // Redirect to the url for the page
246: response.redirect(redirectUrl);
247: }
248:
249: /**
250: * @see org.apache.wicket.RequestCycle#newClientInfo()
251: */
252: protected ClientInfo newClientInfo() {
253: if (getApplication().getRequestCycleSettings()
254: .getGatherExtendedBrowserInfo()) {
255: Session session = getSession();
256: if (session.getMetaData(BROWSER_WAS_POLLED_KEY) == null) {
257: // we haven't done the redirect yet; record that we will be
258: // doing that now and redirect
259: session.setMetaData(BROWSER_WAS_POLLED_KEY,
260: Boolean.TRUE);
261: throw new RestartResponseAtInterceptPageException(
262: new BrowserInfoPage(getRequest()
263: .getRelativePathPrefixToContextRoot()
264: + getRequest().getURL()));
265: }
266: // if we get here, the redirect already has been done; clear
267: // the meta data entry; we don't need it any longer is the client
268: // info object will be cached too
269: session.setMetaData(BROWSER_WAS_POLLED_KEY, (Boolean) null);
270: }
271: return new WebClientInfo(this );
272: }
273:
274: /**
275: * If it's an ajax request we always redirect.
276: *
277: * @see org.apache.wicket.RequestCycle#isRedirect()
278: */
279: public final boolean isRedirect() {
280: if (getWebRequest().isAjax()) {
281: return true;
282: } else {
283: return super.isRedirect();
284: }
285: }
286: }
|