Commits

Anonymous committed 6231668

URL Tag cause duplicates query string

Issue number: WW-1349
Obtained from:
Submitted by:
Reviewed by:

git-svn-id: http://svn.opensymphony.com/svn/webwork/trunk@2711573baa09-0c28-0410-bef9-dab3c582ae83

Comments (0)

Files changed (4)

src/java/com/opensymphony/webwork/components/URL.java

 import javax.servlet.http.HttpUtils;
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Collections;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 /**
  * @author Ian Roughley
  * @author Rene Gielen
  * @author Rainer Hermanns
+ * @author tm_jee
  * @version $Revision$
  * @since 2.2
  *
             }
 
             if (NONE.equalsIgnoreCase(includeParams)) {
+            	mergeRequestParameters(value, parameters, Collections.EMPTY_MAP);
                 ActionContext.getContext().put(XWorkContinuationConfig.CONTINUE_KEY, null);
             } else if (ALL.equalsIgnoreCase(includeParams)) {
-                mergeRequestParameters(parameters, req.getParameterMap());
+                mergeRequestParameters(value, parameters, req.getParameterMap());
 
                 // for ALL also include GET parameters
                 includeGetParameters();
     private void includeGetParameters() {
         if(!(DispatcherUtils.isPortletSupportActive() && PortletActionContext.isPortletRequest())) {
             String query = extractQueryString();
-            if (query != null) {
-                 //mergeRequestParameters(parameters, HttpUtils.parseQueryString(query));
-            	mergeRequestParameters(parameters, UrlHelper.parseQueryString(query));
-            }
+            mergeRequestParameters(value, parameters, UrlHelper.parseQueryString(query));
         }
     }
 
                 result = PortletUrlHelper.buildResourceUrl(value, parameters);
             }
             else {
-                result = UrlHelper.buildUrl(value, req, res, parameters, scheme, includeContext, encode);
+            	String _value = value;
+            	
+            	// We don't include the request parameters cause they would have been 
+            	// prioritised before this [in start(Writer) method]
+            	if (_value != null && _value.indexOf("?") > 0) {
+            		_value = _value.substring(0, _value.indexOf("?"));
+            	}
+                result = UrlHelper.buildUrl(_value, req, res, parameters, scheme, includeContext, encode);
             }
         }
         if ( anchor != null && anchor.length() > 0 ) {
             try {
                 writer.write(result);
             } catch (IOException e) {
-                e.printStackTrace();
                 throw new WebWorkException("IOError: " + e.getMessage(), e);
             }
         }
 
     /**
      * Merge request parameters into current parameters. If a parameter is
-     * already present, than the request parameter will not override its value.
+     * already present, than the request parameter in the current request and value atrribute 
+     * will not override its value.
+     * 
+     * The priority is as follows:-
+     * <ul>
+     * 	<li>parameter from the current request (least priority)</li>
+     *  <li>parameter form the value attribute (more priority)</li>
+     *  <li>parameter from the param tag (most priority)</li>
+     * </ul>
      * 
+     * @param value the value attribute (url to be generated by this component)
      * @param parameters component parameters
      * @param contextParameters request parameters
      */
-    protected void mergeRequestParameters(Map parameters, Map contextParameters){
-        for (Iterator iterator = contextParameters.entrySet().iterator(); iterator.hasNext();) {
+    protected void mergeRequestParameters(String value, Map parameters, Map contextParameters){
+    	
+    	Map mergedParams = new LinkedHashMap(contextParameters);
+    	
+    	// Merge contextParameters (from current request) with parameters specified in value attribute
+    	// eg. value="someAction.action?id=someId&venue=someVenue" 
+    	// where the parameters specified in value attribute takes priority.
+    	
+    	if (value != null && value.trim().length() > 0 && value.indexOf("?") > 0) {
+    		mergedParams = new LinkedHashMap();
+    		
+    		String queryString = value.substring(value.indexOf("?")+1);
+    		
+    		mergedParams = UrlHelper.parseQueryString(queryString);
+    		for (Iterator iterator = contextParameters.entrySet().iterator(); iterator.hasNext();) {
+    			Map.Entry entry = (Map.Entry) iterator.next();
+    			Object key = entry.getKey();
+    			
+    			if (!mergedParams.containsKey(key)) {
+    				mergedParams.put(key, entry.getValue());
+    			}
+    		}
+    	}
+    	
+    	
+    	// Merge parameters specified in value attribute 
+    	// eg. value="someAction.action?id=someId&venue=someVenue" 
+    	// with parameters specified though param tag 
+    	// eg. <param name="id" value="%{'someId'}" />
+    	// where parameters specified through param tag takes priority.
+    	
+        for (Iterator iterator = mergedParams.entrySet().iterator(); iterator.hasNext();) {
             Map.Entry entry = (Map.Entry) iterator.next();
             Object key = entry.getKey();
             

src/java/com/opensymphony/webwork/views/util/UrlHelper.java

  * UrlHelper
  *
  * @author Jason Carreira Created Apr 19, 2003 9:32:19 PM
+ * @author tm_jee
  */
 public class UrlHelper {
     private static final Log LOG = LogFactory.getLog(UrlHelper.class);
     	if (queryString != null) {
     		String[] params = queryString.split("&");
     		for (int a=0; a< params.length; a++) {
-    			String[] tmpParams = params[a].split("=");
-    			String paramName = null;
-    			String paramValue = "";
-    			if (tmpParams.length > 0) {
-    				paramName = tmpParams[0];
-    			}
-    			if (tmpParams.length > 1) {
-    				paramValue = tmpParams[1];
-    			}
-    			if (paramName != null) {
-    				String translatedParamValue = translateAndDecode(paramValue);
-    				queryParams.put(paramName, translatedParamValue);
+    			if (params[a].trim().length() > 0) {
+    				String[] tmpParams = params[a].split("=");
+    				String paramName = null;
+    				String paramValue = "";
+    				if (tmpParams.length > 0) {
+    					paramName = tmpParams[0];
+    				}
+    				if (tmpParams.length > 1) {
+    					paramValue = tmpParams[1];
+    				}
+    				if (paramName != null) {
+    					String translatedParamValue = translateAndDecode(paramValue);
+    					queryParams.put(paramName, translatedParamValue);
+    				}
     			}
     		}
     	}

src/test/com/opensymphony/webwork/views/jsp/URLTagTest.java

 import java.io.StringWriter;
 
 import com.opensymphony.webwork.components.URL;
+
+import com.opensymphony.webwork.views.jsp.ParamTag;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
                                                                         
 public class URLTagTest extends AbstractUITagTest {
 
     private URLTag tag;
+    
+    
+    /**
+     * To test priority of parameter passed in to url component though 
+     * various way 
+     *  - current request url
+     *  - tag's value attribute
+     *  - tag's nested param tag
+     * 
+	 * id1
+	 * ===
+	 * - found in current request url
+	 * - found in tag's value attribute
+	 * - found in tag's param tag
+	 * CONCLUSION: tag's param tag takes precedence (paramId1)
+	 * 
+	 * id2
+	 * ===
+	 * - found in current request url
+	 * - found in tag's value attribute
+	 * CONCLUSION: tag's value attribute take precedence (tagId2)
+	 * 
+	 * urlParam1
+	 * =========
+	 * - found in current request url
+	 * CONCLUSION: param in current request url will be used (urlValue1)
+	 * 
+	 * urlParam2
+	 * =========
+	 * - found in current request url
+	 * CONCLUSION: param in current request url will be used. (urlValue2)
+	 * 
+	 * tagId
+	 * =====
+	 * - found in tag's value attribute
+	 * CONCLUSION: param in tag's value attribute wil; be used. (tagValue)
+	 * 
+	 * param1
+	 * ======
+	 * - found in nested param tag
+	 * CONCLUSION: param in nested param tag will be used. (param1value)
+	 * 
+	 * param2
+	 * ======
+	 * - found in nested param tag
+	 * CONCLUSION: param in nested param tag will be used. (param2value)
+	 */
+    public void testParametersPriority() throws Exception {
+    	request.setQueryString("id1=urlId1&id2=urlId2&urlParam1=urlValue1&urlParam2=urlValue2");
+    	
+    	tag.setValue("testAction.action?id1=tagId1&id2=tagId2&tagId=tagValue");
+    	
+    	ParamTag param1 = new ParamTag();
+    	param1.setPageContext(pageContext);
+    	param1.setName("param1");
+    	param1.setValue("%{'param1value'}");
+    	
+    	ParamTag param2 = new ParamTag();
+    	param2.setPageContext(pageContext);
+    	param2.setName("param2");
+    	param2.setValue("%{'param2value'}");
+    	
+    	ParamTag param3 = new ParamTag();
+    	param3.setPageContext(pageContext);
+    	param3.setName("id1");
+    	param3.setValue("%{'paramId1'}");
+    	
+    	
+    	tag.doStartTag();
+    	param1.doStartTag();
+    	param1.doEndTag();
+    	param2.doStartTag();
+    	param2.doEndTag();
+    	param3.doStartTag();
+    	param3.doEndTag();
+    	
+    	URL url = (URL) tag.getComponent();
+    	Map parameters = url.getParameters();
+    	
+    	
+    	assertNotNull(parameters);
+    	assertEquals(parameters.size(), 7);
+    	assertEquals(parameters.get("id1"), "paramId1");
+    	assertEquals(parameters.get("id2"), "tagId2");
+    	assertEquals(parameters.get("urlParam1"), "urlValue1");
+    	assertEquals(parameters.get("urlParam2"), "urlValue2");
+    	assertEquals(parameters.get("tagId"), "tagValue");
+    	assertEquals(parameters.get("param1"), "param1value");
+    	assertEquals(parameters.get("param2"), "param2value");
+    }
+    
+    
+    /**
+     * To test priority of parameter passed in to url component though 
+     * various way, with includeParams="NONE"
+     *  - current request url
+     *  - tag's value attribute
+     *  - tag's nested param tag
+     *  
+     *  In this case only parameters from the tag itself is taken into account.
+     *  Those from request will not count, only those in tag's value attribute 
+     *  and nested param tag.
+     *  
+     * @throws Exception
+     */
+    public void testParametersPriorityWithIncludeParamsAsNONE() throws Exception {
+    	request.setQueryString("id1=urlId1&id2=urlId2&urlParam1=urlValue1&urlParam2=urlValue2");
+    	
+    	tag.setValue("testAction.action?id1=tagId1&id2=tagId2&tagId=tagValue");
+    	tag.setIncludeParams("NONE");
+    	
+    	ParamTag param1 = new ParamTag();
+    	param1.setPageContext(pageContext);
+    	param1.setName("param1");
+    	param1.setValue("%{'param1value'}");
+    	
+    	ParamTag param2 = new ParamTag();
+    	param2.setPageContext(pageContext);
+    	param2.setName("param2");
+    	param2.setValue("%{'param2value'}");
+    	
+    	ParamTag param3 = new ParamTag();
+    	param3.setPageContext(pageContext);
+    	param3.setName("id1");
+    	param3.setValue("%{'paramId1'}");
+    	
+    	
+    	tag.doStartTag();
+    	param1.doStartTag();
+    	param1.doEndTag();
+    	param2.doStartTag();
+    	param2.doEndTag();
+    	param3.doStartTag();
+    	param3.doEndTag();
+    	
+    	URL url = (URL) tag.getComponent();
+    	Map parameters = url.getParameters();
+    	
+    	assertEquals(parameters.size(), 5);
+    	assertEquals(parameters.get("id1"), "paramId1");
+    	assertEquals(parameters.get("id2"), "tagId2");
+    	assertEquals(parameters.get("tagId"), "tagValue");
+    	assertEquals(parameters.get("param1"), "param1value");
+    	assertEquals(parameters.get("param2"), "param2value");
+    }
 
     public void testIncludeParamsDefaultToGET() throws Exception {
     	request.setQueryString("one=oneVal&two=twoVal&three=threeVal");

src/test/com/opensymphony/webwork/views/util/UrlHelperTest.java

 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import com.opensymphony.webwork.views.util.UrlHelper;
+
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.TreeMap;
     	assertEquals(result.get("bbb"), "bbbval");
     	assertEquals(result.get("ccc"), "");
     }
+    
+    public void testParseEmptyQuery() throws Exception {
+    	Map result = UrlHelper.parseQueryString("");
+    	
+    	assertNotNull(result);
+    	assertEquals(result.size(), 0);
+    }
+    
+    public void testParseNullQuery() throws Exception {
+    	Map result = UrlHelper.parseQueryString(null);
+    	
+    	assertNotNull(result);
+    	assertEquals(result.size(), 0);
+    }
 
     public void testTranslateAndEncode() throws Exception {
     	Object defaultI18nEncoding = Configuration.get(WebWorkConstants.WEBWORK_I18N_ENCODING);