📄 requestcycle.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.wicket;import java.io.Serializable;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import org.apache.wicket.behavior.IBehavior;import org.apache.wicket.protocol.http.BufferedWebResponse;import org.apache.wicket.protocol.http.IRequestLogger;import org.apache.wicket.protocol.http.PageExpiredException;import org.apache.wicket.protocol.http.RequestUtils;import org.apache.wicket.protocol.http.servlet.ServletWebRequest;import org.apache.wicket.request.AbstractRequestCycleProcessor;import org.apache.wicket.request.ClientInfo;import org.apache.wicket.request.IRequestCycleProcessor;import org.apache.wicket.request.RequestParameters;import org.apache.wicket.request.target.component.BookmarkableListenerInterfaceRequestTarget;import org.apache.wicket.request.target.component.BookmarkablePageRequestTarget;import org.apache.wicket.request.target.component.ComponentRequestTarget;import org.apache.wicket.request.target.component.IBookmarkablePageRequestTarget;import org.apache.wicket.request.target.component.IPageRequestTarget;import org.apache.wicket.request.target.component.PageRequestTarget;import org.apache.wicket.request.target.component.listener.BehaviorRequestTarget;import org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget;import org.apache.wicket.request.target.resource.SharedResourceRequestTarget;import org.apache.wicket.util.collections.ArrayListStack;import org.apache.wicket.util.string.AppendingStringBuffer;import org.apache.wicket.util.string.Strings;import org.apache.wicket.util.time.Time;import org.apache.wicket.util.value.ValueMap;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Represents the processing of a request. It is responsible for instructing the * {@link IRequestCycleProcessor request cycle processor} to execute the various steps there are in * the handling of a request (resolving the kind of work that needs to be done, handling of events * and generating a response), and it holds the intended {@link IRequestTarget request target}, * which is an abstraction for e.g. the processing of a bookmarkable page. * <p> * The abstract urlFor() methods are implemented by subclasses of RequestCycle and return encoded * page URLs. The URL returned depends on the kind of page being linked to. Pages broadly fall into * two categories: * <p> * <table> * <tr> * <td valign = "top"><b>1. </b></td> * <td>A page that does not yet exist in a user Session may be encoded as a URL that references the * not-yet-created page by class name. A set of PageParameters can also be encoded into the URL, and * these parameters will be passed to the page constructor if the page later needs to be * instantiated. * <p> * Any page of this type is bookmarkable, and a hint to that effect is given to the user in the URL: * <p> * <ul> * /[Application]?bookmarkablePage=[classname]&[param]=[value] [...] * </ul> * <p> * Bookmarkable pages must either implement a constructor that takes a PageParameters argument or a * default constructor. If a Page has both constructors the constructor with the PageParameters * argument will be used. Links to bookmarkable pages are created by calling the urlFor(Class, * PageParameters) method, where Class is the page class and PageParameters are the parameters to * encode into the URL. * <p> * </td> * </tr> * <tr> * <td valign = "top"><b>2. </b></td> * <td>Stateful pages (that have already been requested by a user) will be present in the user's * Session and can be referenced securely with a session-relative number: * <p> * <ul> * /[Application]?wicket:interface=[pageMapName]:[pageId]: ... * </ul> * <p> * Often, the reason to access an existing session page is due to some kind of "postback" (either a * link click or a form submit) from a page (possibly accessed with the browser's back button or * possibly not). A call to a registered listener is dispatched like so: * <p> * <ul> * /[Application]?wicket:interface=[pageMapName]:[pageId]:[componentPath]:[version]:[interfaceName] * </ul> * <p> * For example: * <p> * <ul> * /[Application]?wicket:interface=:3:signInForm:submit::IFormSubmitListener * </ul> * </td> * </tr> * </table> * <p> * URLs for stateful pages (those that already exist in the session map) are created by calling the * urlFor(Component, Class) method, where Component is the component being linked to and Class is * the interface on the component to call. * <p> * For pages falling into the second category, listener interfaces cannot be invoked unless they * have first been registered via the static registerSecureInterface() method. This method ensures * basic security by restricting the set of interfaces that outsiders can call via GET and POST * requests. Each listener interface has a single method which takes only a RequestCycle parameter. * Currently, the following classes register the following kinds of listener interfaces: * <p> * <table> * <tr> * <th align = "left">Class</th> * <th align = "left">Interface</th> * <th align="left">Purpose</th> * </tr> * <tr> * <td>Form</td> * <td>IFormSubmitListener</td> * <td>Handle form submits</td> * </tr> * <tr> * <td>Image</td> * <td>IResourceListener</td> * <td>Respond to image resource requests</td> * </tr> * <tr> * <td>Link</td> * <td>ILinkListener</td> * <td>Respond to link clicks</td> * </tr> * <tr> * <td>Page</td> * <td>IRedirectListener</td> * <td>Respond to redirects</td> * </tr> * </table> * <p> * The redirectToInterceptPage() and continueToOriginalDestination() methods can be used to * temporarily redirect a user to some page. This is mainly intended for use in signing in users who * have bookmarked a page inside a site that requires the user be authenticated before they can * access the page. When it is discovered that the user is not signed in, the user is redirected to * the sign-in page with redirectToInterceptPage(). When the user has signed in, they are sent on * their way with continueToOriginalDestination(). These methods could also be useful in * "interstitial" advertising or other kinds of "intercepts". * <p> * * @author Jonathan Locke * @author Eelco Hillenius * @author Igor Vaynberg (ivaynberg) */public abstract class RequestCycle{ /** Thread-local that holds the current request cycle. */ private static final ThreadLocal current = new ThreadLocal(); /** Cleaning up after responding to a request. */ private static final int DETACH_REQUEST = 5; /** Request cycle processing is done. */ private static final int DONE = 6; /** Log */ private static final Logger log = LoggerFactory.getLogger(RequestCycle.class); /** No processing has been done. */ private static final int NOT_STARTED = 0; /** Starting the actual request processing. */ private static final int PREPARE_REQUEST = 1; /** Dispatching and handling of events. */ private static final int PROCESS_EVENTS = 3; /** Resolving the {@link RequestParameters} object to a request target. */ private static final int RESOLVE_TARGET = 2; /** Responding using the currently set {@link IRequestTarget}. */ private static final int RESPOND = 4; /** * Gets request cycle for calling thread. * * @return Request cycle for calling thread */ public static RequestCycle get() { return (RequestCycle)current.get(); } /** * Sets the request cycle for the calling thread. You typically DO NOT NEED to call this method, * as the request cycle is set to current for you in the constructor. However, if you have a <a * href="http://issues.apache.org/jira/browse/WICKET-366">very special need</a> to set it to * something else, you can expose this method. * * @param cycle * The request cycle to set current */ protected static void set(RequestCycle cycle) { current.set(cycle); } /** * True if the request cycle should automatically clear feedback messages after processing. True * by default. */ private boolean automaticallyClearFeedbackMessages = true; /** The current stage of event processing. */ private int currentStep = NOT_STARTED; private boolean handlingException = false; /** The original response the request cycle was created with. */ private final Response originalResponse; /** * True if request should be redirected to the resulting page instead of just rendering it back * to the user. */ private boolean redirect; /** holds the stack of set {@link IRequestTarget}, the last set op top. */ private transient final ArrayListStack requestTargets = new ArrayListStack(3); /** * Any page parameters. Only set when the request is resolving and the parameters are passed * into a page. */ private PageParameters pageParameters; /** The session object. */ private Session session; /** the time that this request cycle object was created. */ private final long startTime = System.currentTimeMillis(); /** The application object. */ protected final Application application; /** The processor for this request. */ protected final IRequestCycleProcessor processor; /** The current request. */ protected Request request; /** The current response. */ protected Response response; /** * Boolean if the next to be encoded url is targeting a new window (ModalWindow, popup, tab). * This temporary flag is specifically needed for portlet-support as then such a page needs a * special target (Resource) url. After each urlFor call, this flag is reset to false. */ private transient boolean urlForNewWindowEncoding; /** * Constructor. This instance will be set as the current one for this thread. * * @param application * The application * @param request * The request * @param response * The response */ protected RequestCycle(final Application application, final Request request, final Response response) { this.application = application; this.request = request; this.response = response; originalResponse = response; processor = safeGetRequestProcessor(); // Set this RequestCycle into ThreadLocal variable current.set(this); } /** * Gets the application object. * * @return Application interface */ public final Application getApplication() { return application; } /** * Gets the new agent info object for this session. This method calls * {@link Session#getClientInfo()}, which may or may not cache the client info object and * typically calls {@link #newClientInfo()} when no client info object was cached. * * @return the agent info object based on this request */ public final ClientInfo getClientInfo() { return getSession().getClientInfo(); } /** * Get the original response the request was create with. Access may be necessary with the * response has temporarily being replaced but your components requires access to lets say the * cookie methods of a WebResponse. * * @return The original response object. */ public final Response getOriginalResponse() { return originalResponse; } /** * Any set page parameters. Typically only available when a request to a bookmarkable page with * a {@link Page#Page(PageParameters)} constructor was made. * * @return the page parameters or null */ public final PageParameters getPageParameters() { return pageParameters; } /** * Gets the processor for delegated request cycle handling. * * @return the processor for delegated request cycle handling */ public abstract IRequestCycleProcessor getProcessor(); /** * Gets whether the page for this request should be redirected. * * @return whether the page for this request should be redirected * @deprecated Use {@link #isRedirect()} instead */ public final boolean getRedirect() { return isRedirect(); } /** * Gets the request. * * @return Request object */ public final Request getRequest() { return request; } /** * Gets the current request target. May be null. * * @return the current request target, null if none was set yet. */ public final IRequestTarget getRequestTarget() { return (!requestTargets.isEmpty()) ? (IRequestTarget)requestTargets.peek() : null; } /** * Gets the response. * * @return Response object */ public final Response getResponse() { return response; } /** * Gets the page that is to be rendered for this request in case the last set request target is * of type {@link PageRequestTarget}. * * @return the page or null */ public final Page getResponsePage() { IRequestTarget target = getRequestTarget(); if (target instanceof IPageRequestTarget) { return ((IPageRequestTarget)target).getPage(); } else if (target instanceof BookmarkablePageRequestTarget) { return ((BookmarkablePageRequestTarget)target).getPage(); } return null; } /** * Gets the page class that is to be instantiated and rendered for this request in case the last * set request target is of type {@link BookmarkablePageRequestTarget}. * * @return the page class or null */ public final Class getResponsePageClass() { IRequestTarget target = getRequestTarget(); if (target != null && (target instanceof IBookmarkablePageRequestTarget)) { return ((IBookmarkablePageRequestTarget)target).getPageClass(); } return null; } /** * Gets the session. * * @return Session object */ public final Session getSession() { if (session == null) { session = Session.get(); } return session; } /** * @return The start time for this request */ public final long getStartTime() { return startTime; } /** * Gets whether the page for this request should be redirected. * * @return whether the page for this request should be redirected */ public boolean isRedirect() { return redirect; } /** * Template method that is called when a runtime exception is thrown, just before the actual * handling of the runtime exception. This is called by * {@link AbstractRequestCycleProcessor#respond(RuntimeException, RequestCycle)}. * * @param page * Any page context where the exception was thrown * @param e * The exception * @return Any error page to redirect to */ public Page onRuntimeException(Page page, RuntimeException e) { return null; } /** * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT. * <p> * Redirects browser to the given page. Don't use this method directly, but use * {@link #setResponsePage(Page)} instead. * * @param page * The page to redirect to */ public abstract void redirectTo(final Page page); /** * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT. * <p> * Responds to a request. */ public final void request() { checkReuse();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -