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 */ 016package org.kuali.rice.krad.web.form; 017 018import org.apache.commons.lang.StringUtils; 019import org.codehaus.jackson.map.ObjectMapper; 020import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 021import org.kuali.rice.krad.uif.UifConstants; 022import org.kuali.rice.krad.uif.UifParameters; 023import org.kuali.rice.krad.uif.view.History; 024import org.kuali.rice.krad.uif.view.View; 025import org.kuali.rice.krad.uif.service.ViewService; 026import org.kuali.rice.krad.uif.view.ViewModel; 027import org.kuali.rice.krad.util.KRADUtils; 028import org.springframework.web.multipart.MultipartFile; 029import org.kuali.rice.krad.uif.UifConstants.ViewType; 030 031import javax.servlet.http.HttpServletRequest; 032import java.io.IOException; 033import java.util.ArrayList; 034import java.util.HashMap; 035import java.util.List; 036import java.util.Map; 037import java.util.Properties; 038import java.util.Set; 039import java.util.UUID; 040 041/** 042 * Base form class for views within the KRAD User Interface Framework 043 * 044 * <p> 045 * Holds properties necessary to determine the <code>View</code> instance that 046 * will be used to render the UI 047 * </p> 048 * 049 * @author Kuali Rice Team (rice.collab@kuali.org) 050 */ 051public class UifFormBase implements ViewModel { 052 private static final long serialVersionUID = 8432543267099454434L; 053 054 // current view 055 protected String viewId; 056 protected String viewName; 057 protected ViewType viewTypeName; 058 protected String pageId; 059 protected String methodToCall; 060 protected String formKey; 061 protected String jumpToId; 062 protected String jumpToName; 063 protected String focusId; 064 protected String formPostUrl; 065 066 protected boolean defaultsApplied; 067 068 protected View view; 069 protected View previousView; 070 071 protected Map<String, String> viewRequestParameters; 072 protected List<String> readOnlyFieldsList; 073 074 protected Map<String, Object> newCollectionLines; 075 protected Map<String, String> actionParameters; 076 protected Map<String, Object> clientStateForSyncing; 077 protected Map<String, Set<String>> selectedCollectionLines; 078 079 protected MultipartFile attachmentFile; 080 081 // navigation 082 protected String returnLocation; 083 protected String returnFormKey; 084 085 protected History formHistory; 086 087 protected boolean renderFullView; 088 protected boolean validateDirty; 089 090 public UifFormBase() { 091 formKey = generateFormKey(); 092 renderFullView = true; 093 defaultsApplied = false; 094 095 formHistory = new History(); 096 097 readOnlyFieldsList = new ArrayList<String>(); 098 viewRequestParameters = new HashMap<String, String>(); 099 newCollectionLines = new HashMap<String, Object>(); 100 actionParameters = new HashMap<String, String>(); 101 clientStateForSyncing = new HashMap<String, Object>(); 102 selectedCollectionLines = new HashMap<String, Set<String>>(); 103 } 104 105 /** 106 * Creates the unique id used to store this "conversation" in the session. 107 * The default method generates a java UUID. 108 * 109 * @return 110 */ 111 protected String generateFormKey() { 112 return UUID.randomUUID().toString(); 113 } 114 115 /** 116 * Called after Spring binds the request to the form and before the 117 * controller method is invoked. 118 * 119 * @param request - request object containing the query parameters 120 */ 121 public void postBind(HttpServletRequest request) { 122 // default form post URL to request URL 123 formPostUrl = request.getRequestURL().toString(); 124 125 // get any sent client view state and parse into map 126 if (request.getParameterMap().containsKey(UifParameters.CLIENT_VIEW_STATE)) { 127 String clientStateJSON = request.getParameter(UifParameters.CLIENT_VIEW_STATE); 128 if (StringUtils.isNotBlank(clientStateJSON)) { 129 // change single quotes to double quotes (necessary because the reverse was done for sending) 130 clientStateJSON = StringUtils.replace(clientStateJSON, "'", "\""); 131 132 ObjectMapper mapper = new ObjectMapper(); 133 try { 134 clientStateForSyncing = mapper.readValue(clientStateJSON, Map.class); 135 } catch (IOException e) { 136 throw new RuntimeException("Unable to decode client side state JSON", e); 137 } 138 } 139 } 140 141 // populate read only fields list 142 if (request.getParameter(UifParameters.READ_ONLY_FIELDS) != null) { 143 String readOnlyFields = request.getParameter(UifParameters.READ_ONLY_FIELDS); 144 setReadOnlyFieldsList(KRADUtils.convertStringParameterToList(readOnlyFields)); 145 } 146 } 147 148 /** 149 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewId() 150 */ 151 public String getViewId() { 152 return this.viewId; 153 } 154 155 /** 156 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewId(java.lang.String) 157 */ 158 public void setViewId(String viewId) { 159 this.viewId = viewId; 160 } 161 162 /** 163 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewName() 164 */ 165 public String getViewName() { 166 return this.viewName; 167 } 168 169 /** 170 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewName(java.lang.String) 171 */ 172 public void setViewName(String viewName) { 173 this.viewName = viewName; 174 } 175 176 /** 177 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewTypeName() 178 */ 179 public ViewType getViewTypeName() { 180 return this.viewTypeName; 181 } 182 183 /** 184 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewTypeName(org.kuali.rice.krad.uif.UifConstants.ViewType) 185 */ 186 public void setViewTypeName(ViewType viewTypeName) { 187 this.viewTypeName = viewTypeName; 188 } 189 190 /** 191 * @see org.kuali.rice.krad.uif.view.ViewModel#getPageId() 192 */ 193 public String getPageId() { 194 return this.pageId; 195 } 196 197 /** 198 * @see org.kuali.rice.krad.uif.view.ViewModel#setPageId(java.lang.String) 199 */ 200 public void setPageId(String pageId) { 201 this.pageId = pageId; 202 } 203 204 /** 205 * @see org.kuali.rice.krad.uif.view.ViewModel#getFormPostUrl() 206 */ 207 public String getFormPostUrl() { 208 return this.formPostUrl; 209 } 210 211 /** 212 * @see org.kuali.rice.krad.uif.view.ViewModel#setFormPostUrl(java.lang.String) 213 */ 214 public void setFormPostUrl(String formPostUrl) { 215 this.formPostUrl = formPostUrl; 216 } 217 218 public String getReturnLocation() { 219 return this.returnLocation; 220 } 221 222 public void setReturnLocation(String returnLocation) { 223 this.returnLocation = returnLocation; 224 } 225 226 public String getReturnFormKey() { 227 return this.returnFormKey; 228 } 229 230 public void setReturnFormKey(String returnFormKey) { 231 this.returnFormKey = returnFormKey; 232 } 233 234 /** 235 * Identifies the controller method that should be invoked to fulfill a 236 * request. The value will be matched up against the 'params' setting on the 237 * <code>RequestMapping</code> annotation for the controller method 238 * 239 * @return String method to call 240 */ 241 public String getMethodToCall() { 242 return this.methodToCall; 243 } 244 245 /** 246 * Setter for the method to call 247 * 248 * @param methodToCall 249 */ 250 public void setMethodToCall(String methodToCall) { 251 this.methodToCall = methodToCall; 252 } 253 254 /** 255 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewRequestParameters() 256 */ 257 public Map<String, String> getViewRequestParameters() { 258 return this.viewRequestParameters; 259 } 260 261 /** 262 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewRequestParameters(java.util.Map<java.lang.String,java.lang.String>) 263 */ 264 public void setViewRequestParameters(Map<String, String> viewRequestParameters) { 265 this.viewRequestParameters = viewRequestParameters; 266 } 267 268 /** 269 * @see org.kuali.rice.krad.uif.view.ViewModel#getReadOnlyFieldsList() 270 */ 271 public List<String> getReadOnlyFieldsList() { 272 return readOnlyFieldsList; 273 } 274 275 /** 276 * @see org.kuali.rice.krad.uif.view.ViewModel#setReadOnlyFieldsList(java.util.List<java.lang.String>) 277 */ 278 public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) { 279 this.readOnlyFieldsList = readOnlyFieldsList; 280 } 281 282 /** 283 * @see org.kuali.rice.krad.uif.view.ViewModel#getNewCollectionLines() 284 */ 285 public Map<String, Object> getNewCollectionLines() { 286 return this.newCollectionLines; 287 } 288 289 /** 290 * @see org.kuali.rice.krad.uif.view.ViewModel#setNewCollectionLines(java.util.Map<java.lang.String,java.lang.Object>) 291 */ 292 public void setNewCollectionLines(Map<String, Object> newCollectionLines) { 293 this.newCollectionLines = newCollectionLines; 294 } 295 296 /** 297 * @see org.kuali.rice.krad.uif.view.ViewModel#getActionParameters() 298 */ 299 public Map<String, String> getActionParameters() { 300 return this.actionParameters; 301 } 302 303 /** 304 * Returns the action parameters map as a <code>Properties</code> instance 305 * 306 * @return Properties action parameters 307 */ 308 public Properties getActionParametersAsProperties() { 309 return KRADUtils.convertMapToProperties(actionParameters); 310 } 311 312 /** 313 * @see org.kuali.rice.krad.uif.view.ViewModel#setActionParameters(java.util.Map<java.lang.String,java.lang.String>) 314 */ 315 public void setActionParameters(Map<String, String> actionParameters) { 316 this.actionParameters = actionParameters; 317 } 318 319 /** 320 * Retrieves the value for the given action parameter, or empty string if 321 * not found 322 * 323 * @param actionParameterName - name of the action parameter to retrieve value for 324 * @return String parameter value or empty string 325 */ 326 public String getActionParamaterValue(String actionParameterName) { 327 if ((actionParameters != null) && actionParameters.containsKey(actionParameterName)) { 328 return actionParameters.get(actionParameterName); 329 } 330 331 return ""; 332 } 333 334 /** 335 * Returns the action event that was sent in the action parameters (if any) 336 * 337 * <p> 338 * The action event is a special action parameter that can be sent to indicate a type of action being taken. This 339 * can be looked at by the view or components to render differently 340 * </p> 341 * 342 * TODO: make sure action parameters are getting reinitialized on each request 343 * 344 * @return String action event name or blank if action event was not sent 345 */ 346 public String getActionEvent() { 347 if ((actionParameters != null) && actionParameters.containsKey(UifConstants.UrlParams.ACTION_EVENT)) { 348 return actionParameters.get(UifConstants.UrlParams.ACTION_EVENT); 349 } 350 351 return ""; 352 } 353 354 /** 355 * @see org.kuali.rice.krad.uif.view.ViewModel#getClientStateForSyncing() 356 */ 357 public Map<String, Object> getClientStateForSyncing() { 358 return clientStateForSyncing; 359 } 360 361 /** 362 * @see org.kuali.rice.krad.uif.view.ViewModel#getSelectedCollectionLines() 363 */ 364 public Map<String, Set<String>> getSelectedCollectionLines() { 365 return selectedCollectionLines; 366 } 367 368 /** 369 * @see org.kuali.rice.krad.uif.view.ViewModel#setSelectedCollectionLines(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>) 370 */ 371 public void setSelectedCollectionLines(Map<String, Set<String>> selectedCollectionLines) { 372 this.selectedCollectionLines = selectedCollectionLines; 373 } 374 375 /** 376 * Key string that identifies the form instance in session storage 377 * 378 * <p> 379 * When the view is posted, the previous form instance is retrieved and then 380 * populated from the request parameters. This key string is retrieve the 381 * session form from the session service 382 * </p> 383 * 384 * @return String form session key 385 */ 386 public String getFormKey() { 387 return this.formKey; 388 } 389 390 /** 391 * Setter for the form's session key 392 * 393 * @param formKey 394 */ 395 public void setFormKey(String formKey) { 396 this.formKey = formKey; 397 } 398 399 /** 400 * @see org.kuali.rice.krad.uif.view.ViewModel#isDefaultsApplied() 401 */ 402 public boolean isDefaultsApplied() { 403 return this.defaultsApplied; 404 } 405 406 /** 407 * @see org.kuali.rice.krad.uif.view.ViewModel#setDefaultsApplied(boolean) 408 */ 409 public void setDefaultsApplied(boolean defaultsApplied) { 410 this.defaultsApplied = defaultsApplied; 411 } 412 413 /** 414 * Holder for files that are attached through the view 415 * 416 * @return MultipartFile representing the attachment 417 */ 418 public MultipartFile getAttachmentFile() { 419 return this.attachmentFile; 420 } 421 422 /** 423 * Setter for the form's attachment file 424 * 425 * @param attachmentFile 426 */ 427 public void setAttachmentFile(MultipartFile attachmentFile) { 428 this.attachmentFile = attachmentFile; 429 } 430 431 /** 432 * @return the renderFullView 433 */ 434 public boolean isRenderFullView() { 435 return this.renderFullView; 436 } 437 438 /** 439 * @param renderFullView 440 */ 441 public void setRenderFullView(boolean renderFullView) { 442 this.renderFullView = renderFullView; 443 } 444 445 /** 446 * @see org.kuali.rice.krad.uif.view.ViewModel#getView() 447 */ 448 public View getView() { 449 return this.view; 450 } 451 452 /** 453 * @see org.kuali.rice.krad.uif.view.ViewModel#setView(org.kuali.rice.krad.uif.view.View) 454 */ 455 public void setView(View view) { 456 this.view = view; 457 } 458 459 /** 460 * @see org.kuali.rice.krad.uif.view.ViewModel#getPreviousView() 461 */ 462 public View getPreviousView() { 463 return this.previousView; 464 } 465 466 /** 467 * @see org.kuali.rice.krad.uif.view.ViewModel#setPreviousView(org.kuali.rice.krad.uif.view.View) 468 */ 469 public void setPreviousView(View previousView) { 470 this.previousView = previousView; 471 } 472 473 /** 474 * Instance of the <code>ViewService</code> that can be used to retrieve 475 * <code>View</code> instances 476 * 477 * @return ViewService implementation 478 */ 479 protected ViewService getViewService() { 480 return KRADServiceLocatorWeb.getViewService(); 481 } 482 483 /** 484 * The jumpToId for this form, the element with this id will be jumped to automatically 485 * when the form is loaded in the view. 486 * Using "TOP" or "BOTTOM" will jump to the top or the bottom of the resulting page. 487 * jumpToId always takes precedence over jumpToName, if set. 488 * 489 * @return the jumpToId 490 */ 491 public String getJumpToId() { 492 return this.jumpToId; 493 } 494 495 /** 496 * @param jumpToId the jumpToId to set 497 */ 498 public void setJumpToId(String jumpToId) { 499 this.jumpToId = jumpToId; 500 } 501 502 /** 503 * The jumpToName for this form, the element with this name will be jumped to automatically 504 * when the form is loaded in the view. 505 * WARNING: jumpToId always takes precedence over jumpToName, if set. 506 * 507 * @return the jumpToName 508 */ 509 public String getJumpToName() { 510 return this.jumpToName; 511 } 512 513 /** 514 * @param jumpToName the jumpToName to set 515 */ 516 public void setJumpToName(String jumpToName) { 517 this.jumpToName = jumpToName; 518 } 519 520 /** 521 * Field to place focus on when the page loads 522 * An empty focusId will result in focusing on the first visible input element by default. 523 * 524 * @return the focusId 525 */ 526 public String getFocusId() { 527 return this.focusId; 528 } 529 530 /** 531 * @param focusId the focusId to set 532 */ 533 public void setFocusId(String focusId) { 534 this.focusId = focusId; 535 } 536 537 /** 538 * History parameter representing the History of views that have come before the 539 * viewing of the current view 540 * 541 * <p> 542 * Used for breadcrumb widget generation on the view and also for navigating back 543 * to previous or hub locations 544 * </p> 545 * 546 * @return History instance giving current history 547 */ 548 public History getFormHistory() { 549 return formHistory; 550 } 551 552 /** 553 * Setter for the current History object 554 * 555 * @param history the history to set 556 */ 557 public void setFormHistory(History history) { 558 this.formHistory = history; 559 } 560 561 /** 562 * Indicates whether the form should be validated for dirtyness 563 * 564 * <p> 565 * For FormView, it's necessary to validate when the user tries to navigate out of the form. If set, all the 566 * InputFields will be validated on refresh, navigate, cancel or close Action or on form 567 * unload and if dirty, displays a message and user can decide whether to continue with 568 * the action or stay on the form 569 * </p> 570 * 571 * @return boolean true if dirty validation should be enabled 572 */ 573 public boolean isValidateDirty() { 574 return this.validateDirty; 575 } 576 577 /** 578 * Setter for dirty validation indicator 579 * 580 * @param validateDirty 581 */ 582 public void setValidateDirty(boolean validateDirty) { 583 this.validateDirty = validateDirty; 584 } 585 586}