MockHttpServletRequest.java :  » UnTagged » responder-iq » com » riq » Android Open Source

Android Open Source » UnTagged » responder iq 
responder iq » com » riq » MockHttpServletRequest.java
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.riq;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * This class Mocks a HttpServletRequest for unit test purposes. Currently, it
 * supports servlet API 2.4.
 *
 * <p>
 * To use this class, you specify the request info (URL, parameters) in the
 * constructors.
 *
 * <p>
 * Lots of stuff are still not implemented here. Feel free to implement them.
 */
public class MockHttpServletRequest implements HttpServletRequest {
  protected static final String DEFAULT_HOST = "localhost";
  protected static final int DEFAULT_PORT = 80;
  private static final String COOKIE_HEADER = "Cookie";
  private static final String HOST_HEADER = "Host";
  private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";

  protected String scheme = "http";
  protected String host;
  protected int port;
  protected boolean secure = false;
  protected String method = "GET";
  protected String protocol = "HTTP/1.0";
  protected String contextPath;
  protected String servletPath;
  protected String pathInfo = null;
  protected String queryString;
  protected String ip = "127.0.0.1";
  protected String contentType;

  protected Hashtable<String, String> headers =
      new Hashtable<String, String>();

  // Use a LinkedHashMap so we can generate a query string that is in the same
  // order that we set the parameters
  protected Map<String, String[]> parameters = new LinkedHashMap <String, String[]>();

  protected Set<String> postParameters = new HashSet <String> ();

  protected Map<String, Cookie> cookies = new Hashtable<String, Cookie>();


  // Use a Map rather than a table since the specified behavior of
  // setAttribute() allows null values.
  protected Map<String, Object> attributes = new HashMap<String, Object>();

  protected Locale locale = Locale.US;
  protected List<Locale> locales = null;

  // used by POST methods
  protected byte[] postData;
  protected String characterEncoding;

  // the following two booleans ensure that either getReader() or
  // getInputStream is called, but not both, to conform to specs for the
  // HttpServletRequest class.
  protected boolean getReaderCalled = false;
  protected boolean getInputStreamCalled = false;

  private HttpSession session;

  static final String METHOD_POST = "POST";

  /**
   * Example: http://www.example.com:1234/foo/bar?abc=xyz "www.example.com" is
   * the host 1234 is the port "/foo" is the contextPath "/bar" is the
   * servletPath "abc=xyz" is the queryString
   */
  public MockHttpServletRequest(String host, int port, String contextPath,
      String servletPath, String queryString) {
    constructor(host, port, contextPath, servletPath, queryString);
  }

  public MockHttpServletRequest(String host, String port, String contextPath,
      String servletPath, String queryString) {
    this(host, Integer.parseInt(port), contextPath, servletPath, queryString);
  }

  public MockHttpServletRequest(String contextPath, String servletPath,
      String queryString) {
    this(DEFAULT_HOST, -1, contextPath, servletPath, queryString);
  }

  public MockHttpServletRequest() {
    this(DEFAULT_HOST, DEFAULT_PORT, "", null, null);
  }

  public MockHttpServletRequest(String urlStr) throws MalformedURLException {
    URL url = new URL(urlStr);
    String contextPath;
    String servletPath;
    String path = url.getPath();
    if (path.length() <= 1) {
      // path must be either empty string or "/"
      contextPath = path;
      servletPath = null;
    } else {
      // Look for the second slash which separates the servlet path from the
      // context path. e.g. "/foo/bar"
      int secondSlash = path.indexOf('/', 1);
      if (secondSlash < 0) {
        // No second slash
        contextPath = path;
        servletPath = null;
      } else {
        contextPath = path.substring(0, secondSlash);
        servletPath = path.substring(secondSlash);
      }
    }

    // Set the scheme
    scheme = url.getProtocol();
    if (scheme.equalsIgnoreCase("https")) {
      secure = true;
    }

    int port = url.getPort();

    // Call constructor() instead of this() because the later is only allowed
    // at the begining of a constructor
    constructor(url.getHost(), port, contextPath, servletPath, url.getQuery());
  }

  public MockHttpServletRequest setLocale(Locale locale) {
    this.locale = locale;
    return this;
  }

  public MockHttpServletRequest setLocales(List<Locale> locales) {
    this.locales = locales;
    return this;
  }

