1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.data.jpa;
17
18 import java.sql.Timestamp;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24
25 import org.joda.time.DateTime;
26 import org.kuali.rice.core.api.criteria.AndPredicate;
27 import org.kuali.rice.core.api.criteria.CompositePredicate;
28 import org.kuali.rice.core.api.criteria.CriteriaValue;
29 import org.kuali.rice.core.api.criteria.EqualIgnoreCasePredicate;
30 import org.kuali.rice.core.api.criteria.EqualPredicate;
31 import org.kuali.rice.core.api.criteria.ExistsSubQueryPredicate;
32 import org.kuali.rice.core.api.criteria.GreaterThanOrEqualPredicate;
33 import org.kuali.rice.core.api.criteria.GreaterThanPredicate;
34 import org.kuali.rice.core.api.criteria.InIgnoreCasePredicate;
35 import org.kuali.rice.core.api.criteria.InPredicate;
36 import org.kuali.rice.core.api.criteria.LessThanOrEqualPredicate;
37 import org.kuali.rice.core.api.criteria.LessThanPredicate;
38 import org.kuali.rice.core.api.criteria.LikeIgnoreCasePredicate;
39 import org.kuali.rice.core.api.criteria.LikePredicate;
40 import org.kuali.rice.core.api.criteria.MultiValuedPredicate;
41 import org.kuali.rice.core.api.criteria.NotEqualIgnoreCasePredicate;
42 import org.kuali.rice.core.api.criteria.NotEqualPredicate;
43 import org.kuali.rice.core.api.criteria.NotInIgnoreCasePredicate;
44 import org.kuali.rice.core.api.criteria.NotInPredicate;
45 import org.kuali.rice.core.api.criteria.NotLikeIgnoreCasePredicate;
46 import org.kuali.rice.core.api.criteria.NotLikePredicate;
47 import org.kuali.rice.core.api.criteria.NotNullPredicate;
48 import org.kuali.rice.core.api.criteria.NullPredicate;
49 import org.kuali.rice.core.api.criteria.OrPredicate;
50 import org.kuali.rice.core.api.criteria.OrderByField;
51 import org.kuali.rice.core.api.criteria.OrderDirection;
52 import org.kuali.rice.core.api.criteria.Predicate;
53 import org.kuali.rice.core.api.criteria.PredicateFactory;
54 import org.kuali.rice.core.api.criteria.PropertyPathPredicate;
55 import org.kuali.rice.core.api.criteria.QueryByCriteria;
56 import org.kuali.rice.core.api.criteria.SingleValuedPredicate;
57 import org.kuali.rice.core.api.criteria.SubQueryPredicate;
58 import org.kuali.rice.krad.data.jpa.NativeJpaQueryTranslator.TranslationContext;
59
60
61
62
63
64
65 @SuppressWarnings("rawtypes")
66 abstract class QueryTranslatorBase<C, Q> implements QueryTranslator<C, Q> {
67
68 public static final int MULTI_VALUE_CHUNK_SIZE = 1000;
69
70
71
72
73
74
75
76 protected abstract C createCriteria(Class entityClass);
77
78
79
80
81
82
83
84
85
86
87
88 protected abstract C createCriteriaForSubQuery(Class queryClazz, C parentContext);
89
90
91
92
93
94
95
96 protected abstract C createInnerCriteria(C parent);
97
98
99
100
101
102
103
104 protected abstract String genUpperFunc(String pp);
105
106
107
108
109
110
111
112 protected abstract void addNotNull(C criteria, String propertyPath);
113
114
115
116
117
118
119
120 protected abstract void addIsNull(C criteria, String propertyPath);
121
122
123
124
125
126
127
128
129 protected abstract void addEqualTo(C criteria, String propertyPath, Object value);
130
131
132
133
134
135
136
137
138 protected abstract void addGreaterOrEqualTo(C criteria, String propertyPath, Object value);
139
140
141
142
143
144
145
146
147 protected abstract void addGreaterThan(C criteria, String propertyPath, Object value);
148
149
150
151
152
153
154
155
156 protected abstract void addLessOrEqualTo(C criteria, String propertyPath, Object value);
157
158
159
160
161
162
163
164
165 protected abstract void addLessThan(C criteria, String propertyPath, Object value);
166
167
168
169
170
171
172
173
174 protected abstract void addLike(C criteria, String propertyPath, Object value);
175
176
177
178
179
180
181
182
183 protected abstract void addNotEqualTo(C criteria, String propertyPath, Object value);
184
185
186
187
188
189
190
191
192 protected abstract void addNotLike(C criteria, String propertyPath, Object value);
193
194
195
196
197
198
199
200
201
202
203
204 protected abstract void addNotLikeIgnoreCase(C criteria, String propertyPath, String value);
205
206
207
208
209
210
211
212
213
214
215
216 protected abstract void addIn(C criteria, String propertyPath, Collection values);
217
218
219
220
221
222
223
224
225 protected abstract void addNotIn(C criteria, String propertyPath, Collection values);
226
227
228
229
230
231
232
233 protected abstract void addAnd(C criteria, C inner);
234
235
236
237
238
239
240
241 protected abstract void addOr(C criteria, C inner);
242
243
244
245
246
247
248
249
250
251
252
253 protected abstract void addExistsSubquery(C criteria, String subQueryType, Predicate subQueryPredicate);
254
255
256
257
258
259
260
261
262 protected abstract void addOrderBy(C criteria, String propertyPath, boolean sortAscending);
263
264
265
266
267
268
269
270
271
272 protected void addEqualToIgnoreCase(C criteria, String propertyPath, String value) {
273 addEqualTo(criteria, genUpperFunc(propertyPath), value.toUpperCase());
274 }
275
276
277
278
279
280
281
282
283 protected void addNotEqualToIgnoreCase(C criteria, String propertyPath, String value) {
284 addNotEqualTo(criteria, genUpperFunc(propertyPath), value.toUpperCase());
285 }
286
287
288
289
290
291
292
293
294 protected void addLikeIgnoreCase(C criteria, String propertyPath, String value){
295 addLike(criteria, genUpperFunc(propertyPath),value.toUpperCase());
296 }
297
298
299
300
301
302
303 protected static class UnsupportedPredicateException extends RuntimeException {
304 private static final long serialVersionUID = 1L;
305
306
307
308
309
310
311
312 protected UnsupportedPredicateException(Predicate predicate) {
313 super("Unsupported predicate [" + String.valueOf(predicate) + "]");
314 }
315 }
316
317
318
319
320 @Override
321 public C translateCriteria(Class queryClazz, QueryByCriteria qbc) {
322 final C parent = createCriteria(queryClazz);
323
324 if (qbc.getPredicate() != null) {
325 addPredicate(qbc.getPredicate(), parent);
326 }
327
328 if (!qbc.getOrderByFields().isEmpty()) {
329 addOrderBy(qbc.getOrderByFields(), parent);
330 }
331
332 return parent;
333 }
334
335
336
337
338
339
340
341 protected void addOrderBy(List<OrderByField> orderByFields, C parent) {
342 for (OrderByField field : orderByFields) {
343 addOrderBy(parent, field.getFieldName(), OrderDirection.ASCENDING.equals(field.getOrderDirection()));
344 }
345 }
346
347
348
349
350
351
352
353 protected void addPredicate(Predicate p, C parent) {
354 if (p instanceof PropertyPathPredicate) {
355 final String pp = ((PropertyPathPredicate) p).getPropertyPath();
356 if (p instanceof NotNullPredicate) {
357 addNotNull(parent, pp);
358 } else if (p instanceof NullPredicate) {
359 addIsNull(parent, pp);
360 } else if (p instanceof SingleValuedPredicate) {
361 addSingleValuePredicate((SingleValuedPredicate) p, parent);
362 } else if (p instanceof MultiValuedPredicate) {
363 addMultiValuePredicate((MultiValuedPredicate) p, parent);
364 } else {
365 throw new UnsupportedPredicateException(p);
366 }
367 } else if (p instanceof CompositePredicate) {
368 addCompositePredicate((CompositePredicate) p, parent);
369 } else if (p instanceof SubQueryPredicate) {
370 addSubQueryPredicate((SubQueryPredicate) p, parent);
371 } else {
372 throw new UnsupportedPredicateException(p);
373 }
374 }
375
376
377
378
379
380
381
382 protected void addSingleValuePredicate(SingleValuedPredicate p, C parent) {
383 final Object value = getVal(p.getValue());
384 final String pp = p.getPropertyPath();
385 if (p instanceof EqualPredicate) {
386 addEqualTo(parent, pp, value);
387 } else if (p instanceof EqualIgnoreCasePredicate) {
388 addEqualToIgnoreCase(parent, pp, (String) value);
389 } else if (p instanceof GreaterThanOrEqualPredicate) {
390 addGreaterOrEqualTo(parent, pp, value);
391 } else if (p instanceof GreaterThanPredicate) {
392 addGreaterThan(parent, pp, value);
393 } else if (p instanceof LessThanOrEqualPredicate) {
394 addLessOrEqualTo(parent, pp, value);
395 } else if (p instanceof LessThanPredicate) {
396 addLessThan(parent, pp, value);
397 } else if (p instanceof LikePredicate) {
398
399 addLike(parent, pp, value);
400 } else if(p instanceof LikeIgnoreCasePredicate){
401 addLikeIgnoreCase(parent,pp,(String)value);
402 } else if (p instanceof NotEqualPredicate) {
403 addNotEqualTo(parent, pp, value);
404 } else if (p instanceof NotEqualIgnoreCasePredicate) {
405 addNotEqualToIgnoreCase(parent, pp, (String) value);
406 } else if (p instanceof NotLikeIgnoreCasePredicate) {
407 addNotLikeIgnoreCase(parent, pp, (String) value);
408 } else if (p instanceof NotLikePredicate) {
409 addNotLike(parent, pp, value);
410 } else {
411 throw new UnsupportedPredicateException(p);
412 }
413 }
414
415
416
417
418
419
420
421 protected void addMultiValuePredicate(MultiValuedPredicate p, C parent) {
422 if(p.getValues().size() > MULTI_VALUE_CHUNK_SIZE) {
423
424 splitMultiValuePredicate(p, parent);
425 } else {
426 final String pp = p.getPropertyPath();
427 if (p instanceof InPredicate) {
428 final Set<?> predicateValues = getVals(p.getValues());
429 addIn(parent, pp, predicateValues);
430 } else if (p instanceof InIgnoreCasePredicate) {
431 final Set<String> predicateValues = toUpper(getValsUnsafe(((InIgnoreCasePredicate) p).getValues()));
432 addIn(parent, genUpperFunc(pp), predicateValues);
433 } else if (p instanceof NotInPredicate) {
434 final Set<?> predicateValues = getVals(p.getValues());
435 addNotIn(parent, pp, predicateValues);
436 } else if (p instanceof NotInIgnoreCasePredicate) {
437 final Set<String> predicateValues = toUpper(getValsUnsafe(((NotInIgnoreCasePredicate) p).getValues()));
438 addNotIn(parent, genUpperFunc(pp), predicateValues);
439 } else {
440 throw new UnsupportedPredicateException(p);
441 }
442 }
443 }
444
445
446
447
448
449
450
451
452 private void splitMultiValuePredicate(MultiValuedPredicate p, C parent) {
453 final String pp = p.getPropertyPath();
454 int chunkCount = (int)Math.ceil(p.getValues().size() / (double)MULTI_VALUE_CHUNK_SIZE);
455 Predicate[] multiValuePredicateChunks = new Predicate[chunkCount];
456 Object[] values = p.getValues().toArray();
457 int start = 0;
458 for(int i = 0; i < chunkCount; i++) {
459 Object[] valueChunk = Arrays.copyOfRange(values, start, start + MULTI_VALUE_CHUNK_SIZE);
460 if (p instanceof InPredicate) {
461 multiValuePredicateChunks[i] = PredicateFactory.in(pp, valueChunk);
462 } else if (p instanceof InIgnoreCasePredicate) {
463 multiValuePredicateChunks[i] = PredicateFactory.inIgnoreCase(pp, (CharSequence[])valueChunk);
464 } else if (p instanceof NotInPredicate) {
465 multiValuePredicateChunks[i] = PredicateFactory.notIn(pp, valueChunk);
466 } else if (p instanceof NotInIgnoreCasePredicate) {
467 multiValuePredicateChunks[i] = PredicateFactory.notInIgnoreCase(pp, (CharSequence[])valueChunk);
468 } else {
469 throw new UnsupportedPredicateException(p);
470 }
471
472 start += MULTI_VALUE_CHUNK_SIZE;
473 }
474 addPredicate(PredicateFactory.or(multiValuePredicateChunks), parent);
475 }
476
477
478
479
480
481
482
483 protected void addCompositePredicate(final CompositePredicate p, final C parent) {
484 for (Predicate ip : p.getPredicates()) {
485 final C inner = createInnerCriteria(parent);
486 addPredicate(ip, inner);
487 if (p instanceof AndPredicate) {
488 addAnd(parent, inner);
489 } else if (p instanceof OrPredicate) {
490 addOr(parent, inner);
491 } else {
492 throw new UnsupportedPredicateException(p);
493 }
494 }
495 }
496
497
498
499
500
501
502
503 protected void addSubQueryPredicate(SubQueryPredicate p, C parent) {
504 if (p instanceof ExistsSubQueryPredicate) {
505 addExistsSubquery(parent, p.getSubQueryType(), p.getSubQueryPredicate());
506 } else {
507 throw new UnsupportedPredicateException(p);
508 }
509 }
510
511
512
513
514
515
516
517
518 protected static <U extends CriteriaValue<?>> Object getVal(U toConv) {
519 Object o = toConv.getValue();
520 if (o instanceof DateTime) {
521 return new Timestamp(((DateTime) o).getMillis());
522 }
523 return o;
524 }
525
526
527
528
529
530
531
532
533
534
535
536 @SuppressWarnings("unchecked")
537 protected static <T, U extends CriteriaValue<T>> Set<T> getValsUnsafe(Set<? extends U> toConv) {
538 return (Set<T>) getVals(toConv);
539 }
540
541
542
543
544
545
546
547 protected static Set<?> getVals(Set<? extends CriteriaValue<?>> toConv) {
548 final Set<Object> values = new HashSet<Object>();
549 for (CriteriaValue<?> value : toConv) {
550 values.add(getVal(value));
551 }
552 return values;
553 }
554
555
556
557
558
559
560
561
562
563 private static Set<String> toUpper(Set<String> strs) {
564 final Set<String> values = new HashSet<String>();
565 for (String value : strs) {
566 values.add(value.toUpperCase());
567 }
568 return values;
569 }
570 }