Author: knopp
Date: Sat Jul 28 06:21:24 2007
New Revision: 560540

URL: http://svn.apache.org/viewvc?view=rev&rev=560540
Log:
WICKET-30 - Javadoc, remember amount of trailing slashes, change separator from 
( ) to | 

Modified:
    
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/request/target/coding/HybridUrlCodingStrategy.java

Modified: 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/request/target/coding/HybridUrlCodingStrategy.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/request/target/coding/HybridUrlCodingStrategy.java?view=diff&rev=560540&r1=560539&r2=560540
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/request/target/coding/HybridUrlCodingStrategy.java
 (original)
+++ 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/request/target/coding/HybridUrlCodingStrategy.java
 Sat Jul 28 06:21:24 2007
@@ -36,6 +36,23 @@
 
 
 /**
+ * An URL coding strategy that encodes the mount point, page parameters and 
page
+ * instance information into the URL. The benefits compared to mounting page
+ * with [EMAIL PROTECTED] BookmarkablePageRequestTargetUrlCodingStrategy} are 
that the
+ * mount point is preserved even after invoking listener interfaces (thus you
+ * don't lose bookmarkability after clicking links) and that for ajax only 
pages
+ * the state is preserved on refresh.
+ * <p>
+ * The url with [EMAIL PROTECTED] HybridUrlCodingStrategy} looks like
+ * /mount/path/param1/value1(3) or /mount/path/param1/value1(3:2) where 3 is
+ * page Id and 2 is version number.
+ * <p>
+ * Also to preserve state on refresh with ajax-only pages the
+ * [EMAIL PROTECTED] HybridUrlCodingStrategy} does an immediate redirect after 
hitting
+ * bookmarkable URL, e.g. it immediately redirects from /mount/path to
+ * /mount/path(3) where 3 is the next page id. This preserves the page instance
+ * on subsequent page refresh.
+ * 
  * @author Matej Knopp
  */
 public class HybridUrlCodingStrategy extends 
AbstractRequestTargetUrlCodingStrategy
@@ -56,11 +73,37 @@
                pageClassRef = new WeakReference(pageClass);
        }
 
+       /**
+        * Returns the amount of trailing slashes in the given string
+        * 
+        * @param seq
+        * @return
+        */
+       private int getTrailingSlashesCount(CharSequence seq)
+       {
+               int count = 0;
+               for (int i = seq.length() - 1; i >= 0; --i)
+               {
+                       if (seq.charAt(i) == '/')
+                       {
+                               ++count;
+                       }
+                       else
+                       {
+                               break;
+                       }
+               }
+               return count;
+       }
 
+       /**
+        * @see 
org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#decode(org.apache.wicket.request.RequestParameters)
+        */
        public IRequestTarget decode(RequestParameters requestParameters)
        {
                String parametersFragment = 
requestParameters.getPath().substring(getMountPath().length());
 
+               // try to extract page info
                PageInfoExtraction extraction = 
extractPageInfo(parametersFragment);
 
                PageInfo pageInfo = extraction.getPageInfo();
@@ -68,6 +111,7 @@
                Integer pageVersion = pageInfo != null ? 
pageInfo.getVersionNumber() : null;
                Integer pageId = pageInfo != null ? pageInfo.getPageId() : null;
 
+               // decode parameters
                PageParameters parameters = new 
PageParameters(decodeParameters(extraction
                                .getUrlAfterExtraction(), 
requestParameters.getParameters()));
 
@@ -86,6 +130,11 @@
                final String interfaceParameter = (String)parameters
                                
.remove(WebRequestCodingStrategy.INTERFACE_PARAMETER_NAME);
 
+               // we need to remember the amount of trailing slashes after the 
redirect
+               // (otherwise we'll break relative urls)
+               int originalUrlTrailingSlashesCount = 
getTrailingSlashesCount(extraction
+                               .getUrlAfterExtraction());
+
                if (interfaceParameter != null)
                {
                        // stateless listener interface
@@ -98,7 +147,7 @@
                {
                        // bookmarkable page request
                        return new 
HybridBookmarkablePageRequestTarget(pageMapName, (Class)pageClassRef.get(),
-                                       parameters);
+                                       parameters, 
originalUrlTrailingSlashesCount);
                }
                else
                // hybrid url
@@ -115,14 +164,39 @@
                        }
                        else
                        {
+                               // we didn't find the page, act as bookmarkable 
page request -
+                               // create new instance
                                return new 
HybridBookmarkablePageRequestTarget(pageMapName, (Class)pageClassRef
-                                               .get(), parameters);
+                                               .get(), parameters, 
originalUrlTrailingSlashesCount);
                        }
                }
 
        }
 
