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.service.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.krad.uif.UifConstants; 020import org.kuali.rice.krad.uif.UifParameters; 021import org.kuali.rice.krad.uif.component.MethodInvokerConfig; 022import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; 023import org.kuali.rice.krad.util.GlobalVariables; 024import org.kuali.rice.krad.util.KRADConstants; 025import org.kuali.rice.krad.web.form.UifFormBase; 026import org.kuali.rice.krad.web.service.ModelAndViewService; 027import org.kuali.rice.krad.web.service.RefreshControllerService; 028import org.springframework.web.servlet.ModelAndView; 029import org.springframework.web.servlet.support.RequestContextUtils; 030 031import javax.servlet.http.HttpServletRequest; 032import java.util.Map; 033 034/** 035 * Default implementation of the refresh controller service. 036 * 037 * @author Kuali Rice Team (rice.collab@kuali.org) 038 */ 039public class RefreshControllerServiceImpl implements RefreshControllerService { 040 041 private ModelAndViewService modelAndViewService; 042 043 /** 044 * Handles the refresh call by checking the request parameters and delegating out to helper methods. 045 * 046 * {@inheritDoc} 047 */ 048 @Override 049 public ModelAndView refresh(UifFormBase form) { 050 HttpServletRequest request = form.getRequest(); 051 052 if (request.getParameterMap().containsKey(UifParameters.MESSAGE_TO_DISPLAY)) { 053 String messageToDisplay = request.getParameter(UifParameters.MESSAGE_TO_DISPLAY); 054 055 if (StringUtils.isNotBlank(messageToDisplay)) { 056 GlobalVariables.getMessageMap().putErrorForSectionId(KRADConstants.GLOBAL_ERRORS, messageToDisplay); 057 } 058 } 059 060 if (request.getParameterMap().containsKey(UifParameters.REFRESH_STATUS)) { 061 String refreshStatus = request.getParameter(UifParameters.REFRESH_STATUS); 062 063 // if the return URL reported an error, do not continue with the refresh call 064 if (UifConstants.RefreshStatus.ERROR.equals(refreshStatus)) { 065 return getModelAndViewService().getModelAndView(form); 066 } 067 } 068 069 String refreshCallerType = ""; 070 if (request.getParameterMap().containsKey(KRADConstants.REFRESH_CALLER_TYPE)) { 071 refreshCallerType = request.getParameter(KRADConstants.REFRESH_CALLER_TYPE); 072 } 073 074 if (StringUtils.equals(refreshCallerType, UifConstants.RefreshCallerTypes.MULTI_VALUE_LOOKUP)) { 075 processMultiValueReturn(form, request); 076 } 077 078 if (request.getParameterMap().containsKey(KRADConstants.REFERENCES_TO_REFRESH)) { 079 final String referencesToRefresh = request.getParameter(KRADConstants.REFERENCES_TO_REFRESH); 080 081 Runnable runnable = new Runnable() { 082 @Override 083 public void run() { 084 ViewLifecycle.getHelper().refreshReferences(referencesToRefresh); 085 } 086 }; 087 088 ViewLifecycle.encapsulateLifecycle(form.getView(), form, form.getViewPostMetadata(), null, request, 089 runnable); 090 } 091 092 if (request.getParameterMap().containsKey(UifParameters.QUICKFINDER_ID)) { 093 String quickfinderId = request.getParameter(UifParameters.QUICKFINDER_ID); 094 095 setFocusJumpFromQuickfinder(form, quickfinderId); 096 097 invokeQuickfinderCallback(form, request, quickfinderId); 098 } 099 100 return getModelAndViewService().getModelAndView(form); 101 } 102 103 /** 104 * Handles the return from a multi-value lookup, processing any select line values and invoking the 105 * configured view helper service to create the lines for those values in the model collection. 106 * 107 * <p>There are two supported strategies for returning the selected lines. One, if the lookup view 108 * and the caller are within the same application container, Springs input flash map is used. If however, 109 * the lookup view is outside the caller, then just a standard request parameter is used.</p> 110 * 111 * @param form form instance containing the model data 112 * @param request http request object being handled 113 */ 114 protected void processMultiValueReturn(final UifFormBase form, HttpServletRequest request) { 115 final String lookupCollectionId = request.getParameter(UifParameters.LOOKUP_COLLECTION_ID); 116 117 final String lookupCollectionName = request.getParameter(UifParameters.LOOKUP_COLLECTION_NAME); 118 if (StringUtils.isBlank(lookupCollectionName)) { 119 throw new RuntimeException("Lookup collection name is required for processing multi-value lookup results"); 120 } 121 122 final String multiValueReturnFields = request.getParameter(UifParameters.MULIT_VALUE_RETURN_FILEDS); 123 String selectedLineValuesParam = request.getParameter(UifParameters.SELECTED_LINE_VALUES); 124 125 String flashMapSelectedLineValues = ""; 126 if (RequestContextUtils.getInputFlashMap(request) != null) { 127 flashMapSelectedLineValues = (String) RequestContextUtils.getInputFlashMap(request).get( 128 UifParameters.SELECTED_LINE_VALUES); 129 } 130 131 if (!StringUtils.isBlank(flashMapSelectedLineValues)) { 132 selectedLineValuesParam = flashMapSelectedLineValues; 133 } 134 135 final String selectedLineValues = selectedLineValuesParam; 136 137 Runnable runnable = new Runnable() { 138 @Override 139 public void run() { 140 // invoked view helper to populate the collection from lookup results 141 ViewLifecycle.getHelper().processMultipleValueLookupResults(form, lookupCollectionId, 142 lookupCollectionName, multiValueReturnFields, selectedLineValues); 143 } 144 }; 145 146 ViewLifecycle.encapsulateLifecycle(form.getView(), form, form.getViewPostMetadata(), null, request, runnable); 147 } 148 149 /** 150 * Retrieves the configured focus id and jump id for the quickfinder from the post metadata, and sets 151 * those values onto the form for the view rendering. 152 * 153 * @param form form instance containing the model data 154 * @param quickfinderId id for the quickfinder component that triggered the lookup we are 155 * returning from 156 */ 157 protected void setFocusJumpFromQuickfinder(UifFormBase form, String quickfinderId) { 158 String focusId = (String) form.getViewPostMetadata().getComponentPostData(quickfinderId, 159 UifConstants.PostMetadata.QUICKFINDER_FOCUS_ID); 160 if (StringUtils.isNotBlank(focusId)) { 161 form.setFocusId(focusId); 162 } 163 164 String jumpToId = (String) form.getViewPostMetadata().getComponentPostData(quickfinderId, 165 UifConstants.PostMetadata.QUICKFINDER_JUMP_TO_ID); 166 if (StringUtils.isNotBlank(jumpToId)) { 167 form.setJumpToId(jumpToId); 168 } 169 } 170 171 /** 172 * Retrieves post metadata for the quickfinder component with the given id and if a callback method 173 * has been configured, invokes that callback method. 174 * 175 * @param form form instance containing the model data 176 * @param request http request object being handled 177 * @param quickfinderId id for the quickfinder component that triggered the lookup we are 178 * returning from 179 */ 180 protected void invokeQuickfinderCallback(UifFormBase form, final HttpServletRequest request, 181 final String quickfinderId) { 182 String callbackMethodToCall = (String) form.getViewPostMetadata().getComponentPostData(quickfinderId, 183 UifConstants.PostMetadata.QUICKFINDER_CALLBACK_METHOD_TO_CALL); 184 MethodInvokerConfig callbackMethod = (MethodInvokerConfig) form.getViewPostMetadata(). 185 getComponentPostData(quickfinderId, UifConstants.PostMetadata.QUICKFINDER_CALLBACK_METHOD); 186 187 if (StringUtils.isBlank(callbackMethodToCall) && (callbackMethod == null)) { 188 return; 189 } 190 191 if (callbackMethod == null) { 192 callbackMethod = new MethodInvokerConfig(); 193 } 194 195 // get additional parameters to be passed to the callback method 196 Map<String, String> callbackContext = (Map<String, String>) form.getViewPostMetadata(). 197 getComponentPostData(quickfinderId, UifConstants.PostMetadata.QUICKFINDER_CALLBACK_CONTEXT); 198 199 // if target class or object not set, use view helper service 200 if ((callbackMethod.getTargetClass() == null) && (callbackMethod.getTargetObject() == null)) { 201 callbackMethod.setTargetObject(form.getViewHelperService()); 202 } 203 204 callbackMethod.setTargetMethod(callbackMethodToCall); 205 206 Object[] arguments = new Object[3]; 207 arguments[0] = form; 208 arguments[1] = quickfinderId; 209 arguments[2] = callbackContext; 210 callbackMethod.setArguments(arguments); 211 212 final MethodInvokerConfig methodToInvoke = callbackMethod; 213 214 Runnable runnable = new Runnable() { 215 @Override 216 public void run() { 217 try { 218 methodToInvoke.prepare(); 219 methodToInvoke.invoke(); 220 } catch (Exception e) { 221 throw new RuntimeException("Error invoking callback method for quickfinder: " + quickfinderId, e); 222 } 223 } 224 }; 225 226 ViewLifecycle.encapsulateLifecycle(form.getView(), form, form.getViewPostMetadata(), null, request, runnable); 227 } 228 229 /** 230 * Instance of model and view service to use within the collection service. 231 * 232 * @return ModelAndViewService instance 233 */ 234 protected ModelAndViewService getModelAndViewService() { 235 return modelAndViewService; 236 } 237 238 /** 239 * @see RefreshControllerServiceImpl#getModelAndViewService() 240 */ 241 public void setModelAndViewService(ModelAndViewService modelAndViewService) { 242 this.modelAndViewService = modelAndViewService; 243 } 244}