[Java] RequestMapper package

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

[Java] RequestMapper package

Post by Chris Corbyn »

I know we have one or two Java Developers knocking around here so I figured I may get the odd response. I wanted to extend upon the extremely minimal J2EE spec for <servlet-mapping> abilities to actually affect what's in the request and to be a little more flexible than just a static string. This little package is intended to allow you to specify Mappings of the form "/some/path/:with/:vars/*" where the :with and :vars become named request parameters and the wildcard is evaluated from /key/value pairs.

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;
  
}
Mapper.java

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;
  
}
MutableRequest.java

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);

}
MutableRequestWrapper.java

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);
  }

}
BasicMapping.java

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;
  }
  
}
ComplexMapping.java

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);
  }
  
}
RequestMapper.java

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);
    }
  }
  
}
Last edited by Chris Corbyn on Mon Sep 24, 2007 1:43 pm, edited 1 time in total.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Test cases (depends on jMock):

AbstractMappingTest.java

Code: Select all

/*
 An abstract test case for Mapping classes.
 
 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 junit.framework.TestCase;
import org.jmock.Mockery;
import org.jmock.Expectations;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import org.mayo.jmock.MockRequestFactory;


/**
 * An abstract test case for Mapping classes.
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
abstract public class AbstractMappingTest extends TestCase {
  
  /**
   * Get the Mapping instance with the given pattern.
   * @param String pattern
   * @return Mapping
   */
  abstract public Mapping getMapping(String pattern);
  
  /**
   * Get the Mapping instance with the given pattern and implied parameters.
   * @param Stirng pattern
   * @param Map<String,String> impliedParameters
   * @return Mapping
   */
  abstract public Mapping getMapping(String pattern,
      Map<String,String> impliedParameters);
  
  //Change this to return number of slashes
  // or something else maybe.  It's a tough one to think about
  public void testLengthComputation() {
    Mapping m1 = getMapping("/a/:url/:with/arguments/:in");
    assertEquals(15, m1.getLength());
    Mapping m2 = getMapping("/just/a/static/one");
    assertEquals(18, m2.getLength());
    Mapping m3 = getMapping("/*");
    assertEquals(1, m3.getLength());
    Mapping m4 = getMapping("/foo/bar/*");
    assertEquals(9, m4.getLength());
  }
  
  public void testMatchesBasicRequest() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Mapping m1 = getMapping("/");
    
    final HttpServletRequest req1 = MockRequestFactory.createRequest(mockery,
        "/somewhere/", "/somewhere");
    assertTrue("/ should match /", m1.matchesRequest(req1, "utf-8"));
    final HttpServletRequest req2 = MockRequestFactory.createRequest(mockery,
        "/somewhere/foobar", "/somewhere");
    assertFalse("/foobar should not match /", m1.matchesRequest(req2, "utf-8"));
  }
  
  public void testMatchesPatternRequest() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Mapping m1 = getMapping("/:foo/:bar");
    
    final HttpServletRequest req1 = MockRequestFactory.createRequest(mockery,
        "/x/y/", "");
    assertTrue("/x/y should match /:foo/:bar", m1.matchesRequest(req1, "utf-8"));
    final HttpServletRequest req2 = MockRequestFactory.createRequest(mockery,
        "/place/foo/bar/", "/place");
    assertTrue("/foo/bar should match /:foo/:bar", m1.matchesRequest(req2, "utf-8"));
    final HttpServletRequest req3 = MockRequestFactory.createRequest(mockery,
        "/", "");
    assertFalse("/ should not match /:foo/:bar", m1.matchesRequest(req3, "utf-8"));
    final HttpServletRequest req4 = MockRequestFactory.createRequest(mockery,
        "/context/x", "/context");
    assertFalse("/x should not match /:foo/:bar", m1.matchesRequest(req4, "utf-8"));
  }
  
  public void testMatchesWildcardRequest() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    Mapping m1 = getMapping("/foo bar/*");
    
    final HttpServletRequest req1 = MockRequestFactory.createRequest(mockery,
        "/foo%20bar", "");
    assertTrue("/foo%20bar should match /foo bar/* (wildcard ignored)",
        m1.matchesRequest(req1, "utf-8"));
    final HttpServletRequest req2 = MockRequestFactory.createRequest(mockery,
        "/user/foo%20bar/a/b/c", "/user");
    assertTrue("/foo%20bar/a/b/c should match /foo bar/*",
        m1.matchesRequest(req2, "utf-8"));
    final HttpServletRequest req3 = MockRequestFactory.createRequest(mockery,
        "/user/notfoo%20bar", "/user");
    assertFalse("/notfoo%20bar should not match /foo bar/*",
        m1.matchesRequest(req3, "utf-8"));
    final HttpServletRequest req4 = MockRequestFactory.createRequest(mockery,
        "/a/b/c", "");
    assertFalse("/a/b/c should not match /foo bar/*",
        m1.matchesRequest(req4, "utf-8"));
  }
  
  public void testMatchesParametersWithImpliedParameters() {
    Map<String,String> map1 = new HashMap<String,String>();
    map1.put("foo", "bar");
    map1.put("zip", "button");
    Mapping m1 = getMapping("/", map1);
    
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("zip", "button");
    p1.put("foo", "bar");
    assertTrue("foo and zip are implied so should match",
        m1.matchesParameters(p1));
    assertFalse("foo and zip are needed before match",
        m1.matchesParameters(new HashMap<String,String>()));
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("foo", "bar");
    assertFalse("zip is needed before match",
        m1.matchesParameters(p2));
    Map<String,String> p3 = new HashMap<String,String>();
    p3.put("thing", "nothing");
    assertFalse("There is no parameter 'thing' in the mapping so should not match",
        m1.matchesParameters(p3));
    
    Map<String,String> p4 = new HashMap<String,String>();
    p4.put("foo", "not-bar");
    p4.put("zip", "button");
    assertFalse("Implied foo parameter value must match to success",
        m1.matchesParameters(p4));
    Map<String,String> p5 = new HashMap<String,String>();
    p5.put("zip", "not-button");
    assertFalse("Value of zip parameter must match to succeed",
        m1.matchesParameters(p5));
  }
  
  public void testMatchesParametersForPattern() {
    Mapping m1 = getMapping("/:foo");
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("foo", "bar");
    assertTrue("foo is in URL so should match",
        m1.matchesParameters(p1));
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("foo", "123456");
    assertTrue("foo is in URL so should match",
        m1.matchesParameters(p2));
    Map<String,String> p3 = new HashMap<String,String>();
    p3.put("foo", "bar");
    p3.put("zip", "button");
    assertFalse("zip is not in URL so should not match",
        m1.matchesParameters(p3));
    Map<String,String> p4 = new HashMap<String,String>();
    assertFalse("foo must be in URL so this shouldn't match",
        m1.matchesParameters(p4));
    
    Mapping m2 = getMapping("/test/:abc/zyz/:something");
    Map<String,String> p5 = new HashMap<String,String>();
    p5.put("abc", "test");
    p5.put("something", "blah");
    assertTrue("abc and something are in URL so should match",
        m2.matchesParameters(p5));
    Map<String,String> p6 = new HashMap<String,String>();
    p6.put("abc", "test");
    p6.put("something", "whatever");
    p6.put("nothing", "here");
    assertFalse("nothing is NOT in the URL so shouldn't match",
        m2.matchesParameters(p6));
    Map<String,String> p7 = new HashMap<String,String>();
    p7.put("abc", "test");
    assertFalse("something is in URL but not in parameters",
        m2.matchesParameters(p7));
  }
  
  public void testMatchesParametersWithWildcard() {
    Mapping m1 = getMapping("/:foo/*");
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("foo", "bar");
    assertTrue("The wildcard should be optional, foo should match",
        m1.matchesParameters(p1));
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("foo", "test");
    p2.put("zip", "button");
    assertTrue("The wildcard should accept any extra parameters",
        m1.matchesParameters(p2));
    Map<String,String> p3 = new HashMap<String,String>();
    p3.put("foo", "example");
    p3.put("test", "no");
    p3.put("whatever", "something");
    assertTrue("The wildcard should accept any extra parameters",
        m1.matchesParameters(p3));
    Map<String,String> p4 = new HashMap<String,String>();
    p4.put("not-foo", "bar");
    p4.put("test", "thing");
    assertFalse("foo is not in parameters so should not be matched",
        m1.matchesParameters(p4));
    
    //This matches *anything at all*
    Mapping m2 = getMapping("/test/*");
    Map<String,String> p5 = new HashMap<String,String>();
    p5.put("test", "test");
    assertTrue("There's no required parameters so anything should match",
        m2.matchesParameters(p5));
    Map<String,String> p6 = new HashMap<String,String>();
    p6.put("x", "y");
    p6.put("zip", "");
    assertTrue("There's no required parameters so anything should match",
        m2.matchesParameters(p6));
    Map<String,String> p7 = new HashMap<String,String>();
    assertTrue("There's no required parameters so anything should match",
        m2.matchesParameters(p7));
  }
  
  public void testCommitWithImpliedParameters() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, new HashMap<String,String[]>());
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    
    Map<String,String> map1 = new HashMap<String,String>();
    map1.put("foo", "bar");
    map1.put("x", "y");
    Mapping m1 = getMapping("/", map1);
    
    HttpServletRequest request = m1.commit(mockRequest, "utf-8");
    assertEquals("bar", request.getParameter("foo"));
    assertEquals("y", request.getParameter("x"));
  }
  
  public void testCommitWithPattern() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Mapping m1 = getMapping("/:foo/:zip");
    
    Map<String,String[]> origMap = new HashMap<String,String[]>();
    origMap.put("test", new String[] { "thing" });
    final HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, origMap, "/chris/corbyn", "");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest1);
    }});
    HttpServletRequest request1 = m1.commit(mockRequest1, "utf-8");
    assertEquals("thing", request1.getParameter("test"));
    assertEquals("chris", request1.getParameter("foo"));
    assertEquals("corbyn", request1.getParameter("zip"));
    
    final HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/ctx/posts/123", "/ctx");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest2);
    }});
    HttpServletRequest request2 = m1.commit(mockRequest2, "utf-8");
    assertEquals("posts", request2.getParameter("foo"));
    assertEquals("123", request2.getParameter("zip"));
    
    Mapping m2 = getMapping("/base/:action");
    
    final HttpServletRequest mockRequest4 = MockRequestFactory.createRequest(
        mockery, "/location/base/close%2Fnow", "/location");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest4);
    }});
    HttpServletRequest request4 = m2.commit(mockRequest4, "utf-8");
    assertEquals("close/now", request4.getParameter("action"));
  }
  
  public void testCommitWithWildcard() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Mapping m1 = getMapping("/*");
    
    final HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctx/foo/bar/zip/button", "/ctx");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest1);
    }});
    HttpServletRequest request1 = m1.commit(mockRequest1, "utf-8");
    assertEquals("bar", request1.getParameter("foo"));
    assertEquals("button", request1.getParameter("zip"));
    
    final HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/a/b%20c/d", "");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest2);
    }});
    HttpServletRequest request2 = m1.commit(mockRequest2, "utf-8");
    assertEquals("b c", request2.getParameter("a"));
    assertEquals("", request2.getParameter("d"));
  }
  
  public void testCommitWithCombinedParameters()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Map<String,String> p = new HashMap<String,String>();
    p.put("foo", "bar");
    Mapping m = getMapping("/base/:module/:action/*", p);
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, "/ctxPath/base/forum/createPost/threadId/23/preview/true",
        "/ctxPath");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    HttpServletRequest request = m.commit(mockRequest, "utf-8");
    assertEquals("bar", request.getParameter("foo"));
    assertEquals("forum", request.getParameter("module"));
    assertEquals("createPost", request.getParameter("action"));
    assertEquals("23", request.getParameter("threadId"));
    assertEquals("true", request.getParameter("preview"));
  }
  
  public void testCreateUriWithImpliedParameters()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Map<String,String> map1 = new HashMap<String,String>();
    map1.put("module", "documentation");
    map1.put("action", "showContents");
    Mapping m1 = getMapping("/docs", map1);
    
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctxPath/foo", "/ctxPath");
    
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("module", "documentation");
    p1.put("action", "showContents");
    assertEquals("/ctxPath/docs", m1.createUri(mockRequest1, p1, "utf-8"));
    
    Map<String,String> map2 = new HashMap<String,String>();
    map2.put("page", "index");
    Mapping m2 = getMapping("/", map2);
    
    HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/", "");
    
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("page", "index");
    assertEquals("/", m2.createUri(mockRequest2, p2, "utf-8"));
  }
  
  public void testCreateUriWithPattern() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Mapping m1 = getMapping("/:module/:action");
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/context/wherever/whatever", "/context");
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("action", "delete");
    p1.put("module", "users");
    assertEquals("/context/users/delete", m1.createUri(mockRequest1, p1, "utf-8"));
    
    Mapping m2 = getMapping("/docs/:chapter/:page");
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("chapter", "2");
    p2.put("page", "19");
    assertEquals("/context/docs/2/19", m2.createUri(mockRequest1, p2, "utf-8"));
  }
  
  public void testCreateUriWithWildcard() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Mapping m1 = getMapping("/help/*");
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/", "");
    Map<String,String> p1 = new LinkedHashMap<String,String>();
    p1.put("a", "b");
    p1.put("zip", "button");
    p1.put("test", "foo bar");
    assertEquals("/help/a/b/zip/button/test/foo+bar",
        m1.createUri(mockRequest1, p1, "utf-8"));
    
    Mapping m2 = getMapping("/*");
    HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/userName/foo", "/userName");
    Map<String,String> p2 = new LinkedHashMap<String,String>();
    p2.put("page", "contact");
    assertEquals("/userName/page/contact",
        m2.createUri(mockRequest2, p2, "utf-8"));
  }
  
  public void testCreateUriWithCombinedParameters()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    Map<String,String> map1 = new HashMap<String,String>();
    map1.put("needed", "x");
    Mapping m1 = getMapping("/place/:foo/:bar/*", map1);
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/user/", "/user");
    
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("foo", "param1");
    p1.put("bar", "param2");
    p1.put("needed", "x");
    assertEquals("/user/place/param1/param2",
        m1.createUri(mockRequest1, p1, "utf-8"));
    
    Map<String,String> p2 = new LinkedHashMap<String,String>();
    p2.put("foo", "param1");
    p2.put("bar", "param2");
    p2.put("needed", "x");
    p2.put("extra", "stuff");
    assertEquals("/user/place/param1/param2/extra/stuff",
        m1.createUri(mockRequest1, p2, "utf-8"));
  }
  
}
TestBasicMapping.java

