Package br.com.caelum.vraptor.http.ognl

Source Code of br.com.caelum.vraptor.http.ognl.OgnlParametersProvider$Parameter

/***
* Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
* All rights reserved.
*
* Licensed 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 br.com.caelum.vraptor.http.ognl;

import static com.google.common.base.Predicates.containsPattern;
import static com.google.common.collect.Maps.filterKeys;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.com.caelum.vraptor.converter.ConversionError;
import br.com.caelum.vraptor.http.InvalidParameterException;
import br.com.caelum.vraptor.http.ParameterNameProvider;
import br.com.caelum.vraptor.http.ParametersProvider;
import br.com.caelum.vraptor.ioc.Container;
import br.com.caelum.vraptor.ioc.RequestScoped;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.validator.Message;
import br.com.caelum.vraptor.validator.ValidationMessage;

import com.google.common.base.Defaults;

/**
* Provides parameters using ognl to parse expression values into parameter
* values.
*
* @author guilherme silveira
*/
@RequestScoped
public class OgnlParametersProvider implements ParametersProvider {

  private final ParameterNameProvider provider;

  private static final Logger logger = LoggerFactory.getLogger(OgnlParametersProvider.class);

  private final HttpServletRequest request;

  private final Container container;

  private final OgnlFacade ognl;

  public OgnlParametersProvider(ParameterNameProvider provider,
      HttpServletRequest request, Container container, OgnlFacade ognl) {
    this.provider = provider;
    this.request = request;
    this.container = container;
    this.ognl = ognl;
  }

  public Object[] getParametersFor(ResourceMethod method, List<Message> errors, ResourceBundle bundle) {

    String[] names = provider.parameterNamesFor(method.getMethod());
    Type[] types = method.getMethod().getGenericParameterTypes();
    Class[] classes = method.getMethod().getParameterTypes();
    Object[] result = new Object[types.length];
    for (int i = 0; i < types.length; i++) {
      Map<String, String[]> requestNames = parametersThatStartWith(names[i]);
      result[i] = createParameter(new Parameter(types[i], classes[i], names[i], method), requestNames, bundle, errors);
    }

    return result;

  }

  protected static class Parameter {
    public Type type;
    public Class clazz;
    public String name;
    public ResourceMethod method;

    public Parameter(Type type, Class clazz, String name, ResourceMethod method) {
      this.type = type;
      this.clazz = clazz;
      this.name = name;
      this.method = method;
    }
    public Class actualType() {
      if (type instanceof TypeVariable) {
        ParameterizedType superclass = (ParameterizedType) method.getResource().getType().getGenericSuperclass();
        return (Class) superclass.getActualTypeArguments()[0];
      }
      return clazz;
    }
  }

  protected Object createParameter(Parameter param, Map<String, String[]> requestNames, ResourceBundle bundle, List<Message> errors) {
    Object root;
    if (request.getAttribute(param.name) != null) {
      return request.getAttribute(param.name);
    } else if (param.clazz.isInterface() && container.canProvide(param.clazz)) {
            return container.instanceFor(param.clazz);
        } else if (requestNames.isEmpty()) {
      return Defaults.defaultValue(param.actualType());
    } else {
      root = createRoot(param, requestNames, bundle, errors);
      if (root == null) {
        return null;
      }
    }

    ognl.startContext(param.name, param.type, root, bundle);

    for (Entry<String, String[]> parameter : requestNames.entrySet()) {
      String key = parameter.getKey().replaceFirst("^" + param.name + "\\.?", "");
      String[] values = parameter.getValue();
      setProperty(param.name, key, values, errors);
    }

    return ognl.get(param.name);
  }

  protected Object createRoot(Parameter param, Map<String, String[]> requestNames, ResourceBundle bundle,
      List<Message> errors) {
    if (requestNames.containsKey(param.name)) {
      String[] values = requestNames.get(param.name);
      try {
        return createSimpleParameter(param, values, bundle);
      } catch(ConversionError ex) {
        errors.add(new ValidationMessage(ex.getMessage(), param.name));
        return null;
      }
    }

    try {
      return ognl.nullHandler().instantiate(param.actualType());
    } catch (Exception ex) {
      throw new InvalidParameterException("unable to instantiate type " + param.type, ex);
    }
  }

  protected void setProperty(String name, String key, String[] values, List<Message> errors) {
    try {
      logger.debug("Applying {} with {}",key, values);
      ognl.setValue(name, key, values);
    } catch (ConversionError ex) {
      errors.add(new ValidationMessage(ex.getMessage(), key));
    }
  }

  protected Object createSimpleParameter(Parameter param, String[] values, ResourceBundle bundle) {
    if (param.actualType().isArray()) {
      return createArray(param.actualType(), values, bundle);
    }
    if (List.class.isAssignableFrom(param.actualType())) {
      return createList(param.type, bundle, values);
    }
    return convert(param.actualType(), values[0], bundle);
  }

  protected Object convert(Class clazz, String value, ResourceBundle bundle) {
    return ognl.createAdapter(bundle).convert(value, clazz);
  }

  protected List createList(Type type, ResourceBundle bundle, String[] values) {
    List list = new ArrayList();
    Class actual = getActualType(type);
    for (String value : values) {
      list.add(convert(actual, value, bundle));
    }
    return list;
  }

  protected Object createArray(Class clazz, String[] values, ResourceBundle bundle) {
    Class arrayType = clazz.getComponentType();
    Object array = Array.newInstance(arrayType, values.length);
    for (int i = 0; i < values.length; i++) {
      Array.set(array, i, convert(arrayType, values[i], bundle));
    }
    return array;
  }

  protected Class getActualType(Type type) {
    return (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
  }

  protected Map<String, String[]> parametersThatStartWith(String name) {
    Map<String, String[]> requestNames = filterKeys(request.getParameterMap(), containsPattern("^" + name));
    return new TreeMap<String, String[]>(requestNames);
  }
}
TOP

Related Classes of br.com.caelum.vraptor.http.ognl.OgnlParametersProvider$Parameter

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.