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.service.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020import org.kuali.rice.core.api.CoreApiServiceLocator; 021import org.kuali.rice.core.api.exception.RiceRuntimeException; 022import org.kuali.rice.krad.service.ViewValidationService; 023import org.kuali.rice.krad.uif.UifConstants; 024import org.kuali.rice.krad.uif.UifParameters; 025import org.kuali.rice.krad.uif.component.Component; 026import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; 027import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata; 028import org.kuali.rice.krad.uif.service.ViewService; 029import org.kuali.rice.krad.uif.util.ScriptUtils; 030import org.kuali.rice.krad.uif.util.UifRenderHelperMethods; 031import org.kuali.rice.krad.uif.view.MessageView; 032import org.kuali.rice.krad.uif.view.View; 033import org.kuali.rice.krad.util.KRADConstants; 034import org.kuali.rice.krad.util.KRADUtils; 035import org.kuali.rice.krad.util.UrlFactory; 036import org.kuali.rice.krad.web.form.UifFormBase; 037import org.kuali.rice.krad.web.service.ModelAndViewService; 038import org.springframework.web.servlet.ModelAndView; 039 040import javax.servlet.http.HttpServletRequest; 041import java.util.Map; 042import java.util.Properties; 043 044/** 045 * Default implementation of the model and view service. 046 * 047 * @author Kuali Rice Team (rice.collab@kuali.org) 048 */ 049public class ModelAndViewServiceImpl implements ModelAndViewService { 050 private static final Logger LOG = Logger.getLogger(ModelAndViewServiceImpl.class); 051 052 private ViewService viewService; 053 private ViewValidationService viewValidationService; 054 055 /** 056 * Invokes {@link org.kuali.rice.krad.service.ViewValidationService} to validate the contents of the 057 * given form instance. 058 * 059 * {@inheritDoc} 060 */ 061 @Override 062 public ModelAndView checkForm(UifFormBase form) { 063 getViewValidationService().validateViewSimulation(form); 064 065 return getModelAndView(form); 066 } 067 068 /** 069 * Builds the dialog group with the given id then creates the script for showing the dialog once the 070 * page reloads. 071 * 072 * {@inheritDoc} 073 */ 074 @Override 075 public ModelAndView showDialog(String dialogId, boolean confirmation, UifFormBase form) { 076 if (form.isAjaxRequest()) { 077 form.setAjaxReturnType(UifConstants.AjaxReturnTypes.UPDATEDIALOG.getKey()); 078 form.setUpdateComponentId(dialogId); 079 } 080 081 // run the lifecycle to build the dialog first 082 ModelAndView modelAndView = getModelAndView(form); 083 prepareView(form.getRequest(), modelAndView); 084 085 Component updateComponent; 086 if (form.isAjaxRequest()) { 087 updateComponent = form.getUpdateComponent(); 088 } else { 089 updateComponent = form.getView(); 090 } 091 092 // now add the script that will show the dialog to the on ready of the document 093 String showDialogScript = buildShowDialogScript(dialogId, confirmation, form); 094 095 String onReadyScript = ScriptUtils.appendScript(updateComponent.getOnDocumentReadyScript(), showDialogScript); 096 updateComponent.setOnDocumentReadyScript(onReadyScript); 097 098 form.getRequest().setAttribute(UifParameters.Attributes.VIEW_LIFECYCLE_COMPLETE, "true"); 099 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}