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