View Javadoc
1   /**
2    * Copyright 2005-2016 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.service.impl;
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.core.api.exception.RiceRuntimeException;
22  import org.kuali.rice.krad.service.ViewValidationService;
23  import org.kuali.rice.krad.uif.UifConstants;
24  import org.kuali.rice.krad.uif.UifParameters;
25  import org.kuali.rice.krad.uif.component.Component;
26  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
27  import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
28  import org.kuali.rice.krad.uif.service.ViewService;
29  import org.kuali.rice.krad.uif.util.ScriptUtils;
30  import org.kuali.rice.krad.uif.util.UifRenderHelperMethods;
31  import org.kuali.rice.krad.uif.view.MessageView;
32  import org.kuali.rice.krad.uif.view.View;
33  import org.kuali.rice.krad.util.KRADConstants;
34  import org.kuali.rice.krad.util.KRADUtils;
35  import org.kuali.rice.krad.util.UrlFactory;
36  import org.kuali.rice.krad.web.form.UifFormBase;
37  import org.kuali.rice.krad.web.service.ModelAndViewService;
38  import org.springframework.web.servlet.ModelAndView;
39  
40  import javax.servlet.http.HttpServletRequest;
41  import java.util.Map;
42  import java.util.Properties;
43  
44  /**
45   * Default implementation of the model and view service.
46   *
47   * @author Kuali Rice Team (rice.collab@kuali.org)
48   */
49  public class ModelAndViewServiceImpl implements ModelAndViewService {
50      private static final Logger LOG = Logger.getLogger(ModelAndViewServiceImpl.class);
51  
52      private ViewService viewService;
53      private ViewValidationService viewValidationService;
54  
55      /**
56       * Invokes {@link org.kuali.rice.krad.service.ViewValidationService} to validate the contents of the
57       * given form instance.
58       *
59       * {@inheritDoc}
60       */
61      @Override
62      public ModelAndView checkForm(UifFormBase form) {
63          getViewValidationService().validateViewSimulation(form);
64  
65          return getModelAndView(form);
66      }
67  
68      /**
69       * Builds the dialog group with the given id then creates the script for showing the dialog once the
70       * page reloads.
71       *
72       * {@inheritDoc}
73       */
74      @Override
75      public ModelAndView showDialog(String dialogId, boolean confirmation, UifFormBase form) {
76          if (form.isAjaxRequest()) {
77              form.setAjaxReturnType(UifConstants.AjaxReturnTypes.UPDATEDIALOG.getKey());
78              form.setUpdateComponentId(dialogId);
79          }
80  
81          // run the lifecycle to build the dialog first
82          ModelAndView modelAndView = getModelAndView(form);
83          prepareView(form.getRequest(), modelAndView);
84  
85          Component updateComponent;
86          if (form.isAjaxRequest()) {
87              updateComponent = form.getUpdateComponent();
88          } else {
89              updateComponent = form.getView();
90          }
91  
92          // now add the script that will show the dialog to the on ready of the document
93          String showDialogScript = buildShowDialogScript(dialogId, confirmation, form);
94  
95          String onReadyScript = ScriptUtils.appendScript(updateComponent.getOnDocumentReadyScript(), showDialogScript);
96          updateComponent.setOnDocumentReadyScript(onReadyScript);
97  
98          form.getRequest().setAttribute(UifParameters.Attributes.VIEW_LIFECYCLE_COMPLETE, "true");
99  
100         return modelAndView;
101     }
102 
103     /**
104      * Builds a JavaScript string for invoking the showDialog method with the given dialog parameters.
105      *
106      * @param dialogId id for the dialog group to show
107      * @param confirmation whether the dialog should be shown as a confirmation
108      * @param form instance containing the model data
109      * @return String containing script
110      */
111     protected String buildShowDialogScript(String dialogId, boolean confirmation, UifFormBase form) {
112         StringBuilder showDialogScript = new StringBuilder();
113 
114         showDialogScript.append(UifConstants.JsFunctions.SHOW_DIALOG);
115         showDialogScript.append("('");
116         showDialogScript.append(dialogId);
117         showDialogScript.append("', {responseHandler: ");
118         showDialogScript.append(UifConstants.JsFunctions.HANDLE_SERVER_DIALOG_RESPONSE);
119         showDialogScript.append(",responseEventData:{triggerActionId:'");
120         showDialogScript.append(form.getTriggerActionId());
121         showDialogScript.append("',confirmation:");
122         showDialogScript.append(confirmation);
123         showDialogScript.append("}});");
124 
125         return showDialogScript.toString();
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public ModelAndView performRedirect(UifFormBase form, String baseUrl, Properties urlParameters) {
133         String redirectUrl = UrlFactory.parameterizeUrl(baseUrl, urlParameters);
134 
135         return performRedirect(form, redirectUrl);
136     }
137 
138     /**
139      * {@inheritDoc}
140      */
141     @Override
142     public ModelAndView performRedirect(UifFormBase form, String redirectUrl) {
143         // indicate a redirect is occuring to prevent view processing down the line
144         form.setRequestRedirected(true);
145 
146         // set the ajaxReturnType on the form this will override the return type requested by the client
147         form.setAjaxReturnType(UifConstants.AjaxReturnTypes.REDIRECT.getKey());
148 
149         ModelAndView modelAndView;
150         if (form.isAjaxRequest()) {
151             modelAndView = getModelAndView(form, form.getPageId());
152             modelAndView.addObject("redirectUrl", redirectUrl);
153         } else {
154             modelAndView = new ModelAndView(UifConstants.REDIRECT_PREFIX + redirectUrl);
155         }
156 
157         return modelAndView;
158     }
159 
160     /**
161      * Retrieves an instance of the view with id {@link org.kuali.rice.krad.uif.UifConstants#MESSAGE_VIEW_ID}
162      * and sets the header and message from the given parameters.
163      *
164      * {@inheritDoc}
165      */
166     @Override
167     public ModelAndView getMessageView(UifFormBase form, String headerText, String messageText) {
168         MessageView messageView = (MessageView) getViewService().getViewById(UifConstants.MESSAGE_VIEW_ID);
169 
170         messageView.setHeaderText(headerText);
171         messageView.setMessageText(messageText);
172 
173         form.setViewId(UifConstants.MESSAGE_VIEW_ID);
174         form.setView(messageView);
175 
176         return getModelAndView(form);
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     @Override
183     public ModelAndView getModelAndView(UifFormBase form) {
184         return getModelAndView(form, form.getPageId());
185     }
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public ModelAndView getModelAndView(UifFormBase form, String pageId) {
192         if (StringUtils.isNotBlank(pageId)) {
193             form.setPageId(pageId);
194         }
195 
196         ModelAndView modelAndView = new ModelAndView();
197         modelAndView.addObject(UifConstants.DEFAULT_MODEL_NAME, form);
198         modelAndView.setViewName(UifConstants.SPRING_VIEW_ID);
199 
200         return modelAndView;
201     }
202 
203     /**
204      * {@inheritDoc}
205      */
206     @Override
207     public ModelAndView getModelAndView(UifFormBase form, Map<String, Object> additionalViewAttributes) {
208         ModelAndView modelAndView = getModelAndView(form, form.getPageId());
209 
210         if (additionalViewAttributes != null) {
211             for (Map.Entry<String, Object> additionalViewAttribute : additionalViewAttributes.entrySet()) {
212                 modelAndView.getModelMap().put(additionalViewAttribute.getKey(), additionalViewAttribute.getValue());
213             }
214         }
215 
216         return modelAndView;
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     public ModelAndView getModelAndViewWithInit(UifFormBase form, String viewId) {
224         form.setPageId(null);
225 
226         return getModelAndViewWithInit(form, viewId, null);
227     }
228 
229     /**
230      * {@inheritDoc}
231      */
232     @Override
233     public ModelAndView getModelAndViewWithInit(UifFormBase form, String viewId, String pageId) {
234         View view = getViewService().getViewById(viewId);
235 
236         if (view == null) {
237             throw new RiceRuntimeException("No view was found with view id " + viewId);
238         }
239 
240         form.setView(view);
241         form.setViewId(viewId);
242 
243         return getModelAndView(form, pageId);
244     }
245 
246     /**
247      * {@inheritDoc}
248      */
249     @Override
250     public void prepareView(HttpServletRequest request, ModelAndView modelAndView) {
251         if (modelAndView == null) {
252             return;
253         }
254 
255         Object model = modelAndView.getModelMap().get(UifConstants.DEFAULT_MODEL_NAME);
256         if (!(model instanceof UifFormBase)) {
257             return;
258         }
259 
260         UifFormBase form = (UifFormBase) model;
261 
262         if (!form.isRequestRedirected()) {
263             invokeViewLifecycle(request, form);
264         }
265 
266         // expose additional objects to the templates
267         modelAndView.addObject(UifParameters.REQUEST, request);
268         modelAndView.addObject(KRADConstants.USER_SESSION_KEY, request.getSession().getAttribute(
269                 KRADConstants.USER_SESSION_KEY));
270 
271         Map<String, String> properties = CoreApiServiceLocator.getKualiConfigurationService().getAllProperties();
272         modelAndView.addObject(UifParameters.CONFIG_PROPERTIES, properties);
273 
274         modelAndView.addObject(UifParameters.RENDER_HELPER_METHODS, new UifRenderHelperMethods());
275     }
276 
277     /**
278      * Prepares the {@link org.kuali.rice.krad.uif.view.View} instance contained on the form for rendering.
279      *
280      * @param request servlet request
281      * @param form form instance containing the data and view instance
282      */
283     protected void invokeViewLifecycle(HttpServletRequest request, UifFormBase form) {
284         // for component refreshes only lifecycle for component is performed
285         if (form.isUpdateComponentRequest() || form.isUpdateDialogRequest() || (form.isJsonRequest() && StringUtils
286                 .isNotBlank(form.getUpdateComponentId()))) {
287             String refreshComponentId = form.getUpdateComponentId();
288 
289             Component updateComponent = ViewLifecycle.performComponentLifecycle(form.getView(), form, request,
290                     form.getViewPostMetadata(), refreshComponentId);
291             form.setUpdateComponent(updateComponent);
292         } else {
293             // full view build
294             View view = form.getView();
295             if (view == null) {
296                 LOG.warn("View in form was null: " + form);
297 
298                 if (!form.isJsonRequest()) {
299                     throw new IllegalStateException("View in form was null: " + form);
300                 }
301                 else {
302                     return;
303                 }
304             }
305 
306             Map<String, String> parameterMap = KRADUtils.translateRequestParameterMap(request.getParameterMap());
307             parameterMap.putAll(form.getViewRequestParameters());
308 
309             // build view which will prepare for rendering
310             ViewPostMetadata postMetadata = ViewLifecycle.buildView(view, form, request, parameterMap);
311             form.setViewPostMetadata(postMetadata);
312 
313             if (form.isUpdatePageRequest()) {
314                 Component updateComponent = form.getView().getCurrentPage();
315                 form.setUpdateComponent(updateComponent);
316             }
317 
318             // update the page on the form to reflect the current page of the view
319             form.setPageId(view.getCurrentPageId());
320         }
321     }
322 
323     protected ViewService getViewService() {
324         return viewService;
325     }
326 
327     public void setViewService(ViewService viewService) {
328         this.viewService = viewService;
329     }
330 
331     public ViewValidationService getViewValidationService() {
332         return viewValidationService;
333     }
334 
335     public void setViewValidationService(ViewValidationService viewValidationService) {
336         this.viewValidationService = viewValidationService;
337     }
338 }