1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import java.sql.Timestamp;
19 import java.text.ParseException;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.commons.beanutils.PropertyUtils;
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.commons.lang.Validate;
29 import org.apache.log4j.Logger;
30 import org.kuali.rice.core.api.criteria.Predicate;
31 import org.kuali.rice.core.api.criteria.PredicateFactory;
32 import org.kuali.rice.core.api.criteria.QueryByCriteria;
33 import org.kuali.rice.core.api.datetime.DateTimeService;
34 import org.kuali.rice.core.api.search.SearchOperator;
35 import org.kuali.rice.core.api.util.RiceKeyConstants;
36 import org.kuali.rice.core.api.util.type.TypeUtils;
37 import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbCharBooleanConversion;
38 import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
39 import org.kuali.rice.krad.bo.InactivatableFromTo;
40 import org.kuali.rice.krad.data.DataObjectService;
41 import org.kuali.rice.krad.lookup.LookupInputField;
42 import org.kuali.rice.krad.lookup.LookupUtils;
43 import org.kuali.rice.krad.lookup.LookupView;
44 import org.kuali.rice.krad.service.DataDictionaryService;
45 import org.kuali.rice.krad.uif.UifConstants;
46 import org.kuali.rice.krad.uif.UifParameters;
47 import org.kuali.rice.krad.uif.component.Component;
48 import org.kuali.rice.krad.uif.view.View;
49 import org.kuali.rice.krad.util.GlobalVariables;
50 import org.kuali.rice.krad.util.KRADPropertyConstants;
51 import org.kuali.rice.krad.util.KRADUtils;
52
53
54
55
56
57 public class LookupCriteriaGeneratorImpl implements LookupCriteriaGenerator {
58
59 private static final Logger LOG = Logger.getLogger(LookupCriteriaGeneratorImpl.class);
60
61 private DateTimeService dateTimeService;
62 private DataDictionaryService dataDictionaryService;
63 private DatabasePlatform dbPlatform;
64 private DataObjectService dataObjectService;
65
66 public DateTimeService getDateTimeService() {
67 return dateTimeService;
68 }
69
70 public void setDateTimeService(DateTimeService dateTimeService) {
71 this.dateTimeService = dateTimeService;
72 }
73
74 public DataDictionaryService getDataDictionaryService() {
75 return dataDictionaryService;
76 }
77
78 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
79 this.dataDictionaryService = dataDictionaryService;
80 }
81
82 public DatabasePlatform getDbPlatform() {
83 return dbPlatform;
84 }
85
86 public void setDbPlatform(DatabasePlatform dbPlatform) {
87 this.dbPlatform = dbPlatform;
88 }
89
90 public DataObjectService getDataObjectService() {
91 return dataObjectService;
92 }
93
94 public void setDataObjectService(DataObjectService dataObjectService) {
95 this.dataObjectService = dataObjectService;
96 }
97
98 @Override
99 @Deprecated
100 public QueryByCriteria.Builder generateCriteria(Class<?> type, Map<String, String> formProps, boolean usePrimaryKeysOnly) {
101 if (usePrimaryKeysOnly) {
102 return getCollectionCriteriaFromMapUsingPrimaryKeysOnly(type, instantiateLookupDataObject(type), formProps).toQueryBuilder();
103 } else {
104 return getCollectionCriteriaFromMap(type, instantiateLookupDataObject(type), formProps).toQueryBuilder();
105 }
106 }
107
108 @Override
109 public QueryByCriteria.Builder generateCriteria(Class<?> type, Map<String, String> formProps,
110 List<String> wildcardAsLiteralPropertyNames, boolean usePrimaryKeysOnly) {
111 if (usePrimaryKeysOnly) {
112 return getCollectionCriteriaFromMapUsingPrimaryKeysOnly(type, instantiateLookupDataObject(type), formProps,
113 wildcardAsLiteralPropertyNames).toQueryBuilder();
114 } else {
115 return getCollectionCriteriaFromMap(type, instantiateLookupDataObject(type), formProps, wildcardAsLiteralPropertyNames).toQueryBuilder();
116 }
117 }
118
119 @Override
120 public QueryByCriteria.Builder createObjectCriteriaFromMap(Object example, Map<String, String> formProps) {
121 Predicates criteria = new Predicates();
122
123
124 for (Map.Entry<String, String> formProp : formProps.entrySet()) {
125
126 String propertyName = formProp.getKey();
127 String searchValue = "";
128 if (formProp.getValue() != null) {
129 searchValue = formProp.getValue();
130 }
131
132 Object instanObject = instantiateLookupDataObject((Class<?>)example);
133 if (StringUtils.isNotBlank(searchValue) & PropertyUtils.isWriteable(instanObject, propertyName)) {
134 Class<?> propertyType = getPropertyType(instanObject, propertyName);
135 if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType) ) {
136 addEqualNumeric(criteria, propertyName, propertyType, searchValue);
137 } else if (TypeUtils.isTemporalClass(propertyType)) {
138 addEqualTemporal(criteria, propertyName, searchValue);
139 } else {
140 addEqual(criteria, propertyName, searchValue);
141 }
142 }
143 }
144
145 return criteria.toQueryBuilder();
146 }
147
148
149
150
151
152
153
154 protected Object instantiateLookupDataObject(Class<?> type) {
155 Validate.notNull(type, "DataObject type passed to lookup was null");
156 try {
157 return type.newInstance();
158 } catch (IllegalAccessException e) {
159 throw new RuntimeException("Could not create instance of " + type, e);
160 } catch (InstantiationException e) {
161 throw new RuntimeException("Could not create instance of " + type, e);
162 }
163 }
164
165 protected boolean createCriteria(Object example, String searchValue, String propertyName, Predicates criteria) {
166 return createCriteria(example, searchValue, propertyName, false, false, criteria);
167 }
168
169 public boolean createCriteria(Object example, String searchValue, String propertyName, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Predicates criteria) {
170 return createCriteria(example, searchValue, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral,
171 criteria, null);
172 }
173
174 @Deprecated
175 protected boolean createCriteria(Object example, String searchValue, String propertyName, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Predicates criteria, Map<String, String> searchValues) {
176
177 if (StringUtils.isBlank(searchValue) || !isWriteable(example, propertyName)) {
178 return false;
179 }
180
181
182 Class<?> propertyType = getPropertyType(example, propertyName);
183 if (propertyType == null) {
184
185
186 propertyType = String.class;
187 }
188
189
190 if (example instanceof InactivatableFromTo) {
191 if (KRADPropertyConstants.ACTIVE.equals(propertyName)) {
192 addInactivateableFromToActiveCriteria(example, searchValue, criteria, searchValues);
193 } else if (KRADPropertyConstants.CURRENT.equals(propertyName)) {
194 addInactivateableFromToCurrentCriteria(example, searchValue, criteria, searchValues);
195 } else if (!KRADPropertyConstants.ACTIVE_AS_OF_DATE.equals(propertyName)) {
196 addCriteria(propertyName, searchValue, propertyType, caseInsensitive,
197 treatWildcardsAndOperatorsAsLiteral, criteria);
198 }
199 } else {
200 addCriteria(propertyName, searchValue, propertyType, caseInsensitive, treatWildcardsAndOperatorsAsLiteral,
201 criteria);
202 }
203
204 return true;
205 }
206
207
208
209
210
211
212
213
214
215
216 @Deprecated
217 protected Predicates getCollectionCriteriaFromMap(Class<?> type, Object example, Map<String, String> formProps) {
218 Predicates criteria = new Predicates();
219 for (String propertyName : formProps.keySet()) {
220 boolean caseInsensitive = determineIfAttributeSearchShouldBeCaseInsensitive(type, propertyName);
221 boolean treatWildcardsAndOperatorsAsLiteral = doesLookupFieldTreatWildcardsAndOperatorsAsLiteral(type, propertyName);
222 String searchValue = formProps.get(propertyName);
223 addCriteriaForPropertyValues(example, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria, formProps, searchValue);
224 }
225
226 return criteria;
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 protected Predicates getCollectionCriteriaFromMap(Class<?> type, Object example, Map<String, String> formProps, List<String> wildcardAsLiteralPropertyNames) {
246 Predicates criteria = new Predicates();
247 for (String propertyName : formProps.keySet()) {
248 boolean caseInsensitive = determineIfAttributeSearchShouldBeCaseInsensitive(type, propertyName);
249 boolean treatWildcardsAndOperatorsAsLiteral = wildcardAsLiteralPropertyNames.contains(propertyName);
250 String searchValue = formProps.get(propertyName);
251 addCriteriaForPropertyValues(example, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria, formProps, searchValue);
252 }
253
254 return criteria;
255 }
256
257
258
259
260
261
262
263
264
265
266 protected boolean determineIfAttributeSearchShouldBeCaseInsensitive(Class<?> type, String propertyName) {
267 Boolean caseInsensitive = Boolean.TRUE;
268 if (dataDictionaryService.isAttributeDefined(type, propertyName)) {
269
270
271
272 caseInsensitive = !dataDictionaryService.getAttributeForceUppercase(type, propertyName);
273 }
274 if (caseInsensitive == null) {
275 caseInsensitive = Boolean.TRUE;
276 }
277
278 return caseInsensitive.booleanValue();
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292 protected boolean addCriteriaForPropertyValues(Object example, String propertyName, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Predicates criteria, Map formProps, String... searchValues) {
293 for (String searchValue: searchValues) {
294 if (!createCriteria(example, searchValue, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria, formProps)) {
295 return false;
296 }
297 }
298
299 return true;
300 }
301
302 @Deprecated
303 protected Predicates getCollectionCriteriaFromMapUsingPrimaryKeysOnly(Class<?> type, Object dataObject, Map<String, String> formProps) {
304 Predicates criteria = new Predicates();
305 List<String> pkFields = listPrimaryKeyFieldNames(type);
306 for (String pkFieldName : pkFields) {
307 String pkValue = formProps.get(pkFieldName);
308 if (StringUtils.isBlank(pkValue)) {
309 throw new RuntimeException("Missing pk value for field " + pkFieldName + " when a search based on PK values only is performed.");
310 }
311 else {
312 for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) {
313 if (pkValue.contains(op.op())) {
314 throw new RuntimeException("Value \"" + pkValue + "\" for PK field " + pkFieldName + " contains wildcard/operator characters.");
315 }
316 }
317 }
318
319 boolean treatWildcardsAndOperatorsAsLiteral = doesLookupFieldTreatWildcardsAndOperatorsAsLiteral(type,
320 pkFieldName);
321 createCriteria(dataObject, pkValue, pkFieldName, false, treatWildcardsAndOperatorsAsLiteral, criteria);
322 }
323
324 return criteria;
325 }
326
327 protected Predicates getCollectionCriteriaFromMapUsingPrimaryKeysOnly(Class<?> type, Object dataObject, Map<String, String> formProps, List<String> wildcardAsLiteralPropertyNames) {
328 Predicates criteria = new Predicates();
329 List<String> pkFields = listPrimaryKeyFieldNames(type);
330 for (String pkFieldName : pkFields) {
331 String pkValue = formProps.get(pkFieldName);
332 if (StringUtils.isBlank(pkValue)) {
333 throw new RuntimeException("Missing pk value for field " + pkFieldName + " when a search based on PK values only is performed.");
334 }
335 else {
336 for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) {
337 if (pkValue.contains(op.op())) {
338 throw new RuntimeException("Value \"" + pkValue + "\" for PK field " + pkFieldName + " contains wildcard/operator characters.");
339 }
340 }
341 }
342 boolean treatWildcardsAndOperatorsAsLiteral = wildcardAsLiteralPropertyNames.contains(pkFieldName);
343 createCriteria(dataObject, pkValue, pkFieldName, false, treatWildcardsAndOperatorsAsLiteral, criteria);
344 }
345
346 return criteria;
347 }
348
349 @Deprecated
350 protected boolean doesLookupFieldTreatWildcardsAndOperatorsAsLiteral(Class<?> type, String fieldName) {
351
352 Map<String, String> indexKey = new HashMap<String, String>();
353 indexKey.put(UifParameters.VIEW_NAME, UifConstants.DEFAULT_VIEW_NAME);
354 indexKey.put(UifParameters.DATA_OBJECT_CLASS_NAME, type.getName());
355
356
357 View view = getDataDictionaryService().getDataDictionary().getViewByTypeIndex(UifConstants.ViewType.LOOKUP, indexKey);
358 if (view != null && view instanceof LookupView) {
359 LookupView lookupView = (LookupView) view;
360
361 List<Component> criteriaFields = lookupView.getCriteriaFields();
362 for (Component criteriaField: criteriaFields) {
363 if (criteriaField instanceof LookupInputField) {
364 LookupInputField lookupInputField = (LookupInputField) criteriaField;
365 if (fieldName.equals(lookupInputField.getPropertyName())) {
366
367 return lookupInputField.isDisableWildcardsAndOperators();
368 }
369 }
370 }
371 }
372
373 return false;
374 }
375
376
377
378
379
380 protected Number cleanNumeric(String value, Class<?> propertyType) {
381 String cleanedValue = value.replaceAll("[^-0-9.]", "");
382
383 if (cleanedValue.lastIndexOf('-') > 0) {
384 if (cleanedValue.charAt(0) == '-') {
385 cleanedValue = "-" + cleanedValue.replaceAll("-", "");
386 } else {
387 cleanedValue = cleanedValue.replaceAll("-", "");
388 }
389 }
390
391 int decimalLoc = cleanedValue.lastIndexOf('.');
392 if (cleanedValue.indexOf('.') != decimalLoc) {
393 cleanedValue = cleanedValue.substring(0, decimalLoc).replaceAll("\\.", "") + cleanedValue.substring(decimalLoc);
394 }
395 Object rv = KRADUtils.hydrateAttributeValue(propertyType, cleanedValue);
396
397 if( !(rv instanceof Number)) {
398 throw new NumberFormatException("Value: " + cleanedValue + " cannot be converted into number type");
399 }
400
401 return (Number) rv;
402 }
403
404
405
406 protected void addOrCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Predicates criteria) {
407 addLogicalOperatorCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, SearchOperator.OR.op());
408 }
409
410 protected void addAndCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Predicates criteria) {
411 addLogicalOperatorCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, SearchOperator.AND.op());
412 }
413
414
415
416
417 protected void addCriteria(String propertyName, String propertyValue, Class<?> propertyType, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Predicates criteria) {
418 propertyName = parsePropertyName(criteria, propertyName);
419
420 if (!treatWildcardsAndOperatorsAsLiteral && StringUtils.contains(propertyValue, SearchOperator.OR.op())) {
421 addOrCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria);
422 return;
423 }
424
425 if (!treatWildcardsAndOperatorsAsLiteral && StringUtils.contains(propertyValue, SearchOperator.AND.op())) {
426 addAndCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria);
427 return;
428 }
429
430 if (StringUtils.equalsIgnoreCase(propertyValue, SearchOperator.NULL.op()) || StringUtils.equalsIgnoreCase(propertyValue, SearchOperator.NOT_NULL.op())) {
431
432 if (StringUtils.contains(propertyValue, SearchOperator.NOT.op())) {
433 addIsNotNull(criteria, propertyName);
434 }
435 else {
436 addIsNull(criteria, propertyName);
437 }
438 }
439 else if (TypeUtils.isStringClass(propertyType)) {
440
441
442
443
444
445
446
447
448 if (!treatWildcardsAndOperatorsAsLiteral && StringUtils.contains(propertyValue,
449 SearchOperator.NOT.op())) {
450 addNotCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria);
451 } else if (
452 !treatWildcardsAndOperatorsAsLiteral && propertyValue != null && (
453 StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())
454 || propertyValue.startsWith(">")
455 || propertyValue.startsWith("<") ) ) {
456 addStringRangeCriteria(propertyName, propertyValue, caseInsensitive, criteria);
457 } else {
458 if (treatWildcardsAndOperatorsAsLiteral) {
459 propertyValue = StringUtils.replace(propertyValue, "*", "\\*");
460 propertyValue = StringUtils.replace(propertyValue, "%", "\\%");
461 propertyValue = StringUtils.replace(propertyValue, "?", "\\?");
462 propertyValue = StringUtils.replace(propertyValue, "_", "\\_");
463 }
464 addLike(criteria, propertyName, propertyValue, caseInsensitive);
465 }
466 } else if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType)) {
467 addNumericRangeCriteria(propertyName, propertyValue, propertyType, treatWildcardsAndOperatorsAsLiteral, criteria);
468 } else if (TypeUtils.isTemporalClass(propertyType)) {
469 addDateRangeCriteria(propertyName, propertyValue, treatWildcardsAndOperatorsAsLiteral, criteria);
470 } else if (TypeUtils.isBooleanClass(propertyType)) {
471 addEqualToBoolean(criteria, propertyName, propertyValue);
472 } else {
473 LOG.error("not adding criterion for: " + propertyName + "," + propertyType + "," + propertyValue);
474 }
475 }
476
477 protected void addNotCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Predicates criteria) {
478 String[] splitPropVal = StringUtils.split(propertyValue, SearchOperator.NOT.op());
479
480 try {
481 int strLength = splitPropVal.length;
482
483 if (strLength == 0) {
484 throw new IllegalArgumentException("Improper syntax of NOT operator in " + propertyName);
485 }
486
487 if (strLength > 1) {
488 String expandedNot = SearchOperator.NOT + StringUtils.join(splitPropVal, SearchOperator.AND.op() + SearchOperator.NOT.op());
489
490 addCriteria(propertyName, expandedNot, propertyType, caseInsensitive, false, criteria);
491 } else {
492
493 addNotLike(criteria, propertyName, splitPropVal[0], caseInsensitive);
494 }
495 } catch (IllegalArgumentException ex) {
496 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_NOT_SYNTAX, propertyName);
497 }
498 }
499
500
501
502
503 protected void addDateRangeCriteria(String propertyName, String propertyValue, boolean treatWildcardsAndOperatorsAsLiteral, Predicates criteria) {
504 try {
505 if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) {
506 if (treatWildcardsAndOperatorsAsLiteral) {
507 throw new RuntimeException("Wildcards and operators are not allowed on this date field: " + propertyName);
508 }
509 String[] rangeValues = StringUtils.split(propertyValue, SearchOperator.BETWEEN.op());
510 if (rangeValues.length < 2) {
511 throw new IllegalArgumentException("Improper syntax of BETWEEN operator in " + propertyName);
512 }
513
514 addBetween(criteria, propertyName, parseDate(LookupUtils.scrubQueryCharacters(rangeValues[0])), parseDateUpperBound(LookupUtils.scrubQueryCharacters(rangeValues[1])));
515 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
516 if (treatWildcardsAndOperatorsAsLiteral) {
517 throw new RuntimeException("Wildcards and operators are not allowed on this date field: " + propertyName);
518 }
519 addGreaterThanOrEqual(criteria, propertyName, parseDate(LookupUtils.scrubQueryCharacters(propertyValue)));
520 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
521 if (treatWildcardsAndOperatorsAsLiteral) {
522 throw new RuntimeException("Wildcards and operators are not allowed on this date field: " + propertyName);
523 }
524 addLessThanOrEqual(criteria, propertyName, parseDateUpperBound(LookupUtils.scrubQueryCharacters(propertyValue)));
525 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN.op())) {
526 if (treatWildcardsAndOperatorsAsLiteral) {
527 throw new RuntimeException("Wildcards and operators are not allowed on this date field: " + propertyName);
528 }
529 addGreaterThan(criteria, propertyName, parseDate(LookupUtils.scrubQueryCharacters(propertyValue)));
530 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN.op())) {
531 if (treatWildcardsAndOperatorsAsLiteral) {
532 throw new RuntimeException("Wildcards and operators are not allowed on this date field: " + propertyName);
533 }
534 addLessThan(criteria, propertyName, parseDate(LookupUtils.scrubQueryCharacters(propertyValue)));
535 } else {
536
537 addBetween(criteria, propertyName, parseDate(LookupUtils.scrubQueryCharacters(propertyValue)),
538 parseDateUpperBound(LookupUtils.scrubQueryCharacters(propertyValue)));
539 }
540 } catch (ParseException ex) {
541 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_DATE, propertyValue);
542 } catch (IllegalArgumentException ex) {
543 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_BETWEEN_SYNTAX, propertyName);
544 }
545 }
546
547
548
549
550 protected void addNumericRangeCriteria(String propertyName, String propertyValue, Class<?> propertyType, boolean treatWildcardsAndOperatorsAsLiteral, Predicates criteria) {
551 try {
552 if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) {
553 if (treatWildcardsAndOperatorsAsLiteral) {
554 throw new RuntimeException("Cannot use wildcards and operators on numeric field " + propertyName);
555 }
556 String[] rangeValues = StringUtils.split(propertyValue, SearchOperator.BETWEEN.op());
557 if (rangeValues.length < 2) {
558 throw new IllegalArgumentException("Improper syntax of BETWEEN operator in " + propertyName);
559 }
560
561 addBetween(criteria, propertyName, cleanNumeric(rangeValues[0], propertyType), cleanNumeric(rangeValues[1], propertyType));
562 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
563 if (treatWildcardsAndOperatorsAsLiteral) {
564 throw new RuntimeException("Cannot use wildcards and operators on numeric field " + propertyName);
565 }
566 addGreaterThanOrEqual(criteria, propertyName, cleanNumeric(propertyValue, propertyType));
567 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
568 if (treatWildcardsAndOperatorsAsLiteral) {
569 throw new RuntimeException("Cannot use wildcards and operators on numeric field " + propertyName);
570 }
571 addLessThanOrEqual(criteria, propertyName, cleanNumeric(propertyValue,propertyType));
572 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN.op())) {
573 if (treatWildcardsAndOperatorsAsLiteral) {
574 throw new RuntimeException("Cannot use wildcards and operators on numeric field " + propertyName);
575 }
576 addGreaterThan(criteria, propertyName, cleanNumeric(propertyValue, propertyType));
577 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN.op())) {
578 if (treatWildcardsAndOperatorsAsLiteral) {
579 throw new RuntimeException("Cannot use wildcards and operators on numeric field " + propertyName);
580 }
581 addLessThan(criteria, propertyName, cleanNumeric(propertyValue, propertyType));
582 } else {
583 addEqual(criteria, propertyName, cleanNumeric(propertyValue,propertyType));
584 }
585 } catch (NumberFormatException ex) {
586 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_NUMBER, propertyValue);
587 } catch (IllegalArgumentException ex) {
588 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_BETWEEN_SYNTAX, propertyName);
589 }
590 }
591
592
593
594
595 protected void addStringRangeCriteria(String propertyName, String propertyValue, boolean caseInsensitive, Predicates criteria) {
596 try {
597 if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) {
598 String[] rangeValues = StringUtils.split(propertyValue, SearchOperator.BETWEEN.op());
599 if (rangeValues.length < 2) {
600 throw new IllegalArgumentException("Improper syntax of BETWEEN operator in " + propertyName);
601 }
602
603 addBetween(criteria, propertyName, rangeValues[0], rangeValues[1], caseInsensitive);
604 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
605 addGreaterThanOrEqual(criteria, propertyName, LookupUtils.scrubQueryCharacters(propertyValue), caseInsensitive);
606 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
607 addLessThanOrEqual(criteria, propertyName, LookupUtils.scrubQueryCharacters(propertyValue), caseInsensitive);
608 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN.op())) {
609 addGreaterThan(criteria, propertyName, LookupUtils.scrubQueryCharacters(propertyValue), caseInsensitive);
610 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN.op())) {
611 addLessThan(criteria, propertyName, LookupUtils.scrubQueryCharacters(propertyValue), caseInsensitive);
612 } else {
613 addEqual(criteria, propertyName, LookupUtils.scrubQueryCharacters(propertyValue), caseInsensitive);
614 }
615 } catch (IllegalArgumentException ex) {
616 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_BETWEEN_SYNTAX, propertyName);
617 }
618 }
619
620
621
622
623
624
625
626
627
628 protected void addInactivateableFromToActiveCriteria(Object example, String activeSearchValue, Predicates criteria, Map<String, String> searchValues) {
629 Timestamp activeTimestamp = LookupUtils.getActiveDateTimestampForCriteria(searchValues);
630
631 String activeBooleanStr = (String) (new OjbCharBooleanConversion()).javaToSql(activeSearchValue);
632 if (OjbCharBooleanConversion.DATABASE_BOOLEAN_TRUE_STRING_REPRESENTATION.equals(activeBooleanStr)) {
633
634 Predicates criteriaBeginDate = new Predicates();
635 addLessThanOrEqual(criteriaBeginDate, KRADPropertyConstants.ACTIVE_FROM_DATE, activeTimestamp);
636
637 Predicates criteriaBeginDateNull = new Predicates();
638 addIsNull(criteriaBeginDateNull, KRADPropertyConstants.ACTIVE_FROM_DATE);
639 addOr(criteriaBeginDate, criteriaBeginDateNull);
640
641 addAnd(criteria, criteriaBeginDate);
642
643 Predicates criteriaEndDate = new Predicates();
644 addGreaterThan(criteriaEndDate, KRADPropertyConstants.ACTIVE_TO_DATE, activeTimestamp);
645
646 Predicates criteriaEndDateNull = new Predicates();
647 addIsNull(criteriaEndDateNull, KRADPropertyConstants.ACTIVE_TO_DATE);
648 addOr(criteriaEndDate, criteriaEndDateNull);
649
650 addAnd(criteria, criteriaEndDate);
651 }
652 else if (OjbCharBooleanConversion.DATABASE_BOOLEAN_FALSE_STRING_REPRESENTATION.equals(activeBooleanStr)) {
653
654 Predicates criteriaNonActive = new Predicates();
655 addGreaterThan(criteriaNonActive, KRADPropertyConstants.ACTIVE_FROM_DATE, activeTimestamp);
656
657
658
659
660
661
662
663
664
665
666
667
668 Predicates criteriaEndDate = new Predicates();
669 addLessThanOrEqual(criteriaEndDate, KRADPropertyConstants.ACTIVE_TO_DATE, activeTimestamp);
670 addOr(criteriaNonActive, criteriaEndDate);
671
672 addAnd(criteria, criteriaNonActive);
673 }
674 }
675
676
677
678
679
680 protected void addLogicalOperatorCriteria(String propertyName, String propertyValue, Class<?> propertyType, boolean caseInsensitive, Predicates criteria, String splitValue) {
681 String[] splitPropVal = StringUtils.split(propertyValue, splitValue);
682
683 Predicates subCriteria;
684 if (SearchOperator.OR.op().equals(splitValue)) {
685 subCriteria = new OrPredicates();
686 } else if (SearchOperator.AND.op().equals(splitValue)) {
687 subCriteria = new Predicates();
688 } else {
689 throw new IllegalArgumentException("Invalid split value: " + splitValue);
690 }
691 for (int i = 0; i < splitPropVal.length; i++) {
692 Predicates predicate = new Predicates();
693
694 addCriteria(propertyName, splitPropVal[i], propertyType, caseInsensitive, false, subCriteria);
695 }
696 addAnd(criteria, subCriteria);
697 }
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765 protected java.sql.Date parseDate(String dateString) throws ParseException {
766 dateString = dateString.trim();
767 return dateTimeService.convertToSqlDate(dateString);
768 }
769
770 protected java.sql.Date parseDateUpperBound(String dateString) throws ParseException {
771 dateString = dateString.trim();
772 return dateTimeService.convertToSqlDateUpperBound(dateString);
773 }
774
775 protected List<String> listPrimaryKeyFieldNames(Class<?> type) {
776 return getDataObjectService().getMetadataRepository().getMetadata(type).getPrimaryKeyAttributeNames();
777 }
778
779 protected Class<?> getPropertyType(Object example, String propertyName) {
780 return getDataObjectService().wrap(example).getPropertyType(propertyName);
781 }
782
783
784
785
786
787
788
789
790
791
792
793
794 protected boolean isWriteable(Object o, String p) throws IllegalArgumentException {
795 if (null == o || null == p) {
796 throw new IllegalArgumentException("Cannot check writable status with null arguments.");
797 }
798
799 boolean b = false;
800
801
802 if (!(PropertyUtils.isWriteable(o, p))) {
803
804
805
806 if (-1 != p.indexOf('.')) {
807
808 String[] parts = p.split("\\.");
809
810
811 Class<?> c = getPropertyType(o, parts[0]);
812
813 Object i = null;
814
815
816
817 if (Collection.class.isAssignableFrom(c)) {
818 c = getDataObjectService().getMetadataRepository().getMetadata(o.getClass()).getCollection(parts[0]).getRelatedType();
819 }
820
821
822 try {
823 i = c.newInstance();
824 StringBuffer sb = new StringBuffer();
825 for (int x = 1; x < parts.length; x++) {
826 sb.append(1 == x ? "" : ".").append(parts[x]);
827 }
828 b = isWriteable(i, sb.toString());
829 } catch (InstantiationException ie) {
830 LOG.info(ie);
831 } catch (IllegalAccessException iae) {
832 LOG.info(iae);
833 }
834 }
835 } else {
836 b = true;
837 }
838
839 return b;
840 }
841
842 protected void addEqualNumeric(Predicates criteria, String propertyName, Class<?> propertyClass, String searchValue) {
843 Predicate pred;
844 if (propertyClass.equals(Long.class)) {
845 pred = PredicateFactory.equal(propertyName, new Long(searchValue));
846 } else {
847 pred = PredicateFactory.equal(propertyName, new Integer(searchValue));
848 }
849
850 criteria.addPredicate(pred);
851 }
852
853 protected void addEqualTemporal(Predicates criteria, String propertyName, String searchValue) {
854 try {
855 criteria.addPredicate(PredicateFactory.equal(propertyName, parseDate(LookupUtils.scrubQueryCharacters(
856 searchValue))));
857 } catch (ParseException ex) {
858 GlobalVariables.getMessageMap().putError("lookupCriteria[" + propertyName + "]", RiceKeyConstants.ERROR_DATE, searchValue);
859 }
860 }
861
862 protected void addEqual(Predicates criteria, String propertyName, Object searchValue) {
863 criteria.addPredicate(PredicateFactory.equal(propertyName, searchValue));
864 }
865
866 protected void addIsNull(Predicates criteria, String propertyName) {
867 criteria.addPredicate(PredicateFactory.isNull(propertyName));
868 }
869
870 protected void addIsNotNull(Predicates criteria, String propertyName) {
871 criteria.addPredicate(PredicateFactory.isNotNull(propertyName));
872 }
873
874 protected void addLike(Predicates criteria, String propertyName, String propertyValue) {
875 criteria.addPredicate(PredicateFactory.like(propertyName, propertyValue));
876 }
877
878 protected void addNotLike(Predicates criteria, String propertyName, String propertyValue) {
879 criteria.addPredicate(PredicateFactory.notLike(propertyName, propertyValue));
880 }
881
882 protected void addEqualToBoolean(Predicates criteria, String propertyName, String propertyValue) {
883 String temp = LookupUtils.scrubQueryCharacters(propertyValue);
884 criteria.addPredicate(PredicateFactory.equal(propertyName, ("Y".equalsIgnoreCase(temp) || "T".equalsIgnoreCase(
885 temp) || "1".equalsIgnoreCase(temp) || "true".equalsIgnoreCase(temp))));
886 }
887
888
889
890
891
892
893
894
895 protected String uppercasePropertyName(String propertyName) {
896
897 return dbPlatform.getUpperCaseFunction() + "(" + propertyName + ")";
898 }
899
900 protected void addAnd(Predicates criteria, Predicates criteria2) {
901 criteria.and(criteria2);
902 }
903
904 protected void addLessThan(Predicates criteria, String propertyName, Object propertyValue) {
905 criteria.addPredicate(PredicateFactory.lessThan(propertyName, propertyValue));
906 }
907
908 protected void addLessThanOrEqual(Predicates criteria, String propertyName, Object propertyValue) {
909 criteria.addPredicate(PredicateFactory.lessThanOrEqual(propertyName, propertyValue));
910 }
911
912 protected void addGreaterThan(Predicates criteria, String propertyName, Object propertyValue) {
913 criteria.addPredicate(PredicateFactory.greaterThan(propertyName, propertyValue));
914 }
915
916 protected void addGreaterThanOrEqual(Predicates criteria, String propertyName, Object propertyValue) {
917 criteria.addPredicate(PredicateFactory.greaterThanOrEqual(propertyName, propertyValue));
918 }
919
920 protected void addBetween(Predicates criteria, String propertyName, Object value1, Object value2) {
921 criteria.addPredicate(PredicateFactory.between(propertyName, value1, value2));
922 }
923
924 protected void addOr(Predicates criteria, Predicates criteria2) {
925 criteria.or(criteria2);
926 }
927
928 protected void addEqual(Predicates criteria, String propertyName, String searchValue, boolean caseInsensitive) {
929 if (caseInsensitive) {
930 criteria.addPredicate(PredicateFactory.equalIgnoreCase(propertyName, searchValue));
931 } else {
932 addEqual(criteria, propertyName, searchValue);
933 }
934 }
935
936 protected void addGreaterThan(Predicates criteria, String propertyName, String propertyValue, boolean caseInsensitive) {
937
938 addGreaterThan(criteria, propertyName, propertyValue);
939 }
940
941 protected void addGreaterThanOrEqual(Predicates criteria, String propertyName, String propertyValue, boolean caseInsensitive) {
942
943 addGreaterThanOrEqual(criteria, propertyName, propertyValue);
944 }
945
946 protected void addLessThan(Predicates criteria, String propertyName, String propertyValue, boolean caseInsensitive) {
947
948 addLessThan(criteria, propertyName, propertyValue);
949 }
950
951 protected void addLessThanOrEqual(Predicates criteria, String propertyName, String propertyValue, boolean caseInsensitive) {
952
953 addLessThanOrEqual(criteria, propertyName, propertyValue);
954 }
955
956 protected void addLike(Predicates criteria, String propertyName, String propertyValue, boolean caseInsensitive) {
957 if ( caseInsensitive ) {
958 criteria.addPredicate(PredicateFactory.likeIgnoreCase(propertyName, propertyValue));
959 } else {
960 addLike(criteria, propertyName, propertyValue);
961 }
962 }
963
964 protected void addBetween(Predicates criteria, String propertyName, String value1, String value2, boolean caseInsensitive) {
965
966 addBetween(criteria, propertyName, value1, value2);
967 }
968
969 protected void addNotLike(Predicates criteria, String propertyName, String propertyValue, boolean caseInsensitive) {
970
971 addNotLike(criteria, propertyName, propertyValue);
972 }
973
974 protected String parsePropertyName(Predicates criteria, String fullyQualifiedPropertyName) {
975 return fullyQualifiedPropertyName;
976 }
977
978 protected void addInactivateableFromToCurrentCriteria(Object example, String currentSearchValue, Predicates criteria, Map searchValues) {
979
980
981 }
982
983
984
985
986
987 static class Predicates {
988
989 protected List<Predicate> predicates = new ArrayList<Predicate>();
990
991 void addPredicate(Predicate predicate) {
992 predicates.add(predicate);
993 }
994
995 void or(Predicates pred) {
996 List<Predicate> newpredicates = new ArrayList<Predicate>();
997 newpredicates.add(PredicateFactory.or(getCriteriaPredicate(), pred.getCriteriaPredicate()));
998 predicates = newpredicates;
999 }
1000
1001 void and(Predicates pred) {
1002 addPredicate(pred.getCriteriaPredicate());
1003 }
1004
1005 protected Predicate getCriteriaPredicate() {
1006 if (predicates.size() == 1) {
1007 return predicates.get(0);
1008 }
1009
1010 return PredicateFactory.and(predicates.toArray(new Predicate[predicates.size()]));
1011 }
1012
1013 QueryByCriteria.Builder toQueryBuilder() {
1014 QueryByCriteria.Builder qbc = QueryByCriteria.Builder.create();
1015 qbc.setPredicates(getCriteriaPredicate());
1016 return qbc;
1017 }
1018 }
1019
1020 static class OrPredicates extends Predicates {
1021
1022 @Override
1023 protected Predicate getCriteriaPredicate() {
1024 if (predicates.size() == 1) {
1025 return predicates.get(0);
1026 }
1027
1028 return PredicateFactory.or(predicates.toArray(new Predicate[predicates.size()]));
1029 }
1030
1031 }
1032
1033 }