+       /**
+        * Returns the number of traling slashes in the url when the page in 
request
+        * target was created or null if the number can't be determined.
+        * 
+        * @param requestTarget
+        * @return
+        */
+       private Integer getOriginalOriginalTrailingSlashesCount(IRequestTarget 
requestTarget)
+       {
+               if (requestTarget instanceof ListenerInterfaceRequestTarget)
+               {
+                       ListenerInterfaceRequestTarget target = 
(ListenerInterfaceRequestTarget)requestTarget;
+                       Page page = target.getPage();
+                       return 
(Integer)page.getMetaData(ORIGINAL_TRAILING_SLASHES_COUNT_METADATA_KEY);
+               }
+               return null;
+       }
 
+       /**
+        * Extracts the PageParameters from given request target
+        * 
+        * @param requestTarget
+        * @return
+        */
        private PageParameters getPageParameters(IRequestTarget requestTarget)
        {
                if (requestTarget instanceof BookmarkablePageRequestTarget)
@@ -142,6 +216,12 @@
                }
        }
 
+       /**
+        * Extracts the PageInfo from given request target
+        * 
+        * @param requestTarget
+        * @return
+        */
        private PageInfo getPageInfo(IRequestTarget requestTarget)
        {
                if (requestTarget instanceof BookmarkablePageRequestTarget)
@@ -170,22 +250,73 @@
        }
 
 
-       private static final PageParametersMetadataKey 
PAGE_PARAMETERS_META_DATA_KEY = new PageParametersMetadataKey();
+       // meta data key to store PageParameters in page instance. This is used 
to
+       // save the PageParameters that were
+       // used to create the page instance so that later we can used them when
+       // generating page URL
+       private static final PageParametersMetaDataKey 
PAGE_PARAMETERS_META_DATA_KEY = new PageParametersMetaDataKey();
 
-       private static class PageParametersMetadataKey extends MetaDataKey
+       private static class PageParametersMetaDataKey extends MetaDataKey
        {
+               private static final long serialVersionUID = 1L;
+
                /**
                 * Construct.
                 */
-               public PageParametersMetadataKey()
+               public PageParametersMetaDataKey()
                {
                        super(PageParameters.class);
                }
+       };
+
+       // used to store number of traling slashes in page url (prior the 
PageInfo)
+       // part. This is necessary to maintain
+       // the exact number of slashes after page redirect, so that we don't 
break
+       // things that rely on URL depth
+       // (other mounted URLs)
+       private static final OriginalUrlTrailingSlashesCountMetaDataKey 
ORIGINAL_TRAILING_SLASHES_COUNT_METADATA_KEY = new 
OriginalUrlTrailingSlashesCountMetaDataKey();
 
+       private static class OriginalUrlTrailingSlashesCountMetaDataKey extends 
MetaDataKey
+       {
                private static final long serialVersionUID = 1L;
 
-       };
+               /**
+                * Construct.
+                */
+               public OriginalUrlTrailingSlashesCountMetaDataKey()
+               {
+                       super(Integer.class);
+               }
+
+       }
+
+       /**
+        * Fix the amount of traling slashes in the speciffied buffer.
+        * 
+        * @param buffer
+        * @param desiredCount
+        */
+       private void fixTrailingSlashes(AppendingStringBuffer buffer, int 
desiredCount)
+       {
+               int current = getTrailingSlashesCount(buffer);
+               if (current > desiredCount)
+               {
+                       buffer.setLength(buffer.length() - (current - 
desiredCount));
+               }
+               else if (desiredCount > current)
+               {
+                       int toAdd = desiredCount - current;
+                       while (toAdd > 0)
+                       {
+                               buffer.append("/");
+                               --toAdd;
+                       }
+               }
+       }
 
