Updated Branches:
  refs/heads/master 1f89691bf -> ac4dabeea

FIXED - TAP5-2063: Add support for multivalued parameters in Link 
- apply Alejandro Scandroli's patch + test with modifications


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/ac4dabee
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/ac4dabee
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/ac4dabee

Branch: refs/heads/master
Commit: ac4dabeeae8e0db5425a08477a66a4131addc32b
Parents: 1f89691
Author: kaosko <[email protected]>
Authored: Sat Apr 13 23:50:49 2013 -0700
Committer: kaosko <[email protected]>
Committed: Sat Apr 13 23:50:49 2013 -0700

----------------------------------------------------------------------
 .../src/main/java/org/apache/tapestry5/Link.java   |   15 +++-
 .../apache/tapestry5/corelib/components/Form.java  |   76 +++++++++++----
 .../tapestry5/internal/services/LinkImpl.java      |   48 +++++++---
 .../tapestry5/internal/services/LinkImplTest.java  |   27 +++++
 4 files changed, 130 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ac4dabee/tapestry-core/src/main/java/org/apache/tapestry5/Link.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/Link.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/Link.java
index 437229c..9596335 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/Link.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/Link.java
@@ -45,7 +45,13 @@ public interface Link
      * Returns the value of a specifically named query parameter, or 
<tt>null</tt> if no such query parameter is stored
      * in the link.
      *
