Package org.springframework.springfaces.mvc.navigation.requestmapped

Source Code of org.springframework.springfaces.mvc.navigation.requestmapped.RequestMappedRedirectViewModelBuilder

/*
* Copyright 2010-2012 the original author or authors.
*
* 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 org.springframework.springfaces.mvc.navigation.requestmapped;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.faces.context.FacesContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.http.HttpEntity;
import org.springframework.springfaces.mvc.bind.ReverseDataBinder;
import org.springframework.springfaces.mvc.navigation.requestmapped.filter.AnnotationMethodParameterFilter;
import org.springframework.springfaces.mvc.navigation.requestmapped.filter.MethodParameterFilter;
import org.springframework.springfaces.mvc.navigation.requestmapped.filter.MethodParameterFilterChain;
import org.springframework.springfaces.mvc.navigation.requestmapped.filter.TypeMethodParameterFilter;
import org.springframework.springfaces.mvc.navigation.requestmapped.filter.WebArgumentResolverMethodParameterFilter;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.support.WebRequestDataBinder;
import org.springframework.web.context.request.FacesWebRequest;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartRequest;

/**
* A builder class that can be used to create a model containing items that are relevant to the parameters of a handler
* method.
*
* @author Phillip Webb
* @see #build(NativeWebRequest, Map)
*/
public class RequestMappedRedirectViewModelBuilder {

  /**
   * Annotations that are handled natively my MVC and hence should be filtered.
   */
  private static final AnnotationMethodParameterFilter ANNOTAION_FILTER = new AnnotationMethodParameterFilter(
      RequestHeader.class, RequestBody.class, CookieValue.class, ModelAttribute.class, Value.class);

  /**
   * Types that are handled natively my MVC and hence should be filtered.
   */
  private static final TypeMethodParameterFilter TYPE_FILTER = new TypeMethodParameterFilter(WebRequest.class,
      ServletRequest.class, MultipartRequest.class, ServletResponse.class, HttpSession.class, Principal.class,
      Locale.class, InputStream.class, Reader.class, OutputStream.class, Writer.class, Map.class, Model.class,
      SessionStatus.class, HttpEntity.class, Errors.class);

  private RequestMappedRedirectViewContext context;

  private Method handlerMethod;

  /**
   * The complete set of filters that will be applied to the handler method parameters.
   */
  private MethodParameterFilter methodParameterFilter;

  /**
   * Create a new {@link RequestMappedRedirectViewModelBuilder}.
   * @param context the context for redirect view
   * @param handlerMethod the MVC handler method method
   */
  public RequestMappedRedirectViewModelBuilder(RequestMappedRedirectViewContext context, Method handlerMethod) {
    Assert.notNull(context, "Context must not be null");
    Assert.notNull(handlerMethod, "HandlerMethod must not be null");
    this.context = context;
    this.handlerMethod = handlerMethod;
    this.methodParameterFilter = new MethodParameterFilterChain(ANNOTAION_FILTER, TYPE_FILTER,
        new WebArgumentResolverMethodParameterFilter(context.getCustomArgumentResolvers()));
  }

  /**
   * Build a model form the specified source. The resulting model contains the elements from the source that are
   * relevant to the parameters of the handler method. The following methods will be used to find items from source:
   * <ul>
   * <li>The name of the parameter (specified by an annotation or generated) will be used as the key to get an element
   * from the source.</li>
   * <li>The source will be searched for any values that are an instance of the parameter types. When this method is
   * used the model must contain only a single entry of each type.</li>
   * <ul>
   * NOTE: When the method parameter is not a simple type it will be expanded into multiple model entries using a
   * {@link ReverseDataBinder}.
   *
   * @param request the current native web request
   * @param source a map containing the source of items to add to the model
   * @return a model containing items relevant to the handler method parameters.
   */
  public Map<String, Object> build(NativeWebRequest request, Map<String, ?> source) {
    ParameterNameDiscoverer parameterNameDiscoverer = this.context.getParameterNameDiscoverer();
    if (parameterNameDiscoverer == null) {
      parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
    }
    Map<String, Object> model = new HashMap<String, Object>();
    for (int i = 0; i < this.handlerMethod.getParameterTypes().length; i++) {
      MethodParameter methodParameter = new MethodParameter(this.handlerMethod, i);
      if (!isIgnored(request, methodParameter)) {
        methodParameter.initParameterNameDiscovery(parameterNameDiscoverer);
        PathVariable pathVariable = methodParameter.getParameterAnnotation(PathVariable.class);
        RequestParam requestParam = methodParameter.getParameterAnnotation(RequestParam.class);
        if (pathVariable != null) {
          addToPathVariableModel(model, methodParameter, pathVariable, source);
        } else {
          addRequestParameterToModel(model, methodParameter, requestParam, source);
        }
      }
    }
    return model;
  }

  /**
   * Determines if the specified method parameter should be ignored.
   * @param request the current web request
   * @param methodParameter the method parameter
   * @return <tt>true</tt> if the parameter should be ignored.
   */
  protected boolean isIgnored(NativeWebRequest request, MethodParameter methodParameter) {
    return this.methodParameterFilter.matches(request, methodParameter);
  }

  /**
   * Add a path variable to the model.
   * @param model the model being built
   * @param methodParameter the method parameter
   * @param pathVariable the path variable (never null)
   * @param source the source data map
   */
  private void addToPathVariableModel(Map<String, Object> model, MethodParameter methodParameter,
      PathVariable pathVariable, Map<String, ?> source) {
    String name = pathVariable.value();
    if (name.length() == 0) {
      name = methodParameter.getParameterName();
      assertHasName(name, methodParameter);
    }
    Object value = source.get(name);
    if (value == null) {
      Map.Entry<String, ?> entry = getMapEntryByType(source, methodParameter.getParameterType());
      Assert.state(entry != null, "Unable to find path variable value in model of type "
          + methodParameter.getParameterType().getName());
      value = entry.getValue();
    }
    addIfNotContainsKey(model, name, value);
  }

  /**
   * @param model the model being built
   * @param methodParameter the method parameter
   * @param requestParam The {@link RequestParam} annotation or null;
   * @param source the source data map
   */
  private void addRequestParameterToModel(Map<String, Object> model, MethodParameter methodParameter,
      RequestParam requestParam, Map<String, ?> source) {
    String name = methodParameter.getParameterName();
    Boolean required = false;
    if (requestParam != null) {
      if (StringUtils.hasLength(requestParam.value())) {
        name = requestParam.value();
      }
      required = requestParam.required();
    }
    Object value = StringUtils.hasLength(name) ? source.get(name) : null;
    if (value == null) {
      Map.Entry<String, ?> entry = getMapEntryByType(source, methodParameter.getParameterType());
      if (entry != null) {
        value = entry.getValue();
      }
    }
    if (required) {
      Assert.state(value != null, "Unable to find required request parameter "
          + (StringUtils.hasLength(name) ? "'" + name + "' " : "") + "of type "
          + methodParameter.getParameterType().getName());
    }
    if (BeanUtils.isSimpleProperty(methodParameter.getParameterType())) {
      assertHasName(name, methodParameter);
      addIfNotContainsKey(model, name, value);
    } else {
      WebDataBinder binder = new WebRequestDataBinder(value);
      WebRequest request = new FacesWebRequest(FacesContext.getCurrentInstance());
      if (this.context.getWebBindingInitializer() != null) {
        this.context.getWebBindingInitializer().initBinder(binder, request);
      }
      ReverseDataBinder reverseBinder = new ReverseDataBinder(binder);
      PropertyValues propertyValues = reverseBinder.reverseBind();
      for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
        addIfNotContainsKey(model, propertyValue.getName(), propertyValue.getValue());
      }
    }
  }

  private void assertHasName(String name, MethodParameter methodParameter) {
    Assert.state(StringUtils.hasLength(name), "No parameter name specified for argument of type ["
        + methodParameter.getParameterType().getName()
        + "], and no parameter name information found in class file either.");
  }

  private Entry<String, ?> getMapEntryByType(Map<String, ?> source, Class<?> type) {
    Map.Entry<String, ?> rtn = null;
    for (Map.Entry<String, ?> entry : source.entrySet()) {
      if (type.isInstance(entry.getValue())) {
        Assert.state(rtn == null, "Unable to find single unique value in model of type " + type.getName());
        rtn = entry;
      }
    }
    return rtn;
  }

  private void addIfNotContainsKey(Map<String, Object> model, String name, Object value) {
    if (value != null) {
      if (model.containsKey(name)) {
        return;
      }
      model.put(name, value);
    }
  }

}
TOP

Related Classes of org.springframework.springfaces.mvc.navigation.requestmapped.RequestMappedRedirectViewModelBuilder

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.