Package ch.ralscha.extdirectspring.util

Source Code of ch.ralscha.extdirectspring.util.ParametersResolver

/**
* Copyright 2010-2014 Ralph Schaer <ralphschaer@gmail.com>
*
* 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 ch.ralscha.extdirectspring.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.WebUtils;

import ch.ralscha.extdirectspring.annotation.ExtDirectMethodType;
import ch.ralscha.extdirectspring.bean.ExtDirectRequest;
import ch.ralscha.extdirectspring.bean.ExtDirectStoreReadRequest;
import ch.ralscha.extdirectspring.bean.GroupInfo;
import ch.ralscha.extdirectspring.bean.SortDirection;
import ch.ralscha.extdirectspring.bean.SortInfo;
import ch.ralscha.extdirectspring.controller.SSEWriter;
import ch.ralscha.extdirectspring.filter.Filter;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.TypeFactory;

/**
* Resolver of ExtDirectRequest parameters.
*/
public final class ParametersResolver {

  private static final Log log = LogFactory.getLog(ParametersResolver.class);

  private final UrlPathHelper urlPathHelper = new UrlPathHelper();

  private final ConversionService conversionService;

  private final JsonHandler jsonHandler;

  private final Collection<WebArgumentResolver> webArgumentResolvers;

  private final Expression getPrincipalExpression = new SpelExpressionParser()
      .parseExpression("T(org.springframework.security.core.context.SecurityContextHolder).getContext().getAuthentication()?.getPrincipal()");

  public ParametersResolver(ConversionService conversionService,
      JsonHandler jsonHandler, Collection<WebArgumentResolver> webArgumentResolvers) {
    this.conversionService = conversionService;
    this.jsonHandler = jsonHandler;
    this.webArgumentResolvers = webArgumentResolvers;
  }

  public Object[] prepareParameters(HttpServletRequest request,
      HttpServletResponse response, Locale locale, MethodInfo methodInfo) {
    return prepareParameters(request, response, locale, methodInfo, null);
  }

  public Object[] prepareParameters(HttpServletRequest request,
      HttpServletResponse response, Locale locale, MethodInfo methodInfo,
      SSEWriter sseWriter) {
    List<ParameterInfo> methodParameters = methodInfo.getParameters();
    Object[] parameters = null;
    if (!methodParameters.isEmpty()) {
      parameters = new Object[methodParameters.size()];

      for (int paramIndex = 0; paramIndex < methodParameters.size(); paramIndex++) {
        ParameterInfo methodParameter = methodParameters.get(paramIndex);

        if (methodParameter.isSupportedParameter()) {
          parameters[paramIndex] = SupportedParameters.resolveParameter(
              methodParameter.getType(), request, response, locale,
              sseWriter);
        }
        else if (methodParameter.hasRequestHeaderAnnotation()) {
          parameters[paramIndex] = resolveRequestHeader(request,
              methodParameter);
        }
        else if (methodParameter.hasCookieValueAnnotation()) {
          parameters[paramIndex] = resolveCookieValue(request, methodParameter);
        }
        else if (methodParameter.hasAuthenticationPrincipalAnnotation()) {
          parameters[paramIndex] = resolveAuthenticationPrincipal(methodParameter);
        }
        else {
          parameters[paramIndex] = resolveRequestParam(request, null,
              methodParameter);
        }

      }
    }
    return parameters;
  }

  @SuppressWarnings("unchecked")
  public Object[] resolveParameters(HttpServletRequest request,
      HttpServletResponse response, Locale locale, ExtDirectRequest directRequest,
      MethodInfo methodInfo) throws Exception {

    int jsonParamIndex = 0;
    Map<String, Object> remainingParameters = null;
    ExtDirectStoreReadRequest extDirectStoreReadRequest = null;

    List<Object> directStoreModifyRecords = null;
    Class<?> directStoreEntryClass;

    if (methodInfo.isType(ExtDirectMethodType.STORE_READ)
        || methodInfo.isType(ExtDirectMethodType.FORM_LOAD)
        || methodInfo.isType(ExtDirectMethodType.TREE_LOAD)) {

      List<Object> data = (List<Object>) directRequest.getData();

      if (data != null && data.size() > 0) {
        if (methodInfo.isType(ExtDirectMethodType.STORE_READ)) {
          extDirectStoreReadRequest = new ExtDirectStoreReadRequest();
          remainingParameters = fillReadRequestFromMap(
              extDirectStoreReadRequest, (Map<String, Object>) data.get(0));
        }
        else {
          remainingParameters = (Map<String, Object>) data.get(0);
        }
        jsonParamIndex = 1;
      }
    }
    else if (methodInfo.isType(ExtDirectMethodType.STORE_MODIFY)) {
      directStoreEntryClass = methodInfo.getCollectionType();
      List<Object> data = (List<Object>) directRequest.getData();

      if (directStoreEntryClass != null && data != null && data.size() > 0) {
        Object obj = data.get(0);
        if (obj instanceof List) {
          directStoreModifyRecords = convertObjectEntriesToType(
              (List<Object>) obj, directStoreEntryClass);
        }
        else {
          Map<String, Object> jsonData = (Map<String, Object>) obj;
          Object records = jsonData.get("records");
          if (records != null) {
            if (records instanceof List) {
              directStoreModifyRecords = convertObjectEntriesToType(
                  (List<Object>) records, directStoreEntryClass);
            }
            else {
              directStoreModifyRecords = new ArrayList<Object>();
              directStoreModifyRecords.add(jsonHandler.convertValue(
                  records, directStoreEntryClass));
            }
            remainingParameters = new HashMap<String, Object>(jsonData);
            remainingParameters.remove("records");
          }
          else {
            directStoreModifyRecords = new ArrayList<Object>();
            directStoreModifyRecords.add(jsonHandler.convertValue(jsonData,
                directStoreEntryClass));
          }
        }
        jsonParamIndex = 1;

      }
      else if (data != null && data.size() > 0) {
        Object obj = data.get(0);
        if (obj instanceof Map) {
          remainingParameters = new HashMap<String, Object>(
              (Map<String, Object>) obj);
          remainingParameters.remove("records");
        }
      }
    }
    else if (methodInfo.isType(ExtDirectMethodType.SIMPLE_NAMED)) {
      Map<String, Object> data = (Map<String, Object>) directRequest.getData();
      if (data != null && data.size() > 0) {
        remainingParameters = new HashMap<String, Object>(data);
      }

    }
    else if (methodInfo.isType(ExtDirectMethodType.POLL)) {
      throw new IllegalStateException("this controller does not handle poll calls");
    }
    else if (methodInfo.isType(ExtDirectMethodType.FORM_POST)) {
      throw new IllegalStateException("this controller does not handle form posts");
    }
    else if (methodInfo.isType(ExtDirectMethodType.FORM_POST_JSON)) {
      List<Object> data = (List<Object>) directRequest.getData();

      if (data != null && data.size() > 0) {
        Object obj = data.get(0);
        if (obj instanceof Map) {
          remainingParameters = new HashMap<String, Object>(
              (Map<String, Object>) obj);
          remainingParameters.remove("records");
        }
      }

    }

    List<ParameterInfo> methodParameters = methodInfo.getParameters();
    Object[] parameters = null;

    if (!methodParameters.isEmpty()) {
      parameters = new Object[methodParameters.size()];

      for (int paramIndex = 0; paramIndex < methodParameters.size(); paramIndex++) {
        ParameterInfo methodParameter = methodParameters.get(paramIndex);

        if (methodParameter.isSupportedParameter()) {
          parameters[paramIndex] = SupportedParameters.resolveParameter(
              methodParameter.getType(), request, response, locale);
        }
        else if (ExtDirectStoreReadRequest.class.isAssignableFrom(methodParameter
            .getType())) {
          parameters[paramIndex] = extDirectStoreReadRequest;
        }
        else if (directStoreModifyRecords != null
            && methodParameter.getCollectionType() != null) {
          parameters[paramIndex] = directStoreModifyRecords;
        }
        else if (methodParameter.hasRequestParamAnnotation()) {
          parameters[paramIndex] = resolveRequestParam(null,
              remainingParameters, methodParameter);
        }
        else if (methodParameter.hasRequestHeaderAnnotation()) {
          parameters[paramIndex] = resolveRequestHeader(request,
              methodParameter);
        }
        else if (methodParameter.hasCookieValueAnnotation()) {
          parameters[paramIndex] = resolveCookieValue(request, methodParameter);
        }
        else if (methodParameter.hasAuthenticationPrincipalAnnotation()) {
          parameters[paramIndex] = resolveAuthenticationPrincipal(methodParameter);
        }
        else if (remainingParameters != null
            && remainingParameters.containsKey(methodParameter.getName())) {
          Object jsonValue = remainingParameters.get(methodParameter.getName());
          parameters[paramIndex] = convertValue(jsonValue, methodParameter);
        }
        else if (directRequest.getData() != null
            && directRequest.getData() instanceof List
            && ((List<Object>) directRequest.getData()).size() > jsonParamIndex) {
          Object jsonValue = ((List<Object>) directRequest.getData())
              .get(jsonParamIndex);
          parameters[paramIndex] = convertValue(jsonValue, methodParameter);
          jsonParamIndex++;
        }
        else {

          log.info("WebResolvers size:" + this.webArgumentResolvers.size());
          log.info("ParamIndex:" + paramIndex);

          log.info("Request params size:" + request.getParameterMap().isEmpty());
          log.info("Request params names:" + request.getParameterMap().keySet());
          log.info("Direct Request:" + directRequest.toString());

          MethodParameter p = new MethodParameter(methodInfo.getMethod(),
              paramIndex);
          request.setAttribute("directRequest", directRequest);
          request.setAttribute("extDirectStoreReadRequest",
              extDirectStoreReadRequest);
          ServletWebRequest r = new ServletWebRequest(request);
          Object result = WebArgumentResolver.UNRESOLVED;

          for (WebArgumentResolver resolver : this.webArgumentResolvers) {
            log.info("Resolving with:"
                + resolver.getClass().getCanonicalName());

            result = resolver.resolveArgument(p, r);
            if (result != WebArgumentResolver.UNRESOLVED) {
              log.info("Resolved by:"
                  + resolver.getClass().getCanonicalName());
              parameters[paramIndex] = result;
              break;
            }
          }
          if (result == WebArgumentResolver.UNRESOLVED) {
            throw new IllegalArgumentException(
                "Error, parameter mismatch. Please check your remoting method signature to ensure all supported parameters types are used.");
          }
        }
      }
    }

    return parameters;
  }

  private Object resolveRequestParam(HttpServletRequest request,
      Map<String, Object> valueContainer, final ParameterInfo parameterInfo) {

    if (parameterInfo.getName() != null) {
      Object value;
      if (request != null) {
        value = request.getParameter(parameterInfo.getName());
      }
      else if (valueContainer != null) {
        value = valueContainer.get(parameterInfo.getName());
      }
      else {
        value = null;
      }

      if (value == null) {
        value = parameterInfo.getDefaultValue();
      }

      if (value != null) {
        return convertValue(value, parameterInfo);
      }

      if (parameterInfo.isRequired()) {
        throw new IllegalStateException("Missing parameter '"
            + parameterInfo.getName() + "' of type ["
            + parameterInfo.getTypeDescriptor().getType() + "]");
      }
    }

    return null;
  }

  private Object resolveRequestHeader(HttpServletRequest request,
      ParameterInfo parameterInfo) {
    String value = request.getHeader(parameterInfo.getName());

    if (value == null) {
      value = parameterInfo.getDefaultValue();
    }

    if (value != null) {
      return convertValue(value, parameterInfo);
    }

    if (parameterInfo.isRequired()) {
      throw new IllegalStateException("Missing header '" + parameterInfo.getName()
          + "' of type [" + parameterInfo.getTypeDescriptor().getType() + "]");
    }

    return null;
  }

  private Object resolveCookieValue(HttpServletRequest request,
      ParameterInfo parameterInfo) {

    Cookie cookieValue = WebUtils.getCookie(request, parameterInfo.getName());
    String value = null;

    if (cookieValue != null) {
      value = urlPathHelper.decodeRequestString(request, cookieValue.getValue());
    }
    else {
      value = parameterInfo.getDefaultValue();
    }

    if (value != null) {
      return convertValue(value, parameterInfo);
    }

    if (parameterInfo.isRequired()) {
      throw new IllegalStateException("Missing cookie '" + parameterInfo.getName()
          + "' of type [" + parameterInfo.getTypeDescriptor().getType() + "]");
    }

    return null;
  }

  private Object resolveAuthenticationPrincipal(ParameterInfo parameterInfo) {
    Object principal = getPrincipalExpression.getValue();

    if (principal != null
        && !parameterInfo.getType().isAssignableFrom(principal.getClass())) {
      if (parameterInfo.authenticationPrincipalAnnotationErrorOnInvalidType()) {
        throw new ClassCastException(principal + " is not assignable to "
            + parameterInfo.getType());
      }
      return null;
    }
    return principal;
  }

  private Object convertValue(Object value, ParameterInfo methodParameter) {
    if (value != null) {
      if (methodParameter.getType().equals(value.getClass())) {
        return value;
      }
      else if (conversionService.canConvert(TypeDescriptor.forObject(value),
          methodParameter.getTypeDescriptor())) {

        try {
          return conversionService.convert(value,
              TypeDescriptor.forObject(value),
              methodParameter.getTypeDescriptor());
        }
        catch (ConversionFailedException e) {
          // ignore this exception for collections and arrays.
          // try to convert the value with jackson
          TypeFactory typeFactory = jsonHandler.getMapper().getTypeFactory();
          if (methodParameter.getTypeDescriptor().isCollection()) {
            JavaType type = CollectionType.construct(
                methodParameter.getType(),
                typeFactory.constructType(methodParameter
                    .getTypeDescriptor().getElementTypeDescriptor()
                    .getType()));
            return jsonHandler.convertValue(value, type);
          }
          else if (methodParameter.getTypeDescriptor().isArray()) {
            JavaType type = typeFactory
                .constructArrayType(methodParameter.getTypeDescriptor()
                    .getElementTypeDescriptor().getType());
            return jsonHandler.convertValue(value, type);
          }

          throw e;
        }
      }
      else {
        return jsonHandler.convertValue(value, methodParameter.getType());
      }

    }
    return null;
  }

  private Map<String, Object> fillReadRequestFromMap(ExtDirectStoreReadRequest to,
      Map<String, Object> from) {
    Set<String> foundParameters = new HashSet<String>();

    for (Entry<String, Object> entry : from.entrySet()) {
      String key = entry.getKey();
      Object value = entry.getValue();

      if (key.equals("filter")) {
        List<Filter> filters = new ArrayList<Filter>();

        if (value instanceof String) {
          List<Map<String, Object>> rawFilters = jsonHandler.readValue(
              (String) value,
              new TypeReference<List<Map<String, Object>>>() {/* empty */
              });

          for (Map<String, Object> rawFilter : rawFilters) {
            Filter filter = Filter.createFilter(rawFilter, conversionService);
            if (filter != null) {
              filters.add(filter);
            }
          }
        }
        else if (value instanceof List) {
          @SuppressWarnings("unchecked")
          List<Map<String, Object>> filterList = (List<Map<String, Object>>) value;
          for (Map<String, Object> rawFilter : filterList) {
            Filter filter = Filter.createFilter(rawFilter, conversionService);
            if (filter != null) {
              filters.add(filter);
            }
          }
        }
        to.setFilters(filters);
        foundParameters.add(key);
      }
      else if (key.equals("sort") && value != null && value instanceof List) {

        List<SortInfo> sorters = new ArrayList<SortInfo>();
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> rawSorters = (List<Map<String, Object>>) value;

        for (Map<String, Object> aRawSorter : rawSorters) {
          sorters.add(SortInfo.create(aRawSorter));
        }

        to.setSorters(sorters);
        foundParameters.add(key);
      }
      else if (key.equals("group") && value != null && value instanceof List) {
        List<GroupInfo> groups = new ArrayList<GroupInfo>();
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> rawGroups = (List<Map<String, Object>>) value;

        for (Map<String, Object> aRawGroupInfo : rawGroups) {
          groups.add(GroupInfo.create(aRawGroupInfo));
        }

        to.setGroups(groups);
        foundParameters.add(key);
      }
      else {

        PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(
            to.getClass(), key);
        if (descriptor != null && descriptor.getWriteMethod() != null) {
          try {

            descriptor.getWriteMethod().invoke(
                to,
                conversionService.convert(value,
                    descriptor.getPropertyType()));

            foundParameters.add(key);
          }
          catch (IllegalArgumentException e) {
            log.error("fillObjectFromMap", e);
          }
          catch (IllegalAccessException e) {
            log.error("fillObjectFromMap", e);
          }
          catch (InvocationTargetException e) {
            log.error("fillObjectFromMap", e);
          }
        }
      }
    }

    if (to.getLimit() != null) {
      // this test is no longer needed with extjs 4.0.7 and extjs 4.1.0
      // these two libraries always send page, start and limit
      if (to.getPage() != null && to.getStart() == null) {
        to.setStart(to.getLimit() * (to.getPage() - 1));
        // the else if is still valid for extjs 3 code
      }
      else if (to.getPage() == null && to.getStart() != null) {
        to.setPage(to.getStart() / to.getLimit() + 1);
      }
    }

    if (to.getSort() != null && to.getDir() != null) {
      List<SortInfo> sorters = new ArrayList<SortInfo>();
      sorters.add(new SortInfo(to.getSort(), SortDirection.fromString(to.getDir())));
      to.setSorters(sorters);
    }

    if (to.getGroupBy() != null && to.getGroupDir() != null) {
      List<GroupInfo> groups = new ArrayList<GroupInfo>();
      groups.add(new GroupInfo(to.getGroupBy(), SortDirection.fromString(to
          .getGroupDir())));
      to.setGroups(groups);
    }

    Map<String, Object> remainingParameters = new HashMap<String, Object>();
    for (Entry<String, Object> entry : from.entrySet()) {
      if (!foundParameters.contains(entry.getKey())) {
        remainingParameters.put(entry.getKey(), entry.getValue());
      }
    }
    to.setParams(remainingParameters);

    return remainingParameters;
  }

  private List<Object> convertObjectEntriesToType(List<Object> records,
      Class<?> directStoreType) {
    if (records != null) {
      List<Object> convertedList = new ArrayList<Object>();
      for (Object record : records) {
        Object convertedObject = jsonHandler
            .convertValue(record, directStoreType);
        convertedList.add(convertedObject);
      }
      return convertedList;
    }
    return null;
  }

}
TOP

Related Classes of ch.ralscha.extdirectspring.util.ParametersResolver

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.