-     * @return the string value of the named parameter
+     * <p>Use this method only when you are sure the parameter has only one 
value. If the parameter might have more than
+     * one value, use {@link #getParameterValues}.
+     *
+     * <p>If you use this method with a multivalued parameter, the value 
returned is equal to the first value in the
+     * array returned by <code>getParameterValues</code>.
+     *
+     * @return a string representing the single value of the named parameter
      */
     String getParameterValue(String name);
 
@@ -55,7 +61,6 @@ public interface Link
      *
      * @param parameterName the name of the parameter to store
      * @param value         the value to store, a null or blank value is 
allowed (as of Tapestry 5.3)
-     * @throws IllegalArgumentException if the link already has a parameter 
with the given name
      */
     void addParameter(String parameterName, String value);
 
@@ -155,4 +160,10 @@ public interface Link
      * @since 5.3
      */
     LinkSecurity getSecurity();
+
+    /**
+     * Returns the parameter values for the given name. Returns null if no 
such parameter is stored in the link.
+     */
+    String[] getParameterValues(String parameterName);
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ac4dabee/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
index 59d2bdd..7a69882 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
@@ -14,14 +14,43 @@
 
 package org.apache.tapestry5.corelib.components;
 
-import org.apache.tapestry5.*;
-import org.apache.tapestry5.annotations.*;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+import org.apache.tapestry5.BindingConstants;
+import org.apache.tapestry5.ClientElement;
+import org.apache.tapestry5.ComponentAction;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.EventConstants;
+import org.apache.tapestry5.EventContext;
+import org.apache.tapestry5.Field;
+import org.apache.tapestry5.FormValidationControl;
+import org.apache.tapestry5.Link;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.TrackableComponentEventCallback;
+import org.apache.tapestry5.ValidationDecorator;
+import org.apache.tapestry5.ValidationException;
+import org.apache.tapestry5.ValidationTracker;
+import org.apache.tapestry5.ValidationTrackerImpl;
+import org.apache.tapestry5.annotations.Environmental;
+import org.apache.tapestry5.annotations.Events;
+import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.SupportsInformalParameters;
 import org.apache.tapestry5.corelib.ClientValidation;
 import org.apache.tapestry5.corelib.internal.ComponentActionSink;
 import org.apache.tapestry5.corelib.internal.FormSupportImpl;
 import org.apache.tapestry5.corelib.internal.InternalFormSupport;
 import org.apache.tapestry5.dom.Element;
-import org.apache.tapestry5.internal.*;
+import org.apache.tapestry5.internal.BeanValidationContext;
+import org.apache.tapestry5.internal.BeanValidationContextImpl;
+import org.apache.tapestry5.internal.InternalConstants;
+import org.apache.tapestry5.internal.InternalSymbols;
+import org.apache.tapestry5.internal.TapestryInternalUtils;
 import org.apache.tapestry5.internal.services.HeartbeatImpl;
 import org.apache.tapestry5.internal.util.AutofocusValidationDecorator;
 import org.apache.tapestry5.ioc.Location;
@@ -35,17 +64,17 @@ import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.ioc.util.IdAllocator;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.runtime.Component;
-import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.services.ClientDataEncoder;
+import org.apache.tapestry5.services.ComponentSource;
+import org.apache.tapestry5.services.Environment;
+import org.apache.tapestry5.services.FormSupport;
+import org.apache.tapestry5.services.Heartbeat;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.StreamPageContent;
 import org.apache.tapestry5.services.compatibility.DeprecationWarning;
 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 import org.slf4j.Logger;
 
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-
 /**
  * An HTML form, which will enclose other components to render out the various
  * types of fields.
@@ -364,18 +393,25 @@ public class Form implements ClientElement, 
FormValidationControl
 
         for (String parameterName : link.getParameterNames())
         {
-            String value = link.getParameterValue(parameterName);
-            // The parameter value is expected to be encoded,
-            // but the input value shouldn't be encoded.
-            try
-            {
-                value = URLDecoder.decode(value, "UTF-8");
-            } catch (UnsupportedEncodingException e)
+            String[] values = link.getParameterValues(parameterName);
+
+            for (String value : values)
             {
-                logger.error("Enable to decode parameter value", e);
+                // The parameter value is expected to be encoded,
+                // but the input value shouldn't be encoded.
+                try
+                {
+                    value = URLDecoder.decode(value, "UTF-8");
+                }
+                catch (UnsupportedEncodingException e)
+                {
+                    logger.error(String.format(
+                            "Enable to decode parameter value for parameter %s 
in form %s",
+                            parameterName, form.getName()), e);
+                }
+                writer.element("input", "type", "hidden", "name", 
parameterName, "value", value);
+                writer.end();
             }
-            writer.element("input", "type", "hidden", "name", parameterName, 
"value", value);
-            writer.end();
         }
 
         writer.end(); // div

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ac4dabee/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
index 52f4403..4a5075e 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkImpl.java
@@ -15,18 +15,19 @@
 package org.apache.tapestry5.internal.services;
 
 import org.apache.tapestry5.Link;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.services.BaseURLSource;
 import org.apache.tapestry5.services.ContextPathEncoder;
 import org.apache.tapestry5.services.Response;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 public class LinkImpl implements Link
 {
-    private Map<String, String> parameters;
+       private Map<String, List<String>> parameters;
 
     private final String basePath;
 
@@ -63,20 +64,29 @@ public class LinkImpl implements Link
 
         for (String name : getParameterNames())
         {
-            copy.addParameter(name, parameters.get(name));
+            copy.addParameter(name, getParameterValues(name));
         }
 
         return copy;
     }
 
+    private void addParameter(String parameterName, String[] value)
+    {
+        assert InternalUtils.isNonBlank(parameterName);
+        if (parameters == null)
+            parameters = new TreeMap<String, List<String>>();
+
+        parameters.put(parameterName, Arrays.asList(value));
+    }
+
     public void addParameter(String parameterName, String value)
     {
         assert InternalUtils.isNonBlank(parameterName);
 
         if (parameters == null)
-            parameters = CollectionFactory.newMap();
+            parameters = new TreeMap<String, List<String>>();
 
-        parameters.put(parameterName, value == null ? "" : value);
+        InternalUtils.addToMapList(parameters, parameterName, value == null ? 
"" : value);
     }
 
     public String getBasePath()
@@ -103,7 +113,8 @@ public class LinkImpl implements Link
 
     public String getParameterValue(String name)
     {
-        return InternalUtils.get(parameters, name);
+        List<String> values = InternalUtils.get(parameters, name);
+        return values != null && !values.isEmpty() ? values.get(0) : null;
     }
 
     public void setAnchor(String anchor)
@@ -198,18 +209,21 @@ public class LinkImpl implements Link
 
             for (String name : getParameterNames())
             {
-                String value = parameters.get(name);
+                List<String> values = parameters.get(name);
 
-                builder.append(sep);
+                for (String value : values)
+                {
+                    builder.append(sep);
 
-                // We assume that the name is URL safe and that the value will 
already have been URL
-                // encoded if it is not known to be URL safe.
+                    // We assume that the name is URL safe and that the value 
will already have been URL
+                    // encoded if it is not known to be URL safe.
 
-                builder.append(name);
-                builder.append("=");
-                builder.append(value);
+                    builder.append(name);
+                    builder.append("=");
+                    builder.append(value);
 
-                sep = "&";
+                    sep = "&";
+                }
             }
         }
 
@@ -223,4 +237,10 @@ public class LinkImpl implements Link
         return this;
     }
 
+    public String[] getParameterValues(String parameterName)
+    {
+        List<String> values = InternalUtils.get(parameters, parameterName);
+        return values.toArray(new String[values.size()]);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ac4dabee/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkImplTest.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkImplTest.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkImplTest.java
index 14948b1..5d861d6 100644
--- 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkImplTest.java
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/LinkImplTest.java
@@ -284,6 +284,33 @@ public class LinkImplTest extends InternalBaseTestCase
         verify();
     }
 
+    /**
+     * TAP5-2063
+     */
+    @Test
+    public void multivalued_parameter_support()
+    {
+        Response response = mockResponse();
+
+        String expectedURI = 
"/ctx?barney=&barney=foo&barney=bar&barney=baz&fred=flintstone";
+        train_encodeURL(response, expectedURI, expectedURI);
+
+        replay();
+
+        Link link = new LinkImpl("/ctx", false, LinkSecurity.INSECURE, 
response, null, null);
+
+        link.addParameter("fred", "flintstone");
+        link.addParameter("barney", null);
+        link.addParameter("barney", "foo");
+        link.addParameter("barney", "bar");
+        link.addParameter("barney", "baz");
+
+        assertEquals(link.toURI(), expectedURI);
+
+        verify();
+    }
+
+
     @Test
     public void force_link_to_secure()
     {

Reply via email to