Code: Select all

/*
 Tests for the BasicMapping class.
 
 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;


/**
 * Tests for the BasicMapping class.
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
public class TestBasicMapping extends AbstractMappingTest {
  
  /**
   * Get the Mapping instance with the given pattern.
   * @param String pattern
   * @return Mapping
   */
  public Mapping getMapping(String pattern) {
    return new BasicMapping(pattern);
  }
  
  /**
   * Get the Mapping instance with the given pattern and implied parameters.
   * @param Stirng pattern
   * @param Map<String,String> impliedParameters
   * @return Mapping
   */
  public Mapping getMapping(String pattern,
      Map<String,String> impliedParameters) {
    return new BasicMapping(pattern, impliedParameters);
  }
  
}
TestComplexMapping.java

Code: Select all

/*
 Tests for the ComplexMapping class.
 
 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 org.jmock.Mockery;
import org.jmock.Expectations;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.io.UnsupportedEncodingException;
import org.mayo.jmock.MockRequestFactory;


/**
 * Tests for the ComplexMapping class.
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
public class TestComplexMapping extends AbstractMappingTest {
  
  /**
   * Get the Mapping instance with the given pattern.
   * @param String pattern
   * @return Mapping
   */
  public Mapping getMapping(String pattern) {
    return new ComplexMapping(pattern);
  }
  
  /**
   * Get the Mapping instance with the given pattern and implied parameters.
   * @param Stirng pattern
   * @param Map<String,String> impliedParameters
   * @return Mapping
   */
  public Mapping getMapping(String pattern,
      Map<String,String> impliedParameters) {
    return new ComplexMapping(pattern, impliedParameters);
  }
  
  public void testMatchesRequestWithSuffix()
      throws UnsupportedEncodingException {
    final String encoding = "utf-8";
    Mockery mockery = new Mockery();
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctx/foo.html", "/ctx");
    ComplexMapping m1 = new ComplexMapping("/foo");
    m1.setSuffix(".html");
    assertTrue("Suffix is .html so full pattern is /foo.html.  Match expected.",
        ((Mapping) m1).matchesRequest(mockRequest1, encoding));
    m1.setSuffix(".php");
    assertFalse("Suffix is .php but request has .html so shouldn't match",
        ((Mapping) m1).matchesRequest(mockRequest1, encoding));
    
    HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/docs/introduction.do", "");
    ComplexMapping m2 = new ComplexMapping("/docs/:page");
    m2.setSuffix(".do");
    assertTrue("Suffix is .do so should match",
        ((Mapping) m2).matchesRequest(mockRequest2, encoding));
    
    HttpServletRequest mockRequest3 = MockRequestFactory.createRequest(
        mockery, "/docs/introduction", "");
    assertFalse(".do suffix is missing so should not match",
        ((Mapping) m2).matchesRequest(mockRequest3, encoding));
  }
  
  public void testCommitWithSuffix() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    ComplexMapping m1 = new ComplexMapping("/:x");
    m1.setSuffix(".do");
    
    final HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctx/foo.do", "/ctx");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest1);
    }});
    HttpServletRequest request1 = m1.commit(mockRequest1, "utf-8");
    assertEquals("foo", request1.getParameter("x"));
    
    final HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/a%20b.do", "");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest2);
    }});
    HttpServletRequest request2 = m1.commit(mockRequest2, "utf-8");
    assertEquals("a b", request2.getParameter("x"));
  }
  
  public void testMatchesParametersWithSuffix() {
    Mockery mockery = new Mockery();
    ComplexMapping m1 = new ComplexMapping("/:x");
    m1.setSuffix(".html");
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("x", "whatever");
    assertTrue("x is in params so should match",
        ((Mapping) m1).matchesParameters(p1));
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("x", "test");
    p2.put("blah", "blah");
    assertFalse("blah is not in the request so should not match",
        ((Mapping) m1).matchesParameters(p2));
  }
  
  public void testCreateUriWithSuffix() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "iso-8859-1";
    final HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/foo/bar.html", "/foo");
    ComplexMapping m1 = new ComplexMapping("/test");
    m1.setSuffix(".html");
    Map<String,String> p1 = new HashMap<String,String>();
    assertEquals("/foo/test.html",
        ((Mapping) m1).createUri(mockRequest1, p1, encoding));
    
    ComplexMapping m2 = new ComplexMapping("/:foo/*");
    m2.setSuffix(".do");
    Map<String,String> p2 = new LinkedHashMap<String,String>();
    p2.put("foo", "bar");
    p2.put("zip", "button");
    p2.put("item", "1234");
    assertEquals("/foo/bar/zip/button/item/1234.do",
        ((Mapping) m2).createUri(mockRequest1, p2, encoding));
  }
  
  public void testMatchesRequestWithPrefix()
      throws UnsupportedEncodingException {
    final String encoding = "utf-8";
    Mockery mockery = new Mockery();
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctx/pre/location", "/ctx");
    ComplexMapping m1 = new ComplexMapping("/location");
    m1.setPrefix("/pre");
    assertTrue("Prefix is /pre so full pattern is /pre/location.  Match expected.",
        ((Mapping) m1).matchesRequest(mockRequest1, encoding));
    m1.setSuffix("/path");
    assertFalse("Prefix is /path but request has /pre so shouldn't match",
        ((Mapping) m1).matchesRequest(mockRequest1, encoding));
    
    HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/docs/introduction", "");
    ComplexMapping m2 = new ComplexMapping("/:page");
    m2.setPrefix("/docs");
    assertTrue("Prefix is /docs so should match",
        ((Mapping) m2).matchesRequest(mockRequest2, encoding));
    
    HttpServletRequest mockRequest3 = MockRequestFactory.createRequest(
        mockery, "/introduction", "");
    assertFalse("/docs prefix is missing so should not match",
        ((Mapping) m2).matchesRequest(mockRequest3, encoding));
  }
  
  public void testCommitWithPrefix() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    
    ComplexMapping m1 = new ComplexMapping("/:x");
    m1.setPrefix("/test");
    
    final HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctx/test/foo", "/ctx");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest1);
    }});
    HttpServletRequest request1 = m1.commit(mockRequest1, "utf-8");
    assertEquals("foo", request1.getParameter("x"));
    
    final HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/test/a%20b", "");
    mockery.checking(new Expectations() {{
      ignoring(mockRequest2);
    }});
    HttpServletRequest request2 = m1.commit(mockRequest2, "utf-8");
    assertEquals("a b", request2.getParameter("x"));
  }
  
  public void testMatchesParametersWithPrefix() {
    Mockery mockery = new Mockery();
    ComplexMapping m1 = new ComplexMapping("/:x");
    m1.setPrefix("/bar");
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("x", "whatever");
    assertTrue("x is in params so should match", m1.matchesParameters(p1));
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("x", "test");
    p2.put("blah", "blah");
    assertFalse("blah is not in the request so should not match",
        m1.matchesParameters(p2));
  }
  
  public void testCreateUriWithPrefix() throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "iso-8859-1";
    final HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/foo/bar.html", "/foo");
    ComplexMapping m1 = new ComplexMapping("/test");
    m1.setPrefix("/egg");
    Map<String,String> p1 = new HashMap<String,String>();
    assertEquals("/foo/egg/test",
        ((Mapping) m1).createUri(mockRequest1, p1, encoding));
    
    ComplexMapping m2 = new ComplexMapping("/:foo/*");
    m2.setPrefix("/bacon/eggs");
    Map<String,String> p2 = new LinkedHashMap<String,String>();
    p2.put("foo", "bar");
    p2.put("zip", "button");
    p2.put("item", "1234");
    assertEquals("/foo/bacon/eggs/bar/zip/button/item/1234",
        ((Mapping) m2).createUri(mockRequest1, p2, encoding));
  }
  
  public void testMatchesRequestWithRequirements()
      throws UnsupportedEncodingException {
    final String encoding = "utf-8";
    Mockery mockery = new Mockery();
    HttpServletRequest mockRequest1 = MockRequestFactory.createRequest(
        mockery, "/ctx/page/23", "/ctx");
    ComplexMapping m1 = new ComplexMapping("/page/:num");
    Map<String,String> req1 = new HashMap<String,String>();
    req1.put("num", "\\d+");
    m1.setRequirements(req1);
    assertTrue("Requirement is \\d+ and :num is a number.  Match expected.",
        ((Mapping) m1).matchesRequest(mockRequest1, encoding));
    Map<String,String> req2 = new HashMap<String,String>();
    req2.put("num", "[a-z]+");
    m1.setRequirements(req2);
    assertFalse("Requirement is [a-z]+ but :num is 23 so shouldn't match",
        ((Mapping) m1).matchesRequest(mockRequest1, encoding));
    
    HttpServletRequest mockRequest2 = MockRequestFactory.createRequest(
        mockery, "/introduction/123", "");
    ComplexMapping m2 = new ComplexMapping("/:chapter/:page");
    Map<String,String> req3 = new HashMap<String,String>();
    req3.put("page", "\\d+");
    req3.put("chapter", "[a-z]+");
    m2.setRequirements(req3);
    assertTrue("Requirements are satisfied so should match",
        ((Mapping) m2).matchesRequest(mockRequest2, encoding));
    
    HttpServletRequest mockRequest3 = MockRequestFactory.createRequest(
        mockery, "/introduction/one", "");
    assertFalse(":page requirement is wrong so should not match",
        ((Mapping) m2).matchesRequest(mockRequest3, encoding));
  }
  
  public void testMatchesParametersWithRequirements() {
    Mockery mockery = new Mockery();
    ComplexMapping m1 = new ComplexMapping("/:foo/:bar");
    Map<String,String> req1 = new HashMap<String,String>();
    req1.put("bar", "\\d+");
    m1.setRequirements(req1);
    
    Map<String,String> p1 = new HashMap<String,String>();
    p1.put("foo", "thing");
    p1.put("bar", "2");
    assertTrue("bar is a number so should match",
        ((Mapping) m1).matchesParameters(p1));
    Map<String,String> p2 = new HashMap<String,String>();
    p2.put("foo", "thing");
    p2.put("bar", "nothing");
    assertFalse("bar is not a number so shouldn't match",
        ((Mapping) m1).matchesParameters(p2));
    
    Map<String,String> p3 = new HashMap<String,String>();
    p3.put("bar", "2");
    assertFalse("foo is missing so shouldn't match",
        ((Mapping) m1).matchesParameters(p3));
  }
  
}
TestMutableRequestWrapper.java

