Open Source Repository

Home /jodd/jodd-3.3.2 | Repository Home


jodd/io/http/HttpParams.java
// Copyright (c) 2003-2012, Jodd Team (jodd.org). All Rights Reserved.

package jodd.io.http;

import jodd.servlet.URLCoder;
import jodd.servlet.URLDecoder;
import jodd.util.ArraysUtil;
import jodd.util.KeyValue;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * HTTP parameters for handling both query and request parameters.
 */
public class HttpParams {
  
  protected final Map<String, Object> params;

  protected boolean hasFiles;

  public HttpParams(Map<String, Object> params) {
    this.params = params;
  }

  public HttpParams() {
    this.params = new LinkedHashMap<String, Object>();
  }

  public HttpParams(String query) {
    this(query, false);
  }

  public HttpParams(String query, boolean decode) {
    this.params = new LinkedHashMap<String, Object>();
    addParameters(query, decode);
  }

  // ---------------------------------------------------------------- methods

  /**
   * Returns total number of unique parameter names.
   */
  public int getParamsCount() {
    return params.size();
  }

  /**
   * Returns <code>true</code> if parameters contains
   * at least on non-string parameter, i.e. an upload file.
   */
  public boolean hasFiles() {
    return hasFiles;
  }

  /**
   * Returns parameter value.
   */
  public Object getParameter(String key) {
    return params.get(key);
  }

  /**
   * Adds a parameter.Parameter may be:
   <li>string, for single-value parameters
   <li>string array, for multi-value parameter
   <li>File, for files
   <p>
   * String parameters are accumulated, so adding a
   * parameter with the same name twice will result in
   * having a string array as a value.
   */
  public void addParameter(String key, Object value) {
    Object existing = params.get(key);
    
    if (existing != null) {
      Class type = existing.getClass();

      if (type == String.class) {
        value = new String[] {existing.toString(), value.toString()};
      else if (type == String[].class) {
        value = ArraysUtil.append((String[]) existing, value.toString());
      else {
        hasFiles = true;
      }
    }

    setParameter(key, value);
  }

  /**
   * Sets a parameter. Existing parameters are simply overwritten.
   */
  public void setParameter(String name, Object value) {
    Class type = value.getClass();
    if ((type != String.class&& (type != String[].class)) {
      hasFiles = true;
    }
    params.put(name, value);
  }

  /**
   * Add query parameters by parsing the query string.
   * Optionally, all names and values may be URL decoded.
   */
  public void addParameters(String query, boolean decode) {

    int ndx, ndx2 = 0;
    while (true) {
      ndx = query.indexOf('=', ndx2);
      if (ndx == -1) {
        if (ndx2 < query.length()) {
          params.put(query.substring(ndx2)null);
        }
        break;
      }
      String name = query.substring(ndx2, ndx);
      if (decode) {
        name = URLDecoder.decode(name);
      }

      ndx2 = ndx + 1;
      ndx = query.indexOf('&', ndx2);
      if (ndx == -1) {
        ndx = query.length();
      }
      String value = query.substring(ndx2, ndx);
      if (decode) {
        value = URLDecoder.decode(value);
      }

      Object newValue = value;
      Object existing = params.get(name);

      if (existing != null) {
        if (existing.getClass().isArray()) {
          newValue = ArraysUtil.append(((String[]) existing), newValue);
        else {
          newValue = new String[] {existing.toString(), value};
        }
      }

      params.put(name, newValue);

      ndx2 = ndx + 1;
    }
  }

  /**
   * Removes a parameter.
   */
  public void removeParameter(String key) {
    params.remove(key);
  }

  /**
   * Returns parameters iterator.
   */
  public Iterator<KeyValue<String, Object>> iterate() {
    final Iterator<Map.Entry<String,Object>> iterator = params.entrySet().iterator();

    final KeyValue<String, Object> keyValue = new KeyValue<String, Object>();
    
    return new Iterator<KeyValue<String, Object>>() {
      public boolean hasNext() {
        return iterator.hasNext();
      }

      public KeyValue<String, Object> next() {
        Map.Entry<String,Object> entry = iterator.next();
        keyValue.setKey(entry.getKey());
        keyValue.setValue(entry.getValue());
        return keyValue;
      }

      public void remove() {
        throw new UnsupportedOperationException();
      }
    };
  }

  // ---------------------------------------------------------------- generates

  /**
   * Generates encoded string of parameters.
   */
  public String toString() {
    StringBuilder sb = new StringBuilder();

    boolean first = true;
    for (Map.Entry<String, Object> entry : params.entrySet()) {
      if (first) {
        first = false;
      else {
        sb.append('&');
      }
      String key = URLCoder.encodeQuery(entry.getKey());

      Object value = entry.getValue();
      if (value != null) {
        Class type = value.getClass();
        
        if (type == String[].class) {
          Object[] array = (Object[]) value;
          for (int i = 0; i < array.length; i++) {
            if (i != 0) {
              sb.append('&');
            }
            Object o = array[i];
            sb.append(key);
            sb.append('=');
            sb.append(URLCoder.encodeQuery(o.toString()));
          }
        else {
          sb.append(key);
          sb.append('=');
          sb.append(URLCoder.encodeQuery(value.toString()));
        }
      else {
        sb.append(key);
      }
    }
    return sb.toString();
  }

}