  public MockHttpServletRequest setProtocol(String prot) {
    this.protocol = prot;
    return this;
  }

  public MockHttpServletRequest setSecure(boolean secure) {
    this.secure = secure;
    return this;
  }

  /*
   * Set a header on this request. Note that if the header implies other
   * attributes of the request I will set them accordingly. Specifically:
   *
   * If the header is "Cookie:" then I will automatically call setCookie on all
   * of the name-value pairs found therein.
   *
   * This makes the object easier to use because you can just feed it headers
   * and the object will remain consistent with the behavior you'd expect from a
   * request.
   */
  public MockHttpServletRequest setHeader(String name, String value) {
    if (name.equals(COOKIE_HEADER)) {
      String[] pairs = splitAndTrim(value, ";");
      for (String pair : pairs) {
        int equalsPos = pair.indexOf('=');
        if (equalsPos != -1) {
          String cookieName = pair.substring(0, equalsPos);
          String cookieValue = pair.substring(equalsPos + 1);
          addToCookieMap(new Cookie(cookieName, cookieValue));
        }
      }
      setCookieHeader();
      return this;
    }

    addToHeaderMap(name, value);

    if (name.equals(HOST_HEADER)) {
      host = value;
    }
    return this;
  }

  private void addToHeaderMap(String name, String value) {
    headers.put(name.toLowerCase(), value);
  }

  /**
   * Associates a set of cookies with this Mock request.
   *
   * @param cookies the cookies associated with this request.
   */
  public MockHttpServletRequest setCookies(Cookie... cookies) {
    for (Cookie cookie : cookies) {
      addToCookieMap(cookie);
    }
    setCookieHeader();
    return this;
  }

  /**
   * Sets a single cookie associated with this Mock request. Cookies are
   * cumulative, but ones with the same name will overwrite one another.
   *
   * @param c the cookie to associate with this request.
   */
  public MockHttpServletRequest setCookie(Cookie c) {
    addToCookieMap(c);
    setCookieHeader();
    return this;
  }

  private void addToCookieMap(Cookie c) {
    cookies.put(c.getName(), c);
  }

  /**
   * Sets the "Cookie" HTTP header based on the current cookies.
   */
  private void setCookieHeader() {
    StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (Cookie c : cookies.values()) {
      if (!isFirst) {
        sb.append("; ");
      }
      sb.append(c.getName());
      sb.append('=');
      sb.append(c.getValue());
      isFirst = false;
    }

    // We cannot use setHeader() here, because setHeader() calls this method
    addToHeaderMap(COOKIE_HEADER, sb.toString());
  }

  /**
   * Sets the a parameter in this Mock request.
   *
   * @param name the string key
   * @param values the string array value
   * @param isPost if the paramenter comes in the post body.
   */
  public MockHttpServletRequest setParameter(String name, boolean isPost, String... values) {
    if (isPost) {
      postParameters.add(name);
    }
    parameters.put(name, values);
    // Old query string no longer matches up, so set it to null so it can be
    // regenerated on the next call of getQueryString()
    queryString = null;
    return this;
  }

  /**
   * Sets the a parameter in this Mock request.
   *
   * @param name the string key
   * @param values the string array value
   */
  public MockHttpServletRequest setParameter(String name, String... values) {
    setParameter(name, false, values);
    return this;
  }


  /** Set the path info field. */
  public MockHttpServletRequest setPathInfo(String path) {
    pathInfo = path;
    return this;
  }

  /**
   * Specify the mock POST data.
   *
   * @param postString the mock post data
   * @param encoding format with which to encode mock post data
   */
  public MockHttpServletRequest setPostData(String postString, String encoding)
      throws UnsupportedEncodingException {
    setPostData(postString.getBytes(encoding));
    characterEncoding = encoding;
    return this;
  }

  /**
   * Specify the mock POST data in raw binary format.
   *
   * This implicitly sets character encoding to not specified.
   *
   * @param data the mock post data; this is owned by the caller, so
   *        modifications made after this call will show up when the post data
   *        is read
   */
  public MockHttpServletRequest setPostData(byte[] data) {
    postData = data;
    characterEncoding = null;
    method = METHOD_POST;
    return this;
  }

