You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@apache.org on 2001/02/09 20:33:12 UTC
cvs commit: jakarta-struts/src/share/org/apache/struts/taglib/logic LocalStrings.properties RedirectTag.java
craigmcc 01/02/09 11:33:11
Modified: src/doc struts-html.xml struts-logic.xml
src/share/org/apache/struts/taglib/logic
LocalStrings.properties RedirectTag.java
Log:
Enhance the <logic:redirect> tag so that it has the same three options for
choosing the destination URL that the <html:link> tag has:
- "href" attribute, used unchanged
- "forward" attribute, picks context-relative path by logical name
- "page" attribute, specifies context-relative path starting with "/"
Revision Changes Path
1.7 +3 -2 jakarta-struts/src/doc/struts-html.xml
Index: struts-html.xml
===================================================================
RCS file: /home/cvs/jakarta-struts/src/doc/struts-html.xml,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- struts-html.xml 2001/02/07 23:10:42 1.6
+++ struts-html.xml 2001/02/09 19:33:10 1.7
@@ -1409,8 +1409,8 @@
image will be taken from the attributes of this tag.</p>
<p>The base URL for this image is calculated based on
- the value specified in <code>src</code> or <code>page</code>.
- You <strong>must</strong> specify exactly one of these
+ the value specified in <code>src</code> or <code>page</code>.
+ You <strong>must</strong> specify exactly one of these
attributes.</p>
<p>Normally, the <code>src</code> or <code>page</code> that
@@ -2956,6 +2956,7 @@
</tag>
+
<tag>
<name>reset</name>
1.6 +216 -22 jakarta-struts/src/doc/struts-logic.xml
Index: struts-logic.xml
===================================================================
RCS file: /home/cvs/jakarta-struts/src/doc/struts-logic.xml,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- struts-logic.xml 2000/12/29 20:36:54 1.5
+++ struts-logic.xml 2001/02/09 19:33:10 1.6
@@ -1189,30 +1189,224 @@
</tag>
- <tag>
+ <tag>
- <name>redirect</name>
- <summary>
- Perform an HTTP redirect to the specified URL.
- </summary>
- <tagclass>org.apache.struts.taglib.logic.RedirectTag</tagclass>
- <bodycontent>empty</bodycontent>
- <info>
- <p>Performs a <code>HttpServletResponse.sendRedirect()</code> to the
- specified URL, after applying URL rewriting as needed.</p>
- </info>
-
- <attribute>
- <name>href</name>
- <required>true</required>
- <rtexprvalue>true</rtexprvalue>
- <info>
- <p>The relative or absolute URL to which the client should be
- redirected.</p>
- </info>
- </attribute>
+ <name>redirect</name>
+ <summary>Render an HTTP Redirect</summary>
+ <tagclass>org.apache.struts.taglib.logic.RedirectTag</tagclass>
+ <body-content>empty</body-content>
+ <info>
- </tag>
+ <p>Performs an <code>HttpServletResponse.sendRedirect()</code>
+ call to the hyperlink specified by the attributes to this
+ tag. URL rewriting will be applied automatically, to
+ maintain session state in the absence of cookies.</p>
+
+ <p>The base URL for this redirect is calculated based on
+ which of the following attributes you specify (you must
+ specify exactly one of them):</p>
+ <ul>
+ <li><em>forward</em> - Use the value of this attribute as the
+ name of a global <code>ActionForward</code> to be looked
+ up, and use the context-relative URI found there.</li>
+ <li><em>href</em> - Use the value of this attribute unchanged.
+ </li>
+ <li><em>page</em> - Use the value of this attribute as a
+ context-relative URI, and generate a server-relative URI
+ by including the context path.</li>
+ </ul>
+
+ <p>Normally, the redirect you specify with one of the
+ attributes described in the previous paragraph will be left
+ unchanged (other than URL rewriting if necessary). However,
+ there are two ways you can append one or more dynamically
+ defined query parameters to the hyperlink -- specify a single
+ parameter with the <code>paramId</code> attribute (and its
+ associated attributes to select the value), or specify the
+ <code>name</code> (and optional <code>property</code>)
+ attributes to select a <code>java.util.Map</code> bean that
+ contains one or more parameter ids and corresponding values.
+ </p>
+
+ <p>To specify a single parameter, use the <code>paramId</code>
+ attribute to define the name of the request parameter to be
+ submitted. To specify the corresponding value, use one of the
+ following approaches:</p>
+ <ul>
+ <li><em>Specify only the <code>paramName</code> attribute</em>
+ - The named JSP bean (optionally scoped by the value of the
+ <code>paramScope</code> attribute) must identify a value
+ that can be converted to a String.</li>
+ <li><em>Specify both the <code>paramName</code> and
+ <code>paramProperty</code> attributes</em> - The specified
+ property getter method will be called on the JSP bean
+ identified by the <code>paramName</code> (and optional
+ <code>paramScope</code>) attributes, in order to select
+ a value that can be converted to a String.</li>
+ </ul>
+
+ <p>If you prefer to specify a <code>java.util.Map</code> that
+ contains all of the request parameters to be added to the
+ hyperlink, use one of the following techniques:</p>
+ <ul>
+ <li><em>Specify only the <code>name</code> attribute</em> -
+ The named JSP bean (optionally scoped by the value of
+ the <code>scope</code> attribute) must identify a
+ <code>java.util.Map</code> containing the parameters.</li>
+ <li><em>Specify both <code>name</code> and
+ <code>property</code> attributes</em> - The specified
+ property getter method will be called on the bean
+ identified by the <code>name</code> (and optional
+ <code>scope</code>) attributes, in order to return the
+ <code>java.util.Map</code> containing the parameters.</li>
+ </ul>
+
+ <p>As the <code>Map</code> is processed, the keys are assumed
+ to be the names of query parameters to be appended to the
+ hyperlink. The value associated with each key must be either
+ a String or a String array representing the parameter value(s).
+ If a String array is specified, more than one value for the
+ same query parameter name will be created.</p>
+ </info>
+
+ <attribute>
+ <name>forward</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>Logical name of a global <code>ActionForward</code> that
+ contains the actual content-relative URI of the destination
+ of this redirect. This URI may be dynamically
+ modified by the inclusion of query parameters, as described
+ in the tag description. You <strong>must</strong> specify
+ exactly one of the <code>forward</code> attribute, the
+ <code>href</code> attribute, the <code>linkName</code>
+ attribute, or the <code>page</code> attribute.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>href</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The URL to which this redirect will transfer control.
+ This URL may be dynamically modified
+ by the inclusion of query parameters, as described in the
+ tag description. You <strong>must</strong> specify
+ exactly one of the <code>forward</code> attribute, the
+ <code>href</code> attribute, the <code>linkName</code>
+ attribute, or the <code>page</code> attribute.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>name</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The name of a JSP bean that contains a <code>Map</code>
+ representing the query parameters (if <code>property</code>
+ is not specified), or a JSP bean whose property getter is
+ called to return a <code>Map</code> (if <code>property</code>
+ is specified).</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>page</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The context-relative path (beginning with a "/"
+ character) to which this hyperlink will transfer control
+ if activated. This hyperlink may be dynamically modified
+ by the inclusion of query parameters, as described in the
+ tag description. You <strong>must</strong> specify exactly
+ one of the <code>forward</code> attribute, the
+ <code>href</code> attribute, the <code>linkName</code>
+ attribute, or the <code>page</code> attribute.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>paramId</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The name of the request parameter that will be dynamically
+ added to the generated hyperlink. The corresponding value is
+ defined by the <code>paramName</code> and (optional)
+ <code>paramProperty</code> attributes, optionally scoped by
+ the <code>paramScope</code> attributel</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>paramName</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The name of a JSP bean that is a String containing the
+ value for the request parameter named by <code>paramId</code>
+ (if <code>paramProperty</code> is not specified), or a JSP
+ bean whose property getter is called to return a String
+ (if <code>paramProperty</code> is specified). The JSP bean
+ is constrained to the bean scope specified by the
+ <code>paramScope</code> property, if it is specified.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>paramProperty</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The name of a property of the bean specified by the
+ <code>paramName</code> attribute, whose return value must
+ be a String containing the value of the request parameter
+ (named by the <code>paramId</code> attribute) that will be
+ dynamically added to this hyperlink.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>paramScope</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The scope within which to search for the bean specified
+ by the <code>paramName</code> attribute. If not specified,
+ all scopes are searched.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>property</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The name of a property of the bean specified by the
+ <code>name</code> attribute, whose return value must be
+ a <code>java.util.Map</code> containing the query parameters
+ to be added to the hyperlink. You <strong>must</strong>
+ specify the <code>name</code> attribute if you specify
+ this attribute.</p>
+ </info>
+ </attribute>
+
+ <attribute>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <info>
+ <p>The scope within which to search for the bean specified
+ by the <code>name</code> attribute. If not specified, all
+ scopes are searched.</p>
+ </info>
+ </attribute>
+
+ </tag>
</taglib>
1.3 +1 -0 jakarta-struts/src/share/org/apache/struts/taglib/logic/LocalStrings.properties
Index: LocalStrings.properties
===================================================================
RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/logic/LocalStrings.properties,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- LocalStrings.properties 2001/01/16 01:08:18 1.2
+++ LocalStrings.properties 2001/02/09 19:33:11 1.3
@@ -13,4 +13,5 @@
logic.property=Exception accessing property {1} for bean {0}: {2}
logic.selector=No selector attribute (cookie/header/name/parameter) was specified
logic.variable=Cannot compare null variable to value {0}
+redirect.destination=You must specify exactly one of 'forward', 'href', or 'page'
redirect.redirect=Exception redirecting to {0}: {1}
1.5 +388 -29 jakarta-struts/src/share/org/apache/struts/taglib/logic/RedirectTag.java
Index: RedirectTag.java
===================================================================
RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/logic/RedirectTag.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- RedirectTag.java 2000/10/30 06:02:23 1.4
+++ RedirectTag.java 2001/02/09 19:33:11 1.5
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/logic/RedirectTag.java,v 1.4 2000/10/30 06:02:23 craigmcc Exp $
- * $Revision: 1.4 $
- * $Date: 2000/10/30 06:02:23 $
+ * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/logic/RedirectTag.java,v 1.5 2001/02/09 19:33:11 craigmcc Exp $
+ * $Revision: 1.5 $
+ * $Date: 2001/02/09 19:33:11 $
*
* ====================================================================
*
@@ -64,22 +64,30 @@
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionForwards;
import org.apache.struts.util.BeanUtils;
import org.apache.struts.util.MessageResources;
+import org.apache.struts.util.PropertyUtils;
+import org.apache.struts.util.RequestUtils;
/**
- * Perform a sendRedirect() to the specified URL, and skip evaluating
- * the remainder of the current page.
+ * Generate a URL-encoded redirect to the specified URI.
*
* @author Craig R. McClanahan
- * @version $Revision: 1.4 $ $Date: 2000/10/30 06:02:23 $
+ * @version $Revision: 1.5 $ $Date: 2001/02/09 19:33:11 $
*/
public class RedirectTag extends TagSupport {
@@ -89,16 +97,30 @@
/**
- * The relative or absolute URL to which the client should be redirected.
+ * The logical forward name from which to retrieve the redirect URI.
*/
+ protected String forward = null;
+
+ public String getForward() {
+ return (this.forward);
+ }
+
+ public void setForward(String forward) {
+ this.forward = forward;
+ }
+
+
+ /**
+ * The redirect URI.
+ */
protected String href = null;
public String getHref() {
- return (this.href);
+ return (this.href);
}
public void setHref(String href) {
- this.href = href;
+ this.href = href;
}
@@ -106,58 +128,395 @@
* The message resources for this package.
*/
protected static MessageResources messages =
- MessageResources.getMessageResources
- ("org.apache.struts.taglib.logic.LocalStrings");
+ MessageResources.getMessageResources
+ ("org.apache.struts.taglib.logic.LocalStrings");
+
+
+ /**
+ * The JSP bean name for query parameters.
+ */
+ protected String name = null;
+
+ public String getName() {
+ return (this.name);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+
+ /**
+ * The context-relative page URL (beginning with a slash) to which
+ * this redirect will be rendered.
+ */
+ protected String page = null;
+
+ public String getPage() {
+ return (this.page);
+ }
+
+ public void setPage(String page) {
+ this.page = page;
+ }
+
+ /**
+ * The single-parameter request parameter name to generate.
+ */
+ protected String paramId = null;
+
+ public String getParamId() {
+ return (this.paramId);
+ }
+
+ public void setParamId(String paramId) {
+ this.paramId = paramId;
+ }
+
+ /**
+ * The single-parameter JSP bean name.
+ */
+ protected String paramName = null;
+
+ public String getParamName() {
+ return (this.paramName);
+ }
+
+ public void setParamName(String paramName) {
+ this.paramName = paramName;
+ }
+
+
+ /**
+ * The single-parameter JSP bean property.
+ */
+ protected String paramProperty = null;
+
+ public String getParamProperty() {
+ return (this.paramProperty);
+ }
+
+ public void setParamProperty(String paramProperty) {
+ this.paramProperty = paramProperty;
+ }
+
+
+ /**
+ * The single-parameter JSP bean scope.
+ */
+ protected String paramScope = null;
+
+ public String getParamScope() {
+ return (this.paramScope);
+ }
+
+ public void setParamScope(String paramScope) {
+ this.paramScope = paramScope;
+ }
+
+
+ /**
+ * The JSP bean property name for query parameters.
+ */
+ protected String property = null;
+
+ public String getProperty() {
+ return (this.property);
+ }
+
+ public void setProperty(String property) {
+ this.property = property;
+ }
+
+
+ /**
+ * The scope of the bean specified by the name property, if any.
+ */
+ protected String scope = null;
+
+ public String getScope() {
+ return (this.scope);
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+
// --------------------------------------------------------- Public Methods
/**
- * Defer processing until the end of this tag is encountered.
+ * Defer generation until the end of this tag is encountered.
*
* @exception JspException if a JSP exception has occurred
*/
public int doStartTag() throws JspException {
- return (SKIP_BODY);
+ return (SKIP_BODY);
}
/**
- * Render a redirect to the specified hyperlink, and skip the
- * remainder of the current page.
+ * Render the redirect and skip the remainder of this page.
*
* @exception JspException if a JSP exception has occurred
*/
public int doEndTag() throws JspException {
- // Perform the requested redirect
+ // Perform the redirection
HttpServletResponse response =
(HttpServletResponse) pageContext.getResponse();
- try {
- response.sendRedirect(response.encodeRedirectURL(href));
- } catch (IOException e) {
- pageContext.setAttribute(Action.EXCEPTION_KEY, e,
- PageContext.REQUEST_SCOPE);
- throw new JspException
- (messages.getMessage("redirect.redirect", href, e.toString()));
- }
+ String hyperlink = BeanUtils.filter(hyperlink());
+ try {
+ response.sendRedirect(response.encodeRedirectURL(hyperlink));
+ } catch (IOException e) {
+ throw new JspException
+ (messages.getMessage("common.io"));
+ }
- // Skip the remainder of the current page
- return (SKIP_PAGE);
+ // Skip the remainder of this apge
+ return (SKIP_PAGE);
}
/**
- * Release all allocated resources.
+ * Release any acquired resources.
*/
public void release() {
+
+ super.release();
+ forward = null;
+ href = null;
+ name = null;
+ page = null;
+ paramId = null;
+ paramName = null;
+ paramProperty = null;
+ paramScope = null;
+ property = null;
+ scope = null;
+
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Return the specified hyperlink, modified as necessary with optional
+ * request parameters. Return <code>null</code> if we are generating
+ * a name anchor rather than a hyperlink.
+ *
+ * @exception JspException if an error occurs preparing the hyperlink
+ */
+ protected String hyperlink() throws JspException {
+
+ // Validate the number of href specifiers that were specified
+ int n = 0;
+ if (forward != null)
+ n++;
+ if (href != null)
+ n++;
+ if (page != null)
+ n++;
+ if (n != 1) {
+ JspException e = new JspException
+ (messages.getMessage("redirect.destination"));
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw e;
+ }
+
+ // Start with an unadorned "href"
+ String href = null;
+
+ // If "href" was specified, use it as is
+ if (this.href != null) {
+ href = this.href;
+ }
+
+ // If "forward" was specified, compute the "href" to forward to
+ else if (forward != null) {
+ ActionForwards forwards = (ActionForwards)
+ pageContext.getAttribute(Action.FORWARDS_KEY,
+ PageContext.APPLICATION_SCOPE);
+ if (forwards == null)
+ throw new JspException
+ (messages.getMessage("linkTag.forwards"));
+ ActionForward forward = forwards.findForward(this.forward);
+ if (forward == null)
+ throw new JspException
+ (messages.getMessage("linkTag.forward"));
+ HttpServletRequest request =
+ (HttpServletRequest) pageContext.getRequest();
+ href = RequestUtils.absoluteURL(request, forward.getPath());
+ }
+
+ // If "page" was specified, compute the "href" to forward to
+ else if (page != null) {
+ HttpServletRequest request =
+ (HttpServletRequest) pageContext.getRequest();
+ href = RequestUtils.absoluteURL(request, page);
+ }
+
+ // Append a single-parameter name and value, if requested
+ if ((paramId != null) && (paramName != null)) {
+ if (href.indexOf('?') < 0)
+ href += '?';
+ else
+ href += '&';
+ href += paramId;
+ href += '=';
+ Object bean = RequestUtils.lookup(pageContext,
+ paramName, paramScope);
+ if (bean != null) {
+ if (paramProperty == null)
+ href += bean.toString();
+ else {
+ try {
+ Object value =
+ PropertyUtils.getProperty(bean, paramProperty);
+ if (value != null)
+ href += value.toString();
+ } catch (IllegalAccessException e) {
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("getter.access",
+ paramProperty, paramName));
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getTargetException();
+ pageContext.setAttribute(Action.EXCEPTION_KEY, t,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("getter.result",
+ paramProperty, t.toString()));
+ } catch (NoSuchMethodException e) {
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("getter.method",
+ paramProperty, paramName));
+ }
+ }
+ }
+ }
+
+ // Just return the "href" attribute if there is no bean to look up
+ if ((property != null) && (name == null)) {
+ JspException e = new JspException
+ (messages.getMessage("getter.name"));
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw e;
+ }
+ if (name == null)
+ return (href);
+
+ // Look up the map we will be using
+ Object bean = RequestUtils.lookup(pageContext, name, scope);
+ if (bean == null) {
+ JspException e = new JspException
+ (messages.getMessage("getter.bean", name));
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw e;
+ }
+ Map map = null;
+ if (property == null) {
+ try {
+ map = (Map) bean;
+ } catch (ClassCastException e) {
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("linkTag.type"));
+ }
+ } else {
+ try {
+ map = (Map) PropertyUtils.getProperty(bean, property);
+ if (map == null) {
+ JspException e = new JspException
+ (messages.getMessage("getter.property", property));
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw e;
+ }
+ } catch (IllegalAccessException e) {
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("getter.access", property, name));
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getTargetException();
+ pageContext.setAttribute(Action.EXCEPTION_KEY, t,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("getter.result",
+ property, t.toString()));
+ } catch (ClassCastException e) {
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("linkTag.type"));
+ } catch (NoSuchMethodException e) {
+ pageContext.setAttribute(Action.EXCEPTION_KEY, e,
+ PageContext.REQUEST_SCOPE);
+ throw new JspException
+ (messages.getMessage("getter.method", property, name));
+ }
+ }
+
+ // Append the required query parameters
+ StringBuffer sb = new StringBuffer(href);
+ boolean question = (href.indexOf("?") >= 0);
+ Iterator keys = map.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ Object value = map.get(key);
+ if (value == null) {
+ if (question)
+ sb.append('&');
+ else {
+ sb.append('?');
+ question = true;
+ }
+ sb.append(key);
+ sb.append('=');
+ // Interpret null as "no value specified"
+ } else if (value instanceof String[]) {
+ String values[] = (String[]) value;
+ for (int i = 0; i < values.length; i++) {
+ if (question)
+ sb.append('&');
+ else {
+ sb.append('?');
+ question = true;
+ }
+ sb.append(key);
+ sb.append('=');
+ sb.append(URLEncoder.encode(values[i]));
+ }
+ } else {
+ if (question)
+ sb.append('&');
+ else {
+ sb.append('?');
+ question = true;
+ }
+ sb.append(key);
+ sb.append('=');
+ sb.append(URLEncoder.encode(value.toString()));
+ }
+ }
- super.release();
- href = null;
+ // Return the final result
+ return (sb.toString());
}