001    /**
002     * Copyright 2005-2012 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     */
016    package org.kuali.rice.krad.web.bind;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
020    import org.kuali.rice.krad.uif.UifParameters;
021    import org.kuali.rice.krad.uif.view.View;
022    import org.kuali.rice.krad.uif.UifConstants.ViewType;
023    import org.kuali.rice.krad.uif.service.ViewService;
024    import org.kuali.rice.krad.util.GlobalVariables;
025    import org.kuali.rice.krad.util.KRADUtils;
026    import org.kuali.rice.krad.web.form.UifFormBase;
027    import org.springframework.core.convert.ConversionService;
028    import org.springframework.util.Assert;
029    import org.springframework.validation.AbstractPropertyBindingResult;
030    import org.springframework.web.bind.ServletRequestDataBinder;
031    
032    import javax.servlet.ServletRequest;
033    import javax.servlet.http.HttpServletRequest;
034    import java.util.Map;
035    
036    /**
037     * Override of ServletRequestDataBinder in order to hook in the UifBeanPropertyBindingResult
038     * which instantiates a custom BeanWrapperImpl.
039     *
040     * @author Kuali Rice Team (rice.collab@kuali.org)
041     */
042    public class UifServletRequestDataBinder extends ServletRequestDataBinder {
043        protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
044                UifServletRequestDataBinder.class);
045    
046        private UifBeanPropertyBindingResult bindingResult;
047        private ConversionService conversionService;
048    
049        public UifServletRequestDataBinder(Object target) {
050            super(target);
051            setBindingErrorProcessor(new UifBindingErrorProcessor());
052        }
053    
054        public UifServletRequestDataBinder(Object target, String name) {
055            super(target, name);
056            setBindingErrorProcessor(new UifBindingErrorProcessor());
057        }
058    
059        /**
060         * Allows for a custom binding result class.
061         *
062         * @see org.springframework.validation.DataBinder#initBeanPropertyAccess()
063         */
064        @Override
065        public void initBeanPropertyAccess() {
066            Assert.state(this.bindingResult == null,
067                    "DataBinder is already initialized - call initBeanPropertyAccess before other configuration methods");
068            this.bindingResult = new UifBeanPropertyBindingResult(getTarget(), getObjectName(), isAutoGrowNestedPaths(),
069                    getAutoGrowCollectionLimit());
070            if (this.conversionService != null) {
071                this.bindingResult.initConversion(this.conversionService);
072            }
073        }
074    
075        /**
076         * Allows for the setting attributes to use to find the data dictionary data from Kuali
077         *
078         * @see org.springframework.validation.DataBinder#getInternalBindingResult()
079         */
080        @Override
081        protected AbstractPropertyBindingResult getInternalBindingResult() {
082            if (this.bindingResult == null) {
083                initBeanPropertyAccess();
084            }
085            return this.bindingResult;
086        }
087    
088        /**
089         * Disallows direct field access for Kuali
090         *
091         * @see org.springframework.validation.DataBinder#initDirectFieldAccess()
092         */
093        @Override
094        public void initDirectFieldAccess() {
095            LOG.error("Direct Field access is not allowed in UifServletRequestDataBinder.");
096            throw new RuntimeException("Direct Field access is not allowed in Kuali");
097        }
098    
099        @Override
100        @SuppressWarnings("unchecked")
101        public void bind(ServletRequest request) {
102            super.bind(request);
103    
104            UifFormBase form = (UifFormBase) this.getTarget();
105    
106            // back up previous view instance
107            View previousView = form.getView();
108            form.setPreviousView(previousView);
109    
110            // check for request param that indicates to skip view initialize
111            Boolean skipViewInit = KRADUtils.getRequestParameterAsBoolean(request, UifParameters.SKIP_VIEW_INIT);
112            if ((skipViewInit == null) || !skipViewInit.booleanValue()) {
113                // initialize new view for request
114                View view = null;
115    
116                String viewId = request.getParameter(UifParameters.VIEW_ID);
117                if (viewId != null) {
118                    view = getViewService().getViewById(viewId);
119                } else {
120                    // attempt to get view instance by type parameters
121                    ViewType viewType = null;
122    
123                    String viewTypeName = request.getParameter(UifParameters.VIEW_TYPE_NAME);
124                    viewType = StringUtils.isBlank(viewTypeName) ? form.getViewTypeName() : ViewType.valueOf(viewTypeName);
125    
126                    if (viewType != null) {
127                        Map<String, String> parameterMap = KRADUtils.translateRequestParameterMap(
128                                request.getParameterMap());
129                        view = getViewService().getViewByType(viewType, parameterMap);
130                    }
131    
132                    // if view not found attempt to find one based on the cached form
133                    if (view == null) {
134                        view = getViewFromPreviousModel(form);
135    
136                        if (view != null) {
137                            LOG.warn("Obtained viewId from cached form, this may not be safe!");
138                        }
139                    }
140                }
141    
142                if (view != null) {
143                    form.setViewId(view.getId());
144                    form.setView(view);
145                } else {
146                    form.setViewId(null);
147                    form.setView(null);
148                }
149            }
150    
151            form.postBind((HttpServletRequest) request);
152    
153            // add form to manager
154            GlobalVariables.getUifFormManager().addForm(form);
155        }
156    
157        protected View getViewFromPreviousModel(UifFormBase form) {
158            // maybe we have a view id from the session form
159            if (form.getViewId() != null) {
160                return getViewService().getViewById(form.getViewId());
161            }
162    
163            return null;
164        }
165    
166        public ViewService getViewService() {
167            return KRADServiceLocatorWeb.getViewService();
168        }
169    
170    }