You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2009/10/11 02:02:29 UTC
svn commit: r823984 [5/11] - in /wicket/trunk: ./
wicket/src/main/java/org/apache/wicket/ng/
wicket/src/main/java/org/apache/wicket/ng/application/
wicket/src/main/java/org/apache/wicket/ng/behavior/
wicket/src/main/java/org/apache/wicket/ng/markup/ wi...
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BookmarkablePageRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BookmarkablePageRequestHandler.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BookmarkablePageRequestHandler.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BookmarkablePageRequestHandler.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,69 @@
+/*
+ * 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.ng.request.handler.impl;
+
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.handler.PageClassRequestHandler;
+import org.apache.wicket.ng.request.handler.PageProvider;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * Request handler for bookmarkable pages. This handler is only used to generate URLs. Rendering is
+ * always handled by {@link RenderPageRequestHandler}.
+ *
+ * @author Matej Knopp
+ */
+public class BookmarkablePageRequestHandler implements PageClassRequestHandler
+{
+ private final PageProvider pageProvider;
+
+ /**
+ * Construct.
+ *
+ * @param pageProvider
+ */
+ public BookmarkablePageRequestHandler(PageProvider pageProvider)
+ {
+
+ Check.argumentNotNull(pageProvider, "pageProvider");
+
+ this.pageProvider = pageProvider;
+ }
+
+ public Class<? extends RequestablePage> getPageClass()
+ {
+ return pageProvider.getPageClass();
+ }
+
+ public PageParameters getPageParameters()
+ {
+ return pageProvider.getPageParameters();
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ // not used as BookmarkablePageRequestHandler is only used when generating URLs.
+ // However URL will never be resolved to BookmarkablePageRequestTarget
+ }
+
+ public void detach(RequestCycle requestCycle)
+ {
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BufferedResponseRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BufferedResponseRequestHandler.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BufferedResponseRequestHandler.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/BufferedResponseRequestHandler.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,27 @@
+package org.apache.wicket.ng.request.handler.impl;
+
+import org.apache.wicket.ng.request.RequestHandler;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.response.BufferedWebResponse;
+import org.apache.wicket.ng.request.response.WebResponse;
+
+public class BufferedResponseRequestHandler implements RequestHandler
+{
+ private final BufferedWebResponse bufferedWebResponse;
+
+ public BufferedResponseRequestHandler(BufferedWebResponse bufferedWebResponse)
+ {
+ this.bufferedWebResponse = bufferedWebResponse;
+ }
+
+ public void detach(RequestCycle requestCycle)
+ {
+
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ bufferedWebResponse.writeTo((WebResponse) requestCycle.getResponse());
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/ListenerInterfaceRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/ListenerInterfaceRequestHandler.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/ListenerInterfaceRequestHandler.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/ListenerInterfaceRequestHandler.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,153 @@
+/*
+ * 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.ng.request.handler.impl;
+
+import org.apache.wicket.ng.WicketRuntimeException;
+import org.apache.wicket.ng.behavior.IBehavior;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestableComponent;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.handler.ComponentRequestHandler;
+import org.apache.wicket.ng.request.handler.PageAndComponentProvider;
+import org.apache.wicket.ng.request.handler.PageProvider;
+import org.apache.wicket.ng.request.handler.PageRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.RenderPageRequestHandler.RedirectPolicy;
+import org.apache.wicket.ng.request.listener.RequestListenerInterface;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * Request handler that invokes the listener interface on component and renders page afterwards.
+ *
+ * @author Matej Knopp
+ */
+public class ListenerInterfaceRequestHandler implements PageRequestHandler, ComponentRequestHandler
+{
+ private final PageAndComponentProvider pageComponentProvider;
+ private final RequestListenerInterface listenerInterface;
+ private final Integer behaviorIndex;
+
+ /**
+ * Construct.
+ *
+ * @param pageComponentProvider
+ * @param listenerInterface
+ * @param behaviorIndex
+ */
+ public ListenerInterfaceRequestHandler(PageAndComponentProvider pageComponentProvider,
+ RequestListenerInterface listenerInterface, Integer behaviorIndex)
+ {
+ Check.argumentNotNull(pageComponentProvider, "pageComponentProvider");
+ Check.argumentNotNull(listenerInterface, "listenerInterface");
+
+ this.pageComponentProvider = pageComponentProvider;
+ this.listenerInterface = listenerInterface;
+ this.behaviorIndex = behaviorIndex;
+ }
+
+ /**
+ * Construct.
+ *
+ * @param pageComponentProvider
+ * @param listenerInterface
+ */
+ public ListenerInterfaceRequestHandler(PageAndComponentProvider pageComponentProvider,
+ RequestListenerInterface listenerInterface)
+ {
+ this(pageComponentProvider, listenerInterface, null);
+ }
+
+ public RequestableComponent getComponent()
+ {
+ return pageComponentProvider.getComponent();
+ }
+
+ public RequestablePage getPage()
+ {
+ return pageComponentProvider.getPageInstance();
+ }
+
+ public Class<? extends RequestablePage> getPageClass()
+ {
+ return pageComponentProvider.getPageClass();
+ }
+
+ public PageParameters getPageParameters()
+ {
+ return pageComponentProvider.getPageParameters();
+ }
+
+ public void detach(RequestCycle requestCycle)
+ {
+ pageComponentProvider.detach();
+ }
+
+ /**
+ * Returns the listener interface.
+ *
+ * @return listener interface
+ */
+ public RequestListenerInterface getListenerInterface()
+ {
+ return listenerInterface;
+ }
+
+ /**
+ * Index of target behavior or <code>null</code> if component is the target.
+ *
+ * @return behavior index or <code>null</code>
+ */
+ public Integer getBehaviorIndex()
+ {
+ return behaviorIndex;
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ if (getComponent().getPage() == getPage())
+ {
+ // schedule page render after current request handler is done. this can be overridden during invocation of listener
+ // method (i.e. by calling RequestCycle#setResponsePage)
+ RedirectPolicy policy = getPage().isPageStateless() ? RedirectPolicy.NEVER_REDIRECT : RedirectPolicy.AUTO_REDIRECT;
+ requestCycle.scheduleRequestHandlerAfterCurrent(new RenderPageRequestHandler(new PageProvider(getPage()), policy));
+
+ if (getBehaviorIndex() == null)
+ {
+ listenerInterface.invoke(getComponent());
+ }
+ else
+ {
+ try
+ {
+ IBehavior behavior = getComponent().getBehaviors().get(behaviorIndex);
+ listenerInterface.invoke(getComponent(), behavior);
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ throw new WicketRuntimeException("Couldn't find component behavior.");
+ }
+
+ }
+ }
+ else
+ {
+ throw new WicketRuntimeException("Component " + getComponent() +
+ " has been removed from page.");
+ }
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/RenderPageRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/RenderPageRequestHandler.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/RenderPageRequestHandler.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/RenderPageRequestHandler.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,132 @@
+/*
+ * 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.ng.request.handler.impl;
+
+import org.apache.wicket.ng.Application;
+import org.apache.wicket.ng.request.RequestHandler;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.handler.PageClassRequestHandler;
+import org.apache.wicket.ng.request.handler.PageProvider;
+import org.apache.wicket.ng.request.handler.PageRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.render.RenderPageRequestHandlerDelegate;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * {@link RequestHandler} that renders page instance. Depending on the <code>redirectPolicy</code>
+ * flag and current request strategy the handler either just renders the page to the response, or
+ * redirects to render the page. <code>REDIRECT_TO_BUFFER</code> strategy is also supported.
+ * <p>
+ *
+ * @author Matej Knopp
+ */
+public class RenderPageRequestHandler implements PageRequestHandler, PageClassRequestHandler
+{
+ private final PageProvider pageProvider;
+ private final RedirectPolicy redirectPolicy;
+
+ /**
+ * Determines whether Wicket does a redirect when rendering a page
+ *
+ * @author Matej Knopp
+ */
+ public enum RedirectPolicy
+ {
+ /**
+ * Always redirect if current request URL is different than page URL.
+ */
+ ALWAYS_REDIRECT,
+
+ /**
+ * Never redirect - always render the page to current response.
+ */
+ NEVER_REDIRECT,
+
+ /**
+ * Redirect if necessary. The redirect will happen when all of the following conditions are
+ * met:
+ * <ul>
+ * <li>current request URL is different than page URL
+ * <li>page is not stateless or (page is stateless and session is not temporary)
+ * <li>render strategy is either REDIRECT_TO_BUFFER or REDIRECT_TO_RENDER
+ * </ul>
+ */
+ AUTO_REDIRECT
+ };
+
+ /**
+ * Construct. Renders the page with a redirect if necessary.
+ *
+ * @param pageProvider
+ */
+ public RenderPageRequestHandler(PageProvider pageProvider)
+ {
+ this(pageProvider, RedirectPolicy.AUTO_REDIRECT);
+ }
+
+ /**
+ * Construct.
+ *
+ * @param pageProvider
+ * @param redirectPolicy
+ */
+ public RenderPageRequestHandler(PageProvider pageProvider, RedirectPolicy redirectPolicy)
+ {
+ Check.argumentNotNull(pageProvider, "pageProvider");
+ Check.argumentNotNull(redirectPolicy, "redirectPolicy");
+
+ this.redirectPolicy = redirectPolicy;
+ this.pageProvider = pageProvider;
+ }
+
+ public PageProvider getPageProvider()
+ {
+ return pageProvider;
+ }
+
+ public RedirectPolicy getRedirectPolicy()
+ {
+ return redirectPolicy;
+ }
+
+ public Class<? extends RequestablePage> getPageClass()
+ {
+ return pageProvider.getPageClass();
+ }
+
+ public PageParameters getPageParameters()
+ {
+ return pageProvider.getPageParameters();
+ }
+
+ public void detach(RequestCycle requestCycle)
+ {
+ pageProvider.detach();
+ }
+
+ public RequestablePage getPage()
+ {
+ return pageProvider.getPageInstance();
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ RenderPageRequestHandlerDelegate delegate = Application.get().getRenderPageRequestHandlerDelegate(this);
+ delegate.respond(requestCycle);
+ }
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/RenderPageRequestHandlerDelegate.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/RenderPageRequestHandlerDelegate.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/RenderPageRequestHandlerDelegate.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/RenderPageRequestHandlerDelegate.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,40 @@
+package org.apache.wicket.ng.request.handler.impl.render;
+
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.handler.PageProvider;
+import org.apache.wicket.ng.request.handler.impl.RenderPageRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.RenderPageRequestHandler.RedirectPolicy;
+
+/**
+ * Delegate responsible for rendering the page. Depending on the implementation (web, test, portlet,
+ * etc.) the delegate may or may not support the redirect policy set in the
+ * {@link RenderPageRequestHandler}.
+ *
+ * @author Matej Knopp
+ */
+public abstract class RenderPageRequestHandlerDelegate
+{
+ private final RenderPageRequestHandler renderPageRequestHandler;
+
+ public RenderPageRequestHandlerDelegate(RenderPageRequestHandler renderPageRequestHandler)
+ {
+ this.renderPageRequestHandler = renderPageRequestHandler;
+ }
+
+ public PageProvider getPageProvider()
+ {
+ return renderPageRequestHandler.getPageProvider();
+ }
+
+ public RedirectPolicy getRedirectPolicy()
+ {
+ return renderPageRequestHandler.getRedirectPolicy();
+ }
+
+ public RenderPageRequestHandler getRenderPageRequestHandler()
+ {
+ return renderPageRequestHandler;
+ }
+
+ public abstract void respond(RequestCycle requestCycle);
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/WebRenderPageRequestHandlerDelegate.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/WebRenderPageRequestHandlerDelegate.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/WebRenderPageRequestHandlerDelegate.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/impl/render/WebRenderPageRequestHandlerDelegate.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,226 @@
+package org.apache.wicket.ng.request.handler.impl.render;
+
+import org.apache.wicket.ng.Application;
+import org.apache.wicket.ng.Session;
+import org.apache.wicket.ng.protocol.http.WebApplication;
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.handler.impl.RenderPageRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.RenderPageRequestHandler.RedirectPolicy;
+import org.apache.wicket.ng.request.response.BufferedWebResponse;
+import org.apache.wicket.ng.request.response.Response;
+import org.apache.wicket.ng.request.response.WebResponse;
+import org.apache.wicket.ng.settings.RequestCycleSettings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebRenderPageRequestHandlerDelegate extends RenderPageRequestHandlerDelegate
+{
+
+ public WebRenderPageRequestHandlerDelegate(RenderPageRequestHandler renderPageRequestHandler)
+ {
+ super(renderPageRequestHandler);
+ }
+
+ public RequestablePage getPage()
+ {
+ return getPageProvider().getPageInstance();
+ }
+
+ private boolean isOnePassRender()
+ {
+ return Application.get().getRequestCycleSettings().getRenderStrategy() == RequestCycleSettings.RenderStrategy.ONE_PASS_RENDER;
+ }
+
+ private boolean isRedirectToRender()
+ {
+ return Application.get().getRequestCycleSettings().getRenderStrategy() == RequestCycleSettings.RenderStrategy.REDIRECT_TO_RENDER;
+ }
+
+ private boolean isRedirectToBuffer()
+ {
+ return Application.get().getRequestCycleSettings().getRenderStrategy() == RequestCycleSettings.RenderStrategy.REDIRECT_TO_BUFFER;
+ }
+
+ private void renderPage()
+ {
+ getPage().renderPage();
+ }
+
+ protected String getSessionId()
+ {
+ return Session.get().getId();
+ }
+
+ protected boolean isSessionTemporary()
+ {
+ return Session.get().isTemporary();
+ }
+
+ protected BufferedWebResponse getAndRemoveBufferedResponse(Url url)
+ {
+ return WebApplication.get().getAndRemoveBufferedResponse(getSessionId(), url);
+ }
+
+ protected void storeBufferedResponse(Url url, BufferedWebResponse response)
+ {
+ WebApplication.get().storeBufferedResponse(getSessionId(), url, response);
+ }
+
+ /**
+ * Renders page to a {@link BufferedWebResponse}. All URLs in page will be rendered relative to
+ * <code>targetUrl</code>
+ *
+ * @param targetUrl
+ * @param requestCycle
+ * @return BufferedWebResponse containing page body
+ */
+ protected BufferedWebResponse renderPage(Url targetUrl, RequestCycle requestCycle)
+ {
+ // keep the original response
+ final Response originalResponse = requestCycle.getResponse();
+
+ // buffered web response for page
+ BufferedWebResponse response = new BufferedWebResponse()
+ {
+ @Override
+ public String encodeURL(String url)
+ {
+ return originalResponse.encodeURL(url);
+ }
+ };
+
+ // keep the original base URL
+ Url originalBaseUrl = requestCycle.getUrlRenderer().setBaseUrl(targetUrl);
+
+ try
+ {
+ requestCycle.setResponse(response);
+ getPage().renderPage();
+ return response;
+ }
+ finally
+ {
+ // restore original response and base URL
+ requestCycle.setResponse(originalResponse);
+ requestCycle.getUrlRenderer().setBaseUrl(originalBaseUrl);
+ }
+ }
+
+ private void redirectTo(Url url, RequestCycle requestCycle)
+ {
+ WebResponse response = (WebResponse) requestCycle.getResponse();
+ String relativeUrl = requestCycle.getUrlRenderer().renderUrl(url);
+ response.sendRedirect(relativeUrl);
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ Url currentUrl = requestCycle.getRequest().getUrl();
+ Url targetUrl = requestCycle.urlFor(getRenderPageRequestHandler());
+
+ //
+ // the code below is little hairy but we have to handle 3 redirect policies
+ // and 3 rendering strategies
+ //
+
+ // try to get an already rendered buffered response for current URL
+ BufferedWebResponse bufferedResponse = getAndRemoveBufferedResponse(currentUrl);
+
+ if (bufferedResponse != null)
+ {
+ logger.warn("The Buffered response should be handled by BufferedResponseRequestHandler");
+ // if there is saved response for this URL render it
+ bufferedResponse.writeTo((WebResponse) requestCycle.getResponse());
+ }
+ else if (getRedirectPolicy() == RedirectPolicy.NEVER_REDIRECT || isOnePassRender() //
+ || (targetUrl.equals(currentUrl) && !getPage().isPageStateless()) //
+ || (targetUrl.equals(currentUrl) && isRedirectToRender() && getPage().isPageStateless()))
+ {
+ // if the policy is never to redirect
+ // or one pass render mode is on
+ // or the targetUrl matches current url and the page is not stateless
+ // or the targetUrl matches current url, page is stateless but it's redirect-to-render
+ // just render the page
+ renderPage();
+ }
+ else if (!targetUrl.equals(currentUrl) //
+ && (getRedirectPolicy() == RedirectPolicy.ALWAYS_REDIRECT || isRedirectToRender()))
+ {
+ // if target URL is different
+ // and render policy is always-redirect or it's redirect-to-render
+ redirectTo(targetUrl, requestCycle);
+ }
+ else if (!targetUrl.equals(currentUrl) //
+ && isSessionTemporary() && getPage().isPageStateless())
+ {
+ // if target URL is different and session is temporary and page is stateless
+ // this is special case when page is stateless but there is no session so we can't render it to buffer
+
+ // note: if we had session here we would render the page to buffer and then redirect to URL generated
+ // *after* page has been rendered (the statelessness may change during render). this would save one redirect
+ // because now we have to render to URL generated *before* page is rendered, render the page, get URL
+ // after render and if the URL is different (meaning page is not stateless), save the buffer and redirect again
+ // (which is pretty much what the next step does)
+ redirectTo(targetUrl, requestCycle);
+ }
+ else if (isRedirectToBuffer())
+ {
+ // redirect to buffer
+ BufferedWebResponse response = renderPage(targetUrl, requestCycle);
+
+ // check if the url hasn't changed after page has been rendered
+ // (i.e. the stateless flag might have changed which could result in different page url)
+ Url targetUrl2 = requestCycle.urlFor(this.getRenderPageRequestHandler());
+
+ if (targetUrl.getSegments().equals(targetUrl2.getSegments()) == false)
+ {
+ // the amount of segments is different - generated relative URLs will not work, we
+ // need to rerender the page. This shouldn't happen, but in theory it can - with
+ // RequestHandlerEncoders that produce different URLs with different amount of
+ // segments for stateless and stateful pages
+ response = renderPage(targetUrl2, requestCycle);
+ }
+
+ // if page is still stateless after render
+ if (getPage().isPageStateless() && !enableRedirectForStatelessPage())
+ {
+ // we don't want the redirect to happen for stateless page
+ // example:
+ // when a normal mounted stateful page is hit at /mount/point
+ // wicket renders the page to buffer and redirects to /mount/point?12
+ // but for stateless page the redirect is not necessary
+ // also for listener interface on stateful page we want to redirect
+ // after the listener is invoked, but on stateless page the user
+ // must ask for redirect explicitely
+ response.writeTo((WebResponse) requestCycle.getResponse());
+ }
+ else
+ {
+ storeBufferedResponse(targetUrl2, response);
+
+ redirectTo(targetUrl2, requestCycle);
+ }
+ }
+ else
+ {
+ throw new IllegalStateException("Unknown RenderStrategy.");
+ }
+ }
+
+ /**
+ * When the page renders to buffer and it is still stateless after rendering, this flag
+ * determines whether the redirect will take place or not.
+ * <p>
+ * Normally there is no reason for a stateless page to redirect
+ *
+ * @return boolean value
+ */
+ protected boolean enableRedirectForStatelessPage()
+ {
+ return false;
+ }
+
+ private static Logger logger = LoggerFactory.getLogger(WebRenderPageRequestHandlerDelegate.class);
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceReferenceRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceReferenceRequestHandler.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceReferenceRequestHandler.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceReferenceRequestHandler.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,73 @@
+/*
+ * 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.ng.request.handler.resource;
+
+import org.apache.wicket.ng.request.RequestHandler;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.resource.ResourceReference;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * Request handler for {@link ResourceReference}. This handler is only used to generate URLs.
+ *
+ * @author Matej Knopp
+ */
+public class ResourceReferenceRequestHandler implements RequestHandler
+{
+ private final ResourceReference resourceReference;
+ private final PageParameters pageParameters;
+
+ /**
+ * Construct.
+ *
+ * @param resourceReference
+ * @param pageParameters
+ */
+ public ResourceReferenceRequestHandler(ResourceReference resourceReference, PageParameters pageParameters)
+ {
+ Check.argumentNotNull(resourceReference, "resourceReference");
+
+ this.resourceReference = resourceReference;
+ this.pageParameters = pageParameters;
+ }
+
+ /**
+ * @return resource reference
+ */
+ public ResourceReference getResourceReference()
+ {
+ return resourceReference;
+ }
+
+ /**
+ * @return page parameters
+ */
+ public PageParameters getPageParameters()
+ {
+ return pageParameters;
+ }
+
+ public void detach(RequestCycle requestCycle)
+ {
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceRequestHandler.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceRequestHandler.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/handler/resource/ResourceRequestHandler.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,100 @@
+/*
+ * 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.ng.request.handler.resource;
+
+import java.util.Locale;
+
+import org.apache.wicket.ng.request.RequestHandler;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.resource.Resource;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * Request handler that renders a resource.
+ *
+ * @author Matej Knopp
+ */
+public class ResourceRequestHandler implements RequestHandler
+{
+ private final Resource resource;
+ private final Locale locale;
+ private final String style;
+ private final PageParameters pageParameters;
+
+ /**
+ * Construct.
+ *
+ * @param resource
+ * @param locale
+ * @param style
+ * @param pageParameters
+ */
+ public ResourceRequestHandler(Resource resource, Locale locale, String style,
+ PageParameters pageParameters)
+ {
+ Check.argumentNotNull(resource, "resource");
+
+ this.resource = resource;
+ this.locale = locale;
+ this.style = style;
+ this.pageParameters = pageParameters != null ? pageParameters : new PageParameters();
+ }
+
+ /**
+ * @return locale
+ */
+ public Locale getLocale()
+ {
+ return locale;
+ }
+
+ /**
+ * @return style
+ */
+ public String getStyle()
+ {
+ return style;
+ }
+
+ /**
+ * @return page parameters
+ */
+ public PageParameters getPageParameters()
+ {
+ return pageParameters;
+ }
+
+ /**
+ * @return resource
+ */
+ public Resource getResource()
+ {
+ return resource;
+ }
+
+ public void respond(RequestCycle requestCycle)
+ {
+ Resource.Attributes a = new Resource.Attributes(requestCycle.getRequest(),
+ requestCycle.getResponse(), locale, style, pageParameters);
+ resource.respond(a);
+ }
+
+ public void detach(RequestCycle requestCycle)
+ {
+ }
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/IRequestListener.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/IRequestListener.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/IRequestListener.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/IRequestListener.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,36 @@
+/*
+ * 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.ng.request.listener;
+
+import java.io.Serializable;
+
+
+/**
+ * Base interface for all interfaces that listen for requests from the client browser. All
+ * sub-interfaces of this interface must have a single method which takes no arguments.
+ * <p>
+ * New listener interfaces must be registered with Wicket by constructing a
+ * {@link RequestListenerInterface} object for the given interface class. The best way to do this is
+ * to create a public static final constant field in your request listener interface. Doing this
+ * will cause the interface to automatically register whenever it is used. For example, see
+ * {@link org.apache.wicket.IRedirectListener#INTERFACE}.
+ *
+ * @author Jonathan Locke
+ */
+public interface IRequestListener extends Serializable
+{
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/RequestListenerInterface.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/RequestListenerInterface.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/RequestListenerInterface.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/listener/RequestListenerInterface.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,266 @@
+/*
+ * 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.ng.request.listener;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.wicket.ng.WicketRuntimeException;
+import org.apache.wicket.ng.behavior.IBehavior;
+import org.apache.wicket.ng.request.component.RequestableComponent;
+import org.apache.wicket.ng.request.cycle.RequestHandlerStack.ReplaceHandlerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Base class for request listener interfaces.
+ *
+ * @author Jonathan Locke
+ */
+public class RequestListenerInterface
+{
+ /** Map from name to request listener interface */
+ private static final Map<String, RequestListenerInterface> interfaces = Collections.synchronizedMap(new HashMap<String, RequestListenerInterface>());
+
+ /** Log. */
+ private static final Logger log = LoggerFactory.getLogger(RequestListenerInterface.class);
+
+ /**
+ * Looks up a request interface listener by name.
+ *
+ * @param interfaceName
+ * The interface name
+ * @return The RequestListenerInterface object, or null if none is found
+ *
+ */
+ public static final RequestListenerInterface forName(final String interfaceName)
+ {
+ return interfaces.get(interfaceName);
+ }
+
+ /** The listener interface method */
+ private Method method;
+
+ /** The name of this listener interface */
+ private final String name;
+
+ /**
+ * Constructor.
+ *
+ * @param listenerInterfaceClass
+ * The interface class, which must extend IRequestListener.
+ */
+ public RequestListenerInterface(final Class<? extends IRequestListener> listenerInterfaceClass)
+ {
+ // Ensure that it extends IRequestListener
+ if (!IRequestListener.class.isAssignableFrom(listenerInterfaceClass))
+ {
+ throw new IllegalArgumentException("Class " + listenerInterfaceClass +
+ " must extend IRequestListener");
+ }
+
+
+ // Get interface methods
+ final Method[] methods = listenerInterfaceClass.getMethods();
+
+ // If there is only one method
+ if (methods.length == 1)
+ {
+ // and that method takes no parameters
+ if (methods[0].getParameterTypes().length == 0)
+ {
+ method = methods[0];
+ }
+ else
+ {
+ throw new IllegalArgumentException("Method " + methods[0] + " in interface " +
+ listenerInterfaceClass + " cannot take any arguments");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("Interface " + listenerInterfaceClass +
+ " can have only one method");
+ }
+
+ // Save short class name
+ name = listenerInterfaceClass.getSimpleName();
+
+ // Register this listener
+ register();
+ }
+
+ /**
+ * @return The method for this request listener interface
+ */
+ public final Method getMethod()
+ {
+ return method;
+ }
+
+ /**
+ * @return The name of this request listener interface
+ */
+ public final String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Invokes a given interface on a component.
+ *
+ * @param component
+ * The component
+ */
+ public final void invoke(final RequestableComponent component)
+ {
+ if (!component.canCallListenerInterface())
+ {
+ // just return so that we have a silent fail and just re-render the
+ // page
+ log.info("component not enabled or visible; ignoring call. Component: " + component);
+ return;
+ }
+
+ try
+ {
+ // Invoke the interface method on the component
+ method.invoke(component, new Object[] {});
+ }
+ catch (InvocationTargetException e)
+ {
+ // Honor redirect exception contract defined in IPageFactory
+ // TODO:
+ if (/*e.getTargetException() instanceof AbstractRestartResponseException ||
+ e.getTargetException() instanceof AuthorizationException ||*/
+ e.getTargetException() instanceof ReplaceHandlerException ||
+ e.getTargetException() instanceof WicketRuntimeException)
+ {
+ throw (RuntimeException)e.getTargetException();
+ }
+ throw new WicketRuntimeException("Method " + method.getName() + " of " +
+ method.getDeclaringClass() + " targeted at component " + component +
+ " threw an exception", e);
+ }
+ catch (Exception e)
+ {
+ throw new WicketRuntimeException("Method " + method.getName() + " of " +
+ method.getDeclaringClass() + " targeted at component " + component +
+ " threw an exception", e);
+ }
+ }
+
+ /**
+ * Invokes a given interface on a component's behavior.
+ *
+ * @param component
+ * The component
+ * @param behavior
+ */
+ public final void invoke(final RequestableComponent component, final IBehavior behavior)
+ {
+ if (!component.canCallListenerInterface())
+ {
+ // just return so that we have a silent fail and just re-render the
+ // page
+ log.info("component not enabled or visible; ignoring call. Component: " + component);
+ return;
+ }
+
+ try
+ {
+ // Invoke the interface method on the component
+ method.invoke(behavior, new Object[] {});
+ }
+ catch (InvocationTargetException e)
+ {
+ // Honor redirect exception contract defined in IPageFactory
+ // TODO
+ if (/*e.getTargetException() instanceof AbstractRestartResponseException ||
+ e.getTargetException() instanceof AuthorizationException ||*/
+ e.getTargetException() instanceof WicketRuntimeException)
+ {
+ throw (RuntimeException)e.getTargetException();
+ }
+ throw new WicketRuntimeException("Method " + method.getName() + " of " +
+ method.getDeclaringClass() + " targeted at behavior " + behavior +
+ " on component " + component + " threw an exception", e);
+ }
+ catch (Exception e)
+ {
+ throw new WicketRuntimeException("Method " + method.getName() + " of " +
+ method.getDeclaringClass() + " targeted at behavior " + behavior +
+ " on component " + component + " threw an exception", e);
+ }
+ }
+
+
+ /**
+ * Method to call to register this interface for use
+ */
+ public void register()
+ {
+ // Register this listener interface
+ registerRequestListenerInterface(this);
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "[RequestListenerInterface name=" + name + ", method=" + method + "]";
+ }
+
+
+ /**
+ * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
+ * <p>
+ * In previous versions of Wicket, request listeners were manually registered by calling this
+ * method. Now there is a first class RequestListenerInterface object which should be
+ * constructed as a constant member of the interface to enable automatic interface registration.
+ * <p>
+ * Adds a request listener interface to the map of interfaces that can be invoked by outsiders.
+ *
+ * @param requestListenerInterface
+ * The request listener interface object
+ */
+ private final void registerRequestListenerInterface(
+ final RequestListenerInterface requestListenerInterface)
+ {
+ // Check that a different interface method with the same name has not
+ // already been registered
+ final RequestListenerInterface existingInterface = RequestListenerInterface.forName(requestListenerInterface.getName());
+ if (existingInterface != null &&
+ existingInterface.getMethod() != requestListenerInterface.getMethod())
+ {
+ throw new IllegalStateException("Cannot register listener interface " +
+ requestListenerInterface +
+ " because it conflicts with the already registered interface " + existingInterface);
+ }
+
+ // Save this interface method by the non-qualified class name
+ interfaces.put(requestListenerInterface.getName(), requestListenerInterface);
+
+ log.info("registered listener interface " + this);
+ }
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractBookmarkableMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractBookmarkableMapper.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractBookmarkableMapper.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractBookmarkableMapper.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,298 @@
+/*
+ * 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.ng.request.mapper;
+
+import org.apache.wicket.ng.request.Request;
+import org.apache.wicket.ng.request.RequestHandler;
+import org.apache.wicket.ng.request.RequestMapper;
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.handler.PageAndComponentProvider;
+import org.apache.wicket.ng.request.handler.PageProvider;
+import org.apache.wicket.ng.request.handler.impl.BookmarkableListenerInterfaceRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.BookmarkablePageRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.ListenerInterfaceRequestHandler;
+import org.apache.wicket.ng.request.handler.impl.RenderPageRequestHandler;
+import org.apache.wicket.ng.request.listener.RequestListenerInterface;
+import org.apache.wicket.ng.request.mapper.info.ComponentInfo;
+import org.apache.wicket.ng.request.mapper.info.PageComponentInfo;
+import org.apache.wicket.ng.request.mapper.info.PageInfo;
+import org.apache.wicket.ng.util.lang.Check;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract encoder for Bookmarkable, Hybrid and BookmarkableListenerInterface URLs.
+ *
+ * @author Matej Knopp
+ */
+public abstract class AbstractBookmarkableMapper extends AbstractMapper
+{
+ /**
+ * Construct.
+ */
+ public AbstractBookmarkableMapper()
+ {
+ }
+
+ /**
+ * Represents information stored in URL.
+ *
+ * @author Matej Knopp
+ */
+ protected static final class UrlInfo
+ {
+ private final PageComponentInfo pageComponentInfo;
+ private final PageParameters pageParameters;
+ private final Class<? extends RequestablePage> pageClass;
+
+ /**
+ * Construct.
+ *
+ * @param pageComponentInfo
+ * optional parameter providing the page instance and component information
+ * @param pageClass
+ * mandatory parameter
+ * @param pageParameters
+ * optional parameter providing pageParameters
+ */
+ public UrlInfo(PageComponentInfo pageComponentInfo, Class<? extends RequestablePage> pageClass,
+ PageParameters pageParameters)
+ {
+ Check.argumentNotNull(pageClass, "pageClass");
+
+ this.pageComponentInfo = pageComponentInfo;
+ this.pageParameters = pageParameters != null ? pageParameters : null;
+ this.pageClass = pageClass;
+ }
+
+ /**
+ * @return PageComponentInfo instance or <code>null</code>
+ */
+ public PageComponentInfo getPageComponentInfo()
+ {
+ return pageComponentInfo;
+ }
+
+ /**
+ * @return page class
+ */
+ public Class<? extends RequestablePage> getPageClass()
+ {
+ return pageClass;
+ }
+
+ /**
+ * @return PageParameters instance (never <code>null</code>)
+ */
+ public PageParameters getPageParameters()
+ {
+ return pageParameters;
+ }
+ }
+
+ /**
+ * Parse the given request to an {@link UrlInfo} instance.
+ *
+ * @param request
+ * @return UrlInfo instance or <code>null</code> if this encoder can not handle the request
+ */
+ protected abstract UrlInfo parseRequest(Request request);
+
+ /**
+ * Builds URL for the given {@link UrlInfo} instance. The URL this method produces must be
+ * parseable by the {@link #parseRequest(Request)} method.
+ *
+ * @param info
+ * @return Url result URL
+ */
+ protected abstract Url buildUrl(UrlInfo info);
+
+ /**
+ * Indicates whether hybrid {@link RenderPageRequestHandler} URL for page will be generated only
+ * if page has been created with bookmarkable URL.
+ * <p>
+ * Generic bookmarkable encoders this method should return <code>true</code>. For explicit
+ * (mounted) encoders this method should return <code>false</code>
+ *
+ * @return <code>true</code> if hybrid URL requires page created bookmarkable,
+ * <code>false</code> otherwise.
+ */
+ protected abstract boolean pageMustHaveBeenCreatedBookmarkable();
+
+ /**
+ * @see RequestMapper#getCompatibilityScore(Request)
+ */
+ public abstract int getCompatibilityScore(Request request);
+
+ private RequestHandler processBookmarkable(Class<? extends RequestablePage> pageClass, PageParameters pageParameters)
+ {
+ PageProvider provider = new PageProvider(pageClass, pageParameters);
+ provider.setPageSource(getContext());
+ return new RenderPageRequestHandler(provider);
+ }
+
+ private RequestHandler processHybrid(PageInfo pageInfo, Class<? extends RequestablePage> pageClass,
+ PageParameters pageParameters, Integer renderCount)
+ {
+ PageProvider provider = new PageProvider(pageInfo.getPageId(), pageClass, pageParameters,
+ renderCount);
+ provider.setPageSource(getContext());
+ return new RenderPageRequestHandler(provider);
+ }
+
+ private RequestHandler processListener(PageComponentInfo pageComponentInfo, Class<? extends RequestablePage> pageClass,
+ PageParameters pageParameters)
+ {
+ PageInfo pageInfo = pageComponentInfo.getPageInfo();
+ ComponentInfo componentInfo = pageComponentInfo.getComponentInfo();
+ Integer renderCount = componentInfo != null ? componentInfo.getRenderCount() : null;
+
+ RequestListenerInterface listenerInterface = requestListenerInterfaceFromString(componentInfo
+ .getListenerInterface());
+
+ if (listenerInterface != null)
+ {
+ PageAndComponentProvider provider = new PageAndComponentProvider(pageInfo.getPageId(), pageClass,
+ pageParameters, renderCount, componentInfo.getComponentPath());
+
+ provider.setPageSource(getContext());
+
+ return new ListenerInterfaceRequestHandler(provider, listenerInterface, componentInfo.getBehaviorIndex());
+ }
+ else
+ {
+ logger.warn("Unknown listener interface '" + componentInfo.getListenerInterface() + "'");
+ return null;
+ }
+ }
+
+ public RequestHandler mapRequest(Request request)
+ {
+ UrlInfo urlInfo = parseRequest(request);
+
+ // check if the URL is long enough and starts with the proper segments
+ if (urlInfo != null)
+ {
+ PageComponentInfo info = urlInfo.getPageComponentInfo();
+ Class<? extends RequestablePage> pageClass = urlInfo.getPageClass();
+ PageParameters pageParameters = urlInfo.getPageParameters();
+
+ if (info == null || info.getPageInfo().getPageId() == null)
+ {
+ // if there are is no page instance information (only page map name - optionally)
+ // then this is a simple bookmarkable URL
+ return processBookmarkable(pageClass, pageParameters);
+ }
+ else if (info.getPageInfo().getPageId() != null && info.getComponentInfo() == null)
+ {
+ // if there is page instance information in the URL but no component and listener
+ // interface then this is a hybrid URL - we need to try to reuse existing page
+ // instance
+ return processHybrid(info.getPageInfo(), pageClass, pageParameters, null);
+ }
+ else if (info.getComponentInfo() != null)
+ {
+ // with both page instance and component+listener this is a listener interface URL
+ return processListener(info, pageClass, pageParameters);
+ }
+ }
+ return null;
+ }
+
+ protected boolean checkPageClass(Class<? extends RequestablePage> pageClass)
+ {
+ return true;
+ }
+
+ public Url mapHandler(RequestHandler requestHandler)
+ {
+ if (requestHandler instanceof BookmarkablePageRequestHandler)
+ {
+ // simple bookmarkable URL with no page instance information
+ BookmarkablePageRequestHandler handler = (BookmarkablePageRequestHandler) requestHandler;
+
+ if (!checkPageClass(handler.getPageClass()))
+ {
+ return null;
+ }
+
+ PageInfo info = new PageInfo();
+ UrlInfo urlInfo = new UrlInfo(new PageComponentInfo(info, null), handler.getPageClass(), handler
+ .getPageParameters());
+
+ return buildUrl(urlInfo);
+ }
+ else if (requestHandler instanceof RenderPageRequestHandler)
+ {
+ // possibly hybrid URL - bookmarkable URL with page instance information
+ // but only allowed if the page was created by bookamarkable URL
+
+ RenderPageRequestHandler handler = (RenderPageRequestHandler) requestHandler;
+ RequestablePage page = handler.getPage();
+
+ if (!checkPageClass(page.getClass()))
+ {
+ return null;
+ }
+
+ if (!pageMustHaveBeenCreatedBookmarkable() || page.wasCreatedBookmarkable())
+ {
+ PageInfo info = null;
+ if (!page.isPageStateless())
+ {
+ info = new PageInfo(page);
+ }
+ PageComponentInfo pageComponentInfo = info != null ? new PageComponentInfo(info, null) : null;
+
+ UrlInfo urlInfo = new UrlInfo(pageComponentInfo, page.getClass(), handler.getPageParameters());
+ return buildUrl(urlInfo);
+ }
+ else
+ {
+ return null;
+ }
+
+ }
+ else if (requestHandler instanceof BookmarkableListenerInterfaceRequestHandler)
+ {
+ // listener interface URL with page class information
+ BookmarkableListenerInterfaceRequestHandler handler = (BookmarkableListenerInterfaceRequestHandler) requestHandler;
+ RequestablePage page = handler.getPage();
+
+ if (!checkPageClass(page.getClass()))
+ {
+ return null;
+ }
+
+ PageInfo pageInfo = new PageInfo(page);
+ ComponentInfo componentInfo = new ComponentInfo(page.getRenderCount(),
+ requestListenerInterfaceToString(handler.getListenerInterface()), handler.getComponent().getPath(),
+ handler.getBehaviorIndex());
+
+ UrlInfo urlInfo = new UrlInfo(new PageComponentInfo(pageInfo, componentInfo), page.getClass(), handler
+ .getPageParameters());
+ return buildUrl(urlInfo);
+ }
+
+ return null;
+ }
+
+
+ private static Logger logger = LoggerFactory.getLogger(AbstractBookmarkableMapper.class);
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractMapper.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractMapper.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractMapper.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,295 @@
+/*
+ * 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.ng.request.mapper;
+
+import org.apache.wicket.ng.Application;
+import org.apache.wicket.ng.request.Request;
+import org.apache.wicket.ng.request.RequestMapper;
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.Url.QueryParameter;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.listener.RequestListenerInterface;
+import org.apache.wicket.ng.request.mapper.info.PageComponentInfo;
+import org.apache.wicket.ng.request.mapper.parameters.PageParametersEncoder;
+import org.apache.wicket.ng.util.lang.Check;
+import org.apache.wicket.ng.util.lang.Classes;
+import org.apache.wicket.ng.util.string.Strings;
+
+/**
+ * Convenience class for implementing page/components related encoders.
+ *
+ * @author Matej Knopp
+ */
+public abstract class AbstractMapper implements RequestMapper
+{
+ protected MapperContext getContext()
+ {
+ return Application.get().getEncoderContext();
+ }
+
+ /**
+ * Converts the specified listener interface to String.
+ *
+ * @param listenerInterface
+ * @return listenerInterface name as string
+ */
+ protected String requestListenerInterfaceToString(RequestListenerInterface listenerInterface)
+ {
+ Check.argumentNotNull(listenerInterface, "listenerInterface");
+
+ return getContext().requestListenerInterfaceToString(listenerInterface);
+ }
+
+ /**
+ * Creates listener interface from the specified string
+ *
+ * @param interfaceName
+ * @return listener interface
+ */
+ protected RequestListenerInterface requestListenerInterfaceFromString(String interfaceName)
+ {
+ Check.argumentNotEmpty(interfaceName, "interfaceName");
+
+ return getContext().requestListenerInterfaceFromString(interfaceName);
+ }
+
+ /**
+ * If the string is in a placeholder format ${key} this method returns the key.
+ *
+ * @param s
+ * @return placeholder key or <code>null</code> if string is not in right format
+ */
+ protected static String getPlaceholder(String s)
+ {
+ if (s == null || s.length() < 4 || !s.startsWith("${") || !s.endsWith("}"))
+ {
+ return null;
+ }
+ else
+ {
+ return s.substring(2, s.length() - 1);
+ }
+ }
+
+ /**
+ * Returns true if the given url starts with specified segments. Segments that contain
+ * placelhoders are not compared.
+ *
+ * @param url
+ * @param segments
+ * @return <code>true</code> if the URL starts with the specified segments, <code>false</code>
+ * otherwise
+ */
+ /*
+ * TODO its funny to have a dependency in this method on the #getPlaceHolder method because we
+ * are forcing everyone who extends this to use the ${placeholder} syntax. We should move
+ * #getPlaceHolder out and rewrite this method to have no dependency on it and match only exact
+ * paths. The mappers that use the syntax will have to provide their own implementations.
+ *
+ * Either that or have a pluggable placeholder syntax Placeholder { string start, string end}
+ */
+ protected boolean urlStartsWith(Url url, String... segments)
+ {
+ if (url == null)
+ {
+ return false;
+ }
+ else
+ {
+ if (url.getSegments().size() < segments.length)
+ {
+ return false;
+ }
+ else
+ {
+ for (int i = 0; i < segments.length; ++i)
+ {
+ if (segments[i].equals(url.getSegments().get(i)) == false &&
+ getPlaceholder(segments[i]) == null)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Extracts the {@link PageComponentInfo} from the URL. The {@link PageComponentInfo} is encoded
+ * as the very first query parameter and the parameter consists of name only (no value).
+ *
+ * @param url
+ *
+ * @return PageComponentInfo instance if one was encoded in URL, <code>null</code> otherwise.
+ */
+ protected PageComponentInfo getPageComponentInfo(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalStateException("Argument 'url' may not be null.");
+ }
+ if (url.getQueryParameters().size() > 0)
+ {
+ QueryParameter param = url.getQueryParameters().get(0);
+ if (Strings.isEmpty(param.getValue()))
+ {
+ return PageComponentInfo.parse(param.getName());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Encodes the {@link PageComponentInfo} instance as the first query string parameter to the
+ * URL.
+ *
+ * @param url
+ * @param info
+ */
+ protected void encodePageComponentInfo(Url url, PageComponentInfo info)
+ {
+ if (url == null)
+ {
+ throw new IllegalStateException("Argument 'url' may not be null.");
+ }
+ if (info != null)
+ {
+ String s = info.toString();
+ if (!Strings.isEmpty(s))
+ {
+ QueryParameter parameter = new QueryParameter(s, "");
+ url.getQueryParameters().add(parameter);
+ }
+ }
+ }
+
+ /**
+ * Loads page class with given name.
+ *
+ * @param name
+ * @return class
+ */
+ protected Class< ? extends RequestablePage> getPageClass(String name)
+ {
+ Check.argumentNotEmpty(name, "name");
+
+ return Classes.resolveClass(name);
+ }
+
+ /**
+ * Extracts {@link PageParameters} from the URL using the given {@link PageParametersEncoder}.
+ *
+ * @param request
+ * @param segmentsToSkip
+ * how many URL segments should be skipped because they "belong" to the
+ * {@link RequestMapper}
+ * @param encoder
+ * @return PageParameters instance
+ */
+ protected PageParameters extractPageParameters(Request request, int segmentsToSkip,
+ PageParametersEncoder encoder)
+ {
+ Check.argumentNotNull(request, "request");
+ Check.argumentNotNull(encoder, "encoder");
+
+ // strip the segments and first query parameter from URL
+ Url urlCopy = new Url(request.getUrl());
+ while (segmentsToSkip > 0 && urlCopy.getSegments().isEmpty() == false)
+ {
+ urlCopy.getSegments().remove(0);
+ --segmentsToSkip;
+ }
+
+ if (!urlCopy.getQueryParameters().isEmpty() &&
+ Strings.isEmpty(urlCopy.getQueryParameters().get(0).getValue()))
+ {
+ urlCopy.getQueryParameters().remove(0);
+ }
+
+ PageParameters decoded = encoder.decodePageParameters(request.requestWithUrl(urlCopy));
+ return decoded != null ? decoded : new PageParameters();
+ }
+
+ /**
+ * Encodes the given {@link PageParameters} to the URL using the given
+ * {@link PageParametersEncoder}. The original URL object is unchanged.
+ *
+ * @param url
+ * @param pageParameters
+ * @param encoder
+ * @return URL with encoded parameters
+ */
+ protected Url encodePageParameters(Url url, PageParameters pageParameters,
+ PageParametersEncoder encoder)
+ {
+ Check.argumentNotNull(url, "url");
+ Check.argumentNotNull(encoder, "encoder");
+
+ if (pageParameters == null)
+ {
+ pageParameters = new PageParameters();
+ }
+
+ Url parametersUrl = encoder.encodePageParameters(pageParameters);
+ if (parametersUrl != null)
+ {
+ // copy the url
+ url = new Url(url);
+
+ for (String s : parametersUrl.getSegments())
+ {
+ url.getSegments().add(s);
+ }
+ for (QueryParameter p : parametersUrl.getQueryParameters())
+ {
+ url.getQueryParameters().add(p);
+ }
+ }
+
+ return url;
+ }
+
+ /**
+ * Convenience method for representing mountPath as array of segments
+ *
+ * @param mountPath
+ * @return array of path segments
+ */
+ protected String[] getMountSegments(String mountPath)
+ {
+ if (mountPath.startsWith("/"))
+ {
+ mountPath = mountPath.substring(1);
+ }
+ Url url = Url.parse(mountPath);
+
+ if (url.getSegments().isEmpty())
+ {
+ throw new IllegalArgumentException("Mount path must have at least one segment.");
+ }
+
+ String[] res = new String[url.getSegments().size()];
+ for (int i = 0; i < res.length; ++i)
+ {
+ res[i] = url.getSegments().get(i);
+ }
+ return res;
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractResourceReferenceMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractResourceReferenceMapper.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractResourceReferenceMapper.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/AbstractResourceReferenceMapper.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,133 @@
+/*
+ * 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.ng.request.mapper;
+
+import java.util.Locale;
+
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.Url.QueryParameter;
+import org.apache.wicket.ng.resource.ResourceReference;
+import org.apache.wicket.ng.util.string.Strings;
+
+/**
+ * Base class for encoding and decoding {@link ResourceReference}s
+ *
+ * @author Matej Knopp
+ */
+public abstract class AbstractResourceReferenceMapper extends AbstractMapper
+{
+
+ protected static class ResourceReferenceAttributes
+ {
+ protected Locale locale;
+ protected String style;
+ };
+
+ protected static String encodeResourceReferenceAttributes(ResourceReferenceAttributes attributes)
+ {
+ if (attributes == null || (attributes.locale == null && attributes.style == null))
+ {
+ return null;
+ }
+ else
+ {
+ StringBuilder res = new StringBuilder();
+ if (attributes.locale != null)
+ {
+ res.append(attributes.locale.toString());
+ }
+ if (!Strings.isEmpty(attributes.style))
+ {
+ res.append("-");
+ res.append(attributes.style);
+ }
+ return res.toString();
+ }
+ };
+
+ protected static ResourceReferenceAttributes decodeResourceReferenceAttributes(String attributes)
+ {
+ ResourceReferenceAttributes res = new ResourceReferenceAttributes();
+ if (!Strings.isEmpty(attributes))
+ {
+ String split[] = attributes.split("-", 2);
+ res.locale = parseLocale(split[0]);
+ if (split.length == 2)
+ {
+ res.style = split[1];
+ }
+ }
+ return res;
+ }
+
+ private static Locale parseLocale(String locale)
+ {
+ if (Strings.isEmpty(locale))
+ {
+ return null;
+ }
+ else
+ {
+ String parts[] = locale.toLowerCase().split("_", 3);
+ if (parts.length == 1)
+ {
+ return new Locale(parts[0]);
+ }
+ else if (parts.length == 2)
+ {
+ return new Locale(parts[0], parts[1]);
+ }
+ else if (parts.length == 3)
+ {
+ return new Locale(parts[0], parts[1], parts[2]);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ protected void encodeResourceReferenceAttributes(Url url, ResourceReference reference)
+ {
+ ResourceReferenceAttributes attributes = new ResourceReferenceAttributes();
+ attributes.locale = reference.getLocale();
+ attributes.style = reference.getStyle();
+ String encoded = encodeResourceReferenceAttributes(attributes);
+ if (!Strings.isEmpty(encoded))
+ {
+ url.getQueryParameters().add(new Url.QueryParameter(encoded, ""));
+ }
+ }
+
+ protected ResourceReferenceAttributes getResourceReferenceAttributes(Url url)
+ {
+ if (url == null)
+ {
+ throw new IllegalStateException("Argument 'url' may not be null.");
+ }
+ if (url.getQueryParameters().size() > 0)
+ {
+ QueryParameter param = url.getQueryParameters().get(0);
+ if (Strings.isEmpty(param.getValue()))
+ {
+ return decodeResourceReferenceAttributes(param.getName());
+ }
+ }
+ return new ResourceReferenceAttributes();
+ }
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BookmarkableMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BookmarkableMapper.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BookmarkableMapper.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BookmarkableMapper.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,124 @@
+/*
+ * 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.ng.request.mapper;
+
+import org.apache.wicket.ng.request.Request;
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.mapper.info.PageComponentInfo;
+import org.apache.wicket.ng.request.mapper.parameters.PageParametersEncoder;
+import org.apache.wicket.ng.request.mapper.parameters.SimplePageParametersEncoder;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * Decodes and encodes the following URLs:
+ *
+ * <pre>
+ * Page Class - Render (BookmarkablePageRequestHandler)
+ * /wicket/bookmarkable/org.apache.wicket.MyPage
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?pageMap
+ * (these will redirect to hybrid alternative if page is not stateless)
+ *
+ * Page Instance - Render Hybrid (RenderPageRequestHandler for pages that were created using bookmarkable URLs)
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2.4
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?pageMap.2.4
+ *
+ * Page Instance - Bookmarkable Listener (BookmarkableListenerInterfaceRequestHandler)
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2-click-foo-bar-baz
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2.4-click-foo-bar-baz
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?pageMap.2.4-click-foo-bar-baz
+ * /wicket/bookmarkable/org.apache.wicket.MyPage?2.4-click.1-foo-bar-baz (1 is behavior index)
+ * (these will redirect to hybrid if page is not stateless)
+ * </pre>
+ *
+ * @author Matej Knopp
+ */
+public class BookmarkableMapper extends AbstractBookmarkableMapper
+{
+ private final PageParametersEncoder pageParametersEncoder;
+
+ /**
+ * Construct.
+ *
+ * @param pageParametersEncoder
+ */
+ public BookmarkableMapper(PageParametersEncoder pageParametersEncoder)
+ {
+ Check.argumentNotNull(pageParametersEncoder, "pageParametersEncoder");
+
+ this.pageParametersEncoder = pageParametersEncoder;
+ }
+
+ /**
+ * Construct.
+ */
+ public BookmarkableMapper()
+ {
+ this(new SimplePageParametersEncoder());
+ }
+
+ @Override
+ protected Url buildUrl(UrlInfo info)
+ {
+ Url url = new Url();
+ url.getSegments().add(getContext().getNamespace());
+ url.getSegments().add(getContext().getBookmarkableIdentifier());
+ url.getSegments().add(info.getPageClass().getName());
+
+ encodePageComponentInfo(url, info.getPageComponentInfo());
+
+ return encodePageParameters(url, info.getPageParameters(), pageParametersEncoder);
+ }
+
+ @Override
+ protected UrlInfo parseRequest(Request request)
+ {
+ Url url = request.getUrl();
+ if (url.getSegments().size() >= 3 &&
+ urlStartsWith(url, getContext().getNamespace(),
+ getContext().getBookmarkableIdentifier()))
+ {
+ // try to extract page and component information from URL
+ PageComponentInfo info = getPageComponentInfo(url);
+
+ // load the page class
+ String className = url.getSegments().get(2);
+ Class<? extends RequestablePage> pageClass = getPageClass(className);
+
+ // extract the PageParameters from URL if there are any
+ PageParameters pageParameters = extractPageParameters(request, 3, pageParametersEncoder);
+
+ return new UrlInfo(info, pageClass, pageParameters);
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean pageMustHaveBeenCreatedBookmarkable()
+ {
+ return true;
+ }
+
+ public int getCompatibilityScore(Request request)
+ {
+ // always return 0 here so that the mounts have higher priority
+ return 0;
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BufferedResponseMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BufferedResponseMapper.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BufferedResponseMapper.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/BufferedResponseMapper.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,99 @@
+package org.apache.wicket.ng.request.mapper;
+
+import org.apache.wicket.ng.Session;
+import org.apache.wicket.ng.protocol.http.WebApplication;
+import org.apache.wicket.ng.request.Request;
+import org.apache.wicket.ng.request.RequestHandler;
+import org.apache.wicket.ng.request.RequestMapper;
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.cycle.RequestCycle;
+import org.apache.wicket.ng.request.handler.impl.BufferedResponseRequestHandler;
+import org.apache.wicket.ng.request.response.BufferedWebResponse;
+
+/**
+ * Encoder that intercepts requests for which there is already stored buffer with rendered data.
+ *
+ * @author Matej Knopp
+ */
+public class BufferedResponseMapper implements RequestMapper
+{
+
+ public BufferedResponseMapper()
+ {
+ }
+
+ protected String getSessionId()
+ {
+ return Session.get().getId();
+ }
+
+ protected boolean hasBufferedResponse(Url url)
+ {
+ String sessionId = getSessionId();
+ if (sessionId != null)
+ {
+ return WebApplication.get().hasBufferedResponse(sessionId, url);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ protected BufferedWebResponse getAndRemoveBufferedResponse(Url url)
+ {
+ return WebApplication.get().getAndRemoveBufferedResponse(getSessionId(), url);
+ }
+
+ private Request getRequest(Request original)
+ {
+ // The buffers are stored under "real" URL which can be different
+ // than the URL handlers get due to global URL pre/postprocessing
+ // (i.e. prepending URL with language segment).
+ // Because of that we need find out the real URL from request cycle
+
+ if (RequestCycle.get() != null)
+ {
+ return RequestCycle.get().getRequest();
+ }
+ else
+ {
+ return original;
+ }
+ }
+
+ public RequestHandler mapRequest(Request request)
+ {
+ request = getRequest(request);
+
+ BufferedWebResponse response = getAndRemoveBufferedResponse(request.getUrl());
+ if (response != null)
+ {
+ return new BufferedResponseRequestHandler(response);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public Url mapHandler(RequestHandler requestHandler)
+ {
+ return null;
+ }
+
+ public int getCompatibilityScore(Request request)
+ {
+ request = getRequest(request);
+
+ if (hasBufferedResponse(request.getUrl()))
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MapperContext.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MapperContext.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MapperContext.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MapperContext.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,77 @@
+/*
+ * 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.ng.request.mapper;
+
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.listener.RequestListenerInterface;
+import org.apache.wicket.ng.resource.ResourceReferenceRegistry;
+
+/**
+ * Utility interface for providing and creating new page instances.
+ *
+ * @author Matej Knopp
+ */
+public interface MapperContext extends PageSource
+{
+ /**
+ * @return the namespace for Wicket URLs.
+ */
+ public String getNamespace();
+
+ /**
+ * @return identifier for non bookmarkable URLs
+ */
+ public String getPageIdentifier();
+
+ /**
+ * @return identifier for bookmarkable URLs
+ */
+ public String getBookmarkableIdentifier();
+
+ /**
+ * @return identifier for resources
+ */
+ public String getResourceIdentifier();
+
+ /**
+ * @return {@link ResourceReferenceRegistry}
+ */
+ public ResourceReferenceRegistry getResourceReferenceRegistry();
+
+ /**
+ * Returns the listener interface name as string.
+ *
+ * @param listenerInterface
+ * @return listener interface name as string
+ */
+ public String requestListenerInterfaceToString(RequestListenerInterface listenerInterface);
+
+ /**
+ * Returns listener interface for the name
+ *
+ * @param interfaceName
+ * @return listener interface
+ */
+ public RequestListenerInterface requestListenerInterfaceFromString(String interfaceName);
+
+ /**
+ * Returns the home page class.
+ *
+ * @return home page class
+ */
+ public Class<? extends RequestablePage> getHomePageClass();
+}
Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MountedMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MountedMapper.java?rev=823984&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MountedMapper.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ng/request/mapper/MountedMapper.java Sun Oct 11 00:02:25 2009
@@ -0,0 +1,221 @@
+/*
+ * 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.ng.request.mapper;
+
+import java.lang.ref.WeakReference;
+
+import org.apache.wicket.ng.request.Request;
+import org.apache.wicket.ng.request.Url;
+import org.apache.wicket.ng.request.component.PageParameters;
+import org.apache.wicket.ng.request.component.RequestablePage;
+import org.apache.wicket.ng.request.mapper.info.PageComponentInfo;
+import org.apache.wicket.ng.request.mapper.parameters.PageParametersEncoder;
+import org.apache.wicket.ng.request.mapper.parameters.SimplePageParametersEncoder;
+import org.apache.wicket.ng.util.lang.Check;
+
+/**
+ * Encoder for mounted URL. The mount path can contain parameter placeholders, i.e.
+ * <code>/mount/${foo}/path</code>. In that case the appropriate segment from the URL will be
+ * accessible as named parameter "foo" in the {@link PageParameters}. Similarly when the URL is
+ * constructed, the second segment will contain the value of the "foo" named page parameter.
+ * <p>
+ * Decodes and encodes the following URLs:
+ *
+ * <pre>
+ * Page Class - Render (BookmarkablePageRequestHandler for mounted pages)
+ * /mount/point
+ * (these will redirect to hybrid alternative if page is not stateless)
+ *
+ * IPage Instance - Render Hybrid (RenderPageRequestHandler for mounted pages)
+ * /mount/point?2
+ *
+ * IPage Instance - Bookmarkable Listener (BookmarkableListenerInterfaceRequestHandler for mounted pages)
+ * /mount/point?2-click-foo-bar-baz
+ * /mount/point?2-5.click.1-foo-bar-baz (1 is behavior index, 5 is render count)
+ * (these will redirect to hybrid if page is not stateless)
+ * </pre>
+ *
+ * @author Matej Knopp
+ */
+public class MountedMapper extends AbstractBookmarkableMapper
+{
+ private final PageParametersEncoder pageParametersEncoder;
+ private final String[] mountSegments;
+
+ /** bookmarkable page class. */
+ protected final WeakReference<Class<? extends RequestablePage>> pageClass;
+
+ /**
+ * Construct.
+ *
+ * @param mountPath
+ * @param pageClass
+ * @param pageParametersEncoder
+ */
+ public MountedMapper(String mountPath, Class<? extends RequestablePage> pageClass,
+ PageParametersEncoder pageParametersEncoder)
+ {
+ Check.argumentNotEmpty(mountPath, "mountPath");
+ Check.argumentNotNull(pageClass, "pageClass");
+ Check.argumentNotNull(pageParametersEncoder, "pageParametersEncoder");
+
+ this.pageParametersEncoder = pageParametersEncoder;
+ this.pageClass = new WeakReference<Class<? extends RequestablePage>>(pageClass);
+ this.mountSegments = getMountSegments(mountPath);
+ }
+
+ /**
+ * Construct.
+ *
+ * @param mountPath
+ * @param pageClass
+ */
+ public MountedMapper(String mountPath, Class<? extends RequestablePage> pageClass)
+ {
+ this(mountPath, pageClass, new SimplePageParametersEncoder());
+ }
+
+ @Override
+ protected UrlInfo parseRequest(Request request)
+ {
+ Url url = request.getUrl();
+
+ // when redirect to buffer/render is active and redirectFromHomePage returns true
+ // check mounted class against the home page class. if it matches let wicket redirect
+ // to the mounted URL
+ if (redirectFromHomePage() && checkHomePage(url))
+ {
+ UrlInfo info = new UrlInfo(null, getContext().getHomePageClass(), newPageParameters());
+ return info;
+ }
+ // check if the URL is long enough and starts with the proper segments
+ else if (url.getSegments().size() >= mountSegments.length && urlStartsWith(url, mountSegments))
+ {
+ // try to extract page and component information from URL
+ PageComponentInfo info = getPageComponentInfo(url);
+
+ Class<? extends RequestablePage> pageClass = this.pageClass.get();
+
+ // extract the PageParameters from URL if there are any
+ PageParameters pageParameters = extractPageParameters(request, mountSegments.length, pageParametersEncoder);
+
+ // check if there are placeholders in mount segments
+ for (int i = 0; i < mountSegments.length; ++i)
+ {
+ String placeholder = getPlaceholder(mountSegments[i]);
+ if (placeholder != null)
+ {
+ // extract the parameter from URL
+ pageParameters.addNamedParameter(placeholder, url.getSegments().get(i));
+ }
+ }
+
+ return new UrlInfo(info, pageClass, pageParameters);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ protected PageParameters newPageParameters()
+ {
+ return new PageParameters();
+ }
+
+ @Override
+ protected Url buildUrl(UrlInfo info)
+ {
+ Url url = new Url();
+ for (String s : mountSegments)
+ {
+ url.getSegments().add(s);
+ }
+ encodePageComponentInfo(url, info.getPageComponentInfo());
+
+ PageParameters copy = new PageParameters(info.getPageParameters());
+
+ for (int i = 0; i < mountSegments.length; ++i)
+ {
+ String placeholder = getPlaceholder(mountSegments[i]);
+ if (placeholder != null)
+ {
+ url.getSegments().set(i, copy.getNamedParameter(placeholder).toString(""));
+ copy.removeNamedParameter(placeholder);
+ }
+ }
+
+ return encodePageParameters(url, copy, pageParametersEncoder);
+ }
+
+ /**
+ * Check if the URL is for home page and the home page class match mounted class. If so,
+ * redirect to mounted URL.
+ *
+ * @param url
+ * @return request handler or <code>null</code>
+ */
+ private boolean checkHomePage(Url url)
+ {
+ if (url.getSegments().isEmpty() && url.getQueryParameters().isEmpty())
+ {
+ // this is home page
+ if (pageClass.get().equals(getContext().getHomePageClass()) && redirectFromHomePage())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If this method returns <code>true</code> and application home page class is same as the class
+ * mounted with this encoder, request to home page will result in a redirect to the mounted
+ * path.
+ *
+ * @return whether this encode should respond to home page request when home page class is same
+ * as mounted class.
+ */
+ protected boolean redirectFromHomePage()
+ {
+ return true;
+ }
+
+ @Override
+ protected boolean pageMustHaveBeenCreatedBookmarkable()
+ {
+ return false;
+ }
+
+ public int getCompatibilityScore(Request request)
+ {
+ if (urlStartsWith(request.getUrl(), mountSegments))
+ {
+ return mountSegments.length;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ @Override
+ protected boolean checkPageClass(Class<? extends RequestablePage> pageClass)
+ {
+ return pageClass.equals(this.pageClass.get());
+ }
+}