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.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.UifConstants.ViewType; 023import org.kuali.rice.krad.uif.UifParameters; 024import org.kuali.rice.krad.uif.UifPropertyPaths; 025import org.kuali.rice.krad.uif.component.Component; 026import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata; 027import org.kuali.rice.krad.uif.service.ViewHelperService; 028import org.kuali.rice.krad.uif.service.ViewService; 029import org.kuali.rice.krad.uif.util.SessionTransient; 030import org.kuali.rice.krad.uif.view.View; 031import org.kuali.rice.krad.uif.view.ViewModel; 032import org.kuali.rice.krad.util.CsrfValidator; 033import org.kuali.rice.krad.util.KRADUtils; 034import org.kuali.rice.krad.web.bind.RequestAccessible; 035import org.springframework.web.multipart.MultipartFile; 036 037import javax.servlet.http.HttpServletRequest; 038import java.io.IOException; 039import java.util.ArrayList; 040import java.util.Enumeration; 041import java.util.HashMap; 042import java.util.HashSet; 043import java.util.List; 044import java.util.Map; 045import java.util.Properties; 046import java.util.Set; 047import java.util.UUID; 048 049/** 050 * Base form class for views within the KRAD User Interface Framework. 051 * 052 * <p>Holds properties necessary to determine the {@link org.kuali.rice.krad.uif.view.View} instance that 053 * will be used to render the user interface</p> 054 * 055 * @author Kuali Rice Team (rice.collab@kuali.org) 056 */ 057public class UifFormBase implements ViewModel { 058 059 private static final long serialVersionUID = 8432543267099454434L; 060 061 @RequestAccessible 062 protected String viewId; 063 064 @RequestAccessible 065 protected String viewName; 066 067 @RequestAccessible 068 protected ViewType viewTypeName; 069 070 @RequestAccessible 071 protected String pageId; 072 073 @RequestAccessible 074 protected String methodToCall; 075 076 @RequestAccessible 077 protected String formKey; 078 079 @RequestAccessible 080 @SessionTransient 081 protected String requestedFormKey; 082 083 @RequestAccessible 084 protected String flowKey; 085 086 protected String sessionId; 087 protected int sessionTimeoutInterval; 088 089 @SessionTransient 090 protected HistoryFlow historyFlow; 091 @SessionTransient 092 protected HistoryManager historyManager; 093 094 @RequestAccessible 095 @SessionTransient 096 protected String jumpToId; 097 098 @SessionTransient 099 protected String jumpToName; 100 101 @RequestAccessible 102 @SessionTransient 103 protected String focusId; 104 105 @RequestAccessible 106 @SessionTransient 107 protected boolean dirtyForm; 108 109 protected String formPostUrl; 110 protected String controllerMapping; 111 112 @SessionTransient 113 private String requestUrl; 114 private Map<String, String[]> initialRequestParameters; 115 116 protected String state; 117 118 @RequestAccessible 119 protected boolean renderedInDialog; 120 121 @RequestAccessible 122 protected boolean renderedInIframe; 123 124 @SessionTransient 125 protected String growlScript; 126 127 @SessionTransient 128 protected View view; 129 protected ViewPostMetadata viewPostMetadata; 130 131 protected Map<String, String> viewRequestParameters; 132 protected List<String> readOnlyFieldsList; 133 134 protected Map<String, Object> newCollectionLines; 135 136 @RequestAccessible 137 @SessionTransient 138 protected String triggerActionId; 139 140 @RequestAccessible 141 @SessionTransient 142 protected Map<String, String> actionParameters; 143 144 protected Map<String, Object> clientStateForSyncing; 145 146 @SessionTransient 147 protected Map<String, Set<String>> selectedCollectionLines; 148 149 protected Set<String> selectedLookupResultsCache; 150 151 protected List<Object> addedCollectionItems; 152 153 @SessionTransient 154 protected MultipartFile attachmentFile; 155 156 // navigation 157 @RequestAccessible 158 protected String returnLocation; 159 160 @RequestAccessible 161 protected String returnFormKey; 162 163 @RequestAccessible 164 @SessionTransient 165 protected boolean ajaxRequest; 166 167 @RequestAccessible 168 @SessionTransient 169 protected String ajaxReturnType; 170 171 @SessionTransient 172 private String requestJsonTemplate; 173 @SessionTransient 174 private boolean collectionPagingRequest; 175 176 // dialog fields 177 @RequestAccessible 178 @SessionTransient 179 protected String showDialogId; 180 181 @RequestAccessible 182 @SessionTransient 183 protected String returnDialogId; 184 185 @RequestAccessible 186 @SessionTransient 187 protected String returnDialogResponse; 188 189 @RequestAccessible 190 protected Map<String, String> dialogExplanations; 191 protected Map<String, DialogResponse> dialogResponses; 192 193 @SessionTransient 194 protected boolean requestRedirected; 195 196 @RequestAccessible 197 @SessionTransient 198 protected String updateComponentId; 199 @SessionTransient 200 private Component updateComponent; 201 202 @RequestAccessible 203 protected Map<String, Object> extensionData; 204 205 protected boolean applyDefaultValues; 206 207 protected boolean evaluateFlagsAndModes; 208 protected Boolean canEditView; 209 protected Map<String, Boolean> actionFlags; 210 protected Map<String, Boolean> editModes; 211 212 protected String csrfToken; 213 214 protected HttpServletRequest request; 215 216 private Object dialogDataObject; 217 218 public UifFormBase() { 219 renderedInDialog = false; 220 renderedInIframe = false; 221 requestRedirected = false; 222 223 readOnlyFieldsList = new ArrayList<String>(); 224 viewRequestParameters = new HashMap<String, String>(); 225 newCollectionLines = new HashMap<String, Object>(); 226 actionParameters = new HashMap<String, String>(); 227 clientStateForSyncing = new HashMap<String, Object>(); 228 selectedCollectionLines = new HashMap<String, Set<String>>(); 229 selectedLookupResultsCache = new HashSet<String>(); 230 addedCollectionItems = new ArrayList<Object>(); 231 dialogExplanations = new HashMap<String, String>(); 232 dialogResponses = new HashMap<String, DialogResponse>(); 233 extensionData = new HashMap<String, Object>(); 234 235 applyDefaultValues = true; 236 evaluateFlagsAndModes = true; 237 } 238 239 /** 240 * {@inheritDoc} 241 */ 242 @Override 243 public void preBind(HttpServletRequest request) { 244 String formKeyParam = request.getParameter(UifParameters.FORM_KEY); 245 if (StringUtils.isNotBlank(formKeyParam)) { 246 UifFormManager uifFormManager = (UifFormManager) request.getSession().getAttribute( 247 UifParameters.FORM_MANAGER); 248 249 // retrieves the session form and updates the request from with the session transient attributes 250 uifFormManager.updateFormWithSession(this, formKeyParam); 251 } 252 253 String requestedFormKey = request.getParameter(UifParameters.REQUESTED_FORM_KEY); 254 if (StringUtils.isNotBlank(requestedFormKey)) { 255 setRequestedFormKey(requestedFormKey); 256 } else { 257 setRequestedFormKey(formKeyParam); 258 } 259 260 String csrfToken = CsrfValidator.getSessionToken(request); 261 setCsrfToken(csrfToken); 262 263 this.request = request; 264 } 265 266 /** 267 * {@inheritDoc} 268 */ 269 @Override 270 public void postBind(HttpServletRequest request) { 271 // assign form key if this is a new form or the requested form key is not in session 272 UifFormManager uifFormManager = (UifFormManager) request.getSession().getAttribute(UifParameters.FORM_MANAGER); 273 if (StringUtils.isBlank(formKey) || !uifFormManager.hasSessionForm(formKey)) { 274 formKey = generateFormKey(); 275 } 276 277 // default form post URL to request URL 278 formPostUrl = request.getRequestURL().toString(); 279 280 controllerMapping = request.getPathInfo(); 281 282 if (request.getSession() != null) { 283 sessionId = request.getSession().getId(); 284 sessionTimeoutInterval = request.getSession().getMaxInactiveInterval(); 285 } 286 287 // get any sent client view state and parse into map 288 if (request.getParameterMap().containsKey(UifParameters.CLIENT_VIEW_STATE)) { 289 String clientStateJSON = request.getParameter(UifParameters.CLIENT_VIEW_STATE); 290 if (StringUtils.isNotBlank(clientStateJSON)) { 291 // change single quotes to double quotes (necessary because the reverse was done for sending) 292 clientStateJSON = StringUtils.replace(clientStateJSON, "\\'", "\""); 293 clientStateJSON = StringUtils.replace(clientStateJSON, "\\[", "["); 294 clientStateJSON = StringUtils.replace(clientStateJSON, "\\]", "]"); 295 clientStateJSON = StringUtils.replace(clientStateJSON, "'", "\""); 296 297 ObjectMapper mapper = new ObjectMapper(); 298 try { 299 clientStateForSyncing = mapper.readValue(clientStateJSON, Map.class); 300 } catch (IOException e) { 301 throw new RuntimeException("Unable to decode client side state JSON: " + clientStateJSON, e); 302 } 303 } 304 } 305 306 String requestUrl = KRADUtils.stripXSSPatterns(KRADUtils.getFullURL(request)); 307 setRequestUrl(requestUrl); 308 309 String referer = request.getHeader(UifConstants.REFERER); 310 if (StringUtils.isBlank(referer) && StringUtils.isBlank(getReturnLocation())) { 311 setReturnLocation(UifConstants.NO_RETURN); 312 } else if (StringUtils.isBlank(getReturnLocation())) { 313 setReturnLocation(referer); 314 } 315 316 if (getInitialRequestParameters() == null) { 317 Map<String, String[]> requestParams = new HashMap<String, String[]>(); 318 Enumeration<String> names = request.getParameterNames(); 319 320 while (names != null && names.hasMoreElements()) { 321 String name = KRADUtils.stripXSSPatterns(names.nextElement()); 322 String[] values = KRADUtils.stripXSSPatterns(request.getParameterValues(name)); 323 324 requestParams.put(name, values); 325 } 326 327 requestParams.remove(UifConstants.UrlParams.LOGIN_USER); 328 setInitialRequestParameters(requestParams); 329 } 330 331 // populate read only fields list 332 if (request.getParameter(UifParameters.READ_ONLY_FIELDS) != null) { 333 String readOnlyFields = request.getParameter(UifParameters.READ_ONLY_FIELDS); 334 setReadOnlyFieldsList(KRADUtils.convertStringParameterToList(readOnlyFields)); 335 } 336 337 // collect dialog response, or initialize new map of responses 338 if (request.getParameter(UifParameters.RETURN_FROM_DIALOG) != null) { 339 String dialogExplanation = null; 340 if ((dialogExplanations != null) && dialogExplanations.containsKey(returnDialogId)) { 341 dialogExplanation = dialogExplanations.get(returnDialogId); 342 } 343 344 DialogResponse response = new DialogResponse(returnDialogId, returnDialogResponse, dialogExplanation); 345 this.dialogResponses.put(this.returnDialogId, response); 346 } else { 347 this.dialogResponses = new HashMap<String, DialogResponse>(); 348 } 349 350 Object historyManager = request.getSession().getAttribute(UifConstants.HistoryFlow.HISTORY_MANAGER); 351 if (historyManager != null && historyManager instanceof HistoryManager) { 352 setHistoryManager((HistoryManager) historyManager); 353 354 String flowKey = request.getParameter(UifConstants.HistoryFlow.FLOW); 355 setFlowKey(flowKey); 356 } 357 358 // clean parameters from XSS attacks that will be written out as hiddens 359 this.pageId = KRADUtils.stripXSSPatterns(this.pageId); 360 this.methodToCall = KRADUtils.stripXSSPatterns(this.methodToCall); 361 this.formKey = KRADUtils.stripXSSPatterns(this.formKey); 362 this.requestedFormKey = KRADUtils.stripXSSPatterns(this.requestedFormKey); 363 this.flowKey = KRADUtils.stripXSSPatterns(this.flowKey); 364 this.sessionId = KRADUtils.stripXSSPatterns(this.sessionId); 365 this.formPostUrl = KRADUtils.stripXSSPatterns(this.formPostUrl); 366 this.returnLocation = KRADUtils.stripXSSPatterns(this.returnLocation); 367 this.returnFormKey = KRADUtils.stripXSSPatterns(this.returnFormKey); 368 this.requestUrl = KRADUtils.stripXSSPatterns(this.requestUrl); 369 } 370 371 /** 372 * {@inheritDoc} 373 */ 374 @Override 375 public void preRender(HttpServletRequest request) { 376 // clear dialog properties so previous values do not appear for new dialogs 377 this.returnDialogId = null; 378 this.returnDialogResponse = null; 379 this.dialogExplanations = new HashMap<String, String>(); 380 } 381 382 /** 383 * Creates the unique id used to store this "conversation" in the session. 384 * The default method generates a java UUID. 385 * 386 * @return UUID 387 */ 388 protected String generateFormKey() { 389 return UUID.randomUUID().toString(); 390 } 391 392 /** 393 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewId() 394 */ 395 @Override 396 public String getViewId() { 397 return this.viewId; 398 } 399 400 /** 401 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewId(String) 402 */ 403 @Override 404 public void setViewId(String viewId) { 405 this.viewId = viewId; 406 } 407 408 /** 409 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewName() 410 */ 411 @Override 412 public String getViewName() { 413 return this.viewName; 414 } 415 416 /** 417 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewName(String) 418 */ 419 @Override 420 public void setViewName(String viewName) { 421 this.viewName = viewName; 422 } 423 424 /** 425 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewTypeName() 426 */ 427 @Override 428 public ViewType getViewTypeName() { 429 return this.viewTypeName; 430 } 431 432 /** 433 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewTypeName(org.kuali.rice.krad.uif.UifConstants.ViewType) 434 */ 435 @Override 436 public void setViewTypeName(ViewType viewTypeName) { 437 this.viewTypeName = viewTypeName; 438 } 439 440 /** 441 * @see org.kuali.rice.krad.uif.view.ViewModel#getPageId() 442 */ 443 @Override 444 public String getPageId() { 445 return this.pageId; 446 } 447 448 /** 449 * @see org.kuali.rice.krad.uif.view.ViewModel#setPageId(String) 450 */ 451 @Override 452 public void setPageId(String pageId) { 453 this.pageId = pageId; 454 } 455 456 /** 457 * @see org.kuali.rice.krad.uif.view.ViewModel#getFormPostUrl() 458 */ 459 @Override 460 public String getFormPostUrl() { 461 return this.formPostUrl; 462 } 463 464 /** 465 * @see org.kuali.rice.krad.uif.view.ViewModel#setFormPostUrl(String) 466 */ 467 @Override 468 public void setFormPostUrl(String formPostUrl) { 469 this.formPostUrl = formPostUrl; 470 } 471 472 /** 473 * Name of the controllerMapping for this form (includes slash) 474 * 475 * @return the controllerMapping string 476 */ 477 public String getControllerMapping() { 478 return controllerMapping; 479 } 480 481 /** 482 * The current {@link HistoryFlow} for this form which stores a trail of urls/breadcrumbs primarily used for 483 * path-based breadcrumb display 484 * 485 * @return the {@link HistoryFlow} 486 */ 487 public HistoryFlow getHistoryFlow() { 488 return historyFlow; 489 } 490 491 /** 492 * Set the current HistoryFlow for this form 493 */ 494 public void setHistoryFlow(HistoryFlow historyFlow) { 495 this.historyFlow = historyFlow; 496 } 497 498 /** 499 * The current {@link HistoryManager} that was pulled from session which store all {@link HistoryFlow} objects in 500 * the current session to keep track of the path the user has taken across views (primarily used by path-based 501 * breadcrumbs) 502 * 503 * @return the HistoryManager 504 */ 505 public HistoryManager getHistoryManager() { 506 return historyManager; 507 } 508 509 /** 510 * Set the current HistoryManager 511 */ 512 public void setHistoryManager(HistoryManager historyManager) { 513 this.historyManager = historyManager; 514 } 515 516 /** 517 * The flowKey representing the HistoryFlow this form may be in. 518 * 519 * <p>This allows for a flow to continue by key or start (if set to "start"). 520 * If null or blank, no flow (or path based 521 * breadcrumbs) are being tracked.</p> 522 * 523 * @return the flowKey 524 */ 525 public String getFlowKey() { 526 return flowKey; 527 } 528 529 /** 530 * Set the flowKey 531 */ 532 public void setFlowKey(String flowKey) { 533 this.flowKey = flowKey; 534 } 535 536 /** 537 * The original requestUrl for the View represented by this form (url received by the controller for initial 538 * request) 539 * 540 * @return the requestUrl 541 */ 542 public String getRequestUrl() { 543 return requestUrl; 544 } 545 546 /** 547 * Set the requestUrl 548 */ 549 public void setRequestUrl(String requestUrl) { 550 this.requestUrl = requestUrl; 551 } 552 553 /** 554 * The requestParameters represent all the parameters in the query string that were initially passed to this View 555 * by the initial request 556 * 557 * @return the requestParameters 558 */ 559 public Map<String, String[]> getInitialRequestParameters() { 560 return initialRequestParameters; 561 } 562 563 /** 564 * Set the requestParameters 565 */ 566 public void setInitialRequestParameters(Map<String, String[]> requestParameters) { 567 this.initialRequestParameters = requestParameters; 568 } 569 570 public String getReturnLocation() { 571 return this.returnLocation; 572 } 573 574 public void setReturnLocation(String returnLocation) { 575 this.returnLocation = returnLocation; 576 } 577 578 public String getReturnFormKey() { 579 return this.returnFormKey; 580 } 581 582 public void setReturnFormKey(String returnFormKey) { 583 this.returnFormKey = returnFormKey; 584 } 585 586 /** 587 * Holds the id for the user's current session 588 * 589 * <p> 590 * The user's session id is used to track when a timeout has occurred and enforce the policy 591 * configured with the {@link org.kuali.rice.krad.uif.view.ViewSessionPolicy}. This property gets initialized 592 * in the {@link #postBind(javax.servlet.http.HttpServletRequest)} method and then is written out as a 593 * hidden on the view. Therefore each post done on the view will send back the session id when the view was 594 * rendering, and the {@link org.kuali.rice.krad.web.filter.UifSessionTimeoutFilter} can use that to determine 595 * if a timeout has occurred 596 * </p> 597 * 598 * @return id for the user's current session 599 */ 600 public String getSessionId() { 601 return sessionId; 602 } 603 604 /** 605 * Holds the configured session timeout interval 606 * 607 * <p> 608 * Holds the session timeout interval so it can be referenced to give the user notifications (for example the 609 * session timeout warning reads this property). This is initialized from the session object in 610 * {@link #postBind(javax.servlet.http.HttpServletRequest)} 611 * </p> 612 * 613 * @return amount of time in milliseconds before the session will timeout 614 */ 615 public int getSessionTimeoutInterval() { 616 return sessionTimeoutInterval; 617 } 618 619 /** 620 * Identifies the controller method that should be invoked to fulfill a 621 * request. The value will be matched up against the 'params' setting on the 622 * {@code RequestMapping} annotation for the controller method 623 * 624 * @return String method to call 625 */ 626 public String getMethodToCall() { 627 return this.methodToCall; 628 } 629 630 /** 631 * Setter for the method to call 632 */ 633 public void setMethodToCall(String methodToCall) { 634 this.methodToCall = methodToCall; 635 } 636 637 /** 638 * {@inheritDoc} 639 */ 640 @Override 641 public Map<String, String> getViewRequestParameters() { 642 return this.viewRequestParameters; 643 } 644 645 /** 646 * {@inheritDoc} 647 */ 648 @Override 649 public void setViewRequestParameters(Map<String, String> viewRequestParameters) { 650 this.viewRequestParameters = viewRequestParameters; 651 } 652 653 /** 654 * {@inheritDoc} 655 */ 656 @Override 657 public List<String> getReadOnlyFieldsList() { 658 return readOnlyFieldsList; 659 } 660 661 /** 662 * {@inheritDoc} 663 */ 664 @Override 665 public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) { 666 this.readOnlyFieldsList = readOnlyFieldsList; 667 } 668 669 /** 670 * @see org.kuali.rice.krad.uif.view.ViewModel#getNewCollectionLines() 671 */ 672 @Override 673 public Map<String, Object> getNewCollectionLines() { 674 return this.newCollectionLines; 675 } 676 677 /** 678 * {@inheritDoc} 679 */ 680 @Override 681 public void setNewCollectionLines(Map<String, Object> newCollectionLines) { 682 this.newCollectionLines = newCollectionLines; 683 } 684 685 /** 686 * {@inheritDoc} 687 */ 688 @Override 689 public String getTriggerActionId() { 690 return triggerActionId; 691 } 692 693 /** 694 * {@inheritDoc} 695 */ 696 @Override 697 public void setTriggerActionId(String triggerActionId) { 698 this.triggerActionId = triggerActionId; 699 } 700 701 /** 702 * @see org.kuali.rice.krad.uif.view.ViewModel#getActionParameters() 703 */ 704 @Override 705 public Map<String, String> getActionParameters() { 706 return this.actionParameters; 707 } 708 709 /** 710 * Returns the action parameters map as a {@code Properties} instance 711 * 712 * @return Properties action parameters 713 */ 714 public Properties getActionParametersAsProperties() { 715 return KRADUtils.convertMapToProperties(actionParameters); 716 } 717 718 /** 719 * {@inheritDoc} 720 */ 721 @Override 722 public void setActionParameters(Map<String, String> actionParameters) { 723 this.actionParameters = actionParameters; 724 } 725 726 /** 727 * Retrieves the value for the given action parameter, or empty string if 728 * not found 729 * 730 * @param actionParameterName - name of the action parameter to retrieve value for 731 * @return String parameter value or empty string 732 */ 733 public String getActionParamaterValue(String actionParameterName) { 734 if ((actionParameters != null) && actionParameters.containsKey(actionParameterName)) { 735 return actionParameters.get(actionParameterName); 736 } 737 738 return ""; 739 } 740 741 /** 742 * Returns the action event that was sent in the action parameters (if any) 743 * 744 * <p> 745 * The action event is a special action parameter that can be sent to indicate a type of action being taken. This 746 * can be looked at by the view or components to render differently 747 * </p> 748 * 749 * TODO: make sure action parameters are getting reinitialized on each request 750 * 751 * @return String action event name or blank if action event was not sent 752 */ 753 public String getActionEvent() { 754 if ((actionParameters != null) && actionParameters.containsKey(UifConstants.UrlParams.ACTION_EVENT)) { 755 return actionParameters.get(UifConstants.UrlParams.ACTION_EVENT); 756 } 757 758 return ""; 759 } 760 761 /** 762 * @see org.kuali.rice.krad.uif.view.ViewModel#getClientStateForSyncing() 763 */ 764 @Override 765 public Map<String, Object> getClientStateForSyncing() { 766 return clientStateForSyncing; 767 } 768 769 /** 770 * Setter for the client state 771 */ 772 public void setClientStateForSyncing(Map<String, Object> clientStateForSyncing) { 773 this.clientStateForSyncing = clientStateForSyncing; 774 } 775 776 /** 777 * @see org.kuali.rice.krad.uif.view.ViewModel#getSelectedCollectionLines() 778 */ 779 @Override 780 public Map<String, Set<String>> getSelectedCollectionLines() { 781 return selectedCollectionLines; 782 } 783 784 /** 785 * {@inheritDoc} 786 */ 787 @Override 788 public void setSelectedCollectionLines(Map<String, Set<String>> selectedCollectionLines) { 789 this.selectedCollectionLines = selectedCollectionLines; 790 } 791 792 /** 793 * Holds Set of String identifiers for lines that were selected in a lookup collection results 794 * across multiple pages. 795 * The value in the cache is preserved in the session across multiple requests. This allows for the 796 * server side paging of results to retain the user choices as they move through the pages. 797 * 798 * @return set of identifiers 799 */ 800 public Set<String> getSelectedLookupResultsCache() { 801 return selectedLookupResultsCache; 802 } 803 804 /** 805 * Sets the lookup result selection cache values 806 */ 807 public void setSelectedLookupResultsCache(Set<String> selectedLookupResultsCache) { 808 this.selectedLookupResultsCache = selectedLookupResultsCache; 809 } 810 811 /** 812 * Key string that identifies the form instance in session storage 813 * 814 * <p> 815 * When the view is posted, the previous form instance is retrieved and then 816 * populated from the request parameters. This key string is retrieve the 817 * session form from the session service 818 * </p> 819 * 820 * @return String form session key 821 */ 822 public String getFormKey() { 823 return this.formKey; 824 } 825 826 /** 827 * Setter for the form's session key 828 */ 829 public void setFormKey(String formKey) { 830 this.formKey = formKey; 831 } 832 833 /** 834 * This is the formKey sent on the original request. It may differ from the actual form key stored in formKey 835 * based on if the form still exists in session by this key or not. 836 * 837 * @return the original requested form key 838 */ 839 public String getRequestedFormKey() { 840 return requestedFormKey; 841 } 842 843 /** 844 * Set the requestedFormKey 845 */ 846 public void setRequestedFormKey(String requestedFormKey) { 847 this.requestedFormKey = requestedFormKey; 848 } 849 850 /** 851 * Indicates whether a redirect has been requested for the view 852 * 853 * @return boolean true if redirect was requested, false if not 854 */ 855 public boolean isRequestRedirected() { 856 return requestRedirected; 857 } 858 859 /** 860 * Setter for the request redirect indicator 861 */ 862 public void setRequestRedirected(boolean requestRedirected) { 863 this.requestRedirected = requestRedirected; 864 } 865 866 /** 867 * Holder for files that are attached through the view 868 * 869 * @return MultipartFile representing the attachment 870 */ 871 public MultipartFile getAttachmentFile() { 872 return this.attachmentFile; 873 } 874 875 /** 876 * Setter for the form's attachment file 877 */ 878 public void setAttachmentFile(MultipartFile attachmentFile) { 879 this.attachmentFile = attachmentFile; 880 } 881 882 /** 883 * @see org.kuali.rice.krad.uif.view.ViewModel#getUpdateComponentId() 884 */ 885 @Override 886 public String getUpdateComponentId() { 887 return updateComponentId; 888 } 889 890 /** 891 * @see org.kuali.rice.krad.uif.view.ViewModel#setUpdateComponentId(java.lang.String) 892 */ 893 @Override 894 public void setUpdateComponentId(String updateComponentId) { 895 this.updateComponentId = updateComponentId; 896 } 897 898 /** 899 * @see org.kuali.rice.krad.uif.view.ViewModel#getUpdateComponent() 900 */ 901 public Component getUpdateComponent() { 902 return updateComponent; 903 } 904 905 /** 906 * @see org.kuali.rice.krad.uif.view.ViewModel#setUpdateComponent(org.kuali.rice.krad.uif.component.Component) 907 */ 908 public void setUpdateComponent(Component updateComponent) { 909 this.updateComponent = updateComponent; 910 } 911 912 /** 913 * @see org.kuali.rice.krad.uif.view.ViewModel#getView() 914 */ 915 @Override 916 public View getView() { 917 return this.view; 918 } 919 920 /** 921 * @see org.kuali.rice.krad.uif.view.ViewModel#setView(org.kuali.rice.krad.uif.view.View) 922 */ 923 @Override 924 public void setView(View view) { 925 this.view = view; 926 } 927 928 /** 929 * Returns an instance of the view's configured view helper service. 930 * 931 * <p>First checks if there is an initialized view containing a view helper instance. If not, and there is 932 * a view id on the form, a call is made to retrieve the view helper instance or class configuration.</p> 933 * 934 * {@inheritDoc} 935 */ 936 @Override 937 public ViewHelperService getViewHelperService() { 938 if ((getView() != null) && (getView().getViewHelperService() != null)) { 939 return getView().getViewHelperService(); 940 } 941 942 String viewId = getViewId(); 943 if (StringUtils.isBlank(viewId) && (getView() != null)) { 944 viewId = getView().getId(); 945 } 946 947 if (StringUtils.isBlank(viewId)) { 948 return null; 949 } 950 951 ViewHelperService viewHelperService = 952 (ViewHelperService) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryBeanProperty(viewId, 953 UifPropertyPaths.VIEW_HELPER_SERVICE); 954 if (viewHelperService == null) { 955 Class<?> viewHelperServiceClass = 956 (Class<?>) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryBeanProperty(viewId, 957 UifPropertyPaths.VIEW_HELPER_SERVICE_CLASS); 958 959 if (viewHelperServiceClass != null) { 960 try { 961 viewHelperService = (ViewHelperService) viewHelperServiceClass.newInstance(); 962 } catch (Exception e) { 963 throw new RuntimeException("Unable to instantiate view helper class: " + viewHelperServiceClass, e); 964 } 965 } 966 } 967 968 return viewHelperService; 969 } 970 971 /** 972 * {@inheritDoc} 973 */ 974 @Override 975 public ViewPostMetadata getViewPostMetadata() { 976 return viewPostMetadata; 977 } 978 979 /** 980 * @see UifFormBase#getViewPostMetadata() 981 */ 982 @Override 983 public void setViewPostMetadata(ViewPostMetadata viewPostMetadata) { 984 this.viewPostMetadata = viewPostMetadata; 985 } 986 987 /** 988 * Instance of the {@code ViewService} that can be used to retrieve 989 * {@code View} instances 990 * 991 * @return ViewService implementation 992 */ 993 protected ViewService getViewService() { 994 return KRADServiceLocatorWeb.getViewService(); 995 } 996 997 /** 998 * The jumpToId for this form, the element with this id will be jumped to automatically 999 * when the form is loaded in the view. 1000 * Using "TOP" or "BOTTOM" will jump to the top or the bottom of the resulting page. 1001 * jumpToId always takes precedence over jumpToName, if set. 1002 * 1003 * @return the jumpToId 1004 */ 1005 public String getJumpToId() { 1006 return this.jumpToId; 1007 } 1008 1009 /** 1010 * @param jumpToId the jumpToId to set 1011 */ 1012 public void setJumpToId(String jumpToId) { 1013 this.jumpToId = jumpToId; 1014 } 1015 1016 /** 1017 * The jumpToName for this form, the element with this name will be jumped to automatically 1018 * when the form is loaded in the view. 1019 * WARNING: jumpToId always takes precedence over jumpToName, if set. 1020 * 1021 * @return the jumpToName 1022 */ 1023 public String getJumpToName() { 1024 return this.jumpToName; 1025 } 1026 1027 /** 1028 * @param jumpToName the jumpToName to set 1029 */ 1030 public void setJumpToName(String jumpToName) { 1031 this.jumpToName = jumpToName; 1032 } 1033 1034 /** 1035 * Field to place focus on when the page loads 1036 * An empty focusId will result in focusing on the first visible input element by default. 1037 * 1038 * @return the focusId 1039 */ 1040 public String getFocusId() { 1041 return this.focusId; 1042 } 1043 1044 /** 1045 * @param focusId the focusId to set 1046 */ 1047 public void setFocusId(String focusId) { 1048 this.focusId = focusId; 1049 } 1050 1051 /** 1052 * True when the form is considered dirty (data has changed from original value), false otherwise 1053 * 1054 * <p>For most scenarios, this flag should NOT be set to true. 1055 * If this is set, it must be managed explicitly by the application. This flag exists for marking a 1056 * form dirty from a server call, so it must be changed to false when the form is no longer considered dirty. 1057 * The krad save Action and navigate methodToCall resets this flag back to false, but any other setting of 1058 * this flag must be managed by custom configuration/methods, if custom dirtyForm management is needed.</p> 1059 * 1060 * @return true if the form is considered dirty, false otherwise 1061 */ 1062 public boolean isDirtyForm() { 1063 return dirtyForm; 1064 } 1065 1066 /** 1067 * Sets the dirtyForm flag 1068 * 1069 * <p>For most scenarios, this flag should NOT be set to true. 1070 * If this is set, it must be managed explicitly by the application. This flag exists for marking a 1071 * form dirty from a server call, so it must be changed to false when the form is no longer considered dirty. 1072 * The krad save Action and navigate methodToCall resets this flag back to false, but any other setting of 1073 * this flag must be managed by custom configuration/methods, if custom dirtyForm management is needed.</p> 1074 */ 1075 public void setDirtyForm(boolean dirtyForm) { 1076 this.dirtyForm = dirtyForm; 1077 } 1078 1079 /** 1080 * Set the dirtyForm flag using a String that will be converted to boolean 1081 */ 1082 public void setDirtyForm(String dirtyForm) { 1083 if (dirtyForm != null) { 1084 this.dirtyForm = Boolean.parseBoolean(dirtyForm); 1085 } 1086 } 1087 1088 /** 1089 * Indicates whether the view is rendered within a lightbox 1090 * 1091 * <p> 1092 * Some discussion (for example how a close button behaves) need to change based on whether the 1093 * view is rendered within a lightbox or the standard browser window. This boolean is true when it is 1094 * within a lightbox 1095 * </p> 1096 * 1097 * @return boolean true if view is rendered within a lightbox, false if not 1098 */ 1099 public boolean isRenderedInDialog() { 1100 return this.renderedInDialog; 1101 } 1102 1103 /** 1104 * Setter for the rendered within lightbox indicator 1105 */ 1106 public void setRenderedInDialog(boolean renderedInDialog) { 1107 this.renderedInDialog = renderedInDialog; 1108 } 1109 1110 /** 1111 * Indicates whether the view is rendered within an iframe (this setting must be passed to the View on the url) 1112 * 1113 * @return boolean true if view is rendered within a iframe, false if not 1114 */ 1115 public boolean isRenderedInIframe() { 1116 return renderedInIframe; 1117 } 1118 1119 /** 1120 * @see org.kuali.rice.krad.web.form.UifFormBase#isRenderedInIframe() 1121 */ 1122 public void setRenderedInIframe(boolean renderedInIframe) { 1123 this.renderedInIframe = renderedInIframe; 1124 } 1125 1126 /** 1127 * @see org.kuali.rice.krad.uif.view.ViewModel#isApplyDefaultValues() 1128 */ 1129 @Override 1130 public boolean isApplyDefaultValues() { 1131 return applyDefaultValues; 1132 } 1133 1134 /** 1135 * @see org.kuali.rice.krad.uif.view.ViewModel#setApplyDefaultValues(boolean) 1136 */ 1137 @Override 1138 public void setApplyDefaultValues(boolean applyDefaultValues) { 1139 this.applyDefaultValues = applyDefaultValues; 1140 } 1141 1142 /** 1143 * @see org.kuali.rice.krad.uif.view.ViewModel#isEvaluateFlagsAndModes() 1144 */ 1145 public boolean isEvaluateFlagsAndModes() { 1146 return evaluateFlagsAndModes; 1147 } 1148 1149 /** 1150 * @see org.kuali.rice.krad.uif.view.ViewModel#setEvaluateFlagsAndModes(boolean) 1151 */ 1152 public void setEvaluateFlagsAndModes(boolean evaluateFlagsAndModes) { 1153 this.evaluateFlagsAndModes = evaluateFlagsAndModes; 1154 } 1155 1156 /** 1157 * @see org.kuali.rice.krad.uif.view.ViewModel#isCanEditView() 1158 */ 1159 public Boolean isCanEditView() { 1160 return canEditView; 1161 } 1162 1163 /** 1164 * @see org.kuali.rice.krad.uif.view.ViewModel#setCanEditView(Boolean) 1165 */ 1166 public void setCanEditView(Boolean canEditView) { 1167 this.canEditView = canEditView; 1168 } 1169 1170 /** 1171 * @see org.kuali.rice.krad.uif.view.ViewModel#getActionFlags() 1172 */ 1173 public Map<String, Boolean> getActionFlags() { 1174 return actionFlags; 1175 } 1176 1177 /** 1178 * @see org.kuali.rice.krad.uif.view.ViewModel#setActionFlags(java.util.Map<java.lang.String,java.lang.Boolean>) 1179 */ 1180 public void setActionFlags(Map<String, Boolean> actionFlags) { 1181 this.actionFlags = actionFlags; 1182 } 1183 1184 /** 1185 * @see org.kuali.rice.krad.uif.view.ViewModel#getEditModes() 1186 */ 1187 public Map<String, Boolean> getEditModes() { 1188 return editModes; 1189 } 1190 1191 /** 1192 * @see org.kuali.rice.krad.uif.view.ViewModel#setEditModes(java.util.Map<java.lang.String,java.lang.Boolean>) 1193 */ 1194 public void setEditModes(Map<String, Boolean> editModes) { 1195 this.editModes = editModes; 1196 } 1197 1198 /** 1199 * @see org.kuali.rice.krad.uif.view.ViewModel#getGrowlScript() 1200 */ 1201 @Override 1202 public String getGrowlScript() { 1203 return growlScript; 1204 } 1205 1206 /** 1207 * @see org.kuali.rice.krad.uif.view.ViewModel#setGrowlScript(String) 1208 */ 1209 @Override 1210 public void setGrowlScript(String growlScript) { 1211 this.growlScript = growlScript; 1212 } 1213 1214 /** 1215 * @see org.kuali.rice.krad.uif.view.ViewModel#getState() 1216 */ 1217 @Override 1218 public String getState() { 1219 return state; 1220 } 1221 1222 /** 1223 * @see org.kuali.rice.krad.uif.view.ViewModel#setState(String) 1224 */ 1225 @Override 1226 public void setState(String state) { 1227 this.state = state; 1228 } 1229 1230 /** 1231 * @see org.kuali.rice.krad.uif.view.ViewModel#isAjaxRequest() 1232 */ 1233 @Override 1234 public boolean isAjaxRequest() { 1235 return ajaxRequest; 1236 } 1237 1238 /** 1239 * @see org.kuali.rice.krad.uif.view.ViewModel#setAjaxRequest(boolean) 1240 */ 1241 @Override 1242 public void setAjaxRequest(boolean ajaxRequest) { 1243 this.ajaxRequest = ajaxRequest; 1244 } 1245 1246 /** 1247 * @see org.kuali.rice.krad.uif.view.ViewModel#getAjaxReturnType() 1248 */ 1249 @Override 1250 public String getAjaxReturnType() { 1251 return ajaxReturnType; 1252 } 1253 1254 /** 1255 * @see org.kuali.rice.krad.uif.view.ViewModel#setAjaxReturnType(String) 1256 */ 1257 @Override 1258 public void setAjaxReturnType(String ajaxReturnType) { 1259 this.ajaxReturnType = ajaxReturnType; 1260 } 1261 1262 /** 1263 * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdateComponentRequest() 1264 */ 1265 @Override 1266 public boolean isUpdateComponentRequest() { 1267 return isAjaxRequest() && StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals( 1268 UifConstants.AjaxReturnTypes.UPDATECOMPONENT.getKey()); 1269 } 1270 1271 /** 1272 * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdateDialogRequest() 1273 */ 1274 @Override 1275 public boolean isUpdateDialogRequest() { 1276 return isAjaxRequest() && StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals( 1277 UifConstants.AjaxReturnTypes.UPDATEDIALOG.getKey()); 1278 } 1279 1280 /** 1281 * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdatePageRequest() 1282 */ 1283 @Override 1284 public boolean isUpdatePageRequest() { 1285 return StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals( 1286 UifConstants.AjaxReturnTypes.UPDATEPAGE.getKey()); 1287 } 1288 1289 /** 1290 * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdateNoneRequest() 1291 */ 1292 @Override 1293 public boolean isUpdateNoneRequest() { 1294 return StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals( 1295 UifConstants.AjaxReturnTypes.UPDATENONE.getKey()); 1296 } 1297 1298 /** 1299 * @see org.kuali.rice.krad.uif.view.ViewModel#isJsonRequest() 1300 */ 1301 @Override 1302 public boolean isJsonRequest() { 1303 return StringUtils.isNotBlank(getRequestJsonTemplate()); 1304 } 1305 1306 /** 1307 * @see org.kuali.rice.krad.uif.view.ViewModel#getRequestJsonTemplate() 1308 */ 1309 @Override 1310 public String getRequestJsonTemplate() { 1311 return requestJsonTemplate; 1312 } 1313 1314 /** 1315 * @see org.kuali.rice.krad.uif.view.ViewModel#setRequestJsonTemplate 1316 */ 1317 @Override 1318 public void setRequestJsonTemplate(String requestJsonTemplate) { 1319 this.requestJsonTemplate = requestJsonTemplate; 1320 } 1321 1322 /** 1323 * {@inheritDoc} 1324 */ 1325 @Override 1326 public boolean isCollectionPagingRequest() { 1327 return collectionPagingRequest; 1328 } 1329 1330 /** 1331 * {@inheritDoc} 1332 */ 1333 @Override 1334 public void setCollectionPagingRequest(boolean collectionPagingRequest) { 1335 this.collectionPagingRequest = collectionPagingRequest; 1336 } 1337 1338 /** 1339 * For cases where the request was triggered from within a dialog, we want to show that dialog, 1340 * identified by this id, again. 1341 */ 1342 public String getShowDialogId() { 1343 return showDialogId; 1344 } 1345 1346 /** 1347 * @see UifFormBase#getShowDialogId() 1348 */ 1349 public void setShowDialogId(String dialogId) { 1350 this.showDialogId = dialogId; 1351 } 1352 1353 /** 1354 * Used by the dialog framework to set the dialog id for a return dialog call (when the server has 1355 * triggered a dialog). 1356 * 1357 * <p>Note this is a request only property. On a return call the value for this gets pulled and used to 1358 * create an entry in {@link UifFormBase#getDialogResponses()}</p> 1359 * 1360 * @return String id for the dialog being returned from 1361 */ 1362 public String getReturnDialogId() { 1363 return returnDialogId; 1364 } 1365 1366 /** 1367 * @see UifFormBase#getReturnDialogId() 1368 */ 1369 public void setReturnDialogId(String returnDialogId) { 1370 this.returnDialogId = returnDialogId; 1371 } 1372 1373 /** 1374 * Used by the dialog framework to set the dialog response for a return dialog call (when the server has 1375 * triggered a dialog). 1376 * 1377 * <p>Note this is a request only property. On a return call the value for this gets pulled and used to 1378 * create an entry in {@link UifFormBase#getDialogResponses()}</p> 1379 * 1380 * @return String response for the dialog being returned from 1381 */ 1382 public String getReturnDialogResponse() { 1383 return returnDialogResponse; 1384 } 1385 1386 /** 1387 * @see UifFormBase#getReturnDialogResponse() 1388 */ 1389 public void setReturnDialogResponse(String returnDialogResponse) { 1390 this.returnDialogResponse = returnDialogResponse; 1391 } 1392 1393 /** 1394 * {@inheritDoc} 1395 */ 1396 @Override 1397 public Map<String, String> getDialogExplanations() { 1398 return dialogExplanations; 1399 } 1400 1401 /** 1402 * {@inheritDoc} 1403 */ 1404 @Override 1405 public void setDialogExplanations(Map<String, String> dialogExplanations) { 1406 this.dialogExplanations = dialogExplanations; 1407 } 1408 1409 /** 1410 * {@inheritDoc} 1411 */ 1412 @Override 1413 public Map<String, DialogResponse> getDialogResponses() { 1414 return dialogResponses; 1415 } 1416 1417 /** 1418 * {@inheritDoc} 1419 */ 1420 @Override 1421 public DialogResponse getDialogResponse(String dialogId) { 1422 if ((dialogResponses != null) && dialogResponses.containsKey(dialogId)) { 1423 return dialogResponses.get(dialogId); 1424 } 1425 1426 return null; 1427 } 1428 1429 /** 1430 * {@inheritDoc} 1431 */ 1432 @Override 1433 public void setDialogResponses(Map<String, DialogResponse> dialogResponses) { 1434 this.dialogResponses = dialogResponses; 1435 } 1436 1437 /** 1438 * @see org.kuali.rice.krad.uif.view.ViewModel#getExtensionData() 1439 */ 1440 @Override 1441 public Map<String, Object> getExtensionData() { 1442 return extensionData; 1443 } 1444 1445 /** 1446 * {@inheritDoc} 1447 */ 1448 @Override 1449 public void setExtensionData(Map<String, Object> extensionData) { 1450 this.extensionData = extensionData; 1451 } 1452 1453 /** 1454 * Http servlet request instance for the current request being processed. 1455 * 1456 * @return HttpServletRequest instance 1457 */ 1458 public HttpServletRequest getRequest() { 1459 return request; 1460 } 1461 1462 /** 1463 * @see UifFormBase#getRequest() 1464 */ 1465 public void setRequest(HttpServletRequest request) { 1466 this.request = request; 1467 } 1468 1469 /** 1470 * The {@code List} that contains all newly added items for the collections on the model 1471 * 1472 * <p> 1473 * This list contains the new items for all the collections on the model. 1474 * </p> 1475 * 1476 * @return List of the newly added item lists 1477 */ 1478 public List getAddedCollectionItems() { 1479 return addedCollectionItems; 1480 } 1481 1482 /** 1483 * Setter for the newly added item list 1484 */ 1485 public void setAddedCollectionItems(List addedCollectionItems) { 1486 this.addedCollectionItems = addedCollectionItems; 1487 } 1488 1489 /** 1490 * Indicates whether an collection item has been newly added 1491 * 1492 * <p> 1493 * Tests collection items against the list of newly added items on the model. This list gets cleared when the view 1494 * is submitted and the items are persisted. 1495 * </p> 1496 * 1497 * @param item - the item to test against list of newly added items 1498 * @return boolean true if the item has been newly added 1499 */ 1500 public boolean isAddedCollectionItem(Object item) { 1501 return addedCollectionItems.contains(item); 1502 } 1503 1504 /** 1505 * The data object to bind to for a dialog 1506 * 1507 * <p>The data object serves as a placeholder for temporary properties that might be used within a dialog. The 1508 * purpose of placeholder is to provide a separation between the dialog object and the underlying object for use 1509 * in cases like object manipulation.</p> 1510 */ 1511 public Object getDialogDataObject() { 1512 return dialogDataObject; 1513 } 1514 1515 /** 1516 * @see UifFormBase#getDialogDataObject() 1517 */ 1518 public void setDialogDataObject(Object dataObject) { 1519 this.dialogDataObject = dataObject; 1520 } 1521 1522 @Override 1523 public String toString() { 1524 StringBuilder builder = new StringBuilder(); 1525 builder.append(getClass().getSimpleName()).append(" [viewId=").append(this.viewId).append(", viewName=").append( 1526 this.viewName).append(", viewTypeName=").append(this.viewTypeName).append(", pageId=").append( 1527 this.pageId).append(", methodToCall=").append(this.methodToCall).append(", formKey=").append( 1528 this.formKey).append(", requestedFormKey=").append(this.requestedFormKey).append("]"); 1529 return builder.toString(); 1530 } 1531 1532 public String getCsrfToken() { 1533 return csrfToken; 1534 } 1535 1536 public void setCsrfToken(String csrfToken) { 1537 this.csrfToken = csrfToken; 1538 } 1539 1540}