1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.lookup;
17
18 import org.apache.commons.beanutils.PropertyUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.CoreApiServiceLocator;
21 import org.kuali.rice.core.api.encryption.EncryptionService;
22 import org.kuali.rice.core.api.search.SearchOperator;
23 import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
24 import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
25 import org.kuali.rice.krad.data.KradDataServiceLocator;
26 import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
27 import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException;
28 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
29 import org.kuali.rice.krad.service.ModuleService;
30 import org.kuali.rice.krad.uif.UifConstants;
31 import org.kuali.rice.krad.uif.UifPropertyPaths;
32 import org.kuali.rice.krad.uif.lifecycle.ComponentPostMetadata;
33 import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
34 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
35 import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
36 import org.kuali.rice.krad.util.KRADConstants;
37 import org.kuali.rice.krad.util.KRADPropertyConstants;
38 import org.kuali.rice.krad.util.KRADUtils;
39 import org.kuali.rice.krad.web.form.UifFormBase;
40 import org.springframework.beans.PropertyAccessorUtils;
41
42 import javax.servlet.http.HttpServletRequest;
43
44 import java.security.GeneralSecurityException;
45 import java.sql.Date;
46 import java.sql.Timestamp;
47 import java.text.ParseException;
48 import java.util.ArrayList;
49 import java.util.Calendar;
50 import java.util.Collections;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Set;
56
57
58
59
60
61
62 public class LookupUtils {
63 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LookupUtils.class);
64 private static final String[] searchList = new String[SearchOperator.QUERY_CHARACTERS.size()];
65
66 static {
67 int index = 0;
68 for (SearchOperator operator : SearchOperator.QUERY_CHARACTERS) {
69 searchList[index++] = operator.op();
70 }
71 }
72
73 private static final String[] replacementList = Collections.nCopies(searchList.length, "").toArray(new String[0]);
74
75 private LookupUtils() {}
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public static String retrieveLookupParameterValue(UifFormBase form, HttpServletRequest request,
90 Class<?> lookupObjectClass, String propertyName, String parameterName) {
91 String parameterValue = "";
92
93
94 if (StringUtils.startsWith(parameterName, "'") && StringUtils.endsWith(parameterName, "'")) {
95 parameterValue = StringUtils.substringBetween(parameterName, "'");
96 } else if (parameterValue.startsWith(KRADConstants.LOOKUP_PARAMETER_LITERAL_PREFIX
97 + KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER)) {
98 parameterValue = StringUtils.removeStart(parameterValue, KRADConstants.LOOKUP_PARAMETER_LITERAL_PREFIX
99 + KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER);
100 }
101
102 else if (request.getParameterMap().containsKey(parameterName)) {
103 parameterValue = request.getParameter(parameterName);
104 }
105
106 else {
107 parameterValue = ObjectPropertyUtils.getPropertyValueAsText(form, parameterName);
108 }
109
110 if (parameterValue != null && lookupObjectClass != null
111 && KRADServiceLocatorWeb.getDataObjectAuthorizationService()
112 .attributeValueNeedsToBeEncryptedOnFormsAndLinks(lookupObjectClass, propertyName)) {
113 try {
114 if (CoreApiServiceLocator.getEncryptionService().isEnabled()) {
115 parameterValue = CoreApiServiceLocator.getEncryptionService().encrypt(parameterValue)
116 + EncryptionService.ENCRYPTION_POST_PREFIX;
117 }
118 } catch (GeneralSecurityException e) {
119 LOG.error("Unable to encrypt value for property name: " + propertyName);
120 throw new RuntimeException(e);
121 }
122 }
123
124 return parameterValue;
125 }
126
127
128
129
130
131
132 public static String getBaseLookupUrl() {
133 return CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
134 KRADConstants.KRAD_LOOKUP_URL_KEY);
135 }
136
137
138
139
140
141
142
143
144
145
146
147 public static String forceUppercase(Class<?> dataObjectClass, String fieldName, String fieldValue) {
148
149 if (StringUtils.isBlank(fieldValue)) {
150 return fieldValue;
151 }
152
153
154 if (dataObjectClass == null) {
155 throw new IllegalArgumentException("Parameter dataObjectClass passed in with null value.");
156 }
157
158 if (StringUtils.isBlank(fieldName)) {
159 throw new IllegalArgumentException("Parameter fieldName passed in with empty value.");
160 }
161
162 if (!KRADServiceLocatorWeb.getDataDictionaryService().isAttributeDefined(dataObjectClass, fieldName)
163 .booleanValue()) {
164 return fieldValue;
165 }
166
167 boolean forceUpperCase = false;
168 try {
169 forceUpperCase = KRADServiceLocatorWeb.getDataDictionaryService()
170 .getAttributeForceUppercase(dataObjectClass, fieldName).booleanValue();
171 } catch (UnknownBusinessClassAttributeException ubae) {
172
173 }
174
175 if (forceUpperCase && !fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
176 return fieldValue.toUpperCase();
177 }
178
179 return fieldValue;
180 }
181
182
183
184
185
186
187
188
189
190 public static Map<String, String> forceUppercase(Class<?> dataObjectClass, Map<String, String> fieldValues) {
191 if (dataObjectClass == null) {
192 throw new IllegalArgumentException("Parameter boClass passed in with null value.");
193 }
194
195 if (fieldValues == null) {
196 throw new IllegalArgumentException("Parameter fieldValues passed in with null value.");
197 }
198
199 for (String fieldName : fieldValues.keySet()) {
200 fieldValues.put(fieldName, forceUppercase(dataObjectClass, fieldName, fieldValues.get(fieldName)));
201 }
202
203 return fieldValues;
204 }
205
206
207
208
209
210
211
212
213
214
215
216 public static Integer getSearchResultsLimit(Class dataObjectClass, LookupForm lookupForm) {
217 Integer limit = KRADServiceLocatorWeb.getViewDictionaryService().getResultSetLimitForLookup(dataObjectClass,
218 lookupForm);
219 if (limit == null) {
220 limit = getApplicationSearchResultsLimit();
221 }
222
223 return limit;
224 }
225
226
227
228
229
230
231 public static Integer getApplicationSearchResultsLimit() {
232 String limitString = CoreFrameworkServiceLocator.getParameterService()
233 .getParameterValueAsString(KRADConstants.KRAD_NAMESPACE,
234 KRADConstants.DetailTypes.LOOKUP_PARM_DETAIL_TYPE,
235 KRADConstants.SystemGroupParameterNames.LOOKUP_RESULTS_LIMIT);
236 if (limitString != null) {
237 return Integer.valueOf(limitString);
238 }
239
240 return null;
241 }
242
243
244
245
246
247
248 public static Integer getApplicationMultipleValueSearchResultsLimit() {
249 String limitString = CoreFrameworkServiceLocator.getParameterService()
250 .getParameterValueAsString(KRADConstants.KRAD_NAMESPACE,
251 KRADConstants.DetailTypes.LOOKUP_PARM_DETAIL_TYPE,
252 KRADConstants.SystemGroupParameterNames.MULTIPLE_VALUE_LOOKUP_RESULTS_LIMIT);
253 if (limitString != null) {
254 return Integer.valueOf(limitString);
255 }
256
257 return null;
258 }
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274 public static Timestamp getActiveDateTimestampForCriteria(Map searchValues) {
275 Date activeDate = CoreApiServiceLocator.getDateTimeService().getCurrentSqlDate();
276
277 Timestamp activeTimestamp = null;
278 if (searchValues.containsKey(KRADPropertyConstants.ACTIVE_AS_OF_DATE)) {
279 String activeAsOfDate = (String) searchValues.get(KRADPropertyConstants.ACTIVE_AS_OF_DATE);
280 if (StringUtils.isNotBlank(activeAsOfDate)) {
281 try {
282 activeDate = CoreApiServiceLocator.getDateTimeService()
283 .convertToSqlDate(KRADUtils.clean(activeAsOfDate));
284 } catch (ParseException e) {
285
286 try {
287 activeTimestamp = CoreApiServiceLocator.getDateTimeService()
288 .convertToSqlTimestamp(KRADUtils.clean(activeAsOfDate));
289 } catch (ParseException e1) {
290 throw new RuntimeException("Unable to convert date: " + KRADUtils.clean(activeAsOfDate));
291 }
292 }
293 }
294 }
295
296
297 if (activeTimestamp == null) {
298 Calendar cal = Calendar.getInstance();
299
300 cal.setTime(activeDate);
301 cal.set(Calendar.HOUR, cal.getMaximum(Calendar.HOUR));
302 cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
303 cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
304
305 activeTimestamp = new Timestamp(cal.getTime().getTime());
306 }
307
308 return activeTimestamp;
309 }
310
311
312
313
314
315
316
317
318 public static Map<String, String> preprocessDateFields(Map<String, String> searchCriteria) {
319 Map<String, String> fieldsToUpdate = new HashMap<String, String>();
320 Map<String, String> searchCriteriaUpdated = new HashMap<String, String>(searchCriteria);
321
322 Set<String> fieldsForLookup = searchCriteria.keySet();
323 for (String propName : fieldsForLookup) {
324 if (propName.startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
325 String from_DateValue = searchCriteria.get(propName);
326 String dateFieldName =
327 StringUtils.remove(propName, KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX);
328 String to_DateValue = searchCriteria.get(dateFieldName);
329 String newPropValue = to_DateValue;
330
331 if (StringUtils.isNotEmpty(from_DateValue) && StringUtils.isNotEmpty(to_DateValue)) {
332 newPropValue = from_DateValue + SearchOperator.BETWEEN + to_DateValue;
333 } else if (StringUtils.isNotEmpty(from_DateValue) && StringUtils.isEmpty(to_DateValue)) {
334 newPropValue = SearchOperator.GREATER_THAN_EQUAL.op() + from_DateValue;
335 } else if (StringUtils.isNotEmpty(to_DateValue) && StringUtils.isEmpty(from_DateValue)) {
336 newPropValue = SearchOperator.LESS_THAN_EQUAL.op() + to_DateValue;
337 }
338
339 fieldsToUpdate.put(dateFieldName, newPropValue);
340 }
341 }
342
343
344 Set<String> keysToUpdate = fieldsToUpdate.keySet();
345 for (String updateKey : keysToUpdate) {
346 searchCriteriaUpdated.put(updateKey, fieldsToUpdate.get(updateKey));
347 }
348
349 return searchCriteriaUpdated;
350 }
351
352
353
354
355
356
357
358
359
360
361 public static boolean hasExternalBusinessObjectProperty(Class<?> boClass,
362 Map<String, String> fieldValues) throws IllegalAccessException, InstantiationException {
363 Object sampleBo = boClass.newInstance();
364 for (String key : fieldValues.keySet()) {
365 if (isExternalBusinessObjectProperty(sampleBo, key)) {
366 return true;
367 }
368 }
369
370 return false;
371 }
372
373
374
375
376
377
378
379
380
381
382 public static boolean isExternalBusinessObjectProperty(Object sampleBo, String propertyName) {
383 if (propertyName.indexOf(".") > 0 && !StringUtils.contains(propertyName, "add.")) {
384 Class<?> propertyClass =
385 ObjectPropertyUtils.getPropertyType(sampleBo, StringUtils.substringBeforeLast(propertyName, "."));
386 if (propertyClass != null) {
387 return ExternalizableBusinessObjectUtils.isExternalizableBusinessObjectInterface(propertyClass);
388 }
389 }
390
391 return false;
392 }
393
394
395
396
397
398
399
400
401
402
403 public static Map<String, String> removeExternalizableBusinessObjectFieldValues(Class<?> boClass,
404 Map<String, String> fieldValues) throws IllegalAccessException, InstantiationException {
405 Map<String, String> eboFieldValues = new HashMap<String, String>();
406 Object sampleBo = boClass.newInstance();
407 for (String key : fieldValues.keySet()) {
408 if (!isExternalBusinessObjectProperty(sampleBo, key)) {
409 eboFieldValues.put(key, fieldValues.get(key));
410 }
411 }
412
413 return eboFieldValues;
414 }
415
416
417
418
419
420
421
422
423
424 public static Map<String, String> getExternalizableBusinessObjectFieldValues(String eboPropertyName,
425 Map<String, String> fieldValues) {
426 Map<String, String> eboFieldValues = new HashMap<String, String>();
427 for (String key : fieldValues.keySet()) {
428 if (key.startsWith(eboPropertyName + ".")) {
429 eboFieldValues.put(StringUtils.substringAfterLast(key, "."), fieldValues.get(key));
430 }
431 }
432
433 return eboFieldValues;
434 }
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449 public static List<String> getExternalizableBusinessObjectProperties(Class<?> boClass,
450 Map<String, String> fieldValues) throws IllegalAccessException, InstantiationException {
451 Set<String> eboPropertyNames = new HashSet<String>();
452
453 Object sampleBo = boClass.newInstance();
454 for (String key : fieldValues.keySet()) {
455 if (isExternalBusinessObjectProperty(sampleBo, key)) {
456 eboPropertyNames.add(StringUtils.substringBeforeLast(key, "."));
457 }
458 }
459
460 return new ArrayList<String>(eboPropertyNames);
461 }
462
463
464
465
466
467
468
469
470
471
472
473 public static Class<? extends ExternalizableBusinessObject> getExternalizableBusinessObjectClass(Class<?> boClass,
474 String propertyName) throws IllegalAccessException, InstantiationException {
475 return (Class<? extends ExternalizableBusinessObject>) ObjectPropertyUtils
476 .getPropertyType(boClass.newInstance(), StringUtils.substringBeforeLast(propertyName, "."));
477 }
478
479
480
481
482
483
484
485
486
487
488
489 public static Map<String, String> adjustCriteriaForNestedEBOs(Class<?> dataObjectClass,
490 Map<String, String> searchCriteria,
491 boolean unbounded) throws InstantiationException, IllegalAccessException {
492
493 Map<String, String> nonEboFieldValues = removeExternalizableBusinessObjectFieldValues(
494 dataObjectClass, searchCriteria);
495 if (LOG.isDebugEnabled()) {
496 LOG.debug("Non EBO properties removed: " + nonEboFieldValues);
497 }
498
499
500 List<String> eboPropertyNames = getExternalizableBusinessObjectProperties(dataObjectClass, searchCriteria);
501 if (LOG.isDebugEnabled()) {
502 LOG.debug("EBO properties: " + eboPropertyNames);
503 }
504
505
506 for (String eboPropertyName : eboPropertyNames) {
507
508 Map<String, String> eboFieldValues = LookupUtils.getExternalizableBusinessObjectFieldValues(eboPropertyName,
509 searchCriteria);
510 if (LOG.isDebugEnabled()) {
511 LOG.debug("EBO properties for master EBO property: " + eboPropertyName);
512 LOG.debug("properties: " + eboFieldValues);
513 }
514
515
516 ModuleService eboModuleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(
517 getExternalizableBusinessObjectClass(dataObjectClass, eboPropertyName));
518
519
520 List<?> eboResults = Collections.emptyList();
521 if (eboModuleService != null) {
522 eboResults = eboModuleService.getExternalizableBusinessObjectsListForLookup(
523 getExternalizableBusinessObjectClass(dataObjectClass, eboPropertyName),
524 (Map) eboFieldValues, unbounded);
525 } else {
526 LOG.debug("EBO ModuleService is null: " + eboPropertyName);
527 }
528
529
530 Class<?> eboParentClass;
531 String eboParentPropertyName;
532 if (PropertyAccessorUtils.isNestedOrIndexedProperty(eboPropertyName)) {
533 eboParentPropertyName = StringUtils.substringBeforeLast(eboPropertyName, ".");
534 try {
535 eboParentClass = KradDataServiceLocator.getDataObjectService().wrap(dataObjectClass.newInstance()).getPropertyType(
536 eboParentPropertyName);
537 } catch (Exception ex) {
538 throw new RuntimeException(
539 "Unable to create an instance of the business object class: " + dataObjectClass
540 .getName(), ex);
541 }
542 } else {
543 eboParentClass = dataObjectClass;
544 eboParentPropertyName = null;
545 }
546
547 if (LOG.isDebugEnabled()) {
548 LOG.debug("determined EBO parent class/property name: " + eboParentClass + "/" + eboParentPropertyName);
549 }
550
551
552
553
554 RelationshipDefinition rd = KRADServiceLocatorWeb.getLegacyDataAdapter().getDictionaryRelationship(
555 eboParentClass, eboPropertyName);
556 if (LOG.isDebugEnabled()) {
557 LOG.debug("Obtained RelationshipDefinition for " + eboPropertyName);
558 LOG.debug(rd);
559 }
560
561
562
563
564
565
566
567 if (KRADUtils.isNotNull(rd)) {
568 if (rd.getPrimitiveAttributes().size() > 1) {
569 throw new RuntimeException(
570 "EBO Links don't work for relationships with multiple-field primary keys.");
571 }
572 String boProperty = rd.getPrimitiveAttributes().get(0).getSourceName();
573 String eboProperty = rd.getPrimitiveAttributes().get(0).getTargetName();
574 StringBuffer boPropertyValue = new StringBuffer();
575
576
577
578 for (Object ebo : eboResults) {
579 if (boPropertyValue.length() != 0) {
580 boPropertyValue.append(SearchOperator.OR.op());
581 }
582 try {
583 boPropertyValue.append(PropertyUtils.getProperty(ebo, eboProperty).toString());
584 } catch (Exception ex) {
585 LOG.warn("Unable to get value for " + eboProperty + " on " + ebo);
586 }
587 }
588
589 if (eboParentPropertyName == null) {
590
591 nonEboFieldValues.put(boProperty, boPropertyValue.toString());
592 } else {
593
594 nonEboFieldValues.put(eboParentPropertyName + "." + boProperty, boPropertyValue.toString());
595 }
596 }
597 }
598
599 return nonEboFieldValues;
600 }
601
602
603
604
605
606
607
608 public static String scrubQueryCharacters(String criteriaValue) {
609 return StringUtils.replaceEach(criteriaValue, searchList, replacementList);
610 }
611
612
613
614
615
616
617
618
619
620
621
622 public static String generateMultiValueKey(Object lineDataObject, List<String> fieldConversionKeys) {
623 String lineIdentifier = "";
624
625 if(fieldConversionKeys == null || fieldConversionKeys.isEmpty()) {
626 lineIdentifier =
627 KRADServiceLocatorWeb.getLegacyDataAdapter().getDataObjectIdentifierString(lineDataObject);
628 } else {
629 Collections.sort(fieldConversionKeys);
630 for (String fromFieldName : fieldConversionKeys) {
631 Object fromFieldValue = ObjectPropertyUtils.getPropertyValue(lineDataObject, fromFieldName);
632
633 if (fromFieldValue != null) {
634 lineIdentifier += fromFieldValue;
635 }
636
637 lineIdentifier += ":";
638 }
639 lineIdentifier = StringUtils.removeEnd(lineIdentifier, ":");
640 }
641
642 return lineIdentifier;
643 }
644
645
646
647
648
649
650
651 public static void refreshLookupResultSelections(LookupForm form) {
652 int displayStart = 0;
653 int displayLength = 0;
654
655
656 ViewPostMetadata viewPostMetadata = form.getViewPostMetadata();
657 if (viewPostMetadata != null) {
658
659
660 synchronized (viewPostMetadata) {
661 ComponentPostMetadata oldCollectionGroup = viewPostMetadata.getComponentPostMetadata("uLookupResults");
662 displayStart = (Integer) oldCollectionGroup.getData(UifConstants.PostMetadata.COLL_DISPLAY_START);
663 displayLength = (Integer) oldCollectionGroup.getData(UifConstants.PostMetadata.COLL_DISPLAY_LENGTH);
664 }
665 }
666
667 List<? extends Object> lookupResults = (List<? extends Object>) form.getLookupResults();
668 List<String> fromFieldNames = form.getMultiValueReturnFields();
669
670 Set<String> selectedLines = form.getSelectedCollectionLines().get(UifPropertyPaths.LOOKUP_RESULTS);
671 Set<String> selectedLookupResultsCache = form.getSelectedLookupResultsCache();
672
673 selectedLines = (selectedLines == null) ? new HashSet<String>() : selectedLines;
674
675 for(int i = displayStart; i < displayStart + displayLength; i++ ) {
676 if(i >= form.getLookupResults().size()) break;
677
678 Object lineItem = lookupResults.get(i);
679 String lineIdentifier = LookupUtils.generateMultiValueKey(lineItem, fromFieldNames);
680
681 if(!selectedLines.contains(lineIdentifier)) {
682 selectedLookupResultsCache.remove(lineIdentifier);
683 } else {
684 selectedLookupResultsCache.add(lineIdentifier);
685 }
686 }
687
688 selectedLines.addAll( selectedLookupResultsCache );
689
690 form.getSelectedCollectionLines().put(UifPropertyPaths.LOOKUP_RESULTS, selectedLines);
691 }
692
693 }