001 /** 002 * Copyright 2005-2014 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 */ 016 package org.kuali.rice.krad.uif.field; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.kuali.rice.krad.uif.component.BindingInfo; 020 import org.kuali.rice.krad.uif.component.MethodInvokerConfig; 021 022 import java.io.Serializable; 023 import java.util.ArrayList; 024 import java.util.HashMap; 025 import java.util.List; 026 import java.util.Map; 027 028 /** 029 * Holds configuration for executing a dynamic query on an <code>InputField</code> to 030 * pull data for updating the UI 031 * 032 * <p> 033 * There are two types of query types that can be configured and executed. The first is provided 034 * completely by the framework using the <code>LookupService</code> and will perform a query 035 * against the configured dataObjectClassName using the query parameters and return field mapping. 036 * The second type will invoke a method that will perform the query. This can be configured using the 037 * queryMethodToCall (if the method is on the view helper service), or using the queryMethodInvoker if 038 * the method is on another class or object. 039 * </p> 040 * 041 * @author Kuali Rice Team (rice.collab@kuali.org) 042 */ 043 public class AttributeQuery implements Serializable { 044 private static final long serialVersionUID = -4569905665441735255L; 045 046 private String dataObjectClassName; 047 048 private boolean renderNotFoundMessage; 049 private String returnMessageText; 050 private String returnMessageStyleClasses; 051 052 private Map<String, String> queryFieldMapping; 053 private Map<String, String> returnFieldMapping; 054 private Map<String, String> additionalCriteria; 055 056 private List<String> sortPropertyNames; 057 058 private String queryMethodToCall; 059 private List<String> queryMethodArgumentFieldList; 060 private MethodInvokerConfig queryMethodInvokerConfig; 061 062 public AttributeQuery() { 063 renderNotFoundMessage = true; 064 queryFieldMapping = new HashMap<String, String>(); 065 returnFieldMapping = new HashMap<String, String>(); 066 additionalCriteria = new HashMap<String, String>(); 067 sortPropertyNames = new ArrayList<String>(); 068 queryMethodArgumentFieldList = new ArrayList<String>(); 069 } 070 071 /** 072 * Adjusts the path on the query field mapping from property to match the binding 073 * path prefix of the given <code>BindingInfo</code> 074 * 075 * @param bindingInfo - binding info instance to copy binding path prefix from 076 */ 077 public void updateQueryFieldMapping(BindingInfo bindingInfo) { 078 Map<String, String> adjustedQueryFieldMapping = new HashMap<String, String>(); 079 for (String fromFieldPath : getQueryFieldMapping().keySet()) { 080 String toField = getQueryFieldMapping().get(fromFieldPath); 081 String adjustedFromFieldPath = bindingInfo.getPropertyAdjustedBindingPath(fromFieldPath); 082 083 adjustedQueryFieldMapping.put(adjustedFromFieldPath, toField); 084 } 085 086 this.queryFieldMapping = adjustedQueryFieldMapping; 087 } 088 089 /** 090 * Adjusts the path on the return field mapping to property to match the binding 091 * path prefix of the given <code>BindingInfo</code> 092 * 093 * @param bindingInfo - binding info instance to copy binding path prefix from 094 */ 095 public void updateReturnFieldMapping(BindingInfo bindingInfo) { 096 Map<String, String> adjustedReturnFieldMapping = new HashMap<String, String>(); 097 for (String fromFieldPath : getReturnFieldMapping().keySet()) { 098 String toFieldPath = getReturnFieldMapping().get(fromFieldPath); 099 String adjustedToFieldPath = bindingInfo.getPropertyAdjustedBindingPath(toFieldPath); 100 101 adjustedReturnFieldMapping.put(fromFieldPath, adjustedToFieldPath); 102 } 103 104 this.returnFieldMapping = adjustedReturnFieldMapping; 105 } 106 107 /** 108 * Adjusts the path on the query method arguments field list to match the binding 109 * path prefix of the given <code>BindingInfo</code> 110 * 111 * @param bindingInfo - binding info instance to copy binding path prefix from 112 */ 113 public void updateQueryMethodArgumentFieldList(BindingInfo bindingInfo) { 114 List<String> adjustedArgumentFieldList = new ArrayList<String>(); 115 for (String argumentFieldPath : getQueryMethodArgumentFieldList()) { 116 String adjustedFieldPath = bindingInfo.getPropertyAdjustedBindingPath(argumentFieldPath); 117 adjustedArgumentFieldList.add(adjustedFieldPath); 118 } 119 120 this.queryMethodArgumentFieldList = adjustedArgumentFieldList; 121 } 122 123 /** 124 * Builds String for passing the queryFieldMapping Map as a Javascript object 125 * parameter 126 * 127 * @return String js parameter string 128 */ 129 public String getQueryFieldMappingJsString() { 130 String queryFieldMappingJs = "{"; 131 132 for (String queryField : queryFieldMapping.keySet()) { 133 if (!StringUtils.equals(queryFieldMappingJs, "{")) { 134 queryFieldMappingJs += ","; 135 } 136 137 queryFieldMappingJs += "\"" + queryField + "\":\"" + queryFieldMapping.get(queryField) + "\""; 138 } 139 140 queryFieldMappingJs += "}"; 141 142 return queryFieldMappingJs; 143 } 144 145 /** 146 * Builds String for passing the returnFieldMapping Map as a Javascript object 147 * parameter 148 * 149 * @return String js parameter string 150 */ 151 public String getReturnFieldMappingJsString() { 152 String returnFieldMappingJs = "{"; 153 154 for (String fromField : returnFieldMapping.keySet()) { 155 if (!StringUtils.equals(returnFieldMappingJs, "{")) { 156 returnFieldMappingJs += ","; 157 } 158 159 returnFieldMappingJs += "\"" + returnFieldMapping.get(fromField) + "\":\"" + fromField + "\""; 160 } 161 162 returnFieldMappingJs += "}"; 163 164 return returnFieldMappingJs; 165 } 166 167 /** 168 * Builds String for passing the queryMethodArgumentFieldList as a Javascript array 169 * 170 * @return String js parameter string 171 */ 172 public String getQueryMethodArgumentFieldsJsString() { 173 String queryMethodArgsJs = "["; 174 175 for (String methodArg : queryMethodArgumentFieldList) { 176 if (!StringUtils.equals(queryMethodArgsJs, "{")) { 177 queryMethodArgsJs += ","; 178 } 179 queryMethodArgsJs += "\"" + methodArg + "\""; 180 } 181 182 queryMethodArgsJs += "]"; 183 184 return queryMethodArgsJs; 185 } 186 187 /** 188 * Indicates whether this attribute query is configured to invoke a custom 189 * method as opposed to running the general object query. If either the query method 190 * to call is given, or the query method invoker is not null it is assumed the 191 * intention is to call a custom method 192 * 193 * @return boolean true if a custom method is configured, false if not 194 */ 195 public boolean hasConfiguredMethod() { 196 boolean configuredMethod = false; 197 198 if (StringUtils.isNotBlank(getQueryMethodToCall())) { 199 configuredMethod = true; 200 } else if (getQueryMethodInvokerConfig() != null) { 201 configuredMethod = true; 202 } 203 204 return configuredMethod; 205 } 206 207 /** 208 * Class name for the data object the query should be performed against 209 * 210 * @return String data object class name 211 */ 212 public String getDataObjectClassName() { 213 return dataObjectClassName; 214 } 215 216 /** 217 * Setter for the query data object class name 218 * 219 * @param dataObjectClassName 220 */ 221 public void setDataObjectClassName(String dataObjectClassName) { 222 this.dataObjectClassName = dataObjectClassName; 223 } 224 225 /** 226 * Configures the query parameters by mapping fields in the view 227 * to properties on the data object class for the query 228 * 229 * <p> 230 * Each map entry configures one parameter for the query, where 231 * the map key is the field name to pull the value from, and the 232 * map value is the property name on the object the parameter should 233 * populate. 234 * </p> 235 * 236 * @return Map<String, String> mapping of query parameters 237 */ 238 public Map<String, String> getQueryFieldMapping() { 239 return queryFieldMapping; 240 } 241 242 /** 243 * Setter for the query parameter mapping 244 * 245 * @param queryFieldMapping 246 */ 247 public void setQueryFieldMapping(Map<String, String> queryFieldMapping) { 248 this.queryFieldMapping = queryFieldMapping; 249 } 250 251 /** 252 * Maps properties from the result object of the query to 253 * fields in the view 254 * 255 * <p> 256 * Each map entry configures one return mapping, where the map 257 * key is the field name for the field to populate, and the map 258 * values is the name of the property on the result object to 259 * pull the value from 260 * </p> 261 * 262 * @return Map<String, String> return field mapping 263 */ 264 public Map<String, String> getReturnFieldMapping() { 265 return returnFieldMapping; 266 } 267 268 /** 269 * Setter for the return field mapping 270 * 271 * @param returnFieldMapping 272 */ 273 public void setReturnFieldMapping(Map<String, String> returnFieldMapping) { 274 this.returnFieldMapping = returnFieldMapping; 275 } 276 277 /** 278 * Fixed criteria that will be appended to the dynamic criteria generated 279 * for the query. Map key gives name of the property the criteria should 280 * apply to, and the map value is the value (literal) for the criteria. Standard 281 * lookup wildcards are allowed 282 * 283 * @return Map<String, String> field name/value pairs for query criteria 284 */ 285 public Map<String, String> getAdditionalCriteria() { 286 return additionalCriteria; 287 } 288 289 /** 290 * Setter for the query's additional criteria map 291 * 292 * @param additionalCriteria 293 */ 294 public void setAdditionalCriteria(Map<String, String> additionalCriteria) { 295 this.additionalCriteria = additionalCriteria; 296 } 297 298 /** 299 * List of property names to sort the query results by. The sort 300 * will be performed on each property in the order they are contained 301 * within the list. Each property must be a valid property of the 302 * return query object (the data object in case of the general query) 303 * 304 * @return List<String> property names 305 */ 306 public List<String> getSortPropertyNames() { 307 return sortPropertyNames; 308 } 309 310 /** 311 * Setter for the list of property names to sort results by 312 * 313 * @param sortPropertyNames 314 */ 315 public void setSortPropertyNames(List<String> sortPropertyNames) { 316 this.sortPropertyNames = sortPropertyNames; 317 } 318 319 /** 320 * Indicates whether a message should be added to the query result 321 * object and displayed when the query return object is null 322 * 323 * @return boolean true if not found message should be added, false otherwise 324 */ 325 public boolean isRenderNotFoundMessage() { 326 return renderNotFoundMessage; 327 } 328 329 /** 330 * Setter for the render not found message indicator 331 * 332 * @param renderNotFoundMessage 333 */ 334 public void setRenderNotFoundMessage(boolean renderNotFoundMessage) { 335 this.renderNotFoundMessage = renderNotFoundMessage; 336 } 337 338 /** 339 * Message text to display along with the query result 340 * 341 * @return String literal message text 342 */ 343 public String getReturnMessageText() { 344 return returnMessageText; 345 } 346 347 /** 348 * Setter for the return message text 349 * 350 * @param returnMessageText 351 */ 352 public void setReturnMessageText(String returnMessageText) { 353 this.returnMessageText = returnMessageText; 354 } 355 356 /** 357 * CSS Style classes that should be applied to the return message. 358 * Multiple style classes should be delimited by a space 359 * 360 * @return String style classes 361 */ 362 public String getReturnMessageStyleClasses() { 363 return returnMessageStyleClasses; 364 } 365 366 /** 367 * Setter for the return messages style classes 368 * 369 * @param returnMessageStyleClasses 370 */ 371 public void setReturnMessageStyleClasses(String returnMessageStyleClasses) { 372 this.returnMessageStyleClasses = returnMessageStyleClasses; 373 } 374 375 /** 376 * Configures the name of the method that should be invoked to perform 377 * the query 378 * 379 * <p> 380 * Should contain only the method name (no parameters or return type). If only 381 * the query method name is configured it is assumed to be on the <code>ViewHelperService</code> 382 * for the contained view. 383 * </p> 384 * 385 * @return String query method name 386 */ 387 public String getQueryMethodToCall() { 388 return queryMethodToCall; 389 } 390 391 /** 392 * Setter for the query method name 393 * 394 * @param queryMethodToCall 395 */ 396 public void setQueryMethodToCall(String queryMethodToCall) { 397 this.queryMethodToCall = queryMethodToCall; 398 } 399 400 /** 401 * List of field names that should be passed as arguments to the query method 402 * 403 * <p> 404 * Each entry in the list maps to a method parameter, in the other contained within 405 * the list. The value for the field within the view will be pulled and passed 406 * to the query method as an argument 407 * </p> 408 * 409 * @return List<String> query method argument list 410 */ 411 public List<String> getQueryMethodArgumentFieldList() { 412 return queryMethodArgumentFieldList; 413 } 414 415 /** 416 * Setter for the query method argument list 417 * 418 * @param queryMethodArgumentFieldList 419 */ 420 public void setQueryMethodArgumentFieldList(List<String> queryMethodArgumentFieldList) { 421 this.queryMethodArgumentFieldList = queryMethodArgumentFieldList; 422 } 423 424 /** 425 * Configures the query method target class/object and method name 426 * 427 * <p> 428 * When the query method is not contained on the <code>ViewHelperService</code>, this 429 * can be configured for declaring the target class/object and method. The target class 430 * can be set in which case a new instance will be created and the given method invoked. 431 * Alternatively, the target object instance for the invocation can be given. Or finally 432 * a static method can be configured 433 * </p> 434 * 435 * @return MethodInvokerConfig query method config 436 */ 437 public MethodInvokerConfig getQueryMethodInvokerConfig() { 438 return queryMethodInvokerConfig; 439 } 440 441 /** 442 * Setter for the query method config 443 * 444 * @param queryMethodInvokerConfig 445 */ 446 public void setQueryMethodInvokerConfig(MethodInvokerConfig queryMethodInvokerConfig) { 447 this.queryMethodInvokerConfig = queryMethodInvokerConfig; 448 } 449 }