001: /*
002: * $Id: DefaultRequestTargetResolverStrategy.java,v 1.4 2005/12/30 21:47:05
003: * jonathanlocke Exp $ $Revision: 505100 $ $Date: 2006-03-21 02:33:42 +0100 (di,
004: * 21 mrt 2006) $
005: *
006: * ==============================================================================
007: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
008: * use this file except in compliance with the License. You may obtain a copy of
009: * the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016: * License for the specific language governing permissions and limitations under
017: * the License.
018: */
019: package wicket.request.compound;
020:
021: import javax.servlet.http.HttpServletResponse;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import wicket.Application;
027: import wicket.Component;
028: import wicket.IRedirectListener;
029: import wicket.IRequestTarget;
030: import wicket.Page;
031: import wicket.PageMap;
032: import wicket.PageParameters;
033: import wicket.RequestCycle;
034: import wicket.RequestListenerInterface;
035: import wicket.Session;
036: import wicket.WicketRuntimeException;
037: import wicket.PageMap.Access;
038: import wicket.authorization.UnauthorizedActionException;
039: import wicket.markup.MarkupException;
040: import wicket.markup.html.INewBrowserWindowListener;
041: import wicket.protocol.http.request.WebErrorCodeResponseTarget;
042: import wicket.protocol.http.request.WebExternalResourceRequestTarget;
043: import wicket.request.IRequestCodingStrategy;
044: import wicket.request.RequestParameters;
045: import wicket.request.target.basic.EmptyRequestTarget;
046: import wicket.request.target.component.BookmarkablePageRequestTarget;
047: import wicket.request.target.component.ExpiredPageClassRequestTarget;
048: import wicket.request.target.component.PageRequestTarget;
049: import wicket.request.target.component.listener.RedirectPageRequestTarget;
050: import wicket.request.target.resource.SharedResourceRequestTarget;
051: import wicket.util.string.Strings;
052:
053: /**
054: * Default target resolver strategy. It tries to lookup any registered mount
055: * with {@link wicket.request.IRequestCodingStrategy} and in case no mount was
056: * found, it uses the {@link wicket.request.RequestParameters} object for
057: * default resolving.
058: *
059: * @author Eelco Hillenius
060: * @author Igor Vaynberg
061: * @author Jonathan Locke
062: */
063: public class DefaultRequestTargetResolverStrategy implements
064: IRequestTargetResolverStrategy {
065: /** log. */
066: private static final Log log = LogFactory
067: .getLog(DefaultRequestTargetResolverStrategy.class);
068:
069: /**
070: * Construct.
071: */
072: public DefaultRequestTargetResolverStrategy() {
073: }
074:
075: /**
076: * @see wicket.request.compound.IRequestTargetResolverStrategy#resolve(wicket.RequestCycle,
077: * wicket.request.RequestParameters)
078: */
079: public final IRequestTarget resolve(
080: final RequestCycle requestCycle,
081: final RequestParameters requestParameters) {
082: // first, see whether we can find any mount
083: IRequestTarget mounted = requestCycle.getProcessor()
084: .getRequestCodingStrategy().targetForRequest(
085: requestParameters);
086: if (mounted != null) {
087: // the path was mounted, so return that directly
088: return mounted;
089: }
090:
091: // See whether this request points to a rendered page
092: final String path = requestParameters.getPath();
093: if (requestParameters.getComponentPath() != null) {
094: // marks whether or not we will be processing this request
095: boolean processRequest = true;
096: synchronized (requestCycle.getSession()) {
097: // we need to check if this request has been flagged as
098: // process-only-if-path-is-active and if so make sure this
099: // condition is met
100:
101: if (requestParameters.isOnlyProcessIfPathActive()) {
102: // this request has indeed been flagged as
103: // process-only-if-path-is-active
104:
105: Session session = Session.get();
106: PageMap pageMap = session.pageMapForName(
107: requestParameters.getPageMapName(), false);
108: if (pageMap == null) {
109: // requested pagemap no longer exists - ignore this
110: // request
111: processRequest = false;
112: } else {
113: if (pageMap.getAccessStack().size() > 0) {
114: final Access access = (Access) pageMap
115: .getAccessStack().peek();
116:
117: final int pageId = Integer
118: .parseInt(Strings
119: .firstPathComponent(
120: requestParameters
121: .getComponentPath(),
122: Component.PATH_SEPARATOR));
123:
124: if (pageId != access.getId()) {
125: // the page is no longer the active page
126: // - ignore this request
127: processRequest = false;
128: } else {
129: final int version = requestParameters
130: .getVersionNumber();
131: if (version != Page.LATEST_VERSION
132: && version != access
133: .getVersion()) {
134: // version is no longer the active version -
135: // ignore this request
136: processRequest = false;
137: }
138: }
139: }
140: }
141:
142: }
143:
144: }
145: if (processRequest) {
146: return resolveRenderedPage(requestCycle,
147: requestParameters);
148: } else {
149: return EmptyRequestTarget.getInstance();
150: }
151: }
152: // see whether this request points to a bookmarkable page
153: else if (requestParameters.getBookmarkablePageClass() != null) {
154: return resolveBookmarkablePage(requestCycle,
155: requestParameters);
156: }
157: // see whether this request points to a shared resource
158: else if (requestParameters.getResourceKey() != null) {
159: return resolveSharedResource(requestCycle,
160: requestParameters);
161: }
162: // see whether this request points to the home page
163: else if (Strings.isEmpty(path) || ("/".equals(path))) {
164: return resolveHomePageTarget(requestCycle,
165: requestParameters);
166: }
167:
168: // if we get here, we have no regconized Wicket target, and thus
169: // regard this as a external (non-wicket) resource request on
170: // this server
171: return resolveExternalResource(requestCycle);
172: }
173:
174: /**
175: * Resolves to a shared resource target.
176: *
177: * @param requestCycle
178: * the current request cycle
179: * @param requestParameters
180: * the request parameters object
181: * @return the shared resource as a request target
182: */
183: protected IRequestTarget resolveSharedResource(
184: final RequestCycle requestCycle,
185: final RequestParameters requestParameters) {
186: String resourceKey = requestParameters.getResourceKey();
187: return new SharedResourceRequestTarget(requestParameters);
188: }
189:
190: /**
191: * Resolves to a page target that was previously rendered. Optionally
192: * resolves to a component call target, which is a specialization of a page
193: * target. If no corresponding page could be found, a expired page target
194: * will be returned.
195: *
196: * @param requestCycle
197: * the current request cycle
198: * @param requestParameters
199: * the request parameters object
200: * @return the previously rendered page as a request target
201: */
202: protected IRequestTarget resolveRenderedPage(
203: final RequestCycle requestCycle,
204: final RequestParameters requestParameters) {
205: final String componentPath = requestParameters
206: .getComponentPath();
207: final Session session = requestCycle.getSession();
208: final Page page = session.getPage(requestParameters
209: .getPageMapName(), componentPath, requestParameters
210: .getVersionNumber());
211:
212: // Does page exist?
213: if (page != null) {
214: // Set page on request
215: requestCycle.getRequest().setPage(page);
216:
217: // see whether this resolves to a component call or just the page
218: final String interfaceName = requestParameters
219: .getInterfaceName();
220: if (interfaceName != null) {
221: return resolveListenerInterfaceTarget(requestCycle,
222: page, componentPath, interfaceName,
223: requestParameters);
224: } else {
225: return new PageRequestTarget(page);
226: }
227: } else {
228: // Page was expired from session, probably because backtracking
229: // limit was reached
230: return new ExpiredPageClassRequestTarget();
231: }
232: }
233:
234: /**
235: * Resolves the RequestTarget for the given interface. This method can be
236: * overriden if some special interface needs to resolve to its own target.
237: *
238: * @param requestCycle
239: * The current RequestCycle object
240: * @param page
241: * The page object which holds the component for which this
242: * interface is called on.
243: * @param componentPath
244: * The component path for looking up the component in the page.
245: * @param interfaceName
246: * The interface to resolve.
247: * @param requestParameters
248: * @return The RequestTarget that was resolved
249: */
250: protected IRequestTarget resolveListenerInterfaceTarget(
251: final RequestCycle requestCycle, final Page page,
252: final String componentPath, final String interfaceName,
253: final RequestParameters requestParameters) {
254: if (interfaceName.equals(IRedirectListener.INTERFACE.getName())) {
255: return new RedirectPageRequestTarget(page);
256: } else if (interfaceName
257: .equals(INewBrowserWindowListener.INTERFACE.getName())) {
258: return INewBrowserWindowListener.INTERFACE
259: .newRequestTarget(page, page,
260: INewBrowserWindowListener.INTERFACE,
261: requestParameters);
262: } else {
263: // Get the listener interface we need to call
264: final RequestListenerInterface listener = RequestListenerInterface
265: .forName(interfaceName);
266: if (listener == null) {
267: throw new WicketRuntimeException(
268: "Attempt to access unknown request listener interface "
269: + interfaceName);
270: }
271:
272: // Get component
273: final String pageRelativeComponentPath = Strings
274: .afterFirstPathComponent(componentPath,
275: Component.PATH_SEPARATOR);
276: if (Strings.isEmpty(pageRelativeComponentPath)) {
277: // We have an interface that is not a redirect, but no
278: // component... that must be wrong
279: throw new WicketRuntimeException("When trying to call "
280: + listener + ", a component must be provided");
281: }
282: final Component component = page
283: .get(pageRelativeComponentPath);
284: if (!component.isEnableAllowed()) {
285: throw new UnauthorizedActionException(component,
286: Component.ENABLE);
287: }
288:
289: // Ask the request listener interface object to create a request
290: // target
291: return listener.newRequestTarget(page, component, listener,
292: requestParameters);
293: }
294: }
295:
296: /**
297: * Resolves to a bookmarkable page target.
298: *
299: * @param requestCycle
300: * the current request cycle
301: * @param requestParameters
302: * the request parameters object
303: * @return the bookmarkable page as a request target
304: */
305: protected IRequestTarget resolveBookmarkablePage(
306: final RequestCycle requestCycle,
307: final RequestParameters requestParameters) {
308: String bookmarkablePageClass = requestParameters
309: .getBookmarkablePageClass();
310: Session session = requestCycle.getSession();
311: Application application = session.getApplication();
312: Class pageClass;
313: try {
314: pageClass = session.getClassResolver().resolveClass(
315: bookmarkablePageClass);
316: } catch (RuntimeException e) {
317: return new WebErrorCodeResponseTarget(
318: HttpServletResponse.SC_NOT_FOUND,
319: "Unable to load Bookmarkable Page");
320: }
321:
322: try {
323: PageParameters params = new PageParameters(
324: requestParameters.getParameters());
325: return new BookmarkablePageRequestTarget(requestParameters
326: .getPageMapName(), pageClass, params);
327: } catch (RuntimeException e) {
328: throw new WicketRuntimeException(
329: "Unable to instantiate Page class: "
330: + bookmarkablePageClass
331: + ". See below for details.", e);
332: }
333: }
334:
335: /**
336: * Resolves to a home page target.
337: *
338: * @param requestCycle
339: * the current request cycle.
340: * @param requestParameters
341: * the request parameters object
342: * @return the home page as a request target
343: */
344: protected IRequestTarget resolveHomePageTarget(
345: final RequestCycle requestCycle,
346: final RequestParameters requestParameters) {
347: Session session = requestCycle.getSession();
348: Application application = session.getApplication();
349: try {
350: // Get the home page class
351: Class homePageClass = application.getHomePage();
352:
353: PageParameters parameters = new PageParameters(
354: requestParameters.getParameters());
355: // and create a dummy target for looking up whether the home page is
356: // mounted
357: BookmarkablePageRequestTarget homepageTarget = new BookmarkablePageRequestTarget(
358: homePageClass, parameters);
359: IRequestCodingStrategy requestCodingStrategy = requestCycle
360: .getProcessor().getRequestCodingStrategy();
361: CharSequence path = requestCodingStrategy
362: .pathForTarget(homepageTarget);
363:
364: if (path != null) {
365: // The home page was mounted at the given path.
366: // Issue a redirect to that path
367: requestCycle.setRedirect(true);
368: }
369:
370: // else the home page was not mounted; render it now so
371: // that we will keep a clean path
372: return homepageTarget;
373: } catch (MarkupException e) {
374: // Markup exception should pass without modification. They show
375: // a nice error page
376: throw e;
377: } catch (WicketRuntimeException e) {
378: throw new WicketRuntimeException(
379: "Could not create home page", e);
380: }
381: }
382:
383: /**
384: * Resolves to an external resource.
385: *
386: * @param requestCycle
387: * The current request cycle
388: * @return The external resource request target
389: */
390: protected IRequestTarget resolveExternalResource(
391: RequestCycle requestCycle) {
392: // Get the relative URL we need for loading the resource from
393: // the servlet context
394: // NOTE: we NEED to put the '/' in front as otherwise some versions
395: // of application servers (e.g. Jetty 5.1.x) will fail for requests
396: // like '/mysubdir/myfile.css'
397: final String url = '/' + requestCycle.getRequest()
398: .getRelativeURL();
399: return new WebExternalResourceRequestTarget(url);
400: }
401: }
|