You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by kn...@apache.org on 2009/03/28 18:53:08 UTC

svn commit: r759525 [2/7] - in /wicket/sandbox/knopp/experimental/wicket-ng/src: main/java/org/ main/java/org/apache/ main/java/org/apache/wicket/ main/java/org/apache/wicket/behavior/ main/java/org/apache/wicket/markup/ main/java/org/apache/wicket/mar...

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/behavior/IBehavior.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/behavior/IBehavior.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/behavior/IBehavior.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/behavior/IBehavior.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,6 @@
+package org.apache.wicket.behavior;
+
+public interface IBehavior
+{
+
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/behavior/IBehavior.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/markup/html/link/ILinkListener.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/markup/html/link/ILinkListener.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/markup/html/link/ILinkListener.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/markup/html/link/ILinkListener.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,37 @@
+/*
+ * 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.markup.html.link;
+
+import org.apache.wicket.IRequestListener;
+import org.apache.wicket.RequestListenerInterface;
+
+/**
+ * Listener method for link clicks.
+ * 
+ * @author Jonathan Locke
+ */
+public interface ILinkListener extends IRequestListener
+{
+	/** Listener interface */
+	public static final RequestListenerInterface INTERFACE = new RequestListenerInterface(
+			ILinkListener.class);
+
+	/**
+	 * Called when a link is clicked.
+	 */
+	void onLinkClicked();
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/markup/html/link/ILinkListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IDetachable.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IDetachable.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IDetachable.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IDetachable.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,35 @@
+/*
+ * 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.model;
+
+import java.io.Serializable;
+
+/**
+ * Interface to logic for detaching transient information from a detachable model. Detachable models
+ * are desirable because they reduce the amount of state required by a model, which makes the model
+ * cheaper to replicate in a clustered environment.
+ * 
+ * @author Jonathan Locke
+ */
+public interface IDetachable extends Serializable
+{
+	/**
+	 * Detaches model after use. This is generally used to null out transient references that can be
+	 * re-attached later.
+	 */
+	void detach();
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IDetachable.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IModel.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IModel.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IModel.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IModel.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,75 @@
+/*
+ * 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.model;
+
+
+/**
+ * A IModel wraps the actual model Object used by a Component. IModel implementations are used as a
+ * facade for the real model so that users have control over the actual persistence strategy. Note
+ * that objects implementing this interface will be stored in the Session. Hence, you should use
+ * (non-transient) instance variables sparingly.
+ * <ul>
+ * <li><b>Basic Models </b>- To implement a basic (non-detachable) model which holds its entire
+ * state in the Session, you can use the simple model wrapper {@link Model}.
+ * 
+ * <li><b>Detachable Models </b>- IModel inherits a hook, {@link IDetachable#detach()}, so that
+ * interface implementers can detach transient information when a model is no longer being actively
+ * used by the framework. This reduces memory use and reduces the expense of replicating the model
+ * in a clustered server environment. To implement a detachable model, you should generally extend
+ * {@link LoadableDetachableModel} instead of implementing IModel directly.
+ * 
+ * <li><b>Property Models </b>- The AbstractPropertyModel class provides default functionality for
+ * property models. A property model provides access to a particular property of its wrapped model.
+ * 
+ * <li><b>Compound Property Models </b>- The IModel interface is parameterized by Component,
+ * allowing a model to be shared among several Components. When the {@link IModel#getObject()}method
+ * is called, the value returned will depend on the Component which is asking for the value.
+ * Likewise, the {@link IModel#setObject(Object)}method sets a different property depending on
+ * which Component is doing the setting. For more information on CompoundPropertyModels and model
+ * inheritance, see {@link org.apache.wicket.model.CompoundPropertyModel}and
+ * {@link org.apache.wicket.Page}.
+ * </ul>
+ * 
+ * @see org.apache.wicket.Component#sameInnermostModel(org.apache.wicket.Component)
+ * @see org.apache.wicket.Component#sameInnermostModel(IModel)
+ * 
+ * @author Chris Turner
+ * @author Eelco Hillenius
+ * @author Jonathan Locke
+ * 
+ * TODO 3.0: Vote on renaming get/setObject to get/setValue
+ * 
+ * @param <T>
+ *            Model object.
+ */
+public interface IModel<T> extends IDetachable
+{
+	/**
+	 * Gets the model object.
+	 * 
+	 * @return The model object
+	 */
+	T getObject();
+
+	/**
+	 * Sets the model object.
+	 * 
+	 * @param object
+	 *            The model object
+	 */
+	void setObject(final T object);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/model/IModel.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/PageManager.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/PageManager.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/PageManager.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/PageManager.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,49 @@
+/*
+ * 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.page;
+
+import org.apache.wicket.Page;
+
+/**
+ * Session relative page manager.
+ * 
+ * @author Matej Knopp
+ */
+public interface PageManager
+{
+	/**
+	 * Retrieves page instance with given id.
+	 * 
+	 * @param id
+	 * @return page instance or <code>null</code>
+	 */
+	public Page getPage(int id);
+	
+	/**
+	 * Marks page as changed
+	 * 
+	 * @param page
+	 */
+	public void touchPage(Page page);
+	
+	/**
+	 * Increases the page version
+	 * 
+	 * @param page
+	 */
+	public void bumpVersion(Page page);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/PageManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/page-management.txt
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/page-management.txt?rev=759525&view=auto
==============================================================================
    (empty)

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/page/page-management.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/ContextParamWebApplicationFactory.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/ContextParamWebApplicationFactory.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/ContextParamWebApplicationFactory.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/ContextParamWebApplicationFactory.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,101 @@
+/*
+ * 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.protocol.http;
+
+import org.apache.wicket.WicketRuntimeException;
+
+/**
+ * Factory that creates application objects based on the class name specified in the
+ * {@link ContextParamWebApplicationFactory#APP_CLASS_PARAM} context variable.
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ */
+public class ContextParamWebApplicationFactory implements IWebApplicationFactory
+{
+	/**
+	 * context parameter name that must contain the class name of the application
+	 */
+	public static final String APP_CLASS_PARAM = "applicationClassName";
+
+	/* @see IWebApplicationFactory#createApplication(WicketFilter) */
+	public WebApplication createApplication(WicketFilter filter)
+	{
+		final String applicationClassName = filter.getFilterConfig().getInitParameter(
+			APP_CLASS_PARAM);
+
+		if (applicationClassName == null)
+		{
+			throw new WicketRuntimeException(
+				"servlet init param [" +
+					APP_CLASS_PARAM +
+					"] is missing. If you are trying to use your own implementation of IWebApplicationFactory and get this message then the servlet init param [" +
+					WicketFilter.APP_FACT_PARAM + "] is missing");
+		}
+
+		return createApplication(applicationClassName);
+	}
+
+	/**
+	 * Instantiates the application instance.
+	 * 
+	 * @param applicationClassName
+	 *            the classname of the application to create
+	 * @return the web application
+	 */
+	protected WebApplication createApplication(final String applicationClassName)
+	{
+		try
+		{
+			ClassLoader loader = Thread.currentThread().getContextClassLoader();
+			if (loader == null)
+			{
+				loader = getClass().getClassLoader();
+			}
+			final Class<?> applicationClass = loader.loadClass(applicationClassName);
+			if (WebApplication.class.isAssignableFrom(applicationClass))
+			{
+				// Construct WebApplication subclass
+				return (WebApplication)applicationClass.newInstance();
+			}
+			else
+			{
+				throw new WicketRuntimeException("Application class " + applicationClassName +
+					" must be a subclass of WebApplication");
+			}
+		}
+		catch (ClassNotFoundException e)
+		{
+			throw new WicketRuntimeException("Unable to create application of class " +
+				applicationClassName, e);
+		}
+		catch (InstantiationException e)
+		{
+			throw new WicketRuntimeException("Unable to create application of class " +
+				applicationClassName, e);
+		}
+		catch (IllegalAccessException e)
+		{
+			throw new WicketRuntimeException("Unable to create application of class " +
+				applicationClassName, e);
+		}
+		catch (SecurityException e)
+		{
+			throw new WicketRuntimeException("Unable to create application of class " +
+				applicationClassName, e);
+		}
+	}
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/ContextParamWebApplicationFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/IWebApplicationFactory.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/IWebApplicationFactory.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/IWebApplicationFactory.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/IWebApplicationFactory.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,43 @@
+/*
+ * 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.protocol.http;
+
+/**
+ * A factory interface used by wicket filter to create application objects. Configure your
+ * webapplication to use this factory in web.xml like:
+ * 
+ * <pre>
+ *     &lt;init-param&gt;
+ *       &lt;param-name&gt;applicationFactoryClassName&lt;/param-name&gt;
+ *         &lt;param-value&gt;org.apache.wicket.spring.SpringWebApplicationFactory&lt;/param-value&gt;
+ *     &lt;/init-param&gt;
+ *   
+ * </pre>
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ */
+public interface IWebApplicationFactory
+{
+	/**
+	 * Create application object
+	 * 
+	 * @param filter
+	 *            the wicket filter
+	 * @return application object instance
+	 */
+	WebApplication createApplication(WicketFilter filter);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/IWebApplicationFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/PageExpiredException.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/PageExpiredException.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/PageExpiredException.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/PageExpiredException.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,37 @@
+/*
+ * 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.protocol.http;
+
+import org.apache.wicket.WicketRuntimeException;
+
+/**
+ * Thrown when the {@link org.apache.wicket.protocol.http.WebRequestCycleProcessor} could not
+ * process the request or {@link org.apache.wicket.request.AbstractRequestCycleProcessor} could not
+ * resolve the rendered page.
+ */
+public class PageExpiredException extends WicketRuntimeException
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * @see WicketRuntimeException#WicketRuntimeException(java.lang.String)
+	 */
+	public PageExpiredException(final String message)
+	{
+		super(message);
+	}
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/PageExpiredException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplication.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplication.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplication.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,200 @@
+/*
+ * 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.protocol.http;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.DefaultPageFactory;
+import org.apache.wicket.IPage;
+import org.apache.wicket.IPageFactory;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.RequestCycleContext;
+import org.apache.wicket.RequestListenerInterface;
+import org.apache.wicket.request.RequestHandler;
+import org.apache.wicket.request.RequestHandlerEncoder;
+import org.apache.wicket.request.RequestHandlerEncoderRegistry;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.encoder.BookmarkableEncoder;
+import org.apache.wicket.request.encoder.EncoderContext;
+import org.apache.wicket.request.encoder.PageInstanceEncoder;
+import org.apache.wicket.request.encoder.ResourceReferenceEncoder;
+import org.apache.wicket.request.request.Request;
+import org.apache.wicket.request.response.Response;
+import org.apache.wicket.resource.ResourceReferenceRegistry;
+
+public abstract class WebApplication extends Application
+{
+
+	public WebApplication()
+	{
+		super();
+	}
+	
+	@Override
+	public void internalInit()
+	{		
+		mount(new BookmarkableEncoder());
+		mount(new PageInstanceEncoder());
+		mount(new ResourceReferenceEncoder());
+	}
+
+	protected RequestCycleContext newRequestCycleContext()
+	{
+		RequestCycleContext context = new RequestCycleContext()
+		{
+			public RequestHandler decodeRequestHandler(Request request)
+			{
+				return getRequestHandlerEncoderRegistry().decode(request);
+			}
+
+			public Url encodeRequestHandler(RequestHandler handler)
+			{
+				return getRequestHandlerEncoderRegistry().encode(handler);
+			}
+
+			public RequestHandler getRequestHandlerForException(Exception e)
+			{
+				return WebApplication.this.getRequestHandlerForException(e);
+			}
+		};
+		return context;
+	};
+
+	protected RequestHandler getRequestHandlerForException(Exception e)
+	{
+		return null;
+	};
+
+	public RequestCycle newRequestCycle(Request request, Response response)
+	{
+		RequestCycleContext context = newRequestCycleContext();
+		return new RequestCycle(request, response, context);
+	};
+
+	private RequestHandlerEncoderRegistry requestHandlerEncoderRegistry;
+
+	public RequestHandlerEncoderRegistry getRequestHandlerEncoderRegistry()
+	{
+		if (requestHandlerEncoderRegistry == null)
+		{
+			requestHandlerEncoderRegistry = newRequestHandlerEncoderRegistry();
+		}
+		return requestHandlerEncoderRegistry;
+	};
+
+	protected RequestHandlerEncoderRegistry newRequestHandlerEncoderRegistry()
+	{
+		return new RequestHandlerEncoderRegistry();
+	};
+
+	public static WebApplication get()
+	{
+		return (WebApplication) Application.get();
+	}
+
+	private EncoderContext encoderContext = new EncoderContext()
+	{
+
+		public String getBookmarkableIdentifier()
+		{
+			return "bookmarkable";
+		}
+
+		public String getNamespace()
+		{
+			return "wicket";
+		}
+
+		public String getPageIdentifier()
+		{
+			return "page";
+		}		
+
+		public String getResourceIdentifier()
+		{
+			return "resource";
+		}
+
+		public ResourceReferenceRegistry getResourceReferenceRegistry()
+		{
+			return WebApplication.this.getResourceReferenceRegistry();
+		}		
+
+		public RequestListenerInterface requestListenerInterfaceFromString(String interfaceName)
+		{
+			return RequestListenerInterface.forName(interfaceName);
+		}
+
+		public String requestListenerInterfaceToString(RequestListenerInterface listenerInterface)
+		{
+			return listenerInterface.getName();
+		}
+		
+		public IPage newPageInstance(Class<? extends IPage> pageClass, PageParameters pageParameters)
+		{
+			if (pageParameters == null)
+			{
+				return getPageFactory().newPage(pageClass);
+			}
+			else
+			{
+				return getPageFactory().newPage(pageClass, pageParameters);
+			}
+		}
+		
+		public IPage getPageInstance(int pageId)
+		{
+			return Page.get(pageId);
+		}
+		
+		public Class<? extends IPage> getHomePageClass()
+		{
+			return WebApplication.this.getHomePageClass();
+		}
+	};	
+	
+	public EncoderContext getEncoderContext()
+	{
+		return encoderContext;
+	}
+	
+	private ResourceReferenceRegistry resourceReferenceRegistry;
+	
+	public ResourceReferenceRegistry getResourceReferenceRegistry()
+	{
+		if (resourceReferenceRegistry == null)
+		{
+			resourceReferenceRegistry = new ResourceReferenceRegistry();
+		}
+		return resourceReferenceRegistry;
+	}
+	
+	private IPageFactory pageFactory = new DefaultPageFactory();
+	
+	public IPageFactory getPageFactory()
+	{
+		return pageFactory;
+	}
+	
+	public void mount(RequestHandlerEncoder encoder)
+	{
+		getRequestHandlerEncoderRegistry().register(encoder);
+	}
+	
+	public abstract Class<? extends IPage> getHomePageClass();
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplicationFactoryCreationException.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplicationFactoryCreationException.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplicationFactoryCreationException.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplicationFactoryCreationException.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,43 @@
+/*
+ * 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.protocol.http;
+
+import org.apache.wicket.WicketRuntimeException;
+
+/**
+ * Thrown when the {@link org.apache.wicket.protocol.http.IWebApplicationFactory} could not be
+ * created for some reason.
+ * 
+ * @author Seth Ladd
+ */
+public class WebApplicationFactoryCreationException extends WicketRuntimeException
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param appFactoryClassName
+	 *            name of the application factory
+	 * @param e
+	 *            the cause for the creation problem
+	 */
+	public WebApplicationFactoryCreationException(String appFactoryClassName, Exception e)
+	{
+		super("Unable to create application factory of class " + appFactoryClassName, e);
+	}
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WebApplicationFactoryCreationException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,499 @@
+/*
+ * 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.protocol.http;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.ThreadContext;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.request.request.ServletWebRequest;
+import org.apache.wicket.request.response.ServletWebResponse;
+import org.apache.wicket.util.string.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Filter for initiating handling of Wicket requests.
+ * 
+ * <p>
+ * The advantage of a filter is that, unlike a servlet, it can choose not to process the request and
+ * let whatever is next in chain try. So when using a Wicket filter and a request comes in for
+ * foo.gif the filter can choose not to process it because it knows it is not a wicket-related
+ * request. Since the filter didn't process it, it falls on to the application server to try, and
+ * then it works."
+ * 
+ * @see WicketServlet for documentation
+ * 
+ * @author Jonathan Locke
+ * @author Timur Mehrvarz
+ * @author Juergen Donnerstag
+ * @author Igor Vaynberg (ivaynberg)
+ * @author Al Maw
+ * @author jcompagner
+ */
+public class WicketFilter implements Filter
+{
+	/**
+	 * The name of the root path parameter that specifies the root dir of the app.
+	 */
+	public static final String FILTER_MAPPING_PARAM = "filterMappingUrlPattern";
+
+	/**
+	 * The name of the context parameter that specifies application factory class
+	 */
+	public static final String APP_FACT_PARAM = "applicationFactoryClassName";
+
+	
+	/**
+	 * Checks if the request is for home page and lacks trailing slash. If necessary redirects to
+	 * URL with trailing slash.
+	 * 
+	 * @param request
+	 * @param response
+	 * @param filterPath
+	 * @return <code>true</code> if there is a trailing slash, <code>false</code> if redirect was
+	 *         necessary.
+	 */
+	private boolean checkForTrailingSlash(HttpServletRequest request, HttpServletResponse response,
+		String filterPath)
+	{	
+		// current URI
+		String uri = Strings.stripJSessionId(request.getRequestURI());
+		
+		// home page without trailing slash URI
+		String homePageUri = request.getContextPath() + "/" + filterPath;		
+		if (homePageUri.endsWith("/"))
+		{
+			homePageUri = homePageUri.substring(0, homePageUri.length() - 1);
+		}
+		
+		if (uri.equals(homePageUri))
+		{
+			// construct redirect URL
+			String redirect = uri + "/";
+			if (!Strings.isEmpty(request.getQueryString()))
+			{
+				redirect += "?" + request.getQueryString();
+			}
+			try
+			{
+				// send redirect - this will discard POST parameters if the request is POST
+				// - still better than getting an error because of lacking trailing slash
+				response.sendRedirect(response.encodeRedirectURL(redirect));
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			return false;
+		}
+
+		return true;
+	}
+
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+		throws IOException, ServletException
+	{
+		try
+		{
+			HttpServletRequest httpServletRequest = (HttpServletRequest)request;
+			HttpServletResponse httpServletResponse = (HttpServletResponse)response;
+	
+			String filterPath = getFilterPath(httpServletRequest);
+	
+			webApplication.set();
+			
+			if (checkForTrailingSlash(httpServletRequest, httpServletResponse, filterPath))
+			{
+				ServletWebRequest req = new ServletWebRequest(httpServletRequest, filterPath);
+				ServletWebResponse resp = new ServletWebResponse(httpServletResponse);
+	
+				RequestCycle requestCycle = webApplication.newRequestCycle(req, resp);				
+	
+				if (requestCycle.processRequest())
+				{
+					requestCycle.detach();
+				}
+				else
+				{
+					chain.doFilter(request, response);
+				}
+			}
+		}
+		finally
+		{
+			ThreadContext.detach();
+		}
+	}
+
+	private WebApplication webApplication;
+	
+	/**
+	 * Creates the web application factory instance.
+	 * 
+	 * If no APP_FACT_PARAM is specified in web.xml ContextParamWebApplicationFactory will be used
+	 * by default.
+	 * 
+	 * @see ContextParamWebApplicationFactory
+	 * 
+	 * @return application factory instance
+	 */
+	protected IWebApplicationFactory getApplicationFactory()
+	{
+		final String appFactoryClassName = filterConfig.getInitParameter(APP_FACT_PARAM);
+
+		if (appFactoryClassName == null)
+		{
+			// If no context param was specified we return the default factory
+			return new ContextParamWebApplicationFactory();
+		}
+		else
+		{
+			try
+			{
+				// Try to find the specified factory class
+				final Class<?> factoryClass = Thread.currentThread()
+					.getContextClassLoader()
+					.loadClass(appFactoryClassName);
+
+				// Instantiate the factory
+				return (IWebApplicationFactory)factoryClass.newInstance();
+			}
+			catch (ClassCastException e)
+			{
+				throw new WicketRuntimeException("Application factory class " +
+					appFactoryClassName + " must implement IWebApplicationFactory");
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new WebApplicationFactoryCreationException(appFactoryClassName, e);
+			}
+			catch (InstantiationException e)
+			{
+				throw new WebApplicationFactoryCreationException(appFactoryClassName, e);
+			}
+			catch (IllegalAccessException e)
+			{
+				throw new WebApplicationFactoryCreationException(appFactoryClassName, e);
+			}
+			catch (SecurityException e)
+			{
+				throw new WebApplicationFactoryCreationException(appFactoryClassName, e);
+			}
+		}
+	}
+
+	public void init(FilterConfig filterConfig) throws ServletException
+	{
+		this.filterConfig = filterConfig;	
+		IWebApplicationFactory factory = getApplicationFactory();
+		webApplication = factory.createApplication(this);
+		webApplication.setName(filterConfig.getFilterName());
+		
+		initFilterPath();
+		
+		webApplication.set();
+		try
+		{
+			webApplication.internalInit();
+			webApplication.init();
+		} 
+		finally
+		{
+			ThreadContext.detach();
+		}				
+	}
+	
+	public FilterConfig getFilterConfig()
+	{
+		return filterConfig;
+	}
+
+	private void initFilterPath()
+	{
+		InputStream is = filterConfig.getServletContext().getResourceAsStream("/WEB-INF/web.xml");
+		if (is != null)
+		{
+			try
+			{
+				filterPath = getFilterPath(filterConfig.getFilterName(), is);
+			}
+			catch (ServletException e)
+			{
+				log.error("Error reading servlet/filter path from web.xml", e);
+			}
+			catch (SecurityException e)
+			{
+				// Swallow this at INFO.
+				log.info("Couldn't read web.xml to automatically pick up servlet/filter path: " +
+					e.getMessage());
+			}
+			if (filterPath == null)
+			{
+				log.info("Unable to parse filter mapping web.xml for " +
+					filterConfig.getFilterName() + ". " + "Configure with init-param " +
+					FILTER_MAPPING_PARAM + " if it is not \"/*\".");
+			}
+		}
+	};
+
+	private FilterConfig filterConfig;
+	private String filterPath;
+
+	private boolean servletMode = false;
+
+//	private String getFilterPath(String filterName, InputStream is) throws ServletException
+//	{
+//		String prefix = servletMode ? "servlet" : "filter";
+//		String mapping = prefix + "-mapping";
+//		String name = prefix + "-name";
+//
+//		// Filter mappings look like this:
+//		//
+//		// <filter-mapping> <filter-name>WicketFilter</filter-name>
+//		// <url-pattern>/*</url-pattern> <...> <filter-mapping>
+//		try
+//		{
+//			ArrayList<String> urlPatterns = new ArrayList<String>();
+//			XmlPullParser parser = new XmlPullParser();
+//			parser.parse(is);
+//
+//			while (true)
+//			{
+//				XmlTag elem;
+//				do
+//				{
+//					elem = (XmlTag)parser.nextTag();
+//				}
+//				while (elem != null && (!(elem.getName().equals(mapping) && elem.isOpen())));
+//
+//				if (elem == null)
+//				{
+//					break;
+//				}
+//
+//				String encounteredFilterName = null, urlPattern = null;
+//
+//				do
+//				{
+//					elem = (XmlTag)parser.nextTag();
+//					if (elem.isOpen())
+//					{
+//						parser.setPositionMarker();
+//					}
+//					else if (elem.isClose() && elem.getName().equals(name))
+//					{
+//						encounteredFilterName = parser.getInputFromPositionMarker(elem.getPos())
+//							.toString()
+//							.trim();
+//					}
+//					else if (elem.isClose() && elem.getName().equals("url-pattern"))
+//					{
+//						urlPattern = parser.getInputFromPositionMarker(elem.getPos())
+//							.toString()
+//							.trim();
+//					}
+//				}
+//				while (urlPattern == null || encounteredFilterName == null);
+//
+//				if (filterName.equals(encounteredFilterName))
+//				{
+//					urlPatterns.add(urlPattern);
+//				}
+//			}
+//
+//			String prefixUppered = Character.toUpperCase(prefix.charAt(0)) + prefix.substring(1);
+//
+//			// By the time we get here, we have a list of urlPatterns we match
+//			// this filter against.
+//			// In all likelihood, we will only have one. If we have none, we
+//			// have an error.
+//			// If we have more than one, we pick the first one to use for any
+//			// 302 redirects that require absolute URLs.
+//			if (urlPatterns.size() == 0)
+//			{
+//				throw new IllegalArgumentException("Error initializing Wicket" + prefixUppered +
+//					" - you have no <" + mapping + "> element with a url-pattern that uses " +
+//					prefix + ": " + filterName);
+//			}
+//			String urlPattern = urlPatterns.get(0);
+//
+//			// Check for leading '/' and trailing '*'.
+//			if (!urlPattern.startsWith("/") || !urlPattern.endsWith("*"))
+//			{
+//				throw new IllegalArgumentException("<" + mapping + "> for Wicket" + prefixUppered +
+//					" \"" + filterName + "\" must start with '/' and end with '*'.");
+//			}
+//
+//			// Strip trailing '*' and keep leading '/'.
+//			return stripWildcard(urlPattern);
+//		}
+//		catch (IOException e)
+//		{
+//			throw new ServletException("Error finding <" + prefix + "> " + filterName +
+//				" in web.xml", e);
+//		}
+//		catch (ParseException e)
+//		{
+//			throw new ServletException("Error finding <" + prefix + "> " + filterName +
+//				" in web.xml", e);
+//		}
+//		catch (ResourceStreamNotFoundException e)
+//		{
+//			throw new ServletException("Error finding <" + prefix + "> " + filterName +
+//				" in web.xml", e);
+//		}
+//	}
+	
+		private String getFilterPath(String filterName, String name, Node node)
+	{
+		String foundUrlPattern = null;
+		String foundFilterName = null;
+		
+		for (int i = 0; i < node.getChildNodes().getLength(); ++i)
+		{
+			Node n = node.getChildNodes().item(i);
+			if (name.equals(n.getNodeName()))
+			{
+				foundFilterName = n.getTextContent();
+			}
+			else if ("url-pattern".equals(n.getNodeName()))
+			{
+				foundUrlPattern = n.getTextContent();
+			}
+		}
+		if (filterName.equals(foundFilterName))
+		{
+			return foundUrlPattern;
+		}
+		else
+		{
+			return null;
+		}
+	}
+	
+	private String getFilterPath(String filterName, String mapping, String name, NodeList nodeList)
+	{
+		for (int i = 0; i < nodeList.getLength(); ++i)
+		{
+			Node node = nodeList.item(i);
+			if (mapping.equals(node.getNodeName()))
+			{
+				String path = getFilterPath(filterName, name, node);
+				if (path != null)
+				{
+					return path;
+				}
+			}
+			else
+			{
+				String path = getFilterPath(filterName, mapping, name, node.getChildNodes());
+				if (path != null)
+				{
+					return path;
+				}
+			}
+		}
+		return null;
+	}
+
+	private String getFilterPath(String filterName, InputStream is) throws ServletException
+	{
+		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+		try
+		{
+			DocumentBuilder builder = factory.newDocumentBuilder();
+			Document document = builder.parse(is);
+			
+			String prefix = servletMode ? "servlet" : "filter";
+			String mapping = prefix + "-mapping";
+			String name = prefix + "-name";
+
+			String urlPattern = getFilterPath(filterName, mapping, name, document.getChildNodes());
+			return stripWildcard(urlPattern);
+		} 
+		catch (Exception e) 
+		{
+			throw new ServletException(e);
+		}
+	}
+	
+	protected String getFilterPath(HttpServletRequest request)
+	{
+		if (filterPath != null)
+		{
+			return filterPath;
+		}
+		if (servletMode)
+		{
+			return filterPath = request.getServletPath();
+		}
+		String result;
+		// Legacy migration check.
+		// TODO: Remove this after 1.3 is released and everyone's upgraded.
+
+		result = filterConfig.getInitParameter(FILTER_MAPPING_PARAM);
+		if (result == null || result.equals("/*"))
+		{
+			return "";
+		}
+		else if (!result.startsWith("/") || !result.endsWith("/*"))
+		{
+			throw new WicketRuntimeException("Your " + FILTER_MAPPING_PARAM +
+				" must start with \"/\" and end with \"/*\". It is: " + result);
+		}
+		return filterPath = stripWildcard(result);
+	}
+
+	/**
+	 * Strip trailing '*' and keep leading '/'
+	 * 
+	 * @param result
+	 * @return The stripped String
+	 */	
+	private String stripWildcard(String result)
+	{
+		return result.substring(1, result.length() - 1);
+	}
+
+	public void destroy()
+	{
+		if (webApplication != null)
+		{
+			webApplication.destroy();
+			webApplication = null;
+		}
+	}
+
+	
+	private static final Logger log = LoggerFactory.getLogger(WicketFilter.class);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLDecoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLDecoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLDecoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLDecoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,179 @@
+/*
+ * 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.protocol.http;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.WicketRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Adapted from java.net.URLDecoder, but defines instances for query string decoding versus URL path
+ * component decoding.
+ * <p/>
+ * The difference is important because a space is encoded as a + in a query string, but this is a
+ * valid value in a path component (and is therefore not decode back to a space).
+ * 
+ * @author Doug Donohoe
+ * @see java.net.URLDecoder
+ * @see {@link "http://www.ietf.org/rfc/rfc2396.txt"}
+ */
+public class WicketURLDecoder
+{
+	private static final Logger log = LoggerFactory.getLogger(Application.class);
+
+	private final boolean decodePlus;
+
+	/**
+	 * Encoder used to decode name or value components of a query string.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/notthis/northis/oreventhis?buthis=isokay&asis=thispart
+	 */
+	public static final WicketURLDecoder QUERY_INSTANCE = new WicketURLDecoder(true);
+
+	/**
+	 * Encoder used to decode components of a path.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
+	 */
+	public static final WicketURLDecoder PATH_INSTANCE = new WicketURLDecoder(false);
+
+	/**
+	 * Create decoder
+	 * 
+	 * @param decodePlus
+	 *            - whether to decode + to space
+	 */
+	private WicketURLDecoder(boolean decodePlus)
+	{
+		this.decodePlus = decodePlus;
+	}
+
+	/**
+	 * Calls decode with the application response request encoding as returned by
+	 * Application.get().getRequestCycleSettings().getResponseRequestEncoding()
+	 * 
+	 * @param s
+	 *            Value to encode
+	 * @return String encoded using default Application request/respose encoding
+	 */
+	public String decode(String s)
+	{
+		Application app = null;
+
+		try
+		{
+			app = Application.get();
+		}
+		catch (WicketRuntimeException ignored)
+		{
+			log.warn("No current Application found - defaulting encoding to UTF-8");
+		}
+		return decode(s, app == null ? "UTF-8" : app.getRequestCycleSettings().getResponseRequestEncoding());
+	}
+
+	/**
+	 * @param s
+	 *            string to decode
+	 * @param enc
+	 *            encoding to decode with
+	 * @return decoded string
+	 * @see java.net.URLDecoder#decode(String, String)
+	 */
+	public String decode(String s, String enc)
+	{
+		boolean needToChange = false;
+		int numChars = s.length();
+		StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);
+		int i = 0;
+
+		if (enc.length() == 0)
+		{
+			throw new WicketRuntimeException(new UnsupportedEncodingException("URLDecoder: empty string enc parameter"));
+		}
+
+		char c;
+		byte[] bytes = null;
+		while (i < numChars)
+		{
+			c = s.charAt(i);
+			switch (c)
+			{
+			case '+':
+				sb.append(decodePlus ? ' ' : '+');
+				i++;
+				needToChange = true;
+				break;
+
+			case '%':
+				/*
+				 * Starting with this instance of %, process all consecutive substrings of the form
+				 * %xy. Each substring %xy will yield a byte. Convert all consecutive bytes obtained
+				 * this way to whatever character(s) they represent in the provided encoding.
+				 */
+				try
+				{
+					// (numChars-i)/3 is an upper bound for the number
+					// of remaining bytes
+					if (bytes == null)
+						bytes = new byte[(numChars - i) / 3];
+					int pos = 0;
+
+					while (((i + 2) < numChars) && (c == '%'))
+					{
+						bytes[pos++] = (byte) Integer.parseInt(s.substring(i + 1, i + 3), 16);
+						i += 3;
+						if (i < numChars)
+							c = s.charAt(i);
+					}
+
+					// A trailing, incomplete byte encoding such as
+					// "%x" will cause an exception to be thrown
+					if ((i < numChars) && (c == '%'))
+						throw new IllegalArgumentException("URLDecoder: Incomplete trailing escape (%) pattern");
+
+					try
+					{
+						sb.append(new String(bytes, 0, pos, enc));
+					}
+					catch (UnsupportedEncodingException e)
+					{
+						throw new WicketRuntimeException(e);
+					}
+				}
+				catch (NumberFormatException e)
+				{
+					throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - "
+							+ e.getMessage());
+				}
+				needToChange = true;
+				break;
+
+			default:
+				sb.append(c);
+				i++;
+				break;
+			}
+		}
+
+		return (needToChange ? sb.toString() : s);
+	}
+}
\ No newline at end of file

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLDecoder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,343 @@
+/*
+ * 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.protocol.http;
+
+import java.io.CharArrayWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.BitSet;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.WicketRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Adapted from java.net.URLEncoder, but defines instances for query string encoding versus URL path
+ * component encoding.
+ * <p/>
+ * The difference is important because a space is encoded as a + in a query string, but this is a
+ * valid value in a path component (and is therefore not decode back to a space).
+ * 
+ * @author Doug Donohoe
+ * @see java.net.URLEncoder
+ * @see {@link "http://www.ietf.org/rfc/rfc2396.txt"}
+ */
+public class WicketURLEncoder
+{
+	private static final Logger log = LoggerFactory.getLogger(Application.class);
+
+	/**
+	 * encoder types
+	 */
+	public enum Type
+	{
+		/**
+		 * query type
+		 */
+		QUERY, /**
+		 * path type
+		 */
+		PATH;
+	}
+
+	// list of what not to decode
+	protected BitSet dontNeedEncoding;
+
+	// used in decoding
+	protected static final int caseDiff = ('a' - 'A');
+
+	/**
+	 * Encoder used to encode name or value components of a query string.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/notthis/northis/oreventhis?buthis=isokay&asis=thispart
+	 */
+	public static final WicketURLEncoder QUERY_INSTANCE = new WicketURLEncoder(Type.QUERY);
+
+	/**
+	 * Encoder used to encode components of a path.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
+	 */
+	public static final WicketURLEncoder PATH_INSTANCE = new WicketURLEncoder(Type.PATH);
+
+	/**
+	 * Allow subclass to call constructor.
+	 * 
+	 * @param type
+	 *            encoder type
+	 */
+	protected WicketURLEncoder(Type type)
+	{
+		/*
+		 * This note from java.net.URLEncoder ==================================
+		 * 
+		 * The list of characters that are not encoded has been determined as follows:
+		 * 
+		 * RFC 2396 states: ----- Data characters that are allowed in a URI but do not have a
+		 * reserved purpose are called unreserved. These include upper and lower case letters,
+		 * decimal digits, and a limited set of punctuation marks and symbols.
+		 * 
+		 * unreserved = alphanum | mark
+		 * 
+		 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+		 * 
+		 * Unreserved characters can be escaped without changing the semantics of the URI, but this
+		 * should not be done unless the URI is being used in a context that does not allow the
+		 * unescaped character to appear. -----
+		 * 
+		 * It appears that both Netscape and Internet Explorer escape all special characters from
+		 * this list with the exception of "-", "_", ".", "*". While it is not clear why they are
+		 * escaping the other characters, perhaps it is safest to assume that there might be
+		 * contexts in which the others are unsafe if not escaped. Therefore, we will use the same
+		 * list. It is also noteworthy that this is consistent with O'Reilly's "HTML: The Definitive
+		 * Guide" (page 164).
+		 * 
+		 * As a last note, Intenet Explorer does not encode the "@" character which is clearly not
+		 * unreserved according to the RFC. We are being consistent with the RFC in this matter, as
+		 * is Netscape.
+		 * 
+		 * This bit added by Doug Donohoe ================================== RFC 3986 (2005) updates
+		 * this (http://tools.ietf.org/html/rfc3986):
+		 * 
+		 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+		 * 
+		 * pct-encoded = "%" HEXDIG HEXDIG
+		 * 
+		 * reserved = gen-delims / sub-delims
+		 * 
+		 * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+		 * 
+		 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" // -- PATH
+		 * COMPONENT -- //
+		 * 
+		 * path = (see RFC for all variations) path-abempty =( "/" segment ) segment =pchar pchar =
+		 * unreserved / pct-encoded / sub-delims / ":" / "@" // -- QUERY COMPONENT -- //
+		 * 
+		 * query =( pchar / "/" / "?" )
+		 */
+
+		// unreserved
+		dontNeedEncoding = new BitSet(256);
+		int i;
+		for (i = 'a'; i <= 'z'; i++)
+		{
+			dontNeedEncoding.set(i);
+		}
+		for (i = 'A'; i <= 'Z'; i++)
+		{
+			dontNeedEncoding.set(i);
+		}
+		for (i = '0'; i <= '9'; i++)
+		{
+			dontNeedEncoding.set(i);
+		}
+		dontNeedEncoding.set('-');
+		dontNeedEncoding.set('.');
+		dontNeedEncoding.set('_');
+		dontNeedEncoding.set('~'); // tilde encoded by java.net.URLEncoder version, but RFC is
+		// clear on this
+
+		// sub-delims
+		dontNeedEncoding.set('!');
+		dontNeedEncoding.set('$');
+		// "&" needs to be encoded for query stings
+		dontNeedEncoding.set('\'');
+		// "(" and ")" probably don't need encoding, but we'll be conservative
+		dontNeedEncoding.set('*');
+		// "+" needs to be encoded for query strings (since it means =
+		dontNeedEncoding.set(',');
+		// ";" encoded due to use in path and/or query as delim in some instances (e.g., jsessionid)
+		// "=" needs to be encoded for query strings
+
+		// pchar
+		dontNeedEncoding.set(':'); // allowed and used in wicket interface params
+		dontNeedEncoding.set('@');
+
+		// encoding type-specific
+		switch (type)
+		{
+		// this code consistent with java.net.URLEncoder version
+		case QUERY:
+			dontNeedEncoding.set(' '); /*
+										 * encoding a space to a + is done in the encode() method
+										 */
+			dontNeedEncoding.set('/'); // to allow direct passing of URL in query
+			dontNeedEncoding.set('?'); // to allow direct passing of URL in query
+			break;
+
+		// this added to deal with encoding a PATH component
+		case PATH:
+			// encode ' ' with a % instead of + in path portion
+
+			// path component sub-delim values we do not need to escape
+			dontNeedEncoding.set('&');
+			dontNeedEncoding.set('=');
+			dontNeedEncoding.set('+');
+			break;
+		}
+	}
+
+	/**
+	 * Calls encode with the application response request encoding as returned by
+	 * Application.get().getRequestCycleSettings().getResponseRequestEncoding()
+	 * 
+	 * @param s
+	 *            Value to encode
+	 * @return String encoded using default Application request/respose encoding
+	 */
+	public String encode(String s)
+	{
+		Application app = null;
+
+		try
+		{
+			app = Application.get();
+		}
+		catch (WicketRuntimeException ignored)
+		{
+			log.warn("No current Application found - defaulting encoding to UTF-8");
+		}
+
+		return encode(s, app == null ? "UTF-8" : app.getRequestCycleSettings().getResponseRequestEncoding());
+	}
+
+	/**
+	 * @param s
+	 *            string to encode
+	 * @param enc
+	 *            encoding to use
+	 * @return encoded string
+	 * @see java.net.URLEncoder#encode(String, String)
+	 */
+	public String encode(String s, String enc)
+	{
+		boolean needToChange = false;
+		StringBuffer out = new StringBuffer(s.length());
+		Charset charset;
+		CharArrayWriter charArrayWriter = new CharArrayWriter();
+
+		if (enc == null)
+			throw new NullPointerException("charsetName");
+
+		try
+		{
+			charset = Charset.forName(enc);
+		}
+		catch (IllegalCharsetNameException e)
+		{
+			throw new WicketRuntimeException(new UnsupportedEncodingException(enc));
+		}
+		catch (UnsupportedCharsetException e)
+		{
+			throw new WicketRuntimeException(new UnsupportedEncodingException(enc));
+		}
+
+		for (int i = 0; i < s.length();)
+		{
+			int c = s.charAt(i);
+			// System.out.println("Examining character: " + c);
+			if (dontNeedEncoding.get(c))
+			{
+				if (c == ' ')
+				{
+					c = '+';
+					needToChange = true;
+				}
+				// System.out.println("Storing: " + c);
+				out.append((char) c);
+				i++;
+			}
+			else
+			{
+				// convert to external encoding before hex conversion
+				do
+				{
+					charArrayWriter.write(c);
+					/*
+					 * If this character represents the start of a Unicode surrogate pair, then pass
+					 * in two characters. It's not clear what should be done if a bytes reserved in
+					 * the surrogate pairs range occurs outside of a legal surrogate pair. For now,
+					 * just treat it as if it were any other character.
+					 */
+					if (c >= 0xD800 && c <= 0xDBFF)
+					{
+						/*
+						 * System.out.println(Integer.toHexString(c) + " is high surrogate");
+						 */
+						if ((i + 1) < s.length())
+						{
+							int d = s.charAt(i + 1);
+							/*
+							 * System.out.println("\tExamining " + Integer.toHexString(d));
+							 */
+							if (d >= 0xDC00 && d <= 0xDFFF)
+							{
+								/*
+								 * System.out.println("\t" + Integer.toHexString(d) + " is low
+								 * surrogate");
+								 */
+								charArrayWriter.write(d);
+								i++;
+							}
+						}
+					}
+					i++;
+				}
+				while (i < s.length() && !dontNeedEncoding.get((c = s.charAt(i))));
+
+				charArrayWriter.flush();
+				String str = new String(charArrayWriter.toCharArray());
+				byte[] ba = new byte[0];
+				try
+				{
+					ba = str.getBytes(charset.name());
+				}
+				catch (UnsupportedEncodingException e)
+				{
+					throw new WicketRuntimeException(e);
+				}
+				for (int j = 0; j < ba.length; j++)
+				{
+					out.append('%');
+					char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
+					// converting to use uppercase letter as part of
+					// the hex value if ch is a letter.
+					if (Character.isLetter(ch))
+					{
+						ch -= caseDiff;
+					}
+					out.append(ch);
+					ch = Character.forDigit(ba[j] & 0xF, 16);
+					if (Character.isLetter(ch))
+					{
+						ch -= caseDiff;
+					}
+					out.append(ch);
+				}
+				charArrayWriter.reset();
+				needToChange = true;
+			}
+		}
+
+		return (needToChange ? out.toString() : s);
+	}
+}
\ No newline at end of file

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/protocol/http/WicketURLEncoder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandler.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandler.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandler.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,48 @@
+/*
+ * 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.request;
+
+import org.apache.wicket.RequestCycle;
+
+/**
+ * A request handler is the base entity that is the subject of a request. Different types of request
+ * have different request targets. For instance a request for a bookmarkable page differs from a
+ * request for a link on a previously rendered page, which in turn differs from a request for a
+ * shared resource.
+ * 
+ * @author Eelco Hillenius
+ * @author Matej Knopp
+ */
+public interface RequestHandler
+{
+	/**
+	 * Generates a response.
+	 * 
+	 * @param requestCycle
+	 *            the current request cycle
+	 */
+	void respond(RequestCycle requestCycle);
+
+	/**
+	 * This method is called at the end of a request cycle to indicate that processing is done and
+	 * that cleaning up of the subject(s) of this target may be done.
+	 * 
+	 * @param requestCycle
+	 *            the current request cycle
+	 */
+	void detach(RequestCycle requestCycle);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoder.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoder.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,66 @@
+/*
+ * 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.request;
+
+import org.apache.wicket.request.request.Request;
+
+/**
+ * Encodes {@link RequestHandler}(s) into {@link Url}(s) and decodes {@link Url}(s) to
+ * {@link RequestHandler}(s). For {@link RequestHandler}s and {@link Url}s the implementation
+ * doesn't know the {@link #encode(RequestHandler)} and {@link #decode(Url, RequestParameters)}
+ * methods must return <code>null</code>.
+ * 
+ * @author Matej Knopp
+ */
+public interface RequestHandlerEncoder
+{
+	/**
+	 * Returns {@link RequestHandler} for the request or <code>null</code> if the encoder does not
+	 * recognize the URL.
+	 * 
+	 * @param request
+	 *            provides access to request data (i.e. Url and Parameters)
+	 *            
+	 * @return RequestHandler instance or <code>null</code>
+	 */
+	RequestHandler decode(Request request);
+	
+	/**
+	 * Returns the amount of matching segments for the request. When two {@link RequestHandlerEncoder}s 
+	 * are capable of decoding a request, the one with highest matching segments count will be used.
+	 * <p>
+	 * For example when there are two encoders for mounted page, one mapped to <code>/foo</code> another
+	 * to <code>/foo/bar</code> and the incomming reqest URL is </code>/foo/bar/baz</code>, the encoder
+	 * mapped to <code>/foo/bar</code> will handle the request as it has matching segments count of 2
+	 * while the first one has only matching segments count of 1.
+	 * <p>
+	 * Note that the method can return value &gt; 0 even if the encoder can not decode the request. 
+	 * 
+	 * @param request
+	 * @return count of matching segments
+	 */
+	public int getMachingSegmentsCount(Request request);
+
+	/**
+	 * Returns the {@link Url} for given {@link RequestHandler} or <code>null</code> if the
+	 * encoder does not recognize the request handler.
+	 * 
+	 * @param requestHandler
+	 * @return Url instance or <code>null</code>.
+	 */
+	Url encode(RequestHandler requestHandler);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoderRegistry.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoderRegistry.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoderRegistry.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoderRegistry.java Sat Mar 28 17:53:05 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.request;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.wicket.request.request.Request;
+
+/**
+ * Thread safe registry of {@link RequestHandlerEncoder}s. The encoders are searched depending on
+ * the orders they were registered. If the {@link RequestHandlerEncoder}s can handle
+ * {@link Request} and they have same matching segments count, the last registered encoder has
+ * higher priority.
+ * 
+ * @author Matej Knopp
+ */
+public class RequestHandlerEncoderRegistry
+{
+	/**
+	 * Registers a {@link RequestHandlerEncoder}
+	 * 
+	 * @param encoder
+	 */
+	public void register(RequestHandlerEncoder encoder)
+	{
+		encoders.add(0, encoder);
+	}
+
+	/**
+	 * Unregisters {@link RequestHandlerEncoder}
+	 * 
+	 * @param encoder
+	 */
+	public void unregister(RequestHandlerEncoder encoder)
+	{
+		encoders.remove(encoder);
+	}
+
+	/**
+	 * Searches the registered {@link RequestHandlerEncoder}s to find one that can decode the
+	 * {@link Request}. Each registered {@link RequestHandlerEncoder} is asked to decode the
+	 * {@link Request}. The encoder with highest matching segments count that can decode the
+	 * request is returned.
+	 * 
+	 * @param request
+	 * @return RequestHandler for the request or <code>null</code> if no encoder for the request
+	 *         is found.
+	 */
+	public RequestHandler decode(Request request)
+	{
+		// last found RequestHandler with highest matching segments count
+		RequestHandler last = null;
+		int maxMatchingSegmentsCount = -1;
+
+		for (RequestHandlerEncoder encoder : encoders)
+		{
+			// no handler has been found yet
+			if (last == null)
+			{
+				// try to get the handler immediately, at this point we don't care for matching
+				// segments count
+				last = encoder.decode(request);
+				if (last != null)
+				{
+					// found one - get the matching segments count so that it can be compared
+					// to other encoders found later
+					maxMatchingSegmentsCount = encoder.getMachingSegmentsCount(request);
+				}
+			}
+			else
+			{
+				// we already have a handler, try to find out if this one has bigger matching
+				// segments count
+				int count = encoder.getMachingSegmentsCount(request);
+				if (count > maxMatchingSegmentsCount)
+				{
+					// seems so
+					RequestHandler handler = encoder.decode(request);
+					if (handler != null)
+					{
+						// replace the last one
+						last = handler;
+						maxMatchingSegmentsCount = count;
+					}
+				}
+			}
+		}
+		return last;
+	}
+
+	/**
+	 * Searches the registered {@link RequestHandlerEncoder}s to find one that can encode the
+	 * {@link RequestHandler}. Each registered {@link RequestHandlerEncoder} is asked to encode the
+	 * {@link RequestHandler} until an encoder that can encode the {@link RequestHandler} is found
+	 * or no more encoders are left.
+	 * <p>
+	 * The handlers are searched in reverse order as they have been registered. More recently
+	 * registered handlers have bigger priority.
+	 * 
+	 * @param handler
+	 * @return Url for the handler or <code>null</code> if no encoder for the handler is found.
+	 */
+	public Url encode(RequestHandler handler)
+	{
+		for (RequestHandlerEncoder encoder : encoders)
+		{
+			Url url = encoder.encode(handler);
+			if (url != null)
+			{
+				return url;
+			}
+		}
+		return null;
+	}
+
+	private List<RequestHandlerEncoder> encoders = new CopyOnWriteArrayList<RequestHandlerEncoder>();
+
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerEncoderRegistry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerStack.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerStack.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerStack.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerStack.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,219 @@
+/*
+ * 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.request;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.request.response.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages stack of {@link RequestHandler}s.
+ * 
+ * @author Matej Knopp
+ */
+public abstract class RequestHandlerStack
+{
+	private Response response;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param response
+	 */
+	public RequestHandlerStack(Response response)
+	{
+		this.response = response;
+	}
+
+	// we need both Queue and List interfaces
+	private final LinkedList<RequestHandler> requestHandlers = new LinkedList<RequestHandler>();
+
+	private final List<RequestHandler> inactiveRequestHandlers = new ArrayList<RequestHandler>();
+
+	/**
+	 * Returns currently active {@link RequestHandler}.
+	 * 
+	 * @return Active RequestHandler or <code>null</code> if no handler is active.
+	 */
+	public RequestHandler getActiveRequestHandler()
+	{
+		return requestHandlers.peek();
+	}
+
+	/**
+	 * Executes the specified {@link RequestHandler}. When the specified {@link RequestHandler} 
+	 * finishes, the {@link RequestHandler} that invoked this method continues (unless the new
+	 * {@link RequestHandler} called {@link #replaceAllRequestHandlers(RequestHandler)}.
+	 * 
+	 * @param handler
+	 */
+	public void executeRequestHandler(RequestHandler handler)
+	{
+		final boolean first = requestHandlers.isEmpty();		
+		requestHandlers.add(handler);
+
+		RequestHandler replacementHandler = null;
+		Response originalResponse = response;
+		try
+		{
+			handler.respond(getRequestCycle());
+		}
+		catch (ReplaceHandlerException exception)
+		{
+			if (exception.removeAll && !first)
+			{
+				throw exception;
+			}
+			replacementHandler = exception.replacementRequestHandler;
+		}
+		finally
+		{
+			response = originalResponse;
+			requestHandlers.poll();
+			inactiveRequestHandlers.add(handler);
+		}
+
+		if (replacementHandler != null)
+		{
+			executeRequestHandler(replacementHandler);
+		}
+	}
+
+	/**
+	 * Replaces the currently executed {@link RequestHandler} with new {@link RequestHandler}. The
+	 * currently executed {@link RequestHandler} is terminated and the new {@link RequestHandler} is
+	 * executed.
+	 * 
+	 * @param handler
+	 */
+	public void replaceCurrentRequestHandler(RequestHandler handler)
+	{
+		if (requestHandlers.isEmpty())
+		{
+			executeRequestHandler(handler);
+		}
+		else
+		{
+			throw new ReplaceHandlerException(handler, false);
+		}
+	}
+
+	/**
+	 * Removes the whole {@link RequestHandler} stack, terminates currently running
+	 * {@link RequestHandler} and executes the new {@link RequestHandler}.
+	 * 
+	 * @param handler
+	 */
+	public void replaceAllRequestHandlers(RequestHandler handler)
+	{
+		if (requestHandlers.isEmpty())
+		{
+			executeRequestHandler(handler);
+		}
+		else
+		{
+			throw new ReplaceHandlerException(handler, true);
+		}
+	}
+
+	/**
+	 * Exception to stop current request handler and execute a new one.
+	 * 
+	 * @author Matej Knopp
+	 */
+	private static class ReplaceHandlerException extends RuntimeException
+	{
+		private static final long serialVersionUID = 1L;
+
+		private final boolean removeAll;
+		private final RequestHandler replacementRequestHandler;
+
+		public ReplaceHandlerException(RequestHandler replacementRequestHandler, boolean removeAll)
+		{
+			this.replacementRequestHandler = replacementRequestHandler;
+			this.removeAll = removeAll;
+		}
+
+		@Override
+		public synchronized Throwable fillInStackTrace()
+		{
+			// don't do anything here
+			return null;
+		}
+	};
+
+
+	/**
+	 * Returns the active {@link Response}.
+	 * 
+	 * @return response object.
+	 */
+	public Response getResponse()
+	{
+		return response;
+	}
+
+	/**
+	 * Replaces current {@link Response} with new {@link Response} instance. The original response
+	 * is always restored after the {@link RequestHandler#respond(RequestCycle)} method is finished.
+	 * 
+	 * @param response
+	 * @return Response being replaced.
+	 */
+	public Response setResponse(Response response)
+	{
+		Response current = this.response;
+		this.response = response;
+		return current;
+	}
+
+	protected abstract RequestCycle getRequestCycle();
+
+	/**
+	 * Detaches all {@link RequestHandler}s.
+	 */
+	public void detach()
+	{		
+		if (!requestHandlers.isEmpty())
+		{
+			// All requests handlers should be inactive at this point
+			log.warn("Some of the request handlers are still active.");
+
+			inactiveRequestHandlers.addAll(requestHandlers);
+			requestHandlers.clear();
+		}
+
+		for (RequestHandler handler : inactiveRequestHandlers)
+		{
+			try
+			{
+				handler.detach(getRequestCycle());
+			}
+			catch (Throwable exception)
+			{
+				log.error("Error detaching RequestHandler", exception);
+			}
+		}
+	}
+
+	private static final Logger log = LoggerFactory.getLogger(RequestHandlerStack.class);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestHandlerStack.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestParameters.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestParameters.java?rev=759525&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestParameters.java (added)
+++ wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestParameters.java Sat Mar 28 17:53:05 2009
@@ -0,0 +1,60 @@
+/*
+ * 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.request;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.wicket.util.string.StringValue;
+
+/**
+ * Represents request parameters.
+ * 
+ * @author Matej Knopp
+ */
+public interface RequestParameters
+{
+	/**
+	 * Returns immutable set of all available parameter names.
+	 * 
+	 * @return list of parameter names
+	 */
+	public Set<String> getParameterNames();
+
+	/**
+	 * Returns single value for parameter with specified name. This method always returns non-null
+	 * result even if the parameter does not exist.
+	 * 
+	 * @see StringValue#isNull()
+	 * 
+	 * @param name
+	 *            parameter name
+	 * @return {@link StringValue} wrapping the actual value
+	 */
+	public StringValue getParameterValue(String name);
+
+	/**
+	 * Returns list of values for parameter with specified name. If the parameter does not exist
+	 * this method returns <code>null</code>
+	 * 
+	 * @param name
+	 *            parameter name
+	 * @return list of all values for given parameter or <code>null</code> if parameter does not
+	 *         exist
+	 */
+	public List<StringValue> getParameterValues(String name);
+}

Propchange: wicket/sandbox/knopp/experimental/wicket-ng/src/main/java/org/apache/wicket/request/RequestParameters.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain