I wrote this as part of a little framework I'm building and the usage is intended to be from within a filter (to create the request via Mapper.commit()) then inside JavaBean components and Tags to create clean URIs (from a list of parameters via Mapper.createUri()).
Support so far covers:
* Basic Request Mapping (longest pattern is selected)
* Parameter injection
* Prefix/suffix specifications (standard J2EE design)
* Regex pattern requirements on the URI
I'll post the tests in a following post to break things up a bit. There looks like a lot of code to critique but the first 3 files are interfaces and probably more useful to critique compared with their implementation.
Yet to be added:
* A factory which builds a new Mapper from XML or a properties file
Mapping.java
Code: Select all
/*
Interface for Request Mapping rules.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.io.UnsupportedEncodingException;
/**
* Provides the API for a mapping rule in the RequestMapper system.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
public interface Mapping {
/**
* Returns the length of the pattern, excluding wildcards.
* @return int
*/
public int getLength();
/**
* Returns true only if this mapping matches the provided initial request.
* @param HttpServletRequest request
* @return boolean
* @throws UnsupportedEncodingException
*/
public boolean matchesRequest(HttpServletRequest request, String encoding)
throws UnsupportedEncodingException;
/**
* Returns true only if the Map contains the same parameters as this
* mapping does.
* Implied parameters are not required to be in the Map.
* @param Map<String,String> params
* @return boolean
*/
public boolean matchesParameters(Map<String,String> params);
/**
* Commits this Mapping to the HttpServletRequest given.
* The encoding passed may be used in any URL decoding which is needed.
* @param HttpServletRequest request
* @param String encoding
* @return HttpServletRequest
* @throws UnsupportedEncodingException
*/
public HttpServletRequest commit(HttpServletRequest request,
String encoding) throws UnsupportedEncodingException;
/**
* Use the given request parameters to generate a URI from this mapping.
* @param HttpServletRequest request
* @param Map<String,String> params
* @param String encoding
* @return String
* @throws UnsupportedEncodingException
*/
public String createUri(HttpServletRequest request, Map<String,String> params,
String encoding) throws UnsupportedEncodingException;
}
Code: Select all
/*
Interface for the request Mapper.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.io.UnsupportedEncodingException;
/**
* Provides the API for a Mapper class in the RequestMapper system.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
public interface Mapper {
/**
* Adds a new mapping rule to this MappingContainer.
* @param Mapping mapping
*/
public void addMapping(Mapping mapping);
/**
* Commits this Mapping to the HttpServletRequest given.
* The encoding passed may be used in any URL decoding which is needed.
* @param HttpServletRequest request
* @param String encoding
* @return HttpServletRequest
* @throws UnsupportedEncodingException
*/
public HttpServletRequest commit(HttpServletRequest request,
String encoding) throws UnsupportedEncodingException;
/**
* Use the given request parameters to generate a URI from this mapping.
* The encoding passed may be used in any URLEncoding which is needed.
* @param HttpServletRequest request
* @param Map<String,String> params
* @param String encoding
* @return String
* @throws UnsupportedEncodingException
*/
public String createUri(HttpServletRequest request, Map<String,String> params,
String encoding) throws UnsupportedEncodingException;
}
Code: Select all
/*
This interface extends HttpServletRequest by allowing parameters to be set.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import javax.servlet.http.HttpServletRequest;
/**
* This interface extends HttpServletRequest by allowing parameters to be set.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
public interface MutableRequest extends HttpServletRequest {
/**
* Set a single value for a parameter.
* @param String param
* @param String value
*/
public void setParameter(String param, String value);
/**
* Set a collection of values for a parameter.
* @param String param
* @param String[] values
*/
public void setParameterValues(String param, String[] values);
}
Code: Select all
/*
Provides a wrapped up version of the request provided by the container.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Enumeration;
/**
* This class wraps request parameters provided by the mapping system into the
* default request.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
@SuppressWarnings("deprecation")
public class MutableRequestWrapper extends HttpServletRequestWrapper
implements MutableRequest {
/** An immutable Map of parameters */
private Map<String,String[]> internalParameterMap;
/**
* Constructs a new wrapper from the given request.
* @param HttpServletRequest request
*/
@SuppressWarnings("unchecked")
public MutableRequestWrapper(HttpServletRequest request) {
super(request);
internalParameterMap = super.getParameterMap();
}
/**
* Set a single value for a parameter.
* @param String param
* @param String value
*/
public void setParameter(String param, String value) {
String[] values = { value };
setParameterValues(param, values);
}
/**
* Set a collection of values for a parameter.
* @param String param
* @param String[] values
*/
public void setParameterValues(String param, String[] values) {
internalParameterMap.put(param, values);
}
/**
* Returns an Enumeration over the names of the parameters in this request.
* @return Enumeration<String>
*/
@Override
public Enumeration<String> getParameterNames() {
final Iterator<String> it = internalParameterMap.keySet().iterator();
return new Enumeration<String>() {
public boolean hasMoreElements() {
return it.hasNext();
}
public String nextElement() {
return it.next();
}
};
}
/**
* Get the collection of values for the given parameter.
* This methods returns null if no such parameter exists.
* @param String param
* @return String[]
*/
@Override
public String[] getParameterValues(String param) {
return internalParameterMap.get(param);
}
/**
* Returns the value of the given request parameter.
* If no such parameter exists this method returns null.
* @param String param
* @return String
*/
@Override
public String getParameter(String param) {
String value = null;
String[] values = getParameterValues(param);
if (values != null) {
value = values[0];
}
return value;
}
/**
* Returns an immutable Map containing all parameters in this request.
* @return Map<String,String[]>
*/
@Override
public Map<String,String[]> getParameterMap() {
return new HashMap<String,String[]>(internalParameterMap);
}
}
Code: Select all
/*
Provides a basic implementation of the Mapping interface.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.io.UnsupportedEncodingException;
/**
* Provides a basic implementation of the Mapping interface.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
public class BasicMapping implements Mapping {
/** The pattern which this mapping is for */
private String pattern;
/** The parameters which are in the request without being in the URL */
private Map<String,String> impliedParameters;
/**
* Constructs a new BasicMapping using the given pattern with no
* impliedParameters.
* @param String pattern
*/
public BasicMapping(String pattern) {
this(pattern, new HashMap<String,String>());
}
/**
* Constructs a new BasicMapping using the given pattern with the provided
* impliedParameters.
* @param Map<String,String> impliedParameters
* @param String pattern
*/
public BasicMapping(String pattern, Map<String,String> impliedParameters) {
setPattern(pattern);
setImpliedParameters(impliedParameters);
}
/**
* Set the URI pattern this Mapping matches.
* @param String pattern
*/
public void setPattern(String pattern) {
if (!"/".equals(pattern) && pattern.endsWith("/")) {
pattern = pattern.substring(0, pattern.length() - 1);
}
this.pattern = pattern;
}
/**
* Get the URI pattern this Mapping matches.
* @return String
*/
public String getPattern() {
return pattern;
}
/**
* Set the implied parameters in this Mapping.
* @param Map<String,String> impliedParameters
*/
public void setImpliedParameters(Map<String,String> impliedParameters) {
this.impliedParameters = impliedParameters;
}
/**
* Get the implied parameters in this Mapping.
* @return Map<String,String>
*/
public Map<String,String> getImpliedParameters() {
return impliedParameters;
}
/**
* Returns the length of the pattern, excluding wildcards.
* @return int
*/
public int getLength() {
return pattern.replaceAll("\\*$|:[a-zA-Z_][a-zA-Z0-9_]*", "").length();
}
/**
* Read from the HttpServletRequest to determine the requested path without
* the context path.
* @param HttpServletRequest request
* @return String
*/
protected String getPathFromRequest(HttpServletRequest request) {
String uri = request.getRequestURI().trim();
uri = uri.substring(request.getContextPath().length());
uri = uri.replaceAll("/{2,}", "/");
return uri;
}
/**
* Get a regular expression equivalent of the pattern.
* @return String
*/
protected String getRegex() {
String regex = "\\Q" + pattern.replaceFirst("/\\*$", "\\\\E((?:/.*)?)\\\\Q").
replaceFirst("/$", "\\\\E/?\\\\Q").
replaceAll(":[a-zA-Z_][a-zA-Z0-9_]*", "\\\\E(.+?)\\\\Q") + "\\E";
return regex;
}
/**
* Returns a string which contains :key elements for replacing to create
* a clean URI.
* @return String
*/
protected String getUriTemplate() {
return pattern.replaceFirst("/\\*$", "/:%WILDCARD%");
}
/**
* Returns true only if this initial request matches this Mapping.
* @param HttpServletRequest request
* @return boolean
* @throws UnsupportedEncodingException
*/
public boolean matchesRequest(HttpServletRequest request, String encoding)
throws UnsupportedEncodingException {
String uri = URLDecoder.decode(getPathFromRequest(request), encoding);
String regex = getRegex();
return uri.matches(regex);
}
/**
* Get the keys which are required to be in a request for this pattern to match.
* @return Set<String>
*/
protected Set<String> getRequiredKeys() {
Set<String> keys = new LinkedHashSet<String>();
Matcher m = Pattern.compile(":([a-zA-Z_][a-zA-Z0-9_]*)").matcher(pattern);
while (m.find()) {
keys.add(m.group(1));
}
return keys;
}
/**
* Returns true only if the Map contains the same parameters as this
* mapping does.
* Implied parameters are not required to be in the Map.
* @param Map<String,String> params
* @return boolean
*/
public boolean matchesParameters(Map<String,String> params) {
Set<String> keys = new HashSet<String>(params.keySet());
for (String k : getRequiredKeys()) {
if (!keys.contains(k)) {
return false;
}
keys.remove(k);
}
for (String k : impliedParameters.keySet()) {
if (!keys.contains(k)
|| !impliedParameters.get(k).equals(params.get(k))) {
return false;
}
keys.remove(k);
}
return (keys.isEmpty() || pattern.endsWith("/*"));
}
/**
* Explode out the wildcard portion of the URL to produce an array.
* @param String wildcard
* @return String[]
*/
private String[] parseWildcard(String wildcard) {
if (wildcard.startsWith("/")) {
wildcard = wildcard.substring(1);
}
String[] params = wildcard.split("/");
return params;
}
/**
* Commits this Mapping to the HttpServletRequest given.
* The encoding passed may be used in any URL decoding which is needed.
* @param HttpServletRequest request
* @param String encoding
* @return HttpServletRequest
* @throws UnsupportedEncodingException
*/
public HttpServletRequest commit(HttpServletRequest request,
String encoding) throws UnsupportedEncodingException {
if (!matchesRequest(request, encoding)) {
return request;
}
String uri = getPathFromRequest(request);
String regex = getRegex();
Matcher m = Pattern.compile(regex).matcher(uri);
if (!m.matches()) {
return request;
}
MutableRequest wrapper = new MutableRequestWrapper(request);
int i = 0;
for (String k : getRequiredKeys()) {
wrapper.setParameter(k, URLDecoder.decode(m.group(++i), encoding));
}
//Compute the wildcard portion as /key/value pairs
if (pattern.endsWith("/*")) {
String[] wildcard = parseWildcard(m.group(i + 1));
for (int j = 0; j < wildcard.length; j += 2) {
String k = URLDecoder.decode(wildcard[j], encoding);
String v = "";
if (wildcard.length > j + 1) {
v = URLDecoder.decode(wildcard[j + 1], encoding);
}
wrapper.setParameter(k, v);
}
}
for (String k : impliedParameters.keySet()) {
wrapper.setParameter(k, impliedParameters.get(k));
}
return wrapper;
}
/**
* Use the given request parameters to generate a URI from this mapping.
* The encoding passed may be used in any URLEncoding which is needed.
* @param HttpServletRequest request
* @param Map<String,String> params
* @param String encoding
* @return String
* @throws UnsupportedEncodingException
*/
public String createUri(HttpServletRequest request, Map<String,String> params,
String encoding) throws UnsupportedEncodingException {
if (!matchesParameters(params)) {
return request.getContextPath();
}
String uri = getUriTemplate();
Set<String> keys = new LinkedHashSet<String>(params.keySet());
for (String k : getRequiredKeys()) {
keys.remove(k);
if (!params.containsKey(k)) {
continue;
}
uri = uri.replace(":" + k, URLEncoder.encode(params.get(k), encoding));
}
StringBuffer wildcard = new StringBuffer();
for (String k : keys) {
String v = params.get(k);
if (impliedParameters.containsKey(k) &&
impliedParameters.get(k).equals(v)) {
continue;
}
wildcard.append("/" + URLEncoder.encode(k, encoding));
wildcard.append("/" + URLEncoder.encode(v, encoding));
}
uri = uri.replace("/:%WILDCARD%", wildcard.toString());
return request.getContextPath() + uri;
}
}
Code: Select all
/*
Provides a full featured implementation of the Mapping interface supporting
prefixes, suffixes, implied parameters, wildcards and regex requirements.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
/**
* Provides a full featured implementation of the Mapping interface supporting
* prefixes, suffixes, implied parameters, wildcards and regex requirements.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
public class ComplexMapping extends BasicMapping {
/** The suffix on the URI */
private String suffix = "";
/** The prefix on the URI */
private String prefix = "";
/** Pattern requirements on URI parameters */
private Map<String,String> requirements;
/**
* Constructs a new ComplexMapping using the given pattern with no
* impliedParameters.
* @param String pattern
*/
public ComplexMapping(String pattern) {
this(pattern, new HashMap<String,String>());
}
/**
* Constructs a new ComplexMapping using the given pattern with the provided
* impliedParameters.
* @param Map<String,String> impliedParameters
* @param String pattern
*/
public ComplexMapping(String pattern, Map<String,String> impliedParameters) {
this(pattern, impliedParameters, new HashMap<String,String>());
}
/**
* Constructs a new ComplexMapping with the given pattern, impliedParameters
* and pattern requirements.
* @param String pattern
* @param Map<String,String> impliedParameters
* @param Map<String,String> requirements
*/
public ComplexMapping(String pattern, Map<String,String> impliedParameters,
Map<String,String> requirements) {
this(pattern, impliedParameters, requirements, "", "");
}
/**
* Constructs a new ComplexMapping with the given pattern, impliedParameters,
* pattern requirements, prefix and suffix.
* @param String pattern
* @param Map<String,String> impliedParameters
* @param Map<String,String> requirements
* @param String prefix
* @param String suffix
*/
public ComplexMapping(String pattern, Map<String,String> impliedParameters,
Map<String,String> requirements, String prefix, String suffix) {
super(pattern, impliedParameters);
setRequirements(requirements);
setPrefix(prefix);
setSuffix(suffix);
}
/**
* Sets the suffix required to be on the URI.
* @param String suffix
*/
public void setSuffix(String suffix) {
this.suffix = suffix;
}
/**
* Returns the suffix which is needed on the URI.
* @return String
*/
public String getSuffix() {
return suffix;
}
/**
* Sets the prefix required to be on the URI.
* @param String prefix
*/
public void setPrefix(String prefix) {
if (prefix.endsWith("/")) {
prefix = prefix.substring(0, prefix.length() - 1);
}
this.prefix = prefix;
}
/**
* Returns the prefix which is needed on the URI.
* @return String
*/
public String getPrefix() {
return prefix;
}
/**
* Set the regex requirements for parameters in the request.
* @param Map<String,String> requirements
*/
public void setRequirements(Map<String,String> requirements) {
this.requirements = requirements;
}
/**
* Get the regex requirements for parameters in the request.
* @return Map<String,String>
*/
public Map<String,String> getRequirements() {
return new HashMap<String,String>(requirements);
}
/**
* Get a regular expression equivalent of the pattern.
* @return String
*/
@Override
protected String getRegex() { //Shorten this?
StringBuffer buf = new StringBuffer(Pattern.quote(prefix));
String regex = getPattern();
regex = regex.replaceFirst("/\\*$", "\\\\E((?:/.*)?)\\\\Q");
regex = regex.replaceFirst("/$", "\\\\E/?\\\\Q");
Matcher m = Pattern.compile(":([a-zA-Z_][a-zA-Z0-9_]*)").matcher(regex);
while (m.find()) {
String k = m.group(1);
String requirement;
if (requirements.containsKey(k)) {
requirement = "\\\\E(" + requirements.get(k).replace("\\", "\\\\") +
")\\\\Q";
} else {
requirement = "\\\\E(.+?)\\\\Q";
}
regex = regex.replaceFirst(":" + k, requirement);
}
buf.append("\\Q");
buf.append(regex);
buf.append("\\E");
buf.append(Pattern.quote(suffix));
return buf.toString();
}
/**
* Get a template from which to build this Mapping into a clean URI.
* @return String
*/
@Override
protected String getUriTemplate() {
return prefix + super.getUriTemplate() + suffix;
}
/**
* Returns true only if the parameters passed match this Mapping.
* @param Map<String,String> params
* @return boolean
*/
@Override
public boolean matchesParameters(Map<String,String> params) {
for (String k : getRequiredKeys()) {
if (!params.containsKey(k)) {
return false;
}
String v = params.get(k);
if (requirements.containsKey(k) && !v.matches(requirements.get(k))) {
return false;
}
}
return super.matchesParameters(params);
}
}
Code: Select all
/*
Interface for the Request Mapper.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mayo.requestmapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Map;
import java.util.Set;
import java.util.LinkedHashSet;
import java.net.URLEncoder;
import java.io.UnsupportedEncodingException;
/**
* Uses Mapping strategies to provide request rewriting.
* @author Chris Corbyn <chris@w3style.co.uk>
*/
public class RequestMapper implements Mapper {
/** Mapping objects */
private Set<Mapping> mappings;
/**
* Constructs a new RequestMapper with no Mapping objects.
*/
public RequestMapper() {
mappings = new LinkedHashSet<Mapping>();
}
/**
* Adds a new mapping rule to this RequestMapper.
* @param Mapping mapping
*/
public void addMapping(Mapping mapping) {
mappings.add(mapping);
}
/**
* Commits this Mapping to the HttpServletRequest given.
* The encoding passed may be used in any URL decoding which is needed.
* @param HttpServletRequest request
* @param String encoding
* @return HttpServletRequest
* @throws UnsupportedEncodingException
*/
public HttpServletRequest commit(HttpServletRequest request,
String encoding) throws UnsupportedEncodingException {
Mapping bestMapping = null;
for (Mapping m : mappings) {
if (m.matchesRequest(request, encoding)) {
if (bestMapping == null || bestMapping.getLength() < m.getLength()) {
bestMapping = m;
}
}
}
if (bestMapping != null) {
return bestMapping.commit(request, encoding);
} else {
return request;
}
}
/**
* Create an unclean URI with the provided request parameters in it.
* This is a fallback solution when a clean URI cannot be built.
* @param HttpServletRequest request
* @param Map<String,String> params
* @param String encoding
* @return String
* @throws UnsupportedEncodingException
*/
protected String createQueryStringUri(HttpServletRequest request,
Map<String,String> params, String encoding)
throws UnsupportedEncodingException {
StringBuffer uri = new StringBuffer("/");
String separator = "?";
for (String k : params.keySet()) {
String v = URLEncoder.encode(params.get(k), encoding);
uri.append(separator);
uri.append(URLEncoder.encode(k, encoding));
uri.append("=");
uri.append(v);
separator = "&";
}
return request.getContextPath() + uri.toString();
}
/**
* Use the given request parameters to generate a URI from this mapping.
* The encoding passed may be used in any URLEncoding which is needed.
* @param HttpServletRequest request
* @param Map<String,String> params
* @param String encoding
* @return String
* @throws UnsupportedEncodingException
*/
public String createUri(HttpServletRequest request, Map<String,String> params,
String encoding) throws UnsupportedEncodingException {
Mapping bestMapping = null;
for (Mapping m : mappings) {
if (m.matchesParameters(params)) {
if (bestMapping == null || bestMapping.getLength() < m.getLength()) {
bestMapping = m;
}
}
}
if (bestMapping != null) {
return bestMapping.createUri(request, params, encoding);
} else {
return createQueryStringUri(request, params, encoding);
}
}
}