  /**
   * Set a new value for the query string. The query string will be parsed and
   * all parameters reset.
   *
   * @param queryString representing the new value. i.e.: "bug=1&id=23"
   */
  public MockHttpServletRequest setQueryString(String queryString) {
    this.queryString = queryString;
    parameters.clear();
    decodeQueryString(queryString, parameters);
    return this;
  }

  /**
   * Sets the session for this request.
   *
   * @param session the new session
   */
  public MockHttpServletRequest setSession(HttpSession session) {
    this.session = session;
    return this;
  }

  /**
   * Sets the content type.
   *
   * @param contentType of the request.
   */
  public MockHttpServletRequest setContentType(String contentType) {
    this.contentType = contentType;
    return this;
  }

  // ///////////////////////////////////////////////////////////////////////////
  // Implements methods from HttpServletRequest
  // ///////////////////////////////////////////////////////////////////////////

  public String getAuthType() {
    throw new UnsupportedOperationException();
  }

  public java.lang.String getContextPath() {
    return contextPath;
  }

  public Cookie[] getCookies() {
    if (cookies.isEmpty()) {
      // API promises null return if no cookies
      return null;
    }
    return cookies.values().toArray(new Cookie[cookies.size()]);
  }

  public long getDateHeader(String name) {
    String value = getHeader(name);
    if (value == null) return -1;

    SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT, Locale.US);
    format.setTimeZone(TimeZone.getTimeZone("GMT"));
    try {
      return format.parse(value).getTime();
    } catch (ParseException e) {
      throw new IllegalArgumentException("Cannot parse number from header "
          + name + ':' + value, e);
    }
  }

  public MockHttpServletRequest setDateHeader(String name, long value) {
    SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT, Locale.US);
    format.setTimeZone(TimeZone.getTimeZone("GMT"));
    setHeader(name, format.format(new Date(value)));
    return this;
  }

  public String getHeader(String name) {
    return headers.get(name.toLowerCase());
  }

  public Enumeration<String> getHeaderNames() {
    return headers.keys();
  }

  public Enumeration<?> getHeaders(String name) {
    List<String> values = new ArrayList<String>();
    for (Map.Entry<String, String> entry : headers.entrySet()) {
      if (name.equalsIgnoreCase(entry.getKey())) {
        values.add(entry.getValue());
      }
    }
    return Collections.enumeration(values);
  }

  public int getIntHeader(String name) {
    return Integer.parseInt(getHeader(name));
  }

  public String getMethod() {
    return method;
  }

  public MockHttpServletRequest setMethod(String method) {
    this.method = method;
    return this;
  }

  public String getPathInfo() {
    return pathInfo;
  }

  public String getPathTranslated() {
    throw new UnsupportedOperationException();
  }

  public String getQueryString() {
    try {
      if (queryString == null && !parameters.isEmpty()) {
        boolean hasPrevious = false;
        StringBuilder queryString = new StringBuilder();
        for (Map.Entry<String, String[]> stringEntry : parameters.entrySet()) {
          // We're not interested in blank keys
          if (stringEntry.getKey() == null || stringEntry.getKey().equals("") || postParameters.contains(stringEntry.getKey())) {
            continue;
          }
          if (hasPrevious) {
            queryString.append('&');
          }

          String[] values = stringEntry.getValue();
          // Append the parameters to the query string
          if (values.length == 0) {
            queryString.append(URLEncoder.encode(stringEntry.getKey(), "UTF-8"));
          } else {
            for (int i = 0; i < values.length; i++) {
              queryString.append(URLEncoder.encode(stringEntry.getKey(), "UTF-8")).append('=').append(
                      URLEncoder.encode(values[i], "UTF-8"));
              if (i < values.length - 1) {
                queryString.append('&');
              }
            }
          }
          hasPrevious = true;

        }
        this.queryString = queryString.toString();
      }
      return queryString;
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("Should always support UTF-8", e);
    }
  }

  public String getRemoteUser() {
    throw new UnsupportedOperationException();
  }

  public String getRequestedSessionId() {
    throw new UnsupportedOperationException();
  }

  public String getRequestURI() {
    StringBuilder buf = new StringBuilder();
    if (!contextPath.equals("")) {
      buf.append(contextPath);
    }

    if (servletPath != null && !"".equals(servletPath)) {
      buf.append(servletPath);
    }

    if (buf.length() == 0) {
      buf.append('/');
    }

    return buf.toString();
  }

  public StringBuffer getRequestURL() {
    StringBuffer buf =
        secure ? new StringBuffer("https://") : new StringBuffer("http://");
    buf.append(host);
    if (port >= 0) {
      buf.append(':');
      buf.append(port);
    }
    buf.append(getRequestURI()); // always begins with '/'
    return buf;
  }

  public String getServletPath() {
    return servletPath;
  }

  public MockHttpServletRequest setServletPath(String servletPath) {
    this.servletPath = servletPath;
    return this;
  }

  public HttpSession getSession() {
    return getSession(true);
  }

  public HttpSession getSession(boolean create) {
    // TODO return Mock session if create && session == null
    return session;
  }

  public java.security.Principal getUserPrincipal() {
    throw new UnsupportedOperationException();
  }

  public boolean isRequestedSessionIdFromCookie() {
    throw new UnsupportedOperationException();
  }

  @Deprecated
  public boolean isRequestedSessionIdFromUrl() {
    throw new UnsupportedOperationException("This method is deprecated");
  }

  public boolean isRequestedSessionIdFromURL() {
    throw new UnsupportedOperationException();
  }

  public boolean isRequestedSessionIdValid() {
    throw new UnsupportedOperationException();
  }

  public boolean isUserInRole(String role) {
    throw new UnsupportedOperationException();
  }

  // Implements methods from ServletRequest ///////////////////////////////////

  public Object getAttribute(String name) {
    return attributes.get(name);
  }

  public Enumeration<?> getAttributeNames() {
    return Collections.enumeration(attributes.keySet());
  }

  public String getCharacterEncoding() {
    return characterEncoding;
  }

  public int getContentLength() {
    return (postData == null) ? 0 : postData.length;
  }

  public String getContentType() {
    return contentType;
  }

  /**
   * Get the body of the request (i.e. the POST data) as a binary stream. As per
   * Java docs, this OR getReader() may be called, but not both (attempting that
   * will result in an IllegalStateException)
   *
   */
  public ServletInputStream getInputStream() {
    if (getReaderCalled) {
      throw new IllegalStateException(
          "getInputStream() called after getReader()");
    }
    getInputStreamCalled = true; // so that getReader() can no longer be called

    final InputStream in = new ByteArrayInputStream(postData);
    return new ServletInputStream() {
      @Override public int read() throws IOException {
        return in.read();
      }
    };
  }

  public Locale getLocale() {
    return locale;
  }

  public Enumeration<?> getLocales() {
    return Collections.enumeration(locales);
  }

  public String getParameter(String name) {
    String[] parameters = getParameterValues(name);
    if (parameters == null || parameters.length < 1) {
      return null;
    } else {
      return parameters[0];
    }
  }

  public Map<String, String[]> getParameterMap() {
    return parameters;
  }

  public Enumeration<String> getParameterNames() {
    return Collections.enumeration(parameters.keySet());
  }

  public String[] getParameterValues(String name) {
    return parameters.get(name);
  }

  public String getProtocol() {
    return protocol;
  }

  public BufferedReader getReader() throws IOException {
    if (getInputStreamCalled) {
      throw new IllegalStateException(
          "getReader() called after getInputStream()");
    }

    getReaderCalled = true;
    BufferedReader br = null;
    ByteArrayInputStream bais = new ByteArrayInputStream(postData);
    InputStreamReader isr;
    if (characterEncoding != null) {
      isr = new InputStreamReader(bais, characterEncoding);
    } else {
      isr = new InputStreamReader(bais);
    }
    br = new BufferedReader(isr);
    return br;
  }

  @Deprecated
  public String getRealPath(String path) {
    throw new UnsupportedOperationException("This method is deprecated");
  }

  public String getRemoteAddr() {
    return ip;
  }

  /**
   * Sets the remote IP address for this {@code MockHttpServletRequest}.
   *
   * @param ip the IP to set
   * @return this {@code MockHttpServletRequest} object
   */
  public MockHttpServletRequest setRemoteAddr(String ip) {
    this.ip = ip;
    return this;
  }

  public String getRemoteHost() {
    return "localhost";
  }


  /*
   * (non-Javadoc)
   *
   * New Servlet 2.4 method
   *
   * @see javax.servlet.ServletRequest#getLocalPort()
   */
  public int getLocalPort() {
    return 8080;
  }

  /*
   * (non-Javadoc)
   *
   * New Servlet 2.4 method
   *
   * @see javax.servlet.ServletRequest#getLocalAddr()
   */
  public String getLocalAddr() {
    return "127.0.0.1";
  }

  /*
   * (non-Javadoc)
   *
   * New Servlet 2.4 method
   *
   * @see javax.servlet.ServletRequest#getLocalName()
   */
  public String getLocalName() {
    return "localhost";
  }

  /*
   * (non-Javadoc)
   *
   * New Servlet 2.4 method
   *
   * @see javax.servlet.ServletRequest#getRemotePort()
   */
  public int getRemotePort() {
    throw new UnsupportedOperationException();
  }


  public RequestDispatcher getRequestDispatcher(String path) {
    throw new UnsupportedOperationException();
  }

  public String getScheme() {
    return scheme;
  }

  public String getServerName() {
    return host;
  }

  public int getServerPort() {
    return (port < 0) ? DEFAULT_PORT : port;
  }

  public boolean isSecure() {
    return secure;
  }

  public void removeAttribute(String name) {
    attributes.remove(name);
  }

  public void setAttribute(String name, Object value) {
    attributes.put(name, value);
  }

  /**
   * @inheritDoc
   *
   * For POST requests, this affects interpretation of POST body.
   *
   * For non-POST requests (original author's comment): Do nothing - all request
   * components were created as unicode Strings, so this can't affect how
   * they're interpreted anyway.
   */
  public void setCharacterEncoding(String env) {
    if (method.equals(METHOD_POST)) {
      characterEncoding = env;
    }
  }

  // Helper methods ///////////////////////////////////////////////////////////

  /**
   * This method serves as the central constructor of this class. The reason it
   * is not an actual constructor is that Java doesn't allow calling another
   * constructor at the end of a constructor. e.g.
   *
   * <pre>
   * public MockHttpServletRequest(String foo) {
   *   // Do something here
   *   this(foo, bar); // calling another constructor here is not allowed
   * }
   * </pre>
   */
  protected void constructor(String host, int port, String contextPath,
      String servletPath, String queryString) {
    setHeader(HOST_HEADER, host);
    this.port = port;
    this.contextPath = contextPath;
    this.servletPath = servletPath;
    this.queryString = queryString;
    if (queryString != null) {
      decodeQueryString(queryString, parameters);
    }
  }

  protected void decodeQueryString(String queryString,
      Map<String, String[]> parameters) {
    for (String param : queryString.split("&")) {
      // The first '=' separates the name and value
      int sepPos = param.indexOf('=');
      String name, value;
      if (sepPos < 0) {
        // if no equal is present, assume a blank value
        name = param;
        value = "";
      } else {
        name = param.substring(0, sepPos);
        value = param.substring(sepPos + 1);
      }

      addParameter(parameters, decodeParameterPart(name),
          decodeParameterPart(value));
    }
  }

  private String decodeParameterPart(String str) {
    // borrowed from FormUrlDecoder
    try {
      // we could infer proper encoding from headers, but setCharacterEncoding
      // is a noop.
      return URLDecoder.decode(str, "UTF-8");
    } catch (IllegalArgumentException iae) {
      // According to the javadoc of URLDecoder, when the input string is
      // illegal, it could either leave the illegal characters alone or throw
      // an IllegalArgumentException! To deal with both consistently, we
      // ignore IllegalArgumentException and just return the original string.
      return str;
    } catch (UnsupportedEncodingException e) {
      return str;
    }
  }

  protected void addParameter(Map<String, String[]> parameters, String name,
      String value) {
    if (parameters.containsKey(name)) {
      String[] existingParamValues = parameters.get(name);
      String[] newParamValues = new String[existingParamValues.length + 1];
      System.arraycopy(existingParamValues, 0, newParamValues, 0,
          existingParamValues.length);
      newParamValues[newParamValues.length - 1] = value;
      parameters.put(name, newParamValues);
    } else {
      String[] paramValues = {value,};
      parameters.put(name, paramValues);
    }
  }

  private static String[] splitAndTrim(String str, String delims) {
    StringTokenizer tokenizer = new StringTokenizer(str, delims);
    int n = tokenizer.countTokens();
    String[] list = new String[n];
    for (int i = 0; i < n; i++) {
      list[i] = tokenizer.nextToken().trim();
    }
    return list;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.