+       /**
+        * @see 
org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#encode(org.apache.wicket.IRequestTarget)
+        */
        public CharSequence encode(IRequestTarget requestTarget)
        {
                if (matches(requestTarget) == false)
@@ -200,9 +331,19 @@
                url.append(getMountPath());
                appendParameters(url, parameters);
 
+               // check whether we know if the initial URL ended with slash
+               Integer trailingSlashesCount = 
getOriginalOriginalTrailingSlashesCount(requestTarget);
+               if (trailingSlashesCount != null)
+               {
+                       fixTrailingSlashes(url, 
trailingSlashesCount.intValue());
+               }
+
                return addPageInfo(url.toString(), pageInfo);
        }
 
+       /**
+        * @see 
org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#matches(org.apache.wicket.IRequestTarget)
+        */
        public boolean matches(IRequestTarget requestTarget)
        {
                if (requestTarget instanceof BookmarkablePageRequestTarget)
@@ -219,6 +360,12 @@
                return false;
        }
 
+       /**
+        * Class that encapsulates [EMAIL PROTECTED] PageInfo} instance and the 
URL part prior
+        * the PageInfo part
+        * 
+        * @author Matej Knopp
+        */
        protected static class PageInfoExtraction
        {
                private final String urlAfterExtraction;
@@ -262,9 +409,9 @@
         */
        protected PageInfoExtraction extractPageInfo(String url)
        {
-               int lastIndexLeft = url.lastIndexOf(getBeginSeparator());
                int lastIndexRight = url.lastIndexOf(getEndSeparator());
-               if (lastIndexLeft != -1 && lastIndexRight != -1 && 
lastIndexLeft < lastIndexRight &&
+               int lastIndexLeft = url.lastIndexOf(getBeginSeparator(), 
lastIndexRight - 1);
+               if (lastIndexLeft != -1 && lastIndexRight != -1 &&
                                lastIndexRight - lastIndexLeft > 0 && 
lastIndexRight == url.length() - 1)
                {
                        String infoSubstring = url.substring(lastIndexLeft + 1, 
lastIndexRight);
@@ -279,14 +426,20 @@
 
        protected char getBeginSeparator()
        {
-               return '(';
+               return '|';
        }
 
        protected char getEndSeparator()
        {
-               return ')';
+               return '|';
        }
 
+       /**
+        * Encodes the PageInfo part to the URL
+        * @param url
+        * @param pageInfo
+        * @return
+        */
        protected String addPageInfo(String url, PageInfo pageInfo)
        {
                if (pageInfo != null)
@@ -449,7 +602,7 @@
                                // :pageMapName
                                return new PageInfo(null, null, segments[1]);
                        }
-                       else
+                       else if (segments.length == 3)
                        {
                                if (segments[2].length() == 0 && 
isNumber(segments[1]))
                                {
@@ -469,25 +622,36 @@
 
        };
 
+       /**
+        * BookmarkablePage request target that does a redirect after 
bookmarkable page was rendered 
+        * (only if the bookmarkable page is stateful though)
+        * @author Matej Knopp
+        */
        private static class HybridBookmarkablePageRequestTarget extends 
BookmarkablePageRequestTarget
        {
+               private final int originalUrlTrailingSlashesCount;
+
                /**
                 * Construct.
                 * 
                 * @param pageMapName
                 * @param pageClass
                 * @param pageParameters
+                * @param originalUrlTrailingSlashesCount
                 */
                public HybridBookmarkablePageRequestTarget(String pageMapName, 
Class pageClass,
-                               PageParameters pageParameters)
+                               PageParameters pageParameters, int 
originalUrlTrailingSlashesCount)
                {
                        super(pageMapName, pageClass, pageParameters);
+                       this.originalUrlTrailingSlashesCount = 
originalUrlTrailingSlashesCount;
                }
 
                protected Page newPage(Class pageClass, RequestCycle 
requestCycle)
                {
                        Page page = super.newPage(pageClass, requestCycle);
                        page.setMetaData(PAGE_PARAMETERS_META_DATA_KEY, 
getPageParameters());
+                       
page.setMetaData(ORIGINAL_TRAILING_SLASHES_COUNT_METADATA_KEY, new Integer(
+                                       originalUrlTrailingSlashesCount));
                        return page;
                }
 


Reply via email to