Package com.medallia.spider.api

Source Code of com.medallia.spider.api.DynamicInputImpl

/*
* This file is part of the Spider Web Framework.
*
* The Spider Web Framework 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.
*
* The Spider Web Framework 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 the Spider Web Framework.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.medallia.spider.api;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

import com.medallia.spider.IOHelpers;
import com.medallia.spider.api.StRenderable.DynamicInput;
import com.medallia.spider.api.StRenderable.Input;
import com.medallia.spider.api.StRenderer.InputArgHandler;
import com.medallia.spider.api.StRenderer.InputArgParser;
import com.medallia.tiny.Empty;
import com.medallia.tiny.Encoding;
import com.medallia.tiny.Implement;
import com.medallia.tiny.Strings;

/** Implementation of {@link DynamicInput} that is also used to parse the
* values for the static input variables.
*/
public class DynamicInputImpl implements DynamicInput, InputArgHandler {

  private final Map<String, String[]> inputParams;
  private final Map<String, byte[]> fileUploads;
 
  private final Map<Class<?>, InputArgParser<?>> inputArgParsers = Empty.hashMap();

  /**
   * @param the request from which to read the request parameters
   */
  public DynamicInputImpl(HttpServletRequest request) {
    if (ServletFileUpload.isMultipartContent(request)) {
      this.inputParams = Empty.hashMap();
      this.fileUploads = Empty.hashMap();

      ServletFileUpload upload = new ServletFileUpload();
      try {
        FileItemIterator iter = upload.getItemIterator(request);
        while (iter.hasNext()) {
          FileItemStream item = iter.next();
          String fieldName = item.getFieldName();
          InputStream stream = item.openStream();
          if (item.isFormField()) {
            inputParams.put(fieldName, new String[] { Streams.asString(stream, Encoding.CHARSET_UTF8_NAME) });
          } else {
            fileUploads.put(fieldName, IOHelpers.toByteArray(stream));
          }
        }
      } catch (IOException e) {
        throw new IllegalArgumentException("Failed to parse multipart", e);
      } catch (FileUploadException e) {
        throw new IllegalArgumentException("Failed to parse multipart", e);
      }
    } else {
      @SuppressWarnings("unchecked")
      Map<String, String[]> reqParams = request.getParameterMap();
      this.inputParams = reqParams;
      this.fileUploads = Collections.emptyMap();
    }
  }
 
  @Implement public <X> void registerArgParser(Class<X> type, InputArgParser<X> parser) {
    inputArgParsers.put(type, parser);
  }

  @Implement public <X> X getInput(String name, Class<X> type) {
    return getInput(name, type, emptyAnnotatedElement);
  }
 
  /**
   * Method used for parse values for the methods declared in {@link Input}.
   */
  public <X> X getInput(String name, Class<X> type, AnnotatedElement anno) {
    // Special case for file uploads
    if (type.isArray() && type.getComponentType() == Byte.TYPE) {
      return type.cast(fileUploads.get(name));
    }
   
    if (type.isArray() && anno.isAnnotationPresent(Input.MultiValued.class)) {
      // return type is an array; grab all
      Object o = inputParams.get(name);
      return type.cast(parseMultiValue(type, o, anno));
    }
   
    String v = Strings.extract(inputParams.get(name));
   
    // boolean is used for checkboxes, and false is encoded as a missing value
    if (type == Boolean.class || type == Boolean.TYPE) {
      @SuppressWarnings("unchecked")
      X x = (X) Boolean.valueOf(v != null);
      return x;
    }
   
    // the remaining types have proper null values
    if (v == null) return null;
   
    // Do not use Class.cast here since it does not work on primitive types
    @SuppressWarnings("unchecked")
    X x = (X) parseSingleValue(type, v, anno);
    return x;
  }
 
  /**
   * @param rt some kind of array class
   * @param data null, String or String[]
   * @return parsed data as per parseSingleValue
   * @throws AssertionError if parseSingleValue does
   */
  private Object parseMultiValue(Class<?> rt, Object data, AnnotatedElement anno) throws AssertionError {
    String[] xs;
    // normalize the zero-and-one cases
    if (data == null) {
      xs = new String[0];
    } else if (data instanceof String[]) {
      xs = (String[]) data;
    } else {
      xs = new String[] { data.toString() };
    }
   
    Class<?> comp = rt.getComponentType();
    Object arr = Array.newInstance(rt.getComponentType(), xs.length);
    for (int i=0; i < xs.length; i++) {
      Array.set(arr, i, parseSingleValue(comp, xs[i], anno));
    }
    return arr;
  }

  private Object parseSingleValue(Class<?> rt, String v, AnnotatedElement anno) throws AssertionError {
    if (rt.isEnum()) {
      String vlow = v.toLowerCase();
      for (Enum e : rt.asSubclass(Enum.class).getEnumConstants()) {
        if (e.name().toLowerCase().equals(vlow)) return e;
      }
      throw new AssertionError("Enum constant not found: " + v);
    } else if (rt == Integer.class) {
      // map blank strings to null
      return Strings.hasContent(v) ? Integer.valueOf(v) : null;
    } else if (rt == Integer.TYPE) {
      // primitive int must have a value
      return Integer.valueOf(v);
    } else if (rt == Long.class) {
      // map blank strings to null
      return Strings.hasContent(v) ? Long.valueOf(v) : null;
    } else if (rt == Long.TYPE) {
      // primitive long must have a value
      return Long.valueOf(v);
    } else if (rt == Double.class) {
      // map blank strings to null
      return Strings.hasContent(v) ? Double.valueOf(v) : null;
    } else if (rt == Double.TYPE) {
      // primitive double must have a value
      return Double.valueOf(v);
    } else if (rt == String.class) {
      return v;
    } else if (rt.isArray()) {
      Input.List ann = anno.getAnnotation(Input.List.class);
      if (ann == null) throw new AssertionError("Array type but no annotation (see "+Input.class+"): "+anno);
      String separator = ann.separator();
      String[] strVals = v.split(separator, -1);
      Class<?> arrayType = rt.getComponentType();
      Object a = Array.newInstance(arrayType, strVals.length);
      for (int i = 0; i < strVals.length; i++) {
        Array.set(a, i, parseSingleValue(arrayType, strVals[i], anno));
      }
      return a;
    } else {
      InputArgParser<?> argParser = inputArgParsers.get(rt);
      if (argParser != null) {
        return argParser.parse(v);
      }
    }
    throw new AssertionError("Unknown return type " + rt + " (val: " + v + ")");
  }
 
  private static final AnnotatedElement emptyAnnotatedElement = new AnnotatedElement() {
    @Implement public <T extends Annotation> T getAnnotation(Class<T> annotationType) { return null; }
    @Implement public Annotation[] getAnnotations() { return null; }
    @Implement public Annotation[] getDeclaredAnnotations() { return null; }
    @Implement public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { return false; }
  };

}
TOP

Related Classes of com.medallia.spider.api.DynamicInputImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.