polishing

This commit is contained in:
Juergen Hoeller
2009-02-18 23:51:03 +00:00
parent 85bc98ea4b
commit d3d0111439
9 changed files with 154 additions and 205 deletions

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2008 the original author or authors.
*
* Copyright 2002-2009 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.
@@ -17,8 +17,8 @@
package org.springframework.web.servlet.tags;
/**
* Allows implementing tag to utilize nested spring:param tags.
*
* Allows implementing tag to utilize nested <code>spring:param</code> tags.
*
* @author Scott Andrews
* @since 3.0
* @see ParamTag
@@ -26,11 +26,10 @@ package org.springframework.web.servlet.tags;
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
* Callback hook for nested spring:param tags to pass their value
* to the parent tag.
* @param param the result of the nested <code>spring:param</code> tag
*/
public void addParam(Param param);
void addParam(Param param);
}

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2008 the original author or authors.
*
* Copyright 2002-2009 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.
@@ -23,7 +23,6 @@ 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;
@@ -76,12 +75,9 @@ public class UrlTag extends TagSupport implements ParamAware {
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;
@@ -98,21 +94,79 @@ public class UrlTag extends TagSupport implements ParamAware {
private boolean escapeXml = false;
// tag lifecycle
/**
* Sets the value of the URL
*/
public void setValue(String value) {
if (value.contains(URL_TYPE_ABSOLUTE)) {
this.type = UrlType.ABSOLUTE;
this.value = value;
}
else if (value.startsWith("/")) {
this.type = UrlType.CONTEXT_RELATIVE;
this.value = value;
}
else {
this.type = UrlType.RELATIVE;
this.value = value;
}
}
/**
* Set 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;
}
}
/**
* Set 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;
}
/**
* Set the scope to export the URL variable to. This attribute has no
* meaning unless var is also defined.
*/
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.
*/
public void setEscapeXml(String escapeXml) {
this.escapeXml = Boolean.valueOf(escapeXml);
}
public void addParam(Param param) {
this.params.add(param);
}
@Override
public int doStartTag() throws JspException {
params = new LinkedList<Param>();
templateParams = new HashSet<String>();
this.params = new LinkedList<Param>();
this.templateParams = new HashSet<String>();
return EVAL_BODY_INCLUDE;
}
@Override
public int doEndTag() throws JspException {
String url = createUrl();
if (var == null) {
if (this.var == null) {
// print the url to the writer
try {
pageContext.getOut().print(url);
@@ -125,74 +179,50 @@ public class UrlTag extends TagSupport implements ParamAware {
// 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();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
StringBuilder url = new StringBuilder();
if (type == UrlType.CONTEXT_RELATIVE) {
if (this.type == UrlType.CONTEXT_RELATIVE) {
// add application context to url
if (context == null) {
if (this.context == null) {
url.append(request.getContextPath());
}
else {
url.append(context);
url.append(this.context);
}
}
if (type != UrlType.RELATIVE && type != UrlType.ABSOLUTE
&& !value.startsWith("/")) {
if (this.type != UrlType.RELATIVE && this.type != UrlType.ABSOLUTE && !this.value.startsWith("/")) {
url.append("/");
}
url.append(replaceUriTemplateParams(this.value, this.params, this.templateParams));
url.append(createQueryString(this.params, this.templateParams, (url.indexOf("?") == -1)));
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());
String urlStr = url.toString();
if (this.type != UrlType.ABSOLUTE) {
// Add the session identifier if needed
// (Do not embed the session identifier in a remote link!)
urlStr = response.encodeURL(urlStr);
}
else {
// do not embed the session identifier in a remote link
urlStr = url.toString();
}
if (escapeXml) {
if (this.escapeXml) {
urlStr = escapeXml(urlStr);
}
return urlStr;
}
/**
* Builds the query string from available parameters that have not already
* Build 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.
*
* <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
@@ -201,13 +231,13 @@ public class UrlTag extends TagSupport implements ParamAware {
* @return the query string
* @throws JspException
*/
protected String createQueryString(List<Param> params,
Set<String> usedParams, boolean includeQueryStringDelimiter)
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 (!usedParams.contains(param.getName()) && param.getName() != null && !"".equals(param.getName())) {
if (includeQueryStringDelimiter && qs.length() == 0) {
qs.append("?");
}
@@ -221,28 +251,24 @@ public class UrlTag extends TagSupport implements ParamAware {
}
}
}
return qs.toString();
}
/**
* Replaces template markers in the URL matching available parameters. The
* Replace 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.
*
* <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 {
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;
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()));
@@ -252,9 +278,7 @@ public class UrlTag extends TagSupport implements ParamAware {
}
/**
* URL encode the provided string using the character encoding for the
* response.
*
* URL-encode the providedSstring 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
@@ -263,20 +287,17 @@ public class UrlTag extends TagSupport implements ParamAware {
if (value == null) {
return null;
}
try {
return URLEncoder.encode(value, pageContext.getResponse()
.getCharacterEncoding());
return URLEncoder.encode(value, pageContext.getResponse().getCharacterEncoding());
}
catch (UnsupportedEncodingException e) {
throw new JspException(e);
catch (UnsupportedEncodingException ex) {
throw new JspException(ex);
}
}
/**
* 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
*/
@@ -284,95 +305,31 @@ public class UrlTag extends TagSupport implements ParamAware {
if (xml == null) {
return null;
}
String escapedXml = xml;
for (char xmlChar : XML_CHARS) {
escapedXml = StringUtils.replace(escapedXml, String
.valueOf(xmlChar), entityValue(xmlChar));
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;".
*
* 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();
return new StringBuilder().append("&#").append(Integer.toString(xmlChar)).append(";").toString();
}
// tag attribute accessors
/**
* Sets the value of the URL
* Internal enum that classifies URLs by type.
*/
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;
}
}
private enum UrlType {
/**
* 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);
CONTEXT_RELATIVE, RELATIVE, ABSOLUTE
}
}