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 }