View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.web.controller;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.kuali.rice.core.api.CoreApiServiceLocator;
21  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
22  import org.kuali.rice.krad.uif.UifConstants;
23  import org.kuali.rice.krad.uif.UifParameters;
24  import org.kuali.rice.krad.uif.util.ComponentFactory;
25  import org.kuali.rice.krad.uif.util.ComponentUtils;
26  import org.kuali.rice.krad.uif.view.View;
27  import org.kuali.rice.krad.uif.component.Component;
28  import org.kuali.rice.krad.uif.service.ViewService;
29  import org.kuali.rice.krad.util.KRADConstants;
30  import org.kuali.rice.krad.util.KRADUtils;
31  import org.kuali.rice.krad.web.form.UifFormBase;
32  import org.kuali.rice.krad.web.form.UifFormManager;
33  import org.springframework.web.servlet.ModelAndView;
34  
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  import java.util.ArrayList;
38  import java.util.List;
39  import java.util.Map;
40  
41  /**
42   * Provides helper methods that will be used during the request lifecycle
43   *
44   * <p>
45   * Created to avoid duplication of the methods used by the UifHandlerExceptionResolver
46   * </p>
47   *
48   * @author Kuali Rice Team (rice.collab@kuali.org)
49   */
50  public class UifControllerHelper {
51      private static final Logger LOG = Logger.getLogger(UifControllerHelper.class);
52  
53      /**
54       * Attempts to resolve a view id from the given request
55       *
56       * <p>
57       * First an attempt will be made to find the view id as a request parameter. If no such request parameter
58       * is found, the request will be looked at for view type information and a call will be made to the
59       * view service to find the view id by type
60       * </p>
61       *
62       * <p>
63       * If a view id is found it is stuck in the request as an attribute (under the key
64       * {@link org.kuali.rice.krad.uif.UifParameters#VIEW_ID}) for subsequent retrieval
65       * </p>
66       *
67       * @param request instance to resolve view id for
68       * @return view id if one is found, null if not found
69       */
70      public static String getViewIdFromRequest(HttpServletRequest request) {
71          String viewId = request.getParameter(UifParameters.VIEW_ID);
72  
73          if (StringUtils.isBlank(viewId)) {
74              String viewTypeName = request.getParameter(UifParameters.VIEW_TYPE_NAME);
75  
76              UifConstants.ViewType viewType = null;
77              if (StringUtils.isNotBlank(viewTypeName)) {
78                  viewType = UifConstants.ViewType.valueOf(viewTypeName);
79              }
80  
81              if (viewType != null) {
82                  Map<String, String> parameterMap = KRADUtils.translateRequestParameterMap(request.getParameterMap());
83                  viewId = getViewService().getViewIdForViewType(viewType, parameterMap);
84              }
85          }
86  
87          if (StringUtils.isNotBlank(viewId)) {
88             request.setAttribute(UifParameters.VIEW_ID, viewId);
89          }
90  
91          return viewId;
92      }
93  
94      /**
95       * Configures the <code>ModelAndView</code> instance containing the form
96       * data and pointing to the UIF generic spring view
97       *
98       * @param form - Form instance containing the model data
99       * @param pageId - Id of the page within the view that should be rendered, can
100      * be left blank in which the current or default page is rendered
101      * @return ModelAndView object with the contained form
102      */
103     public static ModelAndView getUIFModelAndView(UifFormBase form, String pageId) {
104         if (StringUtils.isNotBlank(pageId)) {
105             form.setPageId(pageId);
106         }
107 
108         // create the spring return object pointing to View.jsp
109         ModelAndView modelAndView = new ModelAndView();
110         modelAndView.addObject(UifConstants.DEFAULT_MODEL_NAME, form);
111         modelAndView.setViewName(UifConstants.SPRING_VIEW_ID);
112 
113         return modelAndView;
114     }
115 
116     /**
117      * After the controller logic is executed, the form is placed into session
118      * and the corresponding view is prepared for rendering
119      */
120     public static void postControllerHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
121             ModelAndView modelAndView) throws Exception {
122         if (modelAndView == null) {
123             return;
124         }
125 
126         Object model = modelAndView.getModelMap().get(UifConstants.DEFAULT_MODEL_NAME);
127         if (!(model instanceof UifFormBase)) {
128             return;
129         }
130 
131         UifFormBase form = (UifFormBase) model;
132 
133         // handle view building if not a redirect
134         if (!form.isRequestRedirected()) {
135             // prepare view instance
136             prepareViewForRendering(request, form);
137 
138             // for component, page refresh and dialog update need to export the component as a model
139             Component component = null;
140             if (form.isUpdateComponentRequest() || form.isUpdateDialogRequest()) {
141                 component = form.getPostedView().getViewIndex().getComponentById(form.getUpdateComponentId());
142             } else if (form.isUpdatePageRequest()) {
143                 component = form.getView().getCurrentPage();
144             }
145 
146             if (component != null) {
147                 modelAndView.addObject(UifConstants.COMPONENT_MODEL_NAME, component);
148             }
149         }
150 
151         // expose additional objects to the templates
152         modelAndView.addObject(UifParameters.REQUEST, request);
153         modelAndView.addObject(KRADConstants.USER_SESSION_KEY, request.getSession().getAttribute(
154                 KRADConstants.USER_SESSION_KEY));
155 
156         Map<String, String> properties = CoreApiServiceLocator.getKualiConfigurationService().getAllProperties();
157         modelAndView.addObject(UifParameters.CONFIG_PROPERTIES, properties);
158     }
159 
160     /**
161      * Prepares the <code>View</code> instance contained on the form for rendering
162      *
163      * @param request - request object
164      * @param form - form instance containing the data and view instance
165      */
166     public static void prepareViewForRendering(HttpServletRequest request, UifFormBase form) {
167         // for component refreshes only lifecycle for component is performed
168         if (form.isUpdateComponentRequest() || form.isUpdateDialogRequest()) {
169             String refreshComponentId = form.getUpdateComponentId();
170 
171             View postedView = form.getPostedView();
172 
173             // check if the component is nested in a box layout in order to reapply the layout item style
174             boolean boxLayoutHorizontalItem = false;
175             boolean boxLayoutVerticalItem = false;
176 
177             if (form.isUpdateComponentRequest()) {
178                 Component postedComponent = ComponentUtils.findNestedComponentById(postedView, refreshComponentId);
179                 if (postedComponent != null && postedComponent.getCssClasses() != null &&
180                         postedComponent.getCssClasses().contains("uif-boxLayoutHorizontalItem")) {
181                     boxLayoutHorizontalItem = true;
182                 } else if (postedComponent != null && postedComponent.getCssClasses() != null &&
183                         postedComponent.getCssClasses().contains("uif-boxLayoutVerticalItem")) {
184                     boxLayoutVerticalItem = true;
185                 }
186             }
187 
188             // get a new instance of the component
189             Component comp = ComponentFactory.getNewInstanceForRefresh(form.getPostedView(), refreshComponentId);
190 
191             // run lifecycle and update in view
192             postedView.getViewHelperService().performComponentLifecycle(postedView, form, comp, refreshComponentId);
193 
194             // add the layout item style that should happen in the parent BoxLayoutManager
195             // and is skipped in a child component refresh
196             if (boxLayoutHorizontalItem) {
197                 comp.addStyleClass("uif-boxLayoutHorizontalItem");
198             } else if (boxLayoutVerticalItem) {
199                 comp.addStyleClass("uif-boxLayoutVerticalItem");
200             }
201 
202             // regenerate server message content for page
203             postedView.getCurrentPage().getValidationMessages().generateMessages(false, postedView, form,
204                     postedView.getCurrentPage());
205         } else {
206             // full view build
207             View view = form.getView();
208 
209             // set view page to page requested on form
210             if (StringUtils.isNotBlank(form.getPageId())) {
211                 view.setCurrentPageId(form.getPageId());
212             }
213 
214             Map<String, String> parameterMap = KRADUtils.translateRequestParameterMap(request.getParameterMap());
215             parameterMap.putAll(form.getViewRequestParameters());
216 
217             // build view which will prepare for rendering
218             getViewService().buildView(view, form, parameterMap);
219         }
220     }
221 
222     /**
223      * Remove unused forms from breadcrumb history
224      *
225      * <p>
226      * When going back in the breadcrumb history some forms become unused in the breadcrumb history.  Here the unused
227      * forms are being determine and removed from the server to free memory.
228      * </p>
229      *
230      * @param uifFormManager
231      * @param formKey of the current form
232      * @param lastFormKey of the last form
233      */
234     public static void removeUnusedBreadcrumbs(UifFormManager uifFormManager, String formKey, String lastFormKey) {
235         if (StringUtils.isBlank(formKey) || StringUtils.isBlank(lastFormKey) || StringUtils.equals(formKey,
236                 lastFormKey)) {
237             return;
238         }
239 
240         UifFormBase previousForm = uifFormManager.getSessionForm(lastFormKey);
241         if (previousForm == null) {
242             return;
243         }
244 
245         uifFormManager.removeSessionFormByKey(lastFormKey);
246     }
247 
248     protected static ViewService getViewService() {
249         return KRADServiceLocatorWeb.getViewService();
250     }
251 }