1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.rice.krad.uif.service.impl;
17  
18  import java.text.MessageFormat;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.kuali.rice.core.api.CoreApiServiceLocator;
28  import org.kuali.rice.core.api.config.property.ConfigurationService;
29  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
30  import org.kuali.rice.krad.service.LookupService;
31  import org.kuali.rice.krad.uif.UifConstants;
32  import org.kuali.rice.krad.uif.UifParameters;
33  import org.kuali.rice.krad.uif.component.MethodInvokerConfig;
34  import org.kuali.rice.krad.uif.field.AttributeQuery;
35  import org.kuali.rice.krad.uif.field.AttributeQueryResult;
36  import org.kuali.rice.krad.uif.lifecycle.ComponentPostMetadata;
37  import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
38  import org.kuali.rice.krad.uif.service.AttributeQueryService;
39  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
40  import org.kuali.rice.krad.uif.widget.LocationSuggest;
41  import org.kuali.rice.krad.uif.widget.Suggest;
42  import org.kuali.rice.krad.util.BeanPropertyComparator;
43  
44  
45  
46  
47  
48  
49  
50  public class AttributeQueryServiceImpl implements AttributeQueryService {
51      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
52              AttributeQueryServiceImpl.class);
53  
54      private LookupService lookupService;
55      private ConfigurationService configurationService;
56  
57      
58  
59  
60      @Override
61      public AttributeQueryResult performFieldSuggestQuery(ViewPostMetadata viewPostMetadata, String fieldId,
62              String fieldTerm, Map<String, String> queryParameters) {
63          AttributeQueryResult queryResult = new AttributeQueryResult();
64  
65          ComponentPostMetadata inputFieldMetaData = viewPostMetadata.getComponentPostMetadata(fieldId);
66          if (inputFieldMetaData == null) {
67              throw new RuntimeException("Unable to find attribute field instance for id: " + fieldId);
68          }
69  
70          Suggest.SuggestPostData suggestPostData = (Suggest.SuggestPostData) inputFieldMetaData.getData(
71                  UifConstants.PostMetadata.SUGGEST);
72  
73          AttributeQuery suggestQuery = suggestPostData.getSuggestQuery();
74  
75          boolean isUppercaseValue = Boolean.TRUE.equals(inputFieldMetaData.getData(
76                  UifConstants.PostMetadata.INPUT_FIELD_IS_UPPERCASE));
77  
78          
79          Map<String, String> additionalCriteria = new HashMap<String, String>();
80          if (isUppercaseValue) {
81              additionalCriteria.put(suggestPostData.getValuePropertyName(), fieldTerm.toUpperCase() + "*");
82          } else {
83              additionalCriteria.put(suggestPostData.getValuePropertyName(), fieldTerm + "*");
84          }
85  
86          
87          Collection<?> results = null;
88          if (suggestQuery.hasConfiguredMethod()) {
89              Object queryMethodResult = executeAttributeQueryMethod(suggestQuery, queryParameters, true, fieldTerm);
90              if ((queryMethodResult != null) && (queryMethodResult instanceof Collection<?>)) {
91                  results = (Collection<?>) queryMethodResult;
92              }
93          } else {
94              results = executeAttributeQueryCriteria(suggestQuery, queryParameters, additionalCriteria, new ArrayList<String>());
95          }
96  
97          
98          if (results != null) {
99              if (suggestPostData.isReturnFullQueryObject()) {
100                 queryResult.setResultData((List<Object>) results);
101             } else {
102                 retrievePropertiesOnResults(queryResult, results, suggestPostData);
103             }
104         }
105 
106         return queryResult;
107     }
108 
109     
110 
111 
112 
113 
114 
115 
116 
117     protected void retrievePropertiesOnResults(AttributeQueryResult queryResult, Collection<?> results,
118             Suggest.SuggestPostData suggestPostData) {
119         List<Object> suggestData = new ArrayList<Object>();
120         for (Object result : results) {
121             if (result == null) {
122                 continue;
123             }
124 
125             Map<String, String> propMap = new HashMap<String, String>();
126 
127             
128             if (result instanceof String) {
129                 propMap.put(UifParameters.VALUE, (String) result);
130                 propMap.put(UifParameters.LABEL, (String) result);
131             }
132 
133             
134             String suggestFieldValue = null;
135             if (StringUtils.isNotBlank(suggestPostData.getValuePropertyName())) {
136                 suggestFieldValue = ObjectPropertyUtils.getPropertyValueAsText(result,
137                         suggestPostData.getValuePropertyName());
138             } else if (ObjectPropertyUtils.isReadableProperty(result, UifParameters.VALUE)) {
139                 suggestFieldValue = ObjectPropertyUtils.getPropertyValueAsText(result, UifParameters.VALUE);
140             }
141 
142             if (suggestFieldValue != null) {
143                 propMap.put(UifParameters.VALUE, suggestFieldValue);
144             }
145 
146             
147             String suggestFieldLabel = null;
148             if (StringUtils.isNotBlank(suggestPostData.getLabelPropertyName())) {
149                 suggestFieldLabel = ObjectPropertyUtils.getPropertyValueAsText(result,
150                         suggestPostData.getLabelPropertyName());
151             } else if (ObjectPropertyUtils.isReadableProperty(result, UifParameters.LABEL)) {
152                 suggestFieldLabel = ObjectPropertyUtils.getPropertyValueAsText(result, UifParameters.LABEL);
153             }
154 
155             if (suggestFieldLabel != null) {
156                 propMap.put(UifParameters.LABEL, suggestFieldLabel);
157             }
158 
159             
160             if (suggestPostData instanceof LocationSuggest.LocationSuggestPostData) {
161                 handleLocationSuggestProperties((LocationSuggest.LocationSuggestPostData) suggestPostData, result,
162                         propMap);
163             }
164 
165             
166             handleAdditionalSuggestProperties(suggestPostData, result, propMap);
167 
168             
169             if (!propMap.isEmpty()) {
170                 
171                 suggestData.add(propMap);
172             }
173         }
174 
175         queryResult.setResultData(suggestData);
176     }
177 
178     
179 
180 
181 
182 
183 
184 
185     private void handleAdditionalSuggestProperties(Suggest.SuggestPostData suggestPostData, Object result,
186             Map<String, String> propMap) {
187         if (suggestPostData.getAdditionalPropertiesToReturn() != null) {
188             
189             for (String propName : suggestPostData.getAdditionalPropertiesToReturn()) {
190                 String propValue = null;
191 
192                 if (StringUtils.isNotBlank(propName) && ObjectPropertyUtils.isReadableProperty(result, propName)) {
193                     propValue = ObjectPropertyUtils.getPropertyValueAsText(result, propName);
194                 }
195 
196                 if (propValue != null) {
197                     propMap.put(propName, propValue);
198                 }
199             }
200         }
201     }
202 
203     
204 
205 
206 
207 
208 
209 
210     private void handleLocationSuggestProperties(LocationSuggest.LocationSuggestPostData suggestPostData, Object result,
211             Map<String, String> propMap) {
212         
213         String suggestHrefValue = null;
214         if (StringUtils.isNotBlank(suggestPostData.getHrefPropertyName()) && ObjectPropertyUtils.isReadableProperty(
215                 result, suggestPostData.getHrefPropertyName())) {
216             suggestHrefValue = ObjectPropertyUtils.getPropertyValueAsText(result,
217                     suggestPostData.getHrefPropertyName());
218         }
219 
220         
221         if (suggestHrefValue != null) {
222             propMap.put(suggestPostData.getHrefPropertyName(), suggestHrefValue);
223         }
224 
225         
226         String addUrlValue = null;
227         if (StringUtils.isNotBlank(suggestPostData.getAdditionalUrlPathPropertyName()) &&
228                 ObjectPropertyUtils.isReadableProperty(result, suggestPostData.getAdditionalUrlPathPropertyName())) {
229             addUrlValue = ObjectPropertyUtils.getPropertyValueAsText(result,
230                     suggestPostData.getAdditionalUrlPathPropertyName());
231         }
232 
233         
234         if (addUrlValue != null) {
235             propMap.put(suggestPostData.getAdditionalUrlPathPropertyName(), addUrlValue);
236         }
237 
238         if (suggestPostData.getRequestParameterPropertyNames() == null) {
239             return;
240         }
241 
242         
243         for (String key : suggestPostData.getRequestParameterPropertyNames().keySet()) {
244             String prop = suggestPostData.getRequestParameterPropertyNames().get(key);
245             String propValue = null;
246 
247             if (StringUtils.isNotBlank(prop) && ObjectPropertyUtils.isReadableProperty(result, prop)) {
248                 propValue = ObjectPropertyUtils.getPropertyValueAsText(result, prop);
249             }
250 
251             if (propValue != null) {
252                 propMap.put(prop, propValue);
253             }
254         }
255     }
256 
257     
258 
259 
260     @Override
261     public AttributeQueryResult performFieldQuery(ViewPostMetadata viewPostMetadata, String fieldId,
262             Map<String, String> queryParameters) {
263         AttributeQueryResult queryResult = new AttributeQueryResult();
264 
265         
266         ComponentPostMetadata inputFieldMetaData = viewPostMetadata.getComponentPostMetadata(fieldId);
267         if (inputFieldMetaData == null) {
268             throw new RuntimeException("Unable to find attribute field instance for id: " + fieldId);
269         }
270 
271         AttributeQuery fieldQuery = (AttributeQuery) inputFieldMetaData
272                 .getData(UifConstants.PostMetadata.INPUT_FIELD_ATTRIBUTE_QUERY);
273         if (fieldQuery == null) {
274             throw new RuntimeException("Field query not defined for field instance with id: " + fieldId);
275         }
276 
277         
278         Object resultObject = null;
279         if (fieldQuery.hasConfiguredMethod()) {
280             Object queryMethodResult = executeAttributeQueryMethod(fieldQuery, queryParameters, false, null);
281             if (queryMethodResult != null) {
282                 
283                 if (queryMethodResult instanceof AttributeQueryResult) {
284                     return (AttributeQueryResult) queryMethodResult;
285                 }
286 
287                 
288                 if (queryMethodResult instanceof Collection<?>) {
289                     Collection<?> methodResultCollection = (Collection<?>) queryMethodResult;
290                     if (!methodResultCollection.isEmpty()) {
291                         resultObject = methodResultCollection.iterator().next();
292                     }
293                 } else {
294                     resultObject = queryMethodResult;
295                 }
296             }
297         } else {
298             
299             Collection<?> results = executeAttributeQueryCriteria(fieldQuery, queryParameters, null,
300                     new ArrayList<String>(queryParameters.keySet()));
301 
302             if ((results != null) && !results.isEmpty()) {
303                 
304                 if (results.size() > 1) {
305                     
306                     resultObject = null;
307                 } else {
308                     resultObject = results.iterator().next();
309                 }
310             }
311         }
312 
313         if (resultObject != null) {
314             
315             Map<String, String> resultFieldData = new HashMap<String, String>();
316             for (String fromField : fieldQuery.getReturnFieldMapping().keySet()) {
317                 String returnField = fieldQuery.getReturnFieldMapping().get(fromField);
318 
319                 String fieldValueStr = "";
320                 fieldValueStr = ObjectPropertyUtils.getPropertyValueAsText(resultObject, fromField);
321 
322                 resultFieldData.put(returnField, fieldValueStr);
323             }
324             queryResult.setResultFieldData(resultFieldData);
325 
326             fieldQuery.setReturnMessageText("");
327         } else {
328             
329             if (fieldQuery.isRenderNotFoundMessage()) {
330                 String messageTemplate = getConfigurationService().getPropertyValueAsString(
331                         UifConstants.MessageKeys.QUERY_DATA_NOT_FOUND);
332                 String message = MessageFormat.format(messageTemplate, inputFieldMetaData.getData(
333                         UifConstants.PostMetadata.LABEL));
334                 fieldQuery.setReturnMessageText(message.toLowerCase());
335             }
336         }
337 
338         
339         queryResult.setResultMessage(fieldQuery.getReturnMessageText());
340         queryResult.setResultMessageStyleClasses(fieldQuery.getReturnMessageStyleClasses());
341 
342         return queryResult;
343     }
344 
345     
346 
347 
348 
349 
350 
351 
352 
353 
354 
355     protected Object executeAttributeQueryMethod(AttributeQuery attributeQuery, Map<String, String> queryParameters,
356             boolean isSuggestQuery, String queryTerm) {
357         String queryMethodToCall = attributeQuery.getQueryMethodToCall();
358         MethodInvokerConfig queryMethodInvoker = attributeQuery.getQueryMethodInvokerConfig();
359 
360         if (queryMethodInvoker == null) {
361             queryMethodInvoker = new MethodInvokerConfig();
362         }
363 
364         
365         
366         if (StringUtils.isBlank(queryMethodInvoker.getTargetMethod())) {
367             queryMethodInvoker.setTargetMethod(queryMethodToCall);
368         }
369 
370         
371         List<Object> arguments = new ArrayList<Object>();
372         if ((attributeQuery.getQueryMethodArgumentFieldList() != null) &&
373                 (!attributeQuery.getQueryMethodArgumentFieldList().isEmpty())) {
374             
375             int numQueryMethodArguments = attributeQuery.getQueryMethodArgumentFieldList().size();
376             if (isSuggestQuery) {
377                 numQueryMethodArguments += 1;
378             }
379 
380             
381             queryMethodInvoker.setArguments(new Object[numQueryMethodArguments]);
382             Class<?>[] argumentTypes = queryMethodInvoker.getArgumentTypes();
383 
384             if ((argumentTypes == null) || (argumentTypes.length != numQueryMethodArguments)) {
385                 throw new RuntimeException(
386                         "Query method argument field list size does not match found number of method arguments");
387             }
388 
389             for (int i = 0; i < attributeQuery.getQueryMethodArgumentFieldList().size(); i++) {
390                 String methodArgumentFromField = attributeQuery.getQueryMethodArgumentFieldList().get(i);
391                 if (queryParameters.containsKey(methodArgumentFromField)) {
392                     arguments.add(queryParameters.get(methodArgumentFromField));
393                 } else {
394                     arguments.add(null);
395                 }
396             }
397         }
398 
399         if (isSuggestQuery) {
400             arguments.add(queryTerm);
401         }
402 
403         queryMethodInvoker.setArguments(arguments.toArray());
404 
405         try {
406             queryMethodInvoker.prepare();
407 
408             return queryMethodInvoker.invoke();
409         } catch (Exception e) {
410             throw new RuntimeException("Unable to invoke query method: " + queryMethodInvoker.getTargetMethod(), e);
411         }
412     }
413 
414     
415 
416 
417 
418 
419 
420 
421 
422 
423 
424     protected Collection<?> executeAttributeQueryCriteria(AttributeQuery attributeQuery,
425             Map<String, String> queryParameters, Map<String, String> additionalCriteria,
426             List<String> wildcardAsLiteralPropertyNames) {
427         
428         boolean allQueryFieldsPresent = true;
429 
430         Map<String, String> queryCriteria = new HashMap<String, String>();
431         for (String fieldName : attributeQuery.getQueryFieldMapping().values()) {
432             if (queryParameters.containsKey(fieldName) && StringUtils.isNotBlank(queryParameters.get(fieldName))) {
433                 queryCriteria.put(fieldName, queryParameters.get(fieldName));
434             } else {
435                 allQueryFieldsPresent = false;
436                 break;
437             }
438         }
439 
440         
441         if (!allQueryFieldsPresent) {
442             attributeQuery.setRenderNotFoundMessage(false);
443 
444             return null;
445         }
446 
447         
448         for (String fieldName : attributeQuery.getAdditionalCriteria().keySet()) {
449             queryCriteria.put(fieldName, attributeQuery.getAdditionalCriteria().get(fieldName));
450         }
451 
452         
453         if (additionalCriteria != null) {
454             queryCriteria.putAll(additionalCriteria);
455         }
456 
457         Class<?> queryClass;
458         try {
459             queryClass = Class.forName(attributeQuery.getDataObjectClassName());
460         } catch (ClassNotFoundException e) {
461             throw new RuntimeException(
462                     "Invalid data object class given for suggest query: " + attributeQuery.getDataObjectClassName(), e);
463         }
464 
465         
466         Collection<?> results = getLookupService().findCollectionBySearchHelper(queryClass, queryCriteria,
467                 wildcardAsLiteralPropertyNames, true, null);
468 
469         
470         if (!attributeQuery.getSortPropertyNames().isEmpty() && (results != null) && (results.size() > 1)) {
471             Collections.sort((List<?>) results, new BeanPropertyComparator(attributeQuery.getSortPropertyNames()));
472         }
473 
474         return results;
475     }
476 
477     
478 
479 
480 
481 
482     protected LookupService getLookupService() {
483         if (lookupService == null) {
484             lookupService = KRADServiceLocatorWeb.getLookupService();
485         }
486 
487         return lookupService;
488     }
489 
490     
491 
492 
493 
494 
495     public void setLookupService(LookupService lookupService) {
496         this.lookupService = lookupService;
497     }
498 
499     
500 
501 
502 
503 
504     protected ConfigurationService getConfigurationService() {
505         if (configurationService == null) {
506             configurationService = CoreApiServiceLocator.getKualiConfigurationService();
507         }
508 
509         return configurationService;
510     }
511 
512     
513 
514 
515 
516 
517     public void setConfigurationService(ConfigurationService configurationService) {
518         this.configurationService = configurationService;
519     }
520 }