Code: Select all

/*
 Tests for the RequestWrapper class.
 
 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 junit.framework.TestCase;
import org.jmock.Mockery;
import org.jmock.Expectations;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.mayo.jmock.MockRequestFactory;


/**
 * Tests for the MutableRequestWrapper class.
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
public class TestMutableRequestWrapper extends TestCase {
  
  public void testOriginalParameterNames() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("foo", new String[] { "bar" });
    map.put("zip", new String[] { "button" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    Enumeration<String> mockEnum = mockRequest.getParameterNames();
    assertTrue("Mock must have foo param name", mockEnum.hasMoreElements());
    assertEquals("foo", mockEnum.nextElement());
    assertTrue("Mock must have zip param name", mockEnum.hasMoreElements());
    assertEquals("zip", mockEnum.nextElement());
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    Enumeration<String> testEnum = request.getParameterNames();
    assertTrue("No foo param name?", testEnum.hasMoreElements());
    assertEquals("foo", testEnum.nextElement());
    assertTrue("No zip param name?", testEnum.hasMoreElements());
    assertEquals("zip", testEnum.nextElement());
  }
  
  public void testOriginalParameterValues() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("foo", new String[] { "bar" });
    map.put("zip", new String[] { "button" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    String[] mockFooValues = mockRequest.getParameterValues("foo");
    String[] mockZipValues = mockRequest.getParameterValues("zip");
    assertEquals(1, mockFooValues.length);
    assertEquals(1, mockZipValues.length);
    assertEquals("bar", mockFooValues[0]);
    assertEquals("button", mockZipValues[0]);
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    String[] testFooValues = mockRequest.getParameterValues("foo");
    String[] testZipValues = mockRequest.getParameterValues("zip");
    assertEquals(mockFooValues.length, testFooValues.length);
    assertEquals(mockZipValues.length, testZipValues.length);
    assertEquals(mockFooValues[0], testFooValues[0]);
    assertEquals(mockZipValues[0], testZipValues[0]);
  }
  
  public void testOriginalParameters() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("foo", new String[] { "bar" });
    map.put("zip", new String[] { "button" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    assertEquals("bar", mockRequest.getParameter("foo"));
    assertEquals("button", mockRequest.getParameter("zip"));
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    assertEquals(mockRequest.getParameter("foo"), request.getParameter("foo"));
    assertEquals(mockRequest.getParameter("zip"), request.getParameter("zip"));
  }
  
  public void testParameterMap() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("foo", new String[] { "bar" });
    map.put("zip", new String[] { "button" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    assertEquals(map, mockRequest.getParameterMap());
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    assertEquals(mockRequest.getParameterMap(), request.getParameterMap());
  }
  
  public void testParameterMapIsImmutable() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("foo", new String[] { "bar" });
    map.put("zip", new String[] { "button" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    request.getParameterMap().put("wasntThereBefore",
        new String[] { "isThereNow" });
    assertFalse("Should not be possible to inject into the Map",
        request.getParameterMap().containsKey("wasntThereBefore"));
  }
  
  public void testSetParameterValues() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("test", new String[] { "thing" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    String[] barValues = { "x" };
    
    request.setParameterValues("bar", barValues);
    Set<String> wanted1 = new HashSet<String>();
    wanted1.add("test");
    wanted1.add("bar");
    Set<String> got1 = new HashSet<String>();
    Enumeration<String> e1 = request.getParameterNames();
    while (e1.hasMoreElements()) {
      got1.add(e1.nextElement());
    }
    assertEquals(wanted1, got1);
    
    assertEquals("thing", request.getParameter("test"));
    assertEquals("x", request.getParameter("bar"));
    
    String[] testBarValues = request.getParameterValues("bar");
    assertEquals(1, testBarValues.length);
    assertEquals("x", testBarValues[0]);
    
    String[] testTestValues = request.getParameterValues("test");
    assertEquals(1, testTestValues.length);
    assertEquals("thing", testTestValues[0]);
    
    Map<String,String[]> testMap = request.getParameterMap();
    assertEquals(2, testMap.size());
    assertTrue(testMap.containsKey("test"));
    assertTrue(testMap.containsKey("bar"));
    
    String[] testMapTestValues = testMap.get("test");
    assertEquals(1, testMapTestValues.length);
    assertEquals("thing", testMapTestValues[0]);
    
    String[] testMapBarValues = testMap.get("bar");
    assertEquals(1, testMapBarValues.length);
    assertEquals("x", testMapBarValues[0]);
  }
  
  public void testSetParameterValuesMultiCall() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("test", new String[] { "thing" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    String[] barValues = { "x" };
    request.setParameterValues("bar", barValues);
    
    String[] fooValues = { "y" };
    request.setParameterValues("foo", fooValues);
    
    Set<String> wanted1 = new HashSet<String>();
    wanted1.add("test");
    wanted1.add("bar");
    wanted1.add("foo");
    Set<String> got1 = new HashSet<String>();
    Enumeration<String> e1 = request.getParameterNames();
    while (e1.hasMoreElements()) {
      got1.add(e1.nextElement());
    }
    assertEquals(wanted1, got1);
    
    assertEquals("thing", request.getParameter("test"));
    assertEquals("x", request.getParameter("bar"));
    assertEquals("y", request.getParameter("foo"));
    
    String[] testBarValues = request.getParameterValues("bar");
    assertEquals(1, testBarValues.length);
    assertEquals("x", testBarValues[0]);
    
    String[] testFooValues = request.getParameterValues("foo");
    assertEquals(1, testFooValues.length);
    assertEquals("y", testFooValues[0]);
    
    String[] testTestValues = request.getParameterValues("test");
    assertEquals(1, testTestValues.length);
    assertEquals("thing", testTestValues[0]);
    
    Map<String,String[]> testMap = request.getParameterMap();
    assertEquals(3, testMap.size());
    assertTrue(testMap.containsKey("test"));
    assertTrue(testMap.containsKey("bar"));
    assertTrue(testMap.containsKey("foo"));
    
    String[] testMapTestValues = testMap.get("test");
    assertEquals(1, testMapTestValues.length);
    assertEquals("thing", testMapTestValues[0]);
    
    String[] testMapBarValues = testMap.get("bar");
    assertEquals(1, testMapBarValues.length);
    assertEquals("x", testMapBarValues[0]);
    
    String[] testMapFooValues = testMap.get("foo");
    assertEquals(1, testMapFooValues.length);
    assertEquals("y", testMapFooValues[0]);
  }
  
  public void testSetParmameter() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("test", new String[] { "thing" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    
    request.setParameter("bar", "x");
    Set<String> wanted1 = new HashSet<String>();
    wanted1.add("test");
    wanted1.add("bar");
    Set<String> got1 = new HashSet<String>();
    Enumeration<String> e1 = request.getParameterNames();
    while (e1.hasMoreElements()) {
      got1.add(e1.nextElement());
    }
    assertEquals(wanted1, got1);
    
    assertEquals("thing", request.getParameter("test"));
    assertEquals("x", request.getParameter("bar"));
    
    String[] testBarValues = request.getParameterValues("bar");
    assertEquals(1, testBarValues.length);
    assertEquals("x", testBarValues[0]);
    
    String[] testTestValues = request.getParameterValues("test");
    assertEquals(1, testTestValues.length);
    assertEquals("thing", testTestValues[0]);
    
    Map<String,String[]> testMap = request.getParameterMap();
    assertEquals(2, testMap.size());
    assertTrue(testMap.containsKey("test"));
    assertTrue(testMap.containsKey("bar"));
    
    String[] testMapTestValues = testMap.get("test");
    assertEquals(1, testMapTestValues.length);
    assertEquals("thing", testMapTestValues[0]);
    
    String[] testMapBarValues = testMap.get("bar");
    assertEquals(1, testMapBarValues.length);
    assertEquals("x", testMapBarValues[0]);
  }
  
  public void testSetParameterMultiCall() {
    Mockery mockery = new Mockery();
    
    Map<String,String[]> map = new HashMap<String,String[]>();
    map.put("test", new String[] { "thing" });
    
    final HttpServletRequest mockRequest = MockRequestFactory.createRequest(
        mockery, map);
    mockery.checking(new Expectations() {{
      ignoring(mockRequest);
    }});
    
    MutableRequest request = new MutableRequestWrapper(mockRequest);
    request.setParameter("bar", "x");
    request.setParameter("foo", "y");
    
    Set<String> wanted1 = new HashSet<String>();
    wanted1.add("test");
    wanted1.add("bar");
    wanted1.add("foo");
    Set<String> got1 = new HashSet<String>();
    Enumeration<String> e1 = request.getParameterNames();
    while (e1.hasMoreElements()) {
      got1.add(e1.nextElement());
    }
    assertEquals(wanted1, got1);
    
    assertEquals("thing", request.getParameter("test"));
    assertEquals("x", request.getParameter("bar"));
    assertEquals("y", request.getParameter("foo"));
    
    String[] testBarValues = request.getParameterValues("bar");
    assertEquals(1, testBarValues.length);
    assertEquals("x", testBarValues[0]);
    
    String[] testFooValues = request.getParameterValues("foo");
    assertEquals(1, testFooValues.length);
    assertEquals("y", testFooValues[0]);
    
    String[] testTestValues = request.getParameterValues("test");
    assertEquals(1, testTestValues.length);
    assertEquals("thing", testTestValues[0]);
    
    Map<String,String[]> testMap = request.getParameterMap();
    assertEquals(3, testMap.size());
    assertTrue(testMap.containsKey("test"));
    assertTrue(testMap.containsKey("bar"));
    assertTrue(testMap.containsKey("foo"));
    
    String[] testMapTestValues = testMap.get("test");
    assertEquals(1, testMapTestValues.length);
    assertEquals("thing", testMapTestValues[0]);
    
    String[] testMapBarValues = testMap.get("bar");
    assertEquals(1, testMapBarValues.length);
    assertEquals("x", testMapBarValues[0]);
    
    String[] testMapFooValues = testMap.get("foo");
    assertEquals(1, testMapFooValues.length);
    assertEquals("y", testMapFooValues[0]);
  }
  
}
TestRequestMapper.java

Code: Select all

/*
 Tests for the RequestMapper class.
 
 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 junit.framework.TestCase;
import org.jmock.Mockery;
import org.jmock.Expectations;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import org.mayo.jmock.MockRequestFactory;


/**
 * Tests for the RequestMapper class.
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
public class TestRequestMapper extends TestCase {
  
  public void testMappingSelectionForCommit()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "utf-8";
    
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      ignoring(req1);
    }});
    
    final Mapping mapping1 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping1).matchesRequest(req1, encoding);
          will(returnValue(false));
      never(mapping1).commit(req1, encoding);
      ignoring(mapping1);
    }});
    
    final Mapping mapping2 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping2).matchesRequest(req1, encoding);
          will(returnValue(true));
      one(mapping2).commit(req1, encoding);
      ignoring(mapping2);
    }});
    
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping1);
    mapper.addMapping(mapping2);
    mapper.commit(req1, encoding);
    
    mockery.assertIsSatisfied();
  }
  
  public void testMappingSelectionUsesLengthAsAFactorInCommit()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "iso-8859-1";
    
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      ignoring(req1);
    }});
    
    final Mapping mapping1 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping1).matchesRequest(req1, encoding);
          will(returnValue(false));
      allowing(mapping1).getLength(); will(returnValue(1));
      never(mapping1).commit(req1, encoding);
      ignoring(mapping1);
    }});
    
    //Both mapping1 and mapping2 match, but mapping3 is longer
    final Mapping mapping2 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping2).matchesRequest(req1, encoding);
          will(returnValue(true));
      atLeast(1).of(mapping2).getLength(); will(returnValue(5));
      never(mapping2).commit(req1, encoding);
      ignoring(mapping2);
    }});
    
    final Mapping mapping3 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping3).matchesRequest(req1, encoding);
          will(returnValue(true));
      atLeast(1).of(mapping3).getLength(); will(returnValue(8));
      one(mapping3).commit(req1, encoding);
      ignoring(mapping3);
    }});
    
    final Mapping mapping4 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping4).matchesRequest(req1, encoding);
          will(returnValue(false));
      allowing(mapping4).getLength(); will(returnValue(0));
      never(mapping4).commit(req1, encoding);
      ignoring(mapping4);
    }});
    
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping1);
    mapper.addMapping(mapping2);
    mapper.addMapping(mapping3);
    mapper.addMapping(mapping4);
    mapper.commit(req1, encoding);
    
    mockery.assertIsSatisfied();
  }
  
  public void testMappingSelectionForCreateUri()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "utf-8";
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      ignoring(req1);
    }});
    final Map<String,String> map1 = new HashMap<String,String>();
    final Mapping mapping1 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping1).matchesParameters(map1);
          will(returnValue(false));
      never(mapping1).createUri(req1, map1, encoding);
      ignoring(mapping1);
    }});
    final Mapping mapping2 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping2).matchesParameters(map1);
          will(returnValue(true));
      one(mapping2).createUri(req1, map1, encoding);
      ignoring(mapping2);
    }});
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping1);
    mapper.addMapping(mapping2);
    mapper.createUri(req1, map1, encoding);
    mockery.assertIsSatisfied();
  }
  
  public void testMappingSelectionUsesLengthAsAFactorInCreateUri()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "us-ascii";
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      ignoring(req1);
    }});
    final Map<String,String> map1 = new HashMap<String,String>();
    final Mapping mapping1 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping1).matchesParameters(map1);
          will(returnValue(true));
      atLeast(1).of(mapping1).getLength(); will(returnValue(11));
      one(mapping1).createUri(req1, map1, encoding);
      ignoring(mapping1);
    }});
    //10 is less than 11 but both match
    final Mapping mapping2 = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping2).matchesParameters(map1);
          will(returnValue(true));
      atLeast(1).of(mapping2).getLength(); will(returnValue(10));
      never(mapping2).createUri(req1, map1, encoding);
      ignoring(mapping2);
    }});
    
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping1);
    mapper.addMapping(mapping2);
    mapper.createUri(req1, map1, encoding);
    
    mockery.assertIsSatisfied();
  }
  
  public void testMapperProxiesReturnsOnCommit()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "thai-874";
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      allowing(req1).getParameter("test"); will(returnValue("request1"));
      ignoring(req1);
    }});
    final HttpServletRequest req2 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      allowing(req2).getParameter("test"); will(returnValue("request2"));
      ignoring(req2);
    }});
    final Mapping mapping = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping).matchesRequest(req1, encoding);
          will(returnValue(true));
      one(mapping).commit(req1, encoding);
          will(returnValue(req2));
      ignoring(mapping);
    }});
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping);
    assertEquals("request1", req1.getParameter("test"));
    HttpServletRequest testReq = mapper.commit(req1, encoding);
    assertEquals("request2", testReq.getParameter("test"));
    mockery.assertIsSatisfied();
  }
  
  public void testMapperProxiesReturnsOnCreateUri()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "utf-8";
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      ignoring(req1);
    }});
    final Map<String,String> params = new HashMap<String,String>();
    final Mapping mapping = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping).matchesParameters(params);
          will(returnValue(true));
      one(mapping).createUri(req1, params, encoding);
          will(returnValue("/foo/bar"));
      ignoring(mapping);
    }});
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping);
    String uri = mapper.createUri(req1, params, encoding);
    assertEquals("/foo/bar", uri);
    mockery.assertIsSatisfied();
  }
  
  public void testOriginalRequestIsReturnedOnNoMatch()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "thai-874";
    final HttpServletRequest req1 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      allowing(req1).getParameter("test"); will(returnValue("request1"));
      ignoring(req1);
    }});
    final HttpServletRequest req2 = mockery.mock(HttpServletRequest.class);
    mockery.checking(new Expectations() {{
      allowing(req2).getParameter("test"); will(returnValue("request2"));
      ignoring(req2);
    }});
    final Mapping mapping = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping).matchesRequest(req1, encoding);
          will(returnValue(false));
      never(mapping).commit(req1, encoding);
      ignoring(mapping);
    }});
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping);
    assertEquals("request1", req1.getParameter("test"));
    HttpServletRequest testReq = mapper.commit(req1, encoding);
    assertEquals("request1", testReq.getParameter("test"));
    mockery.assertIsSatisfied();
  }
  
  public void testUncleanUriIsReturnedOnNoMatch()
      throws UnsupportedEncodingException {
    Mockery mockery = new Mockery();
    final String encoding = "utf-8";
    final HttpServletRequest req1 = MockRequestFactory.createRequest(mockery,
        "/test/foo", "/test");
    mockery.checking(new Expectations() {{
      ignoring(req1);
    }});
    final Map<String,String> params = new LinkedHashMap<String,String>();
    params.put("foo", "bar");
    params.put("zip", "button");
    final Mapping mapping = mockery.mock(Mapping.class);
    mockery.checking(new Expectations() {{
      atLeast(1).of(mapping).matchesParameters(params);
          will(returnValue(false));
      never(mapping).createUri(req1, params, encoding);
      ignoring(mapping);
    }});
    Mapper mapper = new RequestMapper();
    mapper.addMapping(mapping);
    String uri = mapper.createUri(req1, params, encoding);
    assertEquals("/test/?foo=bar&zip=button", uri);
    mockery.assertIsSatisfied();
  }
  
}
Post Reply