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.lookup.LookupUtils; 020import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 021import org.kuali.rice.krad.service.ModuleService; 022import org.kuali.rice.krad.uif.UifConstants; 023import org.kuali.rice.krad.uif.UifParameters; 024import org.kuali.rice.krad.uif.UifPropertyPaths; 025import org.kuali.rice.krad.uif.field.AttributeQueryResult; 026import org.kuali.rice.krad.uif.service.AttributeQueryService; 027import org.kuali.rice.krad.util.KRADUtils; 028import org.kuali.rice.krad.web.form.UifFormBase; 029import org.kuali.rice.krad.web.service.ModelAndViewService; 030import org.kuali.rice.krad.web.service.QueryControllerService; 031import org.springframework.web.servlet.ModelAndView; 032 033import javax.servlet.http.HttpServletRequest; 034import java.util.HashMap; 035import java.util.Map; 036import java.util.Properties; 037 038/** 039 * Default implementation of the query controller service. 040 * 041 * @author Kuali Rice Team (rice.collab@kuali.org) 042 */ 043public class QueryControllerServiceImpl implements QueryControllerService { 044 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger( 045 QueryControllerServiceImpl.class); 046 047 private ModelAndViewService modelAndViewService; 048 private AttributeQueryService attributeQueryService; 049 050 /** 051 * Inspects the given request and action parameters on the form to build a URL to the requested 052 * lookup view. 053 * 054 * <p>First the data object class for the lookup view is found from the action parameters. A call 055 * is then made to check if there is a module service that handles that class, and if so the URL from the 056 * module service is used. If not, the base url is and other lookup URL parameters are created from the 057 * action parameters and form.</p> 058 * 059 * {@inheritDoc} 060 * 061 * @see QueryControllerServiceImpl#getLookupDataObjectClass(java.util.Properties) 062 * @see QueryControllerServiceImpl#getLookupUrlFromModuleService(java.lang.Class<?>, java.util.Properties) 063 * @see QueryControllerServiceImpl#buildLookupUrlParameters(org.kuali.rice.krad.web.form.UifFormBase, 064 * javax.servlet.http.HttpServletRequest, java.lang.Class<?>, java.util.Properties) 065 */ 066 @Override 067 public ModelAndView performLookup(UifFormBase form) { 068 Properties urlParameters = form.getActionParametersAsProperties(); 069 070 Class<?> lookupDataObjectClass = getLookupDataObjectClass(urlParameters); 071 if (lookupDataObjectClass == null) { 072 throw new RuntimeException("Lookup data object class not found for lookup call"); 073 } 074 075 // Force skip of dirty check 076 urlParameters.put(UifParameters.PERFORM_DIRTY_CHECK, "false"); 077 078 // first give module service the opportunity to build the lookup URL 079 String baseLookupUrl = getLookupUrlFromModuleService(lookupDataObjectClass, urlParameters); 080 if (StringUtils.isNotBlank(baseLookupUrl)) { 081 // url fully built by module service 082 urlParameters = new Properties(); 083 } else { 084 baseLookupUrl = urlParameters.getProperty(UifParameters.BASE_LOOKUP_URL); 085 urlParameters.remove(UifParameters.BASE_LOOKUP_URL); 086 087 buildLookupUrlParameters(form, form.getRequest(), lookupDataObjectClass, urlParameters); 088 } 089 090 return getModelAndViewService().performRedirect(form, baseLookupUrl, urlParameters); 091 } 092 093 /** 094 * Returns the Class instance for the data object whose lookup view was requested. 095 * 096 * @param urlParameters properties containing the lookup configuration 097 * @return Class<?> lookup data object class 098 * @throws java.lang.RuntimeException if class cannot be created from data object class name 099 */ 100 protected Class<?> getLookupDataObjectClass(Properties urlParameters) { 101 Class<?> lookupDataObjectClass; 102 103 String lookupObjectClassName = urlParameters.getProperty(UifParameters.DATA_OBJECT_CLASS_NAME); 104 try { 105 lookupDataObjectClass = Class.forName(lookupObjectClassName); 106 } catch (ClassNotFoundException e) { 107 LOG.error("Unable to get class for name: " + lookupObjectClassName); 108 throw new RuntimeException("Unable to get class for name: " + lookupObjectClassName, e); 109 } 110 111 return lookupDataObjectClass; 112 } 113 114 /** 115 * Attempts to find a module service that claims responsibility for the given data object class and if 116 * found invokes that module service to build the lookup url. 117 * 118 * @param lookupDataObjectClass data object class to find responsible module service for 119 * @param urlParameters properties containing the lookup configuration 120 * @return String lookup URL returned from module service, or null if not module service was found 121 */ 122 protected String getLookupUrlFromModuleService(Class<?> lookupDataObjectClass, Properties urlParameters) { 123 String lookupUrl = null; 124 125 ModuleService responsibleModuleService = 126 KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(lookupDataObjectClass); 127 if (responsibleModuleService != null && responsibleModuleService.isExternalizable(lookupDataObjectClass)) { 128 lookupUrl = responsibleModuleService.getExternalizableDataObjectLookupUrl(lookupDataObjectClass, 129 urlParameters); 130 } 131 132 return lookupUrl; 133 } 134 135 /** 136 * Modifies the given properties object representing the lookup URL parameters to add additional parameters 137 * based on the form and action parameters. 138 * 139 * @param form form instance containing the model data 140 * @param request http request object being handled 141 * @param lookupDataObjectClass data object class the lookup URL is being built for 142 * @param urlParameters properties instance holding the lookup URL parameters 143 */ 144 protected void buildLookupUrlParameters(UifFormBase form, HttpServletRequest request, 145 Class<?> lookupDataObjectClass, Properties urlParameters) { 146 urlParameters.setProperty(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.START); 147 148 String autoSearchString = urlParameters.getProperty(UifParameters.AUTO_SEARCH); 149 if (Boolean.parseBoolean(autoSearchString)) { 150 urlParameters.setProperty(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.SEARCH); 151 } 152 153 buildLookupCriteriaParameters(form, request, lookupDataObjectClass, urlParameters); 154 155 urlParameters.setProperty(UifParameters.RETURN_LOCATION, form.getFormPostUrl()); 156 urlParameters.setProperty(UifParameters.RETURN_FORM_KEY, form.getFormKey()); 157 } 158 159 /** 160 * If lookup criteria parameters were configured, pulls the values for those parameters from the form and 161 * passes as values to pre-populate the lookup view criteria. 162 * 163 * @param form form instance containing the model data 164 * @param request http request object being handled 165 * @param lookupDataObjectClass data object class the lookup URL is being built for 166 * @param urlParameters properties instance holding the lookup URL parameters 167 */ 168 protected void buildLookupCriteriaParameters(UifFormBase form, HttpServletRequest request, 169 Class<?> lookupDataObjectClass, Properties urlParameters) { 170 String lookupParameterString = urlParameters.getProperty(UifParameters.LOOKUP_PARAMETERS); 171 if (StringUtils.isBlank(lookupParameterString)) { 172 return; 173 } 174 175 Map<String, String> lookupParameterFields = KRADUtils.getMapFromParameterString(lookupParameterString); 176 for (Map.Entry<String, String> lookupParameter : lookupParameterFields.entrySet()) { 177 String lookupParameterValue = LookupUtils.retrieveLookupParameterValue(form, request, lookupDataObjectClass, 178 lookupParameter.getValue(), lookupParameter.getKey()); 179 180 if (StringUtils.isNotBlank(lookupParameterValue)) { 181 urlParameters.setProperty(UifPropertyPaths.LOOKUP_CRITERIA + "['" + lookupParameter.getValue() + "']", 182 lookupParameterValue); 183 } 184 } 185 186 urlParameters.remove(UifParameters.LOOKUP_PARAMETERS); 187 } 188 189 /** 190 * Retrieves suggest query parameters from the request and invokes 191 * {@link org.kuali.rice.krad.uif.service.AttributeQueryService#performFieldSuggestQuery} to carry out the 192 * suggest query. 193 * 194 * {@inheritDoc} 195 */ 196 @Override 197 public AttributeQueryResult performFieldSuggest(UifFormBase form) { 198 HttpServletRequest request = form.getRequest(); 199 200 // retrieve query fields from request 201 Map<String, String> queryParameters = new HashMap<String, String>(); 202 for (Object parameterName : request.getParameterMap().keySet()) { 203 if (parameterName.toString().startsWith(UifParameters.QUERY_PARAMETERS)) { 204 String fieldName = StringUtils.substringBetween(parameterName.toString(), 205 UifParameters.QUERY_PARAMETERS + "[\"", "\"]"); 206 String fieldValue = request.getParameter(parameterName.toString()); 207 queryParameters.put(fieldName, fieldValue); 208 } 209 } 210 211 // retrieve id for field to perform query for 212 String queryFieldId = request.getParameter(UifParameters.QUERY_FIELD_ID); 213 if (StringUtils.isBlank(queryFieldId)) { 214 throw new RuntimeException("Unable to find id for field to perform query on under request parameter name: " 215 + UifParameters.QUERY_FIELD_ID); 216 } 217 218 // get the field term to match 219 String queryTerm = request.getParameter(UifParameters.QUERY_TERM); 220 if (StringUtils.isBlank(queryTerm)) { 221 throw new RuntimeException( 222 "Unable to find id for query term value for attribute query on under request parameter name: " 223 + UifParameters.QUERY_TERM); 224 } 225 226 return getAttributeQueryService().performFieldSuggestQuery(form.getViewPostMetadata(), queryFieldId, queryTerm, 227 queryParameters); 228 } 229 230 /** 231 * Retrieves field query parameters from the request and invokes 232 * {@link org.kuali.rice.krad.uif.service.AttributeQueryService#performFieldQuery} to carry out the 233 * field query. 234 * 235 * {@inheritDoc} 236 */ 237 @Override 238 public AttributeQueryResult performFieldQuery(UifFormBase form) { 239 HttpServletRequest request = form.getRequest(); 240 241 // retrieve query fields from request 242 Map<String, String> queryParameters = new HashMap<String, String>(); 243 for (Object parameterName : request.getParameterMap().keySet()) { 244 if (parameterName.toString().startsWith(UifParameters.QUERY_PARAMETERS)) { 245 String fieldName = StringUtils.substringBetween(parameterName.toString(), 246 UifParameters.QUERY_PARAMETERS + "[\"", "\"]"); 247 String fieldValue = request.getParameter(parameterName.toString()); 248 queryParameters.put(fieldName, fieldValue); 249 } 250 } 251 252 // retrieve id for field to perform query for 253 String queryFieldId = request.getParameter(UifParameters.QUERY_FIELD_ID); 254 if (StringUtils.isBlank(queryFieldId)) { 255 throw new RuntimeException("Unable to find id for field to perform query on under request parameter name: " 256 + UifParameters.QUERY_FIELD_ID); 257 } 258 259 return getAttributeQueryService().performFieldQuery(form.getViewPostMetadata(), queryFieldId, queryParameters); 260 } 261 262 /** 263 * Instance of model and view service to use within the collection service. 264 * 265 * @return ModelAndViewService instance 266 */ 267 protected ModelAndViewService getModelAndViewService() { 268 return modelAndViewService; 269 } 270 271 /** 272 * @see CollectionControllerServiceImpl#getModelAndViewService() 273 */ 274 public void setModelAndViewService(ModelAndViewService modelAndViewService) { 275 this.modelAndViewService = modelAndViewService; 276 } 277 278 public AttributeQueryService getAttributeQueryService() { 279 return attributeQueryService; 280 } 281 282 public void setAttributeQueryService(AttributeQueryService attributeQueryService) { 283 this.attributeQueryService = attributeQueryService; 284 } 285}