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 Object suggestFieldValue = null;
135 if (StringUtils.isNotBlank(suggestPostData.getValuePropertyName())) {
136 suggestFieldValue = ObjectPropertyUtils.getPropertyValue(result,
137 suggestPostData.getValuePropertyName());
138 } else if (ObjectPropertyUtils.isReadableProperty(result, UifParameters.VALUE)) {
139 suggestFieldValue = ObjectPropertyUtils.getPropertyValue(result, UifParameters.VALUE);
140 }
141
142 if (suggestFieldValue != null) {
143 propMap.put(UifParameters.VALUE, suggestFieldValue.toString());
144 }
145
146
147 Object suggestFieldLabel = null;
148 if (StringUtils.isNotBlank(suggestPostData.getLabelPropertyName())) {
149 suggestFieldLabel = ObjectPropertyUtils.getPropertyValue(result,
150 suggestPostData.getLabelPropertyName());
151 } else if (ObjectPropertyUtils.isReadableProperty(result, UifParameters.LABEL)) {
152 suggestFieldLabel = ObjectPropertyUtils.getPropertyValue(result, UifParameters.LABEL);
153 }
154
155 if (suggestFieldLabel != null) {
156 propMap.put(UifParameters.LABEL, suggestFieldLabel.toString());
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 Object propValue = null;
191
192 if (StringUtils.isNotBlank(propName) && ObjectPropertyUtils.isReadableProperty(result, propName)) {
193 propValue = ObjectPropertyUtils.getPropertyValue(result, propName);
194 }
195
196 if (propValue != null) {
197 propMap.put(propName, propValue.toString());
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 Object suggestHrefValue = null;
214 if (StringUtils.isNotBlank(suggestPostData.getHrefPropertyName()) && ObjectPropertyUtils.isReadableProperty(
215 result, suggestPostData.getHrefPropertyName())) {
216 suggestHrefValue = ObjectPropertyUtils.getPropertyValue(result, suggestPostData.getHrefPropertyName());
217 }
218
219
220 if (suggestHrefValue != null) {
221 propMap.put(suggestPostData.getHrefPropertyName(), suggestHrefValue.toString());
222 }
223
224
225 Object addUrlValue = null;
226 if (StringUtils.isNotBlank(suggestPostData.getAdditionalUrlPathPropertyName()) &&
227 ObjectPropertyUtils.isReadableProperty(result, suggestPostData.getAdditionalUrlPathPropertyName())) {
228 addUrlValue = ObjectPropertyUtils.getPropertyValue(result,
229 suggestPostData.getAdditionalUrlPathPropertyName());
230 }
231
232
233 if (addUrlValue != null) {
234 propMap.put(suggestPostData.getAdditionalUrlPathPropertyName(), addUrlValue.toString());
235 }
236
237 if (suggestPostData.getRequestParameterPropertyNames() == null) {
238 return;
239 }
240
241
242 for (String key : suggestPostData.getRequestParameterPropertyNames().keySet()) {
243 String prop = suggestPostData.getRequestParameterPropertyNames().get(key);
244 Object propValue = null;
245
246 if (StringUtils.isNotBlank(prop) && ObjectPropertyUtils.isReadableProperty(result, prop)) {
247 propValue = ObjectPropertyUtils.getPropertyValue(result, prop);
248 }
249
250 if (propValue != null) {
251 propMap.put(prop, propValue.toString());
252 }
253 }
254 }
255
256
257
258
259 @Override
260 public AttributeQueryResult performFieldQuery(ViewPostMetadata viewPostMetadata, String fieldId,
261 Map<String, String> queryParameters) {
262 AttributeQueryResult queryResult = new AttributeQueryResult();
263
264
265 ComponentPostMetadata inputFieldMetaData = viewPostMetadata.getComponentPostMetadata(fieldId);
266 if (inputFieldMetaData == null) {
267 throw new RuntimeException("Unable to find attribute field instance for id: " + fieldId);
268 }
269
270 AttributeQuery fieldQuery = (AttributeQuery) inputFieldMetaData
271 .getData(UifConstants.PostMetadata.INPUT_FIELD_ATTRIBUTE_QUERY);
272 if (fieldQuery == null) {
273 throw new RuntimeException("Field query not defined for field instance with id: " + fieldId);
274 }
275
276
277 Object resultObject = null;
278 if (fieldQuery.hasConfiguredMethod()) {
279 Object queryMethodResult = executeAttributeQueryMethod(fieldQuery, queryParameters, false, null);
280 if (queryMethodResult != null) {
281
282 if (queryMethodResult instanceof AttributeQueryResult) {
283 return (AttributeQueryResult) queryMethodResult;
284 }
285
286
287 if (queryMethodResult instanceof Collection<?>) {
288 Collection<?> methodResultCollection = (Collection<?>) queryMethodResult;
289 if (!methodResultCollection.isEmpty()) {
290 resultObject = methodResultCollection.iterator().next();
291 }
292 } else {
293 resultObject = queryMethodResult;
294 }
295 }
296 } else {
297
298 Collection<?> results = executeAttributeQueryCriteria(fieldQuery, queryParameters, null,
299 new ArrayList<String>(queryParameters.keySet()));
300
301 if ((results != null) && !results.isEmpty()) {
302
303 if (results.size() > 1) {
304
305 resultObject = null;
306 } else {
307 resultObject = results.iterator().next();
308 }
309 }
310 }
311
312 if (resultObject != null) {
313
314 Map<String, String> resultFieldData = new HashMap<String, String>();
315 for (String fromField : fieldQuery.getReturnFieldMapping().keySet()) {
316 String returnField = fieldQuery.getReturnFieldMapping().get(fromField);
317
318 String fieldValueStr = "";
319 Object fieldValue = ObjectPropertyUtils.getPropertyValue(resultObject, fromField);
320 if (fieldValue != null) {
321 fieldValueStr = fieldValue.toString();
322 }
323 resultFieldData.put(returnField, fieldValueStr);
324 }
325 queryResult.setResultFieldData(resultFieldData);
326
327 fieldQuery.setReturnMessageText("");
328 } else {
329
330 if (fieldQuery.isRenderNotFoundMessage()) {
331 String messageTemplate = getConfigurationService().getPropertyValueAsString(
332 UifConstants.MessageKeys.QUERY_DATA_NOT_FOUND);
333 String message = MessageFormat.format(messageTemplate, inputFieldMetaData.getData(
334 UifConstants.PostMetadata.LABEL));
335 fieldQuery.setReturnMessageText(message.toLowerCase());
336 }
337 }
338
339
340 queryResult.setResultMessage(fieldQuery.getReturnMessageText());
341 queryResult.setResultMessageStyleClasses(fieldQuery.getReturnMessageStyleClasses());
342
343 return queryResult;
344 }
345
346
347
348
349
350
351
352
353
354
355
356 protected Object executeAttributeQueryMethod(AttributeQuery attributeQuery, Map<String, String> queryParameters,
357 boolean isSuggestQuery, String queryTerm) {
358 String queryMethodToCall = attributeQuery.getQueryMethodToCall();
359 MethodInvokerConfig queryMethodInvoker = attributeQuery.getQueryMethodInvokerConfig();
360
361 if (queryMethodInvoker == null) {
362 queryMethodInvoker = new MethodInvokerConfig();
363 }
364
365
366
367 if (StringUtils.isBlank(queryMethodInvoker.getTargetMethod())) {
368 queryMethodInvoker.setTargetMethod(queryMethodToCall);
369 }
370
371
372 List<Object> arguments = new ArrayList<Object>();
373 if ((attributeQuery.getQueryMethodArgumentFieldList() != null) &&
374 (!attributeQuery.getQueryMethodArgumentFieldList().isEmpty())) {
375
376 int numQueryMethodArguments = attributeQuery.getQueryMethodArgumentFieldList().size();
377 if (isSuggestQuery) {
378 numQueryMethodArguments += 1;
379 }
380
381
382 queryMethodInvoker.setArguments(new Object[numQueryMethodArguments]);
383 Class<?>[] argumentTypes = queryMethodInvoker.getArgumentTypes();
384
385 if ((argumentTypes == null) || (argumentTypes.length != numQueryMethodArguments)) {
386 throw new RuntimeException(
387 "Query method argument field list size does not match found number of method arguments");
388 }
389
390 for (int i = 0; i < attributeQuery.getQueryMethodArgumentFieldList().size(); i++) {
391 String methodArgumentFromField = attributeQuery.getQueryMethodArgumentFieldList().get(i);
392 if (queryParameters.containsKey(methodArgumentFromField)) {
393 arguments.add(queryParameters.get(methodArgumentFromField));
394 } else {
395 arguments.add(null);
396 }
397 }
398 }
399
400 if (isSuggestQuery) {
401 arguments.add(queryTerm);
402 }
403
404 queryMethodInvoker.setArguments(arguments.toArray());
405
406 try {
407 queryMethodInvoker.prepare();
408
409 return queryMethodInvoker.invoke();
410 } catch (Exception e) {
411 throw new RuntimeException("Unable to invoke query method: " + queryMethodInvoker.getTargetMethod(), e);
412 }
413 }
414
415
416
417
418
419
420
421
422
423
424
425 protected Collection<?> executeAttributeQueryCriteria(AttributeQuery attributeQuery,
426 Map<String, String> queryParameters, Map<String, String> additionalCriteria,
427 List<String> wildcardAsLiteralPropertyNames) {
428
429 boolean allQueryFieldsPresent = true;
430
431 Map<String, String> queryCriteria = new HashMap<String, String>();
432 for (String fieldName : attributeQuery.getQueryFieldMapping().values()) {
433 if (queryParameters.containsKey(fieldName) && StringUtils.isNotBlank(queryParameters.get(fieldName))) {
434 queryCriteria.put(fieldName, queryParameters.get(fieldName));
435 } else {
436 allQueryFieldsPresent = false;
437 break;
438 }
439 }
440
441
442 if (!allQueryFieldsPresent) {
443 attributeQuery.setRenderNotFoundMessage(false);
444
445 return null;
446 }
447
448
449 for (String fieldName : attributeQuery.getAdditionalCriteria().keySet()) {
450 queryCriteria.put(fieldName, attributeQuery.getAdditionalCriteria().get(fieldName));
451 }
452
453
454 if (additionalCriteria != null) {
455 queryCriteria.putAll(additionalCriteria);
456 }
457
458 Class<?> queryClass;
459 try {
460 queryClass = Class.forName(attributeQuery.getDataObjectClassName());
461 } catch (ClassNotFoundException e) {
462 throw new RuntimeException(
463 "Invalid data object class given for suggest query: " + attributeQuery.getDataObjectClassName(), e);
464 }
465
466
467 Collection<?> results = getLookupService().findCollectionBySearchHelper(queryClass, queryCriteria,
468 wildcardAsLiteralPropertyNames, true, null);
469
470
471 if (!attributeQuery.getSortPropertyNames().isEmpty() && (results != null) && (results.size() > 1)) {
472 Collections.sort((List<?>) results, new BeanPropertyComparator(attributeQuery.getSortPropertyNames()));
473 }
474
475 return results;
476 }
477
478
479
480
481
482
483 protected LookupService getLookupService() {
484 if (lookupService == null) {
485 lookupService = KRADServiceLocatorWeb.getLookupService();
486 }
487
488 return lookupService;
489 }
490
491
492
493
494
495
496 public void setLookupService(LookupService lookupService) {
497 this.lookupService = lookupService;
498 }
499
500
501
502
503
504
505 protected ConfigurationService getConfigurationService() {
506 if (configurationService == null) {
507 configurationService = CoreApiServiceLocator.getKualiConfigurationService();
508 }
509
510 return configurationService;
511 }
512
513
514
515
516
517
518 public void setConfigurationService(ConfigurationService configurationService) {
519 this.configurationService = configurationService;
520 }
521 }