SPR-5298 JSP tag for building URLs with URI templates

Created spring:url and spring:param tags that enhance the functionality of the JSTL c:url tag.  URI templates are supported in the url value attribute.  They are resolved against the params defined inside the url tag body.  Params that are unable to be applied as URI template are added to the query string.
This commit is contained in:
Scott Andrews 2008-11-16 21:04:46 +00:00
parent ecb86b46a4
commit 912c1234cd
8 changed files with 1364 additions and 0 deletions

View File

@ -0,0 +1,66 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
/**
* Bean used to pass name-value pair parameters from a {@link ParamTag} to a
* {@link ParamAware} tag.
*
* @author Scott Andrews
* @since 3.0
* @see ParamTag
*/
public class Param {
private String name;
private String value;
/**
* @return the non-encoded parameter name
*/
public String getName() {
return name;
}
/**
* Set the non-encoded name of the parameter
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the non-encoded parameter value
*/
public String getValue() {
return value;
}
/**
* Set the non-encoded value of the parameter
*/
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "JSP Tag Param: name '" + name + "', value '" + value + "'";
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
/**
* Allows implementing tag to utilize nested spring:param tags.
*
* @author Scott Andrews
* @since 3.0
* @see ParamTag
*/
public interface ParamAware {
/**
* Callback hook for nested spring:param tags to pass their value to the
* parent tag.
*
* @param param the result of the nested spring:param tag
*/
public void addParam(Param param);
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* JSP tag for collecting name-value parameters and passing them to a
* {@link ParamAware} ancestor in the tag hierarchy.
*
* <p>
* This tag must be nested under a param aware tag.
*
* @author Scott Andrews
* @since 3.0
* @see Param
* @see UrlTag
*/
public class ParamTag extends BodyTagSupport {
private String name;
private String value;
private Param param;
// tag lifecycle
@Override
public int doEndTag() throws JspException {
param = new Param();
param.setName(name);
if (value != null) {
param.setValue(value);
}
else if (getBodyContent() != null) {
// get the value from the tag body
param.setValue(getBodyContent().getString().trim());
}
// find a param aware ancestor
ParamAware paramAwareTag = (ParamAware) findAncestorWithClass(this,
ParamAware.class);
if (paramAwareTag == null) {
throw new JspException(
"The param tag must be a descendant of a tag that supports parameters");
}
paramAwareTag.addParam(param);
return EVAL_PAGE;
}
// tag attribute accessors
/**
* Sets the name of the parameter
*
* <p>
* Required
*
* @param name the parameter name
*/
public void setName(String name) {
this.name = name;
}
/**
* Sets the value of the parameter
*
* <p>
* Optional. If not set, the tag's body content is evaluated
*
* @param value the parameter value
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,371 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
import org.springframework.util.StringUtils;
import org.springframework.web.util.TagUtils;
/**
* JSP tag for creating URLs. Modeled after the JSTL c:url tag with backwards
* compatibility in mind.
*
* <p>
* Enhancements to the JSTL functionality include:
* <ul>
* <li>URL encoded template URI variables</li>
* <li>Server and servlet relative URLs in addition to the standard context
* relative.</li>
* <li>XML escaping of URLs</li>
* </ul>
*
* <p>
* Template URI variables are indicated in the {@link #setValue(String) 'value'}
* attribute and marked by braces '{}'. The braces and attribute name are
* replaced by the URL encoded value of a parameter. If no parameter is
* available the literal value is passed through. Params matched to template
* variables will not be added to the query string.
*
* <p>
* URLs can be XML escaped by setting the {@link #setEscapeXml(String)
* 'escapeXml'} attribute to 'true', the default is 'false'.
*
* @author Scott Andrews
* @since 3.0
* @see ParamTag
*/
public class UrlTag extends TagSupport implements ParamAware {
private static final String URL_TEMPLATE_DELIMITER_PREFIX = "{";
private static final String URL_TEMPLATE_DELIMITER_SUFFIX = "}";
private static final String URL_TYPE_ABSOLUTE = "://";
private enum UrlType {
CONTEXT_RELATIVE, RELATIVE, ABSOLUTE
};
private static final char[] XML_CHARS = { '&', '<', '>', '"', '\'' };
private List<Param> params;
private Set<String> templateParams;
private UrlType type;
private String value;
private String context;
private String var;
private int scope = PageContext.PAGE_SCOPE;
private boolean escapeXml = false;
// tag lifecycle
@Override
public int doStartTag() throws JspException {
params = new LinkedList<Param>();
templateParams = new HashSet<String>();
return EVAL_BODY_INCLUDE;
}
@Override
public int doEndTag() throws JspException {
String url = createUrl();
if (var == null) {
// print the url to the writer
try {
pageContext.getOut().print(url);
}
catch (IOException e) {
throw new JspException(e);
}
}
else {
// store the url as a variable
pageContext.setAttribute(var, url, scope);
}
return EVAL_PAGE;
}
// from ParamAware
public void addParam(Param param) {
params.add(param);
}
// support methods
/**
* Build the URL for the tag from the tag attributes and parameters.
*
* @return the URL value as a String
* @throws JspException
*/
private String createUrl() throws JspException {
HttpServletRequest request = (HttpServletRequest) pageContext
.getRequest();
HttpServletResponse response = (HttpServletResponse) pageContext
.getResponse();
StringBuilder url = new StringBuilder();
if (type == UrlType.CONTEXT_RELATIVE) {
// add application context to url
if (context == null) {
url.append(request.getContextPath());
}
else {
url.append(context);
}
}
if (type != UrlType.RELATIVE && type != UrlType.ABSOLUTE
&& !value.startsWith("/")) {
url.append("/");
}
url.append(replaceUriTemplateParams(value, params, templateParams));
url.append(createQueryString(params, templateParams,
(url.indexOf("?") == -1)));
String urlStr;
if (type != UrlType.ABSOLUTE) {
// add the session identifier if needed
urlStr = response.encodeURL(url.toString());
}
else {
// do not embed the session identifier in a remote link
urlStr = url.toString();
}
if (escapeXml) {
urlStr = escapeXml(urlStr);
}
return urlStr;
}
/**
* Builds the query string from available parameters that have not already
* been applied as template params.
*
* <p>
* The names and values of parameters are URL encoded.
*
* @param params the parameters to build the query string from
* @param usedParams set of parameter names that have been applied as
* template params
* @param includeQueryStringDelimiter true if the query string should start
* with a '?' instead of '&'
* @return the query string
* @throws JspException
*/
protected String createQueryString(List<Param> params,
Set<String> usedParams, boolean includeQueryStringDelimiter)
throws JspException {
StringBuilder qs = new StringBuilder();
for (Param param : params) {
if (!usedParams.contains(param.getName())
&& param.getName() != null && !"".equals(param.getName())) {
if (includeQueryStringDelimiter && qs.length() == 0) {
qs.append("?");
}
else {
qs.append("&");
}
qs.append(urlEncode(param.getName()));
if (param.getValue() != null) {
qs.append("=");
qs.append(urlEncode(param.getValue()));
}
}
}
return qs.toString();
}
/**
* Replaces template markers in the URL matching available parameters. The
* name of matched parameters are added to the used parameters set.
*
* <p>
* Parameter values are URL encoded.
*
* @param uri the URL with template parameters to replace
* @param params parameters used to replace template markers
* @param usedParams set of template parameter names that have been replaced
* @return the URL with template parameters replaced
* @throws JspException
*/
protected String replaceUriTemplateParams(String uri, List<Param> params,
Set<String> usedParams) throws JspException {
for (Param param : params) {
String template = URL_TEMPLATE_DELIMITER_PREFIX + param.getName()
+ URL_TEMPLATE_DELIMITER_SUFFIX;
if (uri.contains(template)) {
usedParams.add(param.getName());
uri = uri.replace(template, urlEncode(param.getValue()));
}
}
return uri;
}
/**
* URL encode the provided string using the character encoding for the
* response.
*
* @param value the value to encode
* @return the URL encoded value
* @throws JspException if the character encoding is invalid
*/
protected String urlEncode(String value) throws JspException {
if (value == null) {
return null;
}
try {
return URLEncoder.encode(value, pageContext.getResponse()
.getCharacterEncoding());
}
catch (UnsupportedEncodingException e) {
throw new JspException(e);
}
}
/**
* XML entity encode the provided string. &#38;, &#60;, &#62;, &#39; and
* &#34; are encoded to their entity values.
*
* @param xml the value to escape
* @return the escaped value
*/
protected String escapeXml(String xml) {
if (xml == null) {
return null;
}
String escapedXml = xml;
for (char xmlChar : XML_CHARS) {
escapedXml = StringUtils.replace(escapedXml, String
.valueOf(xmlChar), entityValue(xmlChar));
}
return escapedXml;
}
/**
* Convert a character value to a XML entity value. The decimal value of the
* character is used.
*
* <p>
* For example, 'A' is converted to "&amp;#65;".
*
* @param xmlChar the character to encode
* @return the entity value
*/
protected String entityValue(char xmlChar) {
return new StringBuilder().append("&#").append(
Integer.toString(xmlChar)).append(";").toString();
}
// tag attribute accessors
/**
* Sets the value of the URL
*/
public void setValue(String value) {
if (value.contains(URL_TYPE_ABSOLUTE)) {
type = UrlType.ABSOLUTE;
this.value = value;
}
else if (value.startsWith("/")) {
type = UrlType.CONTEXT_RELATIVE;
this.value = value;
}
else {
type = UrlType.RELATIVE;
this.value = value;
}
}
/**
* Sets the context path for the URL. Defaults to the current context
*/
public void setContext(String context) {
if (context.startsWith("/")) {
this.context = context;
}
else {
this.context = "/" + context;
}
}
/**
* Sets the variable name to expose the URL under. Defaults to rendering the
* URL to the current JspWriter
*/
public void setVar(String var) {
this.var = var;
}
/**
* Sets the scope to export the URL variable to. This attribute has no
* meaning unless var is also defined.
*
* @param scope the string name of the scope
* @see TagUtils#getScope(String)
*/
public void setScope(String scope) {
this.scope = TagUtils.getScope(scope);
}
/**
* Instructs the tag to XML entity encode the resulting URL.
* <p>
* Defaults to false to maintain compatibility with the JSTL c:url tag.
* <p>
* <b>NOTE:</b> Strongly recommended to set as 'true' when rendering
* directly to the JspWriter in an XML or HTML based file.
*
* @param escapeXml string representation of a boolean
* @see Boolean#valueOf(String)
*/
public void setEscapeXml(String escapeXml) {
this.escapeXml = Boolean.valueOf(escapeXml);
}
}

View File

@ -342,4 +342,71 @@
</attribute>
</tag>
<tag>
<name>url</name>
<tag-class>org.springframework.web.servlet.tags.UrlTag</tag-class>
<body-content>JSP</body-content>
<description>URL tag based on the JSTL c:url tag. This variant is fully
backwards compatible with the standard tag. Enhancements include support
for URL template parameters.</description>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>The URL to build. This value can include template place holders
that are replaced with the URL encoded value of the named parameter. Parameters
must be defined using the param tag inside the body of this tag.</description>
</attribute>
<attribute>
<name>context</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>Specifies a remote application context. The default is the
current application context.</description>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>The name of the variable to export the URL value to.</description>
</attribute>
<attribute>
<name>scope</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>The scope for the var. 'application', 'session', 'request' and
'page' scopes are supported. Defaults to page scope. This attribute has no
effect unless the var attribute is also defined.</description>
</attribute>
<attribute>
<name>escapeXml</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>Escape XML special characters in the resulting URL. 'true' and
'false' are supported. Defaults to 'false' to maintain compatibility with
the JSTL c:url tag. Strongly recommended to set as 'true' when rendering
directly to the JspWriter in an XML or HTML based file.</description>
</attribute>
</tag>
<tag>
<name>param</name>
<tag-class>org.springframework.web.servlet.tags.ParamTag</tag-class>
<body-content>JSP</body-content>
<description>Parameter tag based on the JSTL c:param tag. The sole purpose is to
support params inside the spring:url tag.</description>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>The name of the parameter.</description>
</attribute>
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>The value of the parameter.</description>
</attribute>
</tag>
</taglib>

View File

@ -0,0 +1,109 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import org.springframework.mock.web.MockBodyContent;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Unit tests for ParamTag
*
* @author Scott Andrews
*/
public class ParamTagTests extends AbstractTagTests {
private ParamTag tag;
private MockParamSupportTag parent;
@Override
protected void setUp() throws Exception {
PageContext context = createPageContext();
parent = new MockParamSupportTag();
tag = new ParamTag();
tag.setPageContext(context);
tag.setParent(parent);
}
public void testParamWithNameAndValue() throws JspException {
tag.setName("name");
tag.setValue("value");
int action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("name", parent.getParam().getName());
assertEquals("value", parent.getParam().getValue());
}
public void testParamWithBodyValue() throws JspException {
tag.setName("name");
tag.setBodyContent(new MockBodyContent("value",
new MockHttpServletResponse()));
int action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("name", parent.getParam().getName());
assertEquals("value", parent.getParam().getValue());
}
public void testParamWithNullValue() throws JspException {
tag.setName("name");
int action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("name", parent.getParam().getName());
assertNull(parent.getParam().getValue());
}
public void testParamWithNoParent() {
tag.setName("name");
tag.setValue("value");
tag.setParent(null);
try {
tag.doEndTag();
fail("expected JspException");
}
catch (JspException e) {
// we want this
}
}
private class MockParamSupportTag extends TagSupport implements ParamAware {
private Param param;
public void addParam(Param param) {
this.param = param;
}
public Param getParam() {
return param;
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
import junit.framework.TestCase;
/**
* Unit tests for Param
*
* @author Scott Andrews
*/
public class ParamTests extends TestCase {
private Param param;
@Override
protected void setUp() throws Exception {
param = new Param();
}
public void testName() {
param.setName("name");
assertEquals("name", param.getName());
}
public void testValue() {
param.setValue("value");
assertEquals("value", param.getValue());
}
public void testNullDefaults() {
assertNull(param.getName());
assertNull(param.getValue());
}
}

View File

@ -0,0 +1,571 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.springframework.web.servlet.tags;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockPageContext;
import org.springframework.util.ReflectionUtils;
/**
* Unit tests for UrlTag
*
* @author Scott Andrews
*/
public class UrlTagTests extends AbstractTagTests {
private UrlTag tag;
private MockPageContext context;
@Override
protected void setUp() throws Exception {
context = createPageContext();
tag = new UrlTag();
tag.setPageContext(context);
}
public void testParamSupport() {
assertTrue(tag instanceof ParamAware);
}
public void testDoStartTag() throws JspException {
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
}
public void testDoEndTag() throws JspException {
tag.setValue("url/path");
tag.doStartTag();
int action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
}
public void testVarDefaultScope() throws JspException {
tag.setValue("url/path");
tag.setVar("var");
tag.doStartTag();
tag.doEndTag();
assertEquals("url/path", context.getAttribute("var",
PageContext.PAGE_SCOPE));
}
public void testVarExplicitScope() throws JspException {
tag.setValue("url/path");
tag.setVar("var");
tag.setScope("request");
tag.doStartTag();
tag.doEndTag();
assertEquals("url/path", context.getAttribute("var",
PageContext.REQUEST_SCOPE));
}
public void testSetEscapeXmlDefault() throws JspException {
tag.setValue("url/path");
tag.setVar("var");
tag.doStartTag();
Param param = new Param();
param.setName("n me");
param.setValue("v&l=e");
tag.addParam(param);
param = new Param();
param.setName("name");
param.setValue("value2");
tag.addParam(param);
tag.doEndTag();
assertEquals("url/path?n+me=v%26l%3De&name=value2", context
.getAttribute("var"));
}
public void testSetEscapeXmlFalse() throws JspException {
tag.setValue("url/path");
tag.setVar("var");
tag.setEscapeXml("false");
tag.doStartTag();
Param param = new Param();
param.setName("n me");
param.setValue("v&l=e");
tag.addParam(param);
param = new Param();
param.setName("name");
param.setValue("value2");
tag.addParam(param);
tag.doEndTag();
assertEquals("url/path?n+me=v%26l%3De&name=value2", context
.getAttribute("var"));
}
public void testSetEscapeXmlTrue() throws JspException {
tag.setValue("url/path");
tag.setVar("var");
tag.setEscapeXml("true");
tag.doStartTag();
Param param = new Param();
param.setName("n me");
param.setValue("v&l=e");
tag.addParam(param);
param = new Param();
param.setName("name");
param.setValue("value2");
tag.addParam(param);
tag.doEndTag();
assertEquals("url/path?n+me=v%26l%3De&#38;name=value2", context
.getAttribute("var"));
}
public void testCreateQueryStringNoParams() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("", queryString);
}
public void testCreateQueryStringOneParam() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("value");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("?name=value", queryString);
}
public void testCreateQueryStringOneParamForExsistingQueryString()
throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("value");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, false);
assertEquals("&name=value", queryString);
}
public void testCreateQueryStringOneParamEmptyValue() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("?name=", queryString);
}
public void testCreateQueryStringOneParamNullValue() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue(null);
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("?name", queryString);
}
public void testCreateQueryStringOneParamAlreadyUsed() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("value");
params.add(param);
usedParams.add("name");
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("", queryString);
}
public void testCreateQueryStringTwoParams() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("value");
params.add(param);
param = new Param();
param.setName("name");
param.setValue("value2");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("?name=value&name=value2", queryString);
}
public void testCreateQueryStringUrlEncoding() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("n me");
param.setValue("v&l=e");
params.add(param);
param = new Param();
param.setName("name");
param.setValue("value2");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("?n+me=v%26l%3De&name=value2", queryString);
}
public void testCreateQueryStringParamNullName() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName(null);
param.setValue("value");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("", queryString);
}
public void testCreateQueryStringParamEmptyName() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("");
param.setValue("value");
params.add(param);
String queryString = tag.createQueryString(params, usedParams, true);
assertEquals("", queryString);
}
public void testReplaceUriTemplateParamsNoParams() throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
String uri = tag.replaceUriTemplateParams("url/path", params,
usedParams);
assertEquals("url/path", uri);
assertEquals(0, usedParams.size());
}
public void testReplaceUriTemplateParamsTemplateWithoutParamMatch()
throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
String uri = tag.replaceUriTemplateParams("url/{path}", params,
usedParams);
assertEquals("url/{path}", uri);
assertEquals(0, usedParams.size());
}
public void testReplaceUriTemplateParamsTemplateWithParamMatch()
throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("value");
params.add(param);
String uri = tag.replaceUriTemplateParams("url/{name}", params,
usedParams);
assertEquals("url/value", uri);
assertEquals(1, usedParams.size());
assertTrue(usedParams.contains("name"));
}
public void testReplaceUriTemplateParamsTemplateWithParamMatchNamePreEncoding()
throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("n me");
param.setValue("value");
params.add(param);
String uri = tag.replaceUriTemplateParams("url/{n me}", params,
usedParams);
assertEquals("url/value", uri);
assertEquals(1, usedParams.size());
assertTrue(usedParams.contains("n me"));
}
public void testReplaceUriTemplateParamsTemplateWithParamMatchValueEncoded()
throws JspException {
List<Param> params = new LinkedList<Param>();
Set<String> usedParams = new HashSet<String>();
Param param = new Param();
param.setName("name");
param.setValue("v lue");
params.add(param);
String uri = tag.replaceUriTemplateParams("url/{name}", params,
usedParams);
assertEquals("url/v+lue", uri);
assertEquals(1, usedParams.size());
assertTrue(usedParams.contains("name"));
}
public void testCreateUrlRemoteServer() throws JspException {
tag.setValue("http://www.springframework.org/");
tag.doStartTag();
// String uri = tag.createUrl();
String uri = invokeCreateUrl(tag);
assertEquals("http://www.springframework.org/", uri);
}
public void testCreateUrlRelative() throws JspException {
tag.setValue("url/path");
tag.doStartTag();
String uri = invokeCreateUrl(tag);
assertEquals("url/path", uri);
}
public void testCreateUrlLocalContext() throws JspException {
((MockHttpServletRequest) context.getRequest())
.setContextPath("/app-context");
tag.setValue("/url/path");
tag.doStartTag();
String uri = invokeCreateUrl(tag);
assertEquals("/app-context/url/path", uri);
}
public void testCreateUrlRemoteContext() throws JspException {
((MockHttpServletRequest) context.getRequest())
.setContextPath("/app-context");
tag.setValue("/url/path");
tag.setContext("some-other-context");
tag.doStartTag();
String uri = invokeCreateUrl(tag);
assertEquals("/some-other-context/url/path", uri);
}
public void testCreateUrlRemoteContextWithSlash() throws JspException {
((MockHttpServletRequest) context.getRequest())
.setContextPath("/app-context");
tag.setValue("/url/path");
tag.setContext("/some-other-context");
tag.doStartTag();
String uri = invokeCreateUrl(tag);
assertEquals("/some-other-context/url/path", uri);
}
public void testCreateUrlWithParams() throws JspException {
tag.setValue("url/path");
tag.doStartTag();
Param param = new Param();
param.setName("name");
param.setValue("value");
tag.addParam(param);
param = new Param();
param.setName("n me");
param.setValue("v lue");
tag.addParam(param);
String uri = invokeCreateUrl(tag);
assertEquals("url/path?name=value&n+me=v+lue", uri);
}
public void testCreateUrlWithTemplateParams() throws JspException {
tag.setValue("url/{name}");
tag.doStartTag();
Param param = new Param();
param.setName("name");
param.setValue("value");
tag.addParam(param);
param = new Param();
param.setName("n me");
param.setValue("v lue");
tag.addParam(param);
String uri = invokeCreateUrl(tag);
assertEquals("url/value?n+me=v+lue", uri);
}
public void testCreateUrlWithParamAndExsistingQueryString()
throws JspException {
tag.setValue("url/path?foo=bar");
tag.doStartTag();
Param param = new Param();
param.setName("name");
param.setValue("value");
tag.addParam(param);
String uri = invokeCreateUrl(tag);
assertEquals("url/path?foo=bar&name=value", uri);
}
public void testUrlEncode() throws JspException {
assertEquals("my+name", tag.urlEncode("my name"));
}
public void testUrlEncodeNull() throws JspException {
assertNull(tag.urlEncode(null));
}
public void testUrlEncodeBadEncoding() {
context.getResponse().setCharacterEncoding("bad encoding");
try {
tag.urlEncode("my name");
fail("expected JspException");
}
catch (JspException e) {
// we want this
}
}
public void testEscapeXml() {
assertEquals("&#60;script type=&#34;text/javascript&#34;&#62;", tag
.escapeXml("<script type=\"text/javascript\">"));
}
public void testEscapeXmlNull() {
assertNull(tag.escapeXml(null));
}
public void testEntityValueAmpersand() {
assertEquals("&#38;", tag.entityValue('&'));
}
public void testEntityValueLessThan() {
assertEquals("&#60;", tag.entityValue('<'));
}
public void testEntityValueGreaterThan() {
assertEquals("&#62;", tag.entityValue('>'));
}
public void testEntityValueSingleQuote() {
assertEquals("&#39;", tag.entityValue('\''));
}
public void testEntityValueDoubleQuote() {
assertEquals("&#34;", tag.entityValue('"'));
}
public void testJspWriterOutput() {
// TODO assert that the output to the JspWriter is the expected output
}
public void testServletRepsonseEncodeUrl() {
// TODO assert that HttpServletResponse.encodeURL(String) is invoked for
// non absolute urls
}
// support methods
private String invokeCreateUrl(UrlTag tag) {
Method createUrl = ReflectionUtils.findMethod(tag.getClass(),
"createUrl");
ReflectionUtils.makeAccessible(createUrl);
return (String) ReflectionUtils.invokeMethod(createUrl, tag);
}
}