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 2008/09/15 14:15:54 UTC

svn commit: r695446 - in /wicket/sandbox/knopp/experimental/wicket/src: main/java/org/apache/_wicket/ main/java/org/apache/_wicket/request/ main/java/org/apache/_wicket/request/encoder/ main/java/org/apache/_wicket/request/handler/impl/ test/java/org/a...

Author: knopp
Date: Mon Sep 15 05:15:52 2008
New Revision: 695446

URL: http://svn.apache.org/viewvc?rev=695446&view=rev
Log: (empty)

Added:
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractEncoder.java   (with props)
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractNotMountedEncoder.java   (with props)
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/ComponentInfo.java   (with props)
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageComponentInfo.java   (with props)
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageInfo.java   (with props)
    wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/
    wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/ComponentInfoTest.java   (with props)
    wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/PageComponentInfoTest.java   (with props)
Modified:
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/IPage.java
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoder.java
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoderRegistry.java
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/EncoderContext.java
    wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/handler/impl/BookmarkablePageRequestHandler.java

Modified: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/IPage.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/IPage.java?rev=695446&r1=695445&r2=695446&view=diff
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/IPage.java (original)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/IPage.java Mon Sep 15 05:15:52 2008
@@ -28,25 +28,25 @@
 	/**
 	 * @return A stable identifier for this page map entry
 	 */
-	public int getPageMapId();
+	public int getNumericId();
 
 	/**
 	 * @return The current version number of this page. If the page has been changed once, the
 	 *         return value will be 1. If the page has not yet been revised, the version returned
 	 *         will be 0, indicating that the page is still in its original state.
 	 */
-	public int getPageMapVersion();
+	public int getCurrentVersionNumber();
 
 	/**
 	 * @return String The PageMap name
 	 */
 	public String getPageMapName();
-	
+
 	/**
-	 * Renders the page 
+	 * Renders the page
 	 */
 	public void renderPage();
-	
+
 	/**
 	 * Bookmarkable page can be instantiated using a bookmarkable URL.
 	 * 
@@ -55,19 +55,29 @@
 	public boolean isBookmarkable();
 
 	/**
+	 * Returns whether the page instance was created by a bookmarkable URL. Non mounted pages have
+	 * to be created using bookmarkable URL in order to have hybrid URLs later. Otherwise it would
+	 * be a potential security risk.
+	 * 
+	 * @return <code>true</code> if this page has been created by a bookmarkable URL,
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean wasCreatedBookmarkable();
+
+	/**
 	 * Gets whether the page is stateless. Components on stateless page must not render any
 	 * statefull urls, and components on statefull page must not render any stateless urls.
 	 * Statefull urls are urls, which refer to a certain (current) page instance.
 	 * 
 	 * @return Whether this page is stateless
 	 */
-	public boolean isStateless();
+	 // noe that this has different semantics than Component#isStateless()
+	public boolean isPageStateless();
 
 	/**
-	 * Returns the {@link PageParameters} for the page. Each bookmarkable page instance
-	 * should have {@link PageParameters} associated with it. The page parameters are
-	 * initialized from URL when page is created and are updated on every page render
-	 * request.
+	 * Returns the {@link PageParameters} for the page. Each bookmarkable page instance should have
+	 * {@link PageParameters} associated with it. The page parameters are initialized from URL when
+	 * page is created and are updated on every page render request.
 	 * 
 	 * @return page parameters or <code>null</code>
 	 */

Modified: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoder.java?rev=695446&r1=695445&r2=695446&view=diff
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoder.java (original)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoder.java Mon Sep 15 05:15:52 2008
@@ -38,6 +38,22 @@
 	 * @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 maching 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

Modified: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoderRegistry.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoderRegistry.java?rev=695446&r1=695445&r2=695446&view=diff
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoderRegistry.java (original)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/RequestHandlerEncoderRegistry.java Mon Sep 15 05:15:52 2008
@@ -23,7 +23,9 @@
 
 /**
  * Thread safe registry of {@link RequestHandlerEncoder}s. The encoders are searched depending on
- * the orders they were registered. Last registered encoder has the highest priority.
+ * 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
  */
@@ -52,11 +54,8 @@
 	/**
 	 * 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} until an encoder that can decode the {@link Request} 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.
+	 * {@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
@@ -64,15 +63,44 @@
 	 */
 	public RequestHandler decode(Request request)
 	{
+		// last found RequestHandler with highest matching segments count
+		RequestHandler last = null;
+		int maxMatchingSegmentsCount = -1;
+
 		for (RequestHandlerEncoder encoder : encoders)
 		{
-			RequestHandler handler = encoder.decode(request);
-			if (handler != null)
+			// no handler has been found yet
+			if (last == null)
 			{
-				return handler;
+				// 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 null;
+		return last;
 	}
 
 	/**

Added: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractEncoder.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractEncoder.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,65 @@
+/*
+ * 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.encoder;
+
+import org.apache._wicket.request.RequestHandler;
+import org.apache._wicket.request.RequestHandlerEncoder;
+import org.apache._wicket.request.Url;
+import org.apache._wicket.request.request.Request;
+import org.apache.wicket.RequestListenerInterface;
+
+public abstract class AbstractEncoder implements RequestHandlerEncoder
+{
+	protected EncoderContext getContext()
+	{
+		return null;
+	};
+
+	protected String requestListenerInterfaceToString(RequestListenerInterface listenerInterface)
+	{
+		if (listenerInterface == null)
+		{
+			throw new IllegalArgumentException("Argument 'listenerInterface' may not be null.");
+		}
+		return listenerInterface.getName();
+	}
+	
+	protected RequestListenerInterface requestListenerIntefaceFromString(String interfaceName)
+	{
+		if (interfaceName == null)
+		{
+			throw new IllegalArgumentException("Argument 'interfaceName' may not be null.");
+		}
+		return RequestListenerInterface.forName(interfaceName);
+	}
+	
+	public RequestHandler decode(Request request)
+	{
+		return null;
+	}
+
+	public Url encode(RequestHandler requestHandler)
+	{
+		return null;
+	}
+
+	public int getMachingSegmentsCount(Request request)
+	{
+		return 0;
+	}
+
+}

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

Added: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractNotMountedEncoder.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractNotMountedEncoder.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractNotMountedEncoder.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/AbstractNotMountedEncoder.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,47 @@
+/*
+ * 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.encoder;
+
+public class AbstractNotMountedEncoder extends AbstractEncoder
+{
+
+	protected String getNamespace()
+	{
+		// 
+		return "wicket";
+	}
+	
+	protected String getPageIdentifier()
+	{
+		// /wicket/page?abc.2.4
+		return "page";
+	}
+	
+	protected String getBookmarkableIdentifier()
+	{
+		// /wicket/bookmarkable/org.apache.wicket.MyPage
+		return "bookmarkable";
+	}
+	
+	protected String getListenerIdentifier()
+	{
+		// /wicket/listener?2:click:foo:bar:baz
+		return "listener";
+	}
+
+	
+}

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

Added: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/ComponentInfo.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/ComponentInfo.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/ComponentInfo.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/ComponentInfo.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,98 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Encodes listener inteface and component path in form of
+ * &lt;listenerInterface&gt;:&lt;componentPath&gt;
+ * 
+ * @author Matej Knopp
+ */
+class ComponentInfo
+{
+	private final String listenerInterface;
+	private final String componentPath;
+
+	public ComponentInfo(String listenerInterface, String componentPath)
+	{
+		this.listenerInterface = listenerInterface;
+		this.componentPath = componentPath;
+	}
+
+	public String getComponentPath()
+	{
+		return componentPath;
+	}
+
+	public String getListenerInterface()
+	{
+		return listenerInterface;
+	}
+
+	@Override
+	public String toString()
+	{
+		StringBuilder result = new StringBuilder();
+		if (listenerInterface != null)
+		{
+			result.append(listenerInterface);
+		}
+		result.append(":");
+		if (componentPath != null)
+		{
+			result.append(componentPath);
+		}
+		return result.toString();
+	}
+
+	/**
+	 * Parses the given string.
+	 * 
+	 * @param string
+	 * @return component info or <code>null</code> if the string is not in correct format.
+	 */
+	public static ComponentInfo parse(String string)
+	{
+		if (Strings.isEmpty(string))
+		{
+			return null;
+		}
+		int i = string.indexOf(':');
+		if (i == -1)
+		{
+			return null;
+		}
+		else
+		{
+			String listenerInterface = string.substring(0, i);
+			String componentPath = string.substring(i + 1);
+
+			if (Strings.isEmpty(listenerInterface))
+			{
+				listenerInterface = null;
+			}
+			if (Strings.isEmpty(componentPath))
+			{
+				componentPath = null;
+			}
+			return new ComponentInfo(listenerInterface, componentPath);
+		}
+	}
+
+}

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

Modified: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/EncoderContext.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/EncoderContext.java?rev=695446&r1=695445&r2=695446&view=diff
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/EncoderContext.java (original)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/EncoderContext.java Mon Sep 15 05:15:52 2008
@@ -45,5 +45,5 @@
 	 * @return new page instance
 	 */
 	public IPage newPageInstance(String pageMapName, Class<? extends IPage> pageClass,
-		PageParameters pageParameters);
+		PageParameters pageParameters);	
 }

Added: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageComponentInfo.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageComponentInfo.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageComponentInfo.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageComponentInfo.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,105 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Encapsulates both page and component info.
+ * Rendered in form of &lt;pageInfo&gt:&lt;componentInfo&gt;
+ * 
+ * @author Matej Knopp
+ */
+class PageComponentInfo
+{
+	private final PageInfo pageInfo;
+	private final ComponentInfo componentInfo;
+
+	public PageComponentInfo(PageInfo pageInfo, ComponentInfo componentInfo)
+	{
+		if (pageInfo == null)
+		{
+			throw new IllegalArgumentException("Argument 'pageInfo' may nut be null.");
+		}
+		this.pageInfo = pageInfo;
+		this.componentInfo = componentInfo;
+	}
+	
+	public PageInfo getPageInfo()
+	{
+		return pageInfo;
+	}
+	
+	public ComponentInfo getComponentInfo()
+	{
+		return componentInfo;
+	}
+	
+	@Override
+	public String toString()
+	{
+		StringBuilder result = new StringBuilder();
+		if (pageInfo != null)
+		{
+			result.append(pageInfo.toString());
+		}		
+		if (componentInfo != null)
+		{
+			result.append(":");
+			result.append(componentInfo);
+		}
+		
+		return result.toString();
+	}
+	
+	/**
+	 * Parses the given string
+	 * 
+	 * @param s
+	 * @return {@link PageComponentInfo} or <code>null</code> if the string is not in valid format.
+	 */
+	public static PageComponentInfo parse(String s)
+	{
+		if (Strings.isEmpty(s))
+		{
+			return null;
+		}
+		
+		final PageInfo pageInfo;
+		final ComponentInfo componentInfo;
+		
+		int i = s.indexOf(':');
+		if (i == -1)
+		
+		{
+			pageInfo = PageInfo.parse(s);
+			componentInfo = null;
+		}
+		else
+		{
+			pageInfo = PageInfo.parse(s.substring(0, i));
+			componentInfo = ComponentInfo.parse(s.substring(i + 1));	
+		}
+			
+		if (pageInfo == null)
+		{
+			return null;
+		}
+		
+		return new PageComponentInfo(pageInfo, componentInfo);
+	}
+}

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

Added: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageInfo.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageInfo.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageInfo.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/encoder/PageInfo.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,270 @@
+/*
+ * 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.encoder;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Possible string representation of PageInfo:
+ * <ul>
+ * <li>pageId
+ * <li>pageId.version
+ * <li>pageMap (only if pageMap contains a letter)
+ * <li>.pageMap
+ * <li>pageMap.pageId.version
+ * <li>pageMap.pageId (only if pageMap contains a letter)
+ * </ul>
+ * 
+ * @author Matej Knopp
+ */
+class PageInfo
+{
+	private final Integer pageId;
+	private final Integer versionNumber;
+	private final String pageMapName;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param pageId
+	 * @param versionNumber
+	 * @param pageMapName
+	 */
+	public PageInfo(Integer pageId, Integer versionNumber, String pageMapName)
+	{
+		if ((pageId == null && (versionNumber != null || pageMapName == null)) ||
+			(versionNumber == null && (pageId != null || pageMapName == null)))
+		{
+			throw new IllegalArgumentException(
+				"Either both pageId and versionNumber must be null or none of them.");
+		}
+		this.pageId = pageId;
+		this.versionNumber = versionNumber;
+		this.pageMapName = pageMapName;
+	}
+
+	/**
+	 * @return page id
+	 */
+	public Integer getPageId()
+	{
+		return pageId;
+	}
+
+	/**
+	 * @return page version number
+	 */
+	public Integer getVersionNumber()
+	{
+		return versionNumber;
+	}
+
+	/**
+	 * @return pagemap name
+ 	 */
+	public String getPageMapName()
+	{
+		return pageMapName;
+	}
+
+	private static char getPageInfoSeparator()
+	{
+		return '.';
+	}
+
+	/**
+	 * <ul>
+	 * <li>pageId
+	 * <li>pageId.version
+	 * <li>pageMap (only in if pagemap starts with a letter)
+	 * <li>.pageMap
+	 * <li>pageMap.pageId (only in if pageMap name starts with a letter)
+	 * <li>pageMap.pageId.version
+	 * </ul>
+	 */
+	@Override
+	public String toString()
+	{
+		String pageMapName = this.pageMapName;
+
+		// we don't need to encode the pageMapName when the pageId is unique
+		// per session
+		if (pageMapName != null && pageId != null && Application.exists() &&
+			Application.get().getSessionSettings().isPageIdUniquePerSession())
+		{
+			pageMapName = null;
+		}
+
+		AppendingStringBuffer buffer = new AppendingStringBuffer(5);
+
+		final boolean pmEmpty = Strings.isEmpty(pageMapName);
+		final boolean pmContainsLetter = !pmEmpty && !isNumber(pageMapName);
+
+
+		if (pageId != null && pmEmpty && versionNumber.intValue() == 0)
+		{
+			// pageId
+			buffer.append(pageId);
+		}
+		else if (pageId != null && pmEmpty && versionNumber.intValue() != 0)
+		{
+			// pageId.version
+			buffer.append(pageId);
+			buffer.append(getPageInfoSeparator());
+			buffer.append(versionNumber);
+		}
+		else if (pageId == null && pmContainsLetter)
+		{
+			// pageMap (must start with letter)
+			buffer.append(pageMapName);
+		}
+		else if (pageId == null && !pmEmpty && !pmContainsLetter)
+		{
+			// .pageMap
+			buffer.append(getPageInfoSeparator());
+			buffer.append(pageMapName);
+		}
+		else if (pmContainsLetter && pageId != null && versionNumber.intValue() == 0)
+		{
+			// pageMap.pageId (pageMap must start with a letter)
+			buffer.append(pageMapName);
+			buffer.append(getPageInfoSeparator());
+			buffer.append(pageId);
+		}
+		else if (!pmEmpty && pageId != null)
+		{
+			// pageMap.pageId.pageVersion
+			buffer.append(pageMapName);
+			buffer.append(getPageInfoSeparator());
+			buffer.append(pageId);
+			buffer.append(getPageInfoSeparator());
+			buffer.append(versionNumber);
+		}
+
+		return buffer.toString();
+	}
+
+	/**
+	 * Method that rigidly checks if the string consists of digits only.
+	 * 
+	 * @param string
+	 * @return whether the string consists of digits only
+	 */
+	private static boolean isNumber(String string)
+	{
+		if (string == null || string.length() == 0)
+		{
+			return false;
+		}
+		for (int i = 0; i < string.length(); ++i)
+		{
+			if (Character.isDigit(string.charAt(i)) == false)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * <ul>
+	 * <li>pageId
+	 * <li>pageId.version
+	 * <li>pageMap (only in if pagemap starts with a letter)
+	 * <li>.pageMap
+	 * <li>pageMap.pageId (only in if pageMap name starts with a letter)
+	 * <li>pageMap.pageId.version
+	 * </ul>
+	 * 
+	 * @param src
+	 * @return page insfo instance or <code>null</code> if the string couldn't have been parsed 
+	 */
+	public static PageInfo parse(String src)
+	{
+		if (src == null || src.length() == 0)
+		{
+			return null;
+		}
+
+		String segments[] = Strings.split(src, getPageInfoSeparator());
+
+		if (segments.length > 3)
+		{
+			return null;
+		}
+
+		// go trhough the segments to determine if they don't contains invalid characters
+		for (int i = 0; i < segments.length; ++i)
+		{
+			for (int j = 0; j < segments[i].length(); ++j)
+			{
+				char c = segments[i].charAt(j);
+				if (!Character.isLetterOrDigit(c) && c != '-' && c != '_')
+				{
+					return null;
+				}
+			}
+		}
+
+		if (segments.length == 1 && isNumber(segments[0]))
+		{
+			// pageId
+			return new PageInfo(Integer.valueOf(segments[0]), new Integer(0), null);
+		}
+		else if (segments.length == 2 && isNumber(segments[0]) && isNumber(segments[1]))
+		{
+			// pageId:pageVersion
+			return new PageInfo(Integer.valueOf(segments[0]), Integer.valueOf(segments[1]), null);
+		}
+		else if (segments.length == 1 && !isNumber(segments[0]))
+		{
+			// pageMap (starts with letter)
+			return new PageInfo(null, null, segments[0]);
+		}
+		else if (segments.length == 2 && segments[0].length() == 0)
+		{
+			// .pageMap
+			return new PageInfo(null, null, segments[1]);
+		}
+		else if (segments.length == 2 && !isNumber(segments[0]) && isNumber(segments[1]))
+		{
+			// pageMap.pageId (pageMap starts with letter)
+			return new PageInfo(Integer.valueOf(segments[1]), new Integer(0), segments[0]);
+		}
+		else if (segments.length == 3)
+		{
+			if (segments[2].length() == 0 && isNumber(segments[1]))
+			{
+				// we don't encode it like this, but we still should be able
+				// to parse it
+				// pageMapName.pageId.
+				return new PageInfo(Integer.valueOf(segments[1]), new Integer(0), segments[0]);
+			}
+			else if (isNumber(segments[1]) && isNumber(segments[2]))
+			{
+				// pageMapName.pageId.pageVersion
+				return new PageInfo(Integer.valueOf(segments[1]), Integer.valueOf(segments[2]),
+					segments[0]);
+			}
+		}
+
+		return null;
+	}
+
+};

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

Modified: wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/handler/impl/BookmarkablePageRequestHandler.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/handler/impl/BookmarkablePageRequestHandler.java?rev=695446&r1=695445&r2=695446&view=diff
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/handler/impl/BookmarkablePageRequestHandler.java (original)
+++ wicket/sandbox/knopp/experimental/wicket/src/main/java/org/apache/_wicket/request/handler/impl/BookmarkablePageRequestHandler.java Mon Sep 15 05:15:52 2008
@@ -30,7 +30,7 @@
 public class BookmarkablePageRequestHandler implements PageClassRequestHandler
 {
 	private final Class<? extends IPage> pageClass;
-
+  
 	private final String pageMapName;
 
 	private final PageParameters pageParameters;

Added: wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/ComponentInfoTest.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/ComponentInfoTest.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/ComponentInfoTest.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/ComponentInfoTest.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,96 @@
+/*
+ * 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.encoder;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author Matej Knopp
+ */
+public class ComponentInfoTest extends TestCase
+{
+
+	/**
+	 * 
+	 * Construct.
+	 */
+	public ComponentInfoTest()
+	{
+	}
+
+	/**
+	 * 
+	 */
+	public void test1()
+	{
+		String s = "listener:component:path";
+		ComponentInfo info = ComponentInfo.parse(s);
+		assertEquals("listener", info.getListenerInterface());
+		assertEquals("component:path", info.getComponentPath());
+		
+		assertEquals(s, info.toString());
+	}
+
+	/**
+	 * 
+	 */
+	public void test2()
+	{
+		String s = ":component:path";
+		ComponentInfo info = ComponentInfo.parse(s);
+		assertEquals(null, info.getListenerInterface());
+		assertEquals("component:path", info.getComponentPath());
+		
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test3()
+	{
+		String s = "listener:";
+		ComponentInfo info = ComponentInfo.parse(s);
+		assertEquals("listener", info.getListenerInterface());
+		assertEquals(null, info.getComponentPath());
+		
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test4()
+	{
+		String s = ":";
+		ComponentInfo info = ComponentInfo.parse(s);
+		assertEquals(null, info.getListenerInterface());
+		assertEquals(null, info.getComponentPath());
+		
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test5()
+	{
+		String s = "abcd";
+		assertEquals(null, ComponentInfo.parse(s));
+	}
+}

Propchange: wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/ComponentInfoTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/PageComponentInfoTest.java
URL: http://svn.apache.org/viewvc/wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/PageComponentInfoTest.java?rev=695446&view=auto
==============================================================================
--- wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/PageComponentInfoTest.java (added)
+++ wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/PageComponentInfoTest.java Mon Sep 15 05:15:52 2008
@@ -0,0 +1,169 @@
+/*
+ * 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.encoder;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author Matej Knopp
+ */
+public class PageComponentInfoTest extends TestCase
+{
+
+	/**
+	 * Construct.
+	 */
+	public PageComponentInfoTest()
+	{
+	}
+
+	private void testPageInfoOnly(PageComponentInfo info, String pageMapName, Integer pageId,
+		Integer versionNumber)
+	{
+		assertNull(info.getComponentInfo());
+		assertNotNull(info.getPageInfo());
+
+		assertEquals(pageMapName, info.getPageInfo().getPageMapName());
+		assertEquals(pageId, info.getPageInfo().getPageId());
+		assertEquals(versionNumber, info.getPageInfo().getVersionNumber());
+	}
+
+	private void testPageComponentInfo(PageComponentInfo info, String pageMapName, Integer pageId,
+		Integer versionNumber, String listener, String componentPath)
+	{
+		assertNotNull(info.getComponentInfo());
+		assertNotNull(info.getPageInfo());
+
+		assertEquals(pageMapName, info.getPageInfo().getPageMapName());
+		assertEquals(pageId, info.getPageInfo().getPageId());
+		assertEquals(versionNumber, info.getPageInfo().getVersionNumber());
+		
+		assertEquals(listener, info.getComponentInfo().getListenerInterface());
+		assertEquals(componentPath, info.getComponentInfo().getComponentPath());
+	}
+
+	/**
+	 * 
+	 */
+	public void test1()
+	{
+		String s = "2:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, null, 2, 0, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test2()
+	{
+		String s = "2.4:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, null, 2, 4, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+
+	/**
+	 * 
+	 */
+	public void test3()
+	{
+		String s = "pagemap.2.4:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "pagemap", 2, 4, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test4()
+	{
+		String s = "pagemap:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "pagemap", null, null, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test5()
+	{
+		String s = "123pagemap:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "123pagemap", null, null, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test6()
+	{
+		String s = "123pagemap:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "123pagemap", null, null, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test7()
+	{
+		String s = "123pagemap.2:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "123pagemap", 2, 0, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test8()
+	{
+		String s = ".123:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "123", null, null, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test9()
+	{
+		String s = "123.2.0:click:foo:bar:baz";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageComponentInfo(info, "123", 2, 0, "click", "foo:bar:baz");
+		assertEquals(s, info.toString());
+	}
+	
+	/**
+	 * 
+	 */
+	public void test10()
+	{
+		String s = "abc.2";
+		PageComponentInfo info = PageComponentInfo.parse(s);
+		testPageInfoOnly(info, "abc", 2, 0);
+		assertEquals(s, info.toString());
+	}
+}

Propchange: wicket/sandbox/knopp/experimental/wicket/src/test/java/org/apache/_wicket/request/encoder/PageComponentInfoTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain