001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.web.controller;
017
018import org.kuali.rice.krad.uif.UifConstants;
019import org.kuali.rice.krad.web.form.UifFormBase;
020import org.springframework.core.MethodParameter;
021import org.springframework.validation.BindException;
022import org.springframework.validation.Errors;
023import org.springframework.web.bind.ServletRequestDataBinder;
024import org.springframework.web.bind.WebDataBinder;
025import org.springframework.web.bind.annotation.ModelAttribute;
026import org.springframework.web.bind.support.WebDataBinderFactory;
027import org.springframework.web.context.request.NativeWebRequest;
028import org.springframework.web.method.support.HandlerMethodArgumentResolver;
029import org.springframework.web.method.support.ModelAndViewContainer;
030
031import javax.servlet.ServletRequest;
032import java.util.Map;
033
034/**
035 * @author Kuali Rice Team (rice.collab@kuali.org)
036 */
037public class UifDefaultFormMethodArgumentResolver implements HandlerMethodArgumentResolver {
038
039    /**
040     * Default Constructor.
041     */
042    public UifDefaultFormMethodArgumentResolver() {
043        super();
044    }
045
046    /**
047     * {@inheritDoc}
048     */
049    @Override
050    public boolean supportsParameter(MethodParameter parameter) {
051        boolean isUifForm = false;
052
053        if (!parameter.hasParameterAnnotation(ModelAttribute.class) && UifFormBase.class.isAssignableFrom(
054                parameter.getParameterType())) {
055            isUifForm = true;
056        }
057
058        return isUifForm;
059    }
060
061    /**
062     * {@inheritDoc}
063     */
064    @Override
065    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
066            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
067        String name = UifConstants.DEFAULT_MODEL_NAME;
068
069        Object attribute = null;
070        if (mavContainer.containsAttribute(name)) {
071            attribute = mavContainer.getModel().get(name);
072        }
073
074        WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
075        if (binder.getTarget() != null) {
076            ServletRequest servletRequest = webRequest.getNativeRequest(ServletRequest.class);
077            ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
078            servletBinder.bind(servletRequest);
079
080            if (binder.getBindingResult().hasErrors()) {
081                if (isBindExceptionRequired(parameter)) {
082                    throw new BindException(binder.getBindingResult());
083                }
084            }
085        }
086
087        Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
088        mavContainer.removeAttributes(bindingResultModel);
089        mavContainer.addAllAttributes(bindingResultModel);
090
091        return binder.getTarget();
092    }
093
094    /**
095     * Whether to raise a {@link BindException} on validation errors.
096     *
097     * @param parameter the method argument
098     * @return {@code true} if the next method argument is not of type {@link org.springframework.validation.Errors}.
099     */
100    protected boolean isBindExceptionRequired(MethodParameter parameter) {
101        int i = parameter.getParameterIndex();
102        Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
103        boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
104
105        return !hasBindingResult;
106    }
107
108}