View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.data.jpa;
17  
18  import org.joda.time.DateTime;
19  import org.kuali.rice.core.api.criteria.AndPredicate;
20  import org.kuali.rice.core.api.criteria.CompositePredicate;
21  import org.kuali.rice.core.api.criteria.CriteriaValue;
22  import org.kuali.rice.core.api.criteria.EqualIgnoreCasePredicate;
23  import org.kuali.rice.core.api.criteria.EqualPredicate;
24  import org.kuali.rice.core.api.criteria.GreaterThanOrEqualPredicate;
25  import org.kuali.rice.core.api.criteria.GreaterThanPredicate;
26  import org.kuali.rice.core.api.criteria.InIgnoreCasePredicate;
27  import org.kuali.rice.core.api.criteria.InPredicate;
28  import org.kuali.rice.core.api.criteria.LessThanOrEqualPredicate;
29  import org.kuali.rice.core.api.criteria.LessThanPredicate;
30  import org.kuali.rice.core.api.criteria.LikeIgnoreCasePredicate;
31  import org.kuali.rice.core.api.criteria.LikePredicate;
32  import org.kuali.rice.core.api.criteria.MultiValuedPredicate;
33  import org.kuali.rice.core.api.criteria.NotEqualIgnoreCasePredicate;
34  import org.kuali.rice.core.api.criteria.NotEqualPredicate;
35  import org.kuali.rice.core.api.criteria.NotInIgnoreCasePredicate;
36  import org.kuali.rice.core.api.criteria.NotInPredicate;
37  import org.kuali.rice.core.api.criteria.NotLikePredicate;
38  import org.kuali.rice.core.api.criteria.NotNullPredicate;
39  import org.kuali.rice.core.api.criteria.NullPredicate;
40  import org.kuali.rice.core.api.criteria.OrPredicate;
41  import org.kuali.rice.core.api.criteria.Predicate;
42  import org.kuali.rice.core.api.criteria.PropertyPathPredicate;
43  import org.kuali.rice.core.api.criteria.SingleValuedPredicate;
44  
45  import java.sql.Timestamp;
46  import java.util.Collection;
47  import java.util.HashSet;
48  import java.util.Set;
49  
50  /**
51   * Base {@link QueryTranslator} implementation.
52   *
53   * @author Kuali Rice Team (rice.collab@kuali.org)
54   */
55  abstract class QueryTranslatorBase<C, Q> implements QueryTranslator<C, Q> {
56  
57      /**
58       * Creates a criteria from the given type.
59       *
60       * @param entityClass the type to create the criteria from.
61       * @return a criteria created from the given type.
62       */
63      protected abstract C createCriteria(Class entityClass);
64  
65      /**
66       * Creates a critera from the given parent critiera.
67       *
68       * @param parent the parent critera to create a criteria from.
69       * @return a critera created from a given parent criteria.
70       */
71      protected abstract C createInnerCriteria(C parent);
72  
73      /**
74       * Generates the uppercase function form of the property.
75       *
76       * @param pp the property to modify.
77       * @return the uppercase function form of the property.
78       */
79      protected abstract String genUpperFunc(String pp);
80  
81      /**
82       * Adds a NOT NULL clause to the property.
83       *
84       * @param criteria the criteria to add to.
85       * @param propertyPath the property to add to.
86       */
87      protected abstract void addNotNull(C criteria, String propertyPath);
88  
89      /**
90       * Adds an IS NULL clause to the property.
91       *
92       * @param criteria the criteria to add to.
93       * @param propertyPath the property to add to.
94       */
95      protected abstract void addIsNull(C criteria, String propertyPath);
96  
97      /**
98       * Adds a "=" clause to the property.
99       *
100      * @param criteria the criteria to add to.
101      * @param propertyPath the property to add to.
102      * @param value the value to compare.
103      */
104     protected abstract void addEqualTo(C criteria, String propertyPath, Object value);
105 
106     /**
107      * Adds a ">=" clause to the property.
108      *
109      * @param criteria the criteria to add to.
110      * @param propertyPath the property to add to.
111      * @param value the value to compare.
112      */
113     protected abstract void addGreaterOrEqualTo(C criteria, String propertyPath, Object value);
114 
115     /**
116      * Adds a ">" clause to the property.
117      *
118      * @param criteria the criteria to add to.
119      * @param propertyPath the property to add to.
120      * @param value the value to compare.
121      */
122     protected abstract void addGreaterThan(C criteria, String propertyPath, Object value);
123 
124     /**
125      * Adds a "<=" clause to the property.
126      *
127      * @param criteria the criteria to add to.
128      * @param propertyPath the property to add to.
129      * @param value the value to compare.
130      */
131     protected abstract void addLessOrEqualTo(C criteria, String propertyPath, Object value);
132 
133     /**
134      * Adds a "<" clause to the property.
135      *
136      * @param criteria the criteria to add to.
137      * @param propertyPath the property to add to.
138      * @param value the value to compare.
139      */
140     protected abstract void addLessThan(C criteria, String propertyPath, Object value);
141 
142     /**
143      * Adds a LIKE clause to the property.
144      *
145      * @param criteria the criteria to add to.
146      * @param propertyPath the property to add to.
147      * @param value the value to compare.
148      */
149     protected abstract void addLike(C criteria, String propertyPath, Object value);
150 
151     /**
152      * Adds a != clause to the property.
153      *
154      * @param criteria the criteria to add to.
155      * @param propertyPath the property to add to.
156      * @param value the value to compare.
157      */
158     protected abstract void addNotEqualTo(C criteria, String propertyPath, Object value);
159 
160     /**
161      * Adds a NOT LIKE clause to the property.
162      *
163      * @param criteria the criteria to add to.
164      * @param propertyPath the property to add to.
165      * @param value the value to compare.
166      */
167     protected abstract void addNotLike(C criteria, String propertyPath, Object value);
168 
169     /**
170      * Adds an IN clause to the property.
171      *
172      * @param criteria the criteria to add to.
173      * @param propertyPath the property to add to.
174      * @param values the values to compare.
175      */
176     protected abstract void addIn(C criteria, String propertyPath, Collection values);
177 
178     /**
179      * Adds a NOT IN clause to the property.
180      *
181      * @param criteria the criteria to add to.
182      * @param propertyPath the property to add to.
183      * @param values the values to compare.
184      */
185     protected abstract void addNotIn(C criteria, String propertyPath, Collection values);
186 
187     /**
188      * Adds an AND clause between criteria.
189      *
190      * @param criteria the criteria to add to.
191      * @param inner the criteria to AND.
192      */
193     protected abstract void addAnd(C criteria, C inner);
194 
195     /**
196      * Adds an OR clause between criteria.
197      *
198      * @param criteria the criteria to add to.
199      * @param inner the criteria to OR.
200      */
201     protected abstract void addOr(C criteria, C inner);
202 
203     /**
204      * Adds a "=" clause to the property, ignoring case.
205      *
206      * @param criteria the criteria to add to.
207      * @param propertyPath the property to add to.
208      * @param value the value to compare.
209      */
210     protected void addEqualToIgnoreCase(C criteria, String propertyPath, String value) {
211         addEqualTo(criteria, genUpperFunc(propertyPath), value.toUpperCase());
212     }
213 
214     /**
215      * Adds a != clause to the property, ignoring case.
216      *
217      * @param criteria the criteria to add to.
218      * @param propertyPath the property to add to.
219      * @param value the value to compare.
220      */
221     protected void addNotEqualToIgnoreCase(C criteria, String propertyPath, String value) {
222         addNotEqualTo(criteria, genUpperFunc(propertyPath), value.toUpperCase());
223     }
224 
225     /**
226      * Adds a LIKE clause to the property, ignoring case.
227      *
228      * @param criteria the criteria to add to.
229      * @param propertyPath the property to add to.
230      * @param value the value to compare.
231      */
232     protected void addLikeIgnoreCase(C criteria, String propertyPath, String value){
233         addLike(criteria, genUpperFunc(propertyPath),value.toUpperCase());
234     }
235 
236     /**
237      * An error to throw when the {@link Predicate} is not recognized.
238      *
239      * <p>This is a fatal error since this implementation should support all known predicates.</p>
240      */
241     protected static class UnsupportedPredicateException extends RuntimeException {
242 
243         /**
244          * Creates an exception for if the {@link Predicate} is not recognized.
245          * @param predicate the {@link Predicate} in error.
246          */
247         protected UnsupportedPredicateException(Predicate predicate) {
248             super("Unsupported predicate [" + String.valueOf(predicate) + "]");
249         }
250     }
251 
252     /**
253      * {@inheritDoc}
254      */
255     @Override
256     public C translateCriteria(Class queryClazz, Predicate predicate) {
257         final C parent = createCriteria(queryClazz);
258 
259         if (predicate != null) {
260             addPredicate(predicate, parent);
261         }
262 
263         return parent;
264     }
265 
266     /**
267      * Adds a predicate to a criteria.
268      *
269      * @param p the {@link Predicate} to add.
270      * @param parent the parent criteria to add to.
271      */
272     protected void addPredicate(Predicate p, C parent) {
273         if (p instanceof PropertyPathPredicate) {
274             final String pp = ((PropertyPathPredicate) p).getPropertyPath();
275             if (p instanceof NotNullPredicate) {
276                 addNotNull(parent, pp);
277             } else if (p instanceof NullPredicate) {
278                 addIsNull(parent, pp);
279             } else if (p instanceof SingleValuedPredicate) {
280                 addSingleValuePredicate((SingleValuedPredicate) p, parent);
281             } else if (p instanceof MultiValuedPredicate) {
282                 addMultiValuePredicate((MultiValuedPredicate) p, parent);
283             } else {
284                 throw new UnsupportedPredicateException(p);
285             }
286         } else if (p instanceof CompositePredicate) {
287             addCompositePredicate((CompositePredicate) p, parent);
288         } else {
289             throw new UnsupportedPredicateException(p);
290         }
291     }
292 
293     /**
294      * Adds a single valued predicate to a criteria.
295      *
296      * @param p the single valued predicate to add.
297      * @param parent the parent criteria to add to.
298      */
299     protected void addSingleValuePredicate(SingleValuedPredicate p, C parent) {
300         final Object value = getVal(p.getValue());
301         final String pp = p.getPropertyPath();
302         if (p instanceof EqualPredicate) {
303             addEqualTo(parent, pp, value);
304         } else if (p instanceof EqualIgnoreCasePredicate) {
305             addEqualToIgnoreCase(parent, pp, (String) value);
306         } else if (p instanceof GreaterThanOrEqualPredicate) {
307             addGreaterOrEqualTo(parent, pp, value);
308         } else if (p instanceof GreaterThanPredicate) {
309             addGreaterThan(parent, pp, value);
310         } else if (p instanceof LessThanOrEqualPredicate) {
311             addLessOrEqualTo(parent, pp, value);
312         } else if (p instanceof LessThanPredicate) {
313             addLessThan(parent, pp, value);
314         } else if (p instanceof LikePredicate) {
315             //no need to convert * or ? since ojb handles the conversion/escaping
316             addLike(parent, pp, value);
317         } else if(p instanceof LikeIgnoreCasePredicate){
318             addLikeIgnoreCase(parent,pp,(String)value);
319         } else if (p instanceof NotEqualPredicate) {
320             addNotEqualTo(parent, pp, value);
321         } else if (p instanceof NotEqualIgnoreCasePredicate) {
322             addNotEqualToIgnoreCase(parent, pp, (String) value);
323         } else if (p instanceof NotLikePredicate) {
324             addNotLike(parent, pp, value);
325         } else {
326             throw new UnsupportedPredicateException(p);
327         }
328     }
329 
330     /**
331      * Adds a multi-valued predicate to a criteria.
332      *
333      * @param p the multi-valued predicate to add.
334      * @param parent the parent criteria to add to.
335      */
336     protected void addMultiValuePredicate(MultiValuedPredicate p, C parent) {
337         final String pp = p.getPropertyPath();
338         if (p instanceof InPredicate) {
339             final Set<?> values = getVals(p.getValues());
340             addIn(parent, pp, values);
341         } else if (p instanceof InIgnoreCasePredicate) {
342             final Set<String> values = toUpper(getValsUnsafe(((InIgnoreCasePredicate) p).getValues()));
343             addIn(parent, genUpperFunc(pp), values);
344         } else if (p instanceof NotInPredicate) {
345             final Set<?> values = getVals(p.getValues());
346             addNotIn(parent, pp, values);
347         } else if (p instanceof NotInIgnoreCasePredicate) {
348             final Set<String> values = toUpper(getValsUnsafe(((NotInIgnoreCasePredicate) p).getValues()));
349             addNotIn(parent, genUpperFunc(pp), values);
350         } else {
351             throw new UnsupportedPredicateException(p);
352         }
353     }
354 
355     /**
356      * Adds a composite predicate to a criteria.
357      *
358      * @param p the composite predicate to add.
359      * @param parent the parent criteria to add to.
360      */
361     protected void addCompositePredicate(final CompositePredicate p, final C parent) {
362         for (Predicate ip : p.getPredicates()) {
363             final C inner = createInnerCriteria(parent);
364             addPredicate(ip, inner);
365             if (p instanceof AndPredicate) {
366                 addAnd(parent, inner);
367             } else if (p instanceof OrPredicate) {
368                 addOr(parent, inner);
369             } else {
370                 throw new UnsupportedPredicateException(p);
371             }
372         }
373     }
374 
375     /**
376      * Converts any {@link DateTime} values to {@link Timestamp}s.
377      *
378      * @param toConv the {@link CriteriaValue} to convert.
379      * @param <U> the type of the {@link CriteriaValue}.
380      * @return the {@link CriteriaValue} converted.
381      */
382     protected static <U extends CriteriaValue<?>> Object getVal(U toConv) {
383         Object o = toConv.getValue();
384         if (o instanceof DateTime) {
385             return new Timestamp(((DateTime) o).getMillis());
386         }
387         return o;
388     }
389 
390     /**
391      * Converts a set of {@link CriteriaValue}s.
392      *
393      * <p>This is unsafe because values could be converted resulting in a class cast exception.</p>
394      *
395      * @param toConv the {@link CriteriaValue} to convert.
396      * @param <U> the initial type of the {@link CriteriaValue} set.
397      * @param <T> the final type of the {@link CriteriaValue} set.
398      * @return the {@link CriteriaValue} set converted.
399      */
400     @SuppressWarnings("unchecked")
401     protected static <T, U extends CriteriaValue<T>> Set<T> getValsUnsafe(Set<? extends U> toConv) {
402         return (Set<T>) getVals(toConv);
403     }
404 
405     /**
406      * Converts a set of {@link CriteriaValue}s to an undefined type.
407      *
408      * @param toConv the {@link CriteriaValue} to convert.
409      * @return a set of {@link CriteriaValue}s as an undefined type.
410      */
411     protected static Set<?> getVals(Set<? extends CriteriaValue<?>> toConv) {
412         final Set<Object> values = new HashSet<Object>();
413         for (CriteriaValue<?> value : toConv) {
414             values.add(getVal(value));
415         }
416         return values;
417     }
418 
419     /**
420      * Converts a set of strings to upper case.
421      *
422      * <p>Here we are eliding performance for function composition.</p>
423      *
424      * @param strs the set of strings to convert.
425      * @return a set of uppercase strings.
426      */
427     private static Set<String> toUpper(Set<String> strs) {
428         final Set<String> values = new HashSet<String>();
429         for (String value : strs) {
430             values.add(value.toUpperCase());
431         }
432         return values;
433     }
434 }