1 package org.kuali.rice.core.impl.criteria;
2
3 import org.apache.ojb.broker.query.Criteria;
4 import org.apache.ojb.broker.query.Query;
5 import org.apache.ojb.broker.query.QueryFactory;
6 import org.kuali.rice.core.api.criteria.AndPredicate;
7 import org.kuali.rice.core.api.criteria.CompositePredicate;
8 import org.kuali.rice.core.api.criteria.CountFlag;
9 import org.kuali.rice.core.api.criteria.CriteriaLookupService;
10 import org.kuali.rice.core.api.criteria.CriteriaValue;
11 import org.kuali.rice.core.api.criteria.EqualIgnoreCasePredicate;
12 import org.kuali.rice.core.api.criteria.EqualPredicate;
13 import org.kuali.rice.core.api.criteria.GenericQueryResults;
14 import org.kuali.rice.core.api.criteria.GreaterThanOrEqualPredicate;
15 import org.kuali.rice.core.api.criteria.GreaterThanPredicate;
16 import org.kuali.rice.core.api.criteria.InIgnoreCasePredicate;
17 import org.kuali.rice.core.api.criteria.InPredicate;
18 import org.kuali.rice.core.api.criteria.LessThanOrEqualPredicate;
19 import org.kuali.rice.core.api.criteria.LessThanPredicate;
20 import org.kuali.rice.core.api.criteria.LikePredicate;
21 import org.kuali.rice.core.api.criteria.LookupCustomizer;
22 import org.kuali.rice.core.api.criteria.MultiValuedPredicate;
23 import org.kuali.rice.core.api.criteria.NotEqualIgnoreCasePredicate;
24 import org.kuali.rice.core.api.criteria.NotEqualPredicate;
25 import org.kuali.rice.core.api.criteria.NotInIgnoreCasePredicate;
26 import org.kuali.rice.core.api.criteria.NotInPredicate;
27 import org.kuali.rice.core.api.criteria.NotLikePredicate;
28 import org.kuali.rice.core.api.criteria.NotNullPredicate;
29 import org.kuali.rice.core.api.criteria.NullPredicate;
30 import org.kuali.rice.core.api.criteria.OrPredicate;
31 import org.kuali.rice.core.api.criteria.Predicate;
32 import org.kuali.rice.core.api.criteria.PropertyPathPredicate;
33 import org.kuali.rice.core.api.criteria.QueryByCriteria;
34 import org.kuali.rice.core.api.criteria.SingleValuedPredicate;
35 import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb;
36
37 import java.util.ArrayList;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Set;
41
42 public class CriteriaLookupServiceOjbImpl extends PlatformAwareDaoBaseOjb implements CriteriaLookupService {
43
44 @Override
45 public <T> GenericQueryResults<T> lookup(final Class<T> queryClass, final QueryByCriteria criteria) {
46 return lookup(queryClass, criteria, LookupCustomizer.Builder.<T>create().build());
47 }
48
49 @Override
50 public <T> GenericQueryResults<T> lookup(final Class<T> queryClass, final QueryByCriteria criteria, LookupCustomizer<T> customizer) {
51 if (queryClass == null) {
52 throw new IllegalArgumentException("queryClass is null");
53 }
54
55 if (criteria == null) {
56 throw new IllegalArgumentException("criteria is null");
57 }
58
59 if (customizer == null) {
60 throw new IllegalArgumentException("customizer is null");
61 }
62
63 final Criteria parent = new Criteria();
64
65 if (criteria.getPredicate() != null) {
66 addPredicate(criteria.getPredicate(), parent, customizer.getPredicateTransform());
67 }
68
69 switch (criteria.getCountFlag()) {
70 case ONLY:
71 return forCountOnly(queryClass, criteria, parent);
72 case NONE:
73 return forRowResults(queryClass, criteria, parent, criteria.getCountFlag(), customizer.getResultTransform());
74 case INCLUDE:
75 return forRowResults(queryClass, criteria, parent, criteria.getCountFlag(), customizer.getResultTransform());
76 default: throw new UnsupportedCountFlagException(criteria.getCountFlag());
77 }
78 }
79
80
81 private <T> GenericQueryResults<T> forRowResults(final Class<T> queryClass, final QueryByCriteria criteria, final Criteria ojbCriteria, CountFlag flag, LookupCustomizer.Transform<T, T> transform) {
82 final Query ojbQuery = QueryFactory.newQuery(queryClass, ojbCriteria);
83 final GenericQueryResults.Builder<T> results = GenericQueryResults.Builder.<T>create();
84
85 if (flag == CountFlag.INCLUDE) {
86 results.setTotalRowCount(getPersistenceBrokerTemplate().getCount(ojbQuery));
87 }
88
89
90 final int startAtIndex = criteria.getStartAtIndex() != null ? criteria.getStartAtIndex() + 1 : 1;
91 ojbQuery.setStartAtIndex(startAtIndex);
92
93 if (criteria.getMaxResults() != null) {
94
95
96 ojbQuery.setEndAtIndex(criteria.getMaxResults() + startAtIndex);
97 }
98
99 @SuppressWarnings("unchecked")
100 final List<T> rows = new ArrayList<T>(getPersistenceBrokerTemplate().getCollectionByQuery(ojbQuery));
101
102 if (criteria.getMaxResults() != null && rows.size() > criteria.getMaxResults()) {
103 results.setMoreResultsAvailable(true);
104
105 rows.remove(criteria.getMaxResults().intValue());
106 }
107
108 results.setResults(transformResults(rows, transform));
109 return results.build();
110 }
111
112 private static <T> List<T> transformResults(List<T> results, LookupCustomizer.Transform<T, T> transform) {
113 final List<T> list = new ArrayList<T>();
114 for (T r : results) {
115 list.add(transform.apply(r));
116 }
117 return list;
118 }
119
120
121 private <T> GenericQueryResults<T> forCountOnly(final Class<T> queryClass, final QueryByCriteria criteria, final Criteria ojbCriteria) {
122 final Query ojbQuery = QueryFactory.newQuery(queryClass, ojbCriteria);
123 final GenericQueryResults.Builder<T> results = GenericQueryResults.Builder.<T>create();
124 results.setTotalRowCount(getPersistenceBrokerTemplate().getCount(ojbQuery));
125
126 return results.build();
127 }
128
129
130 private void addPredicate(Predicate p, Criteria parent, LookupCustomizer.Transform<Predicate, Predicate> transform) {
131 p = transform.apply(p);
132
133 if (p instanceof PropertyPathPredicate) {
134 final String pp = ((PropertyPathPredicate) p).getPropertyPath();
135 if (p instanceof NotNullPredicate) {
136 parent.addNotNull(pp);
137 } else if (p instanceof NullPredicate) {
138 parent.addIsNull(pp);
139 } else if (p instanceof SingleValuedPredicate) {
140 addSingleValuePredicate((SingleValuedPredicate) p, parent);
141 } else if (p instanceof MultiValuedPredicate) {
142 addMultiValuePredicate((MultiValuedPredicate) p, parent);
143 } else {
144 throw new UnsupportedPredicateException(p);
145 }
146 } else if (p instanceof CompositePredicate) {
147 addCompositePredicate((CompositePredicate) p, parent, transform);
148 } else {
149 throw new UnsupportedPredicateException(p);
150 }
151 }
152
153
154 private void addSingleValuePredicate(SingleValuedPredicate p, Criteria parent) {
155 final Object value = p.getValue().getValue();
156 final String pp = p.getPropertyPath();
157 if (p instanceof EqualPredicate) {
158 parent.addEqualTo(pp, value);
159 } else if (p instanceof EqualIgnoreCasePredicate) {
160 parent.addEqualTo(genUpperFunc(pp), ((String) value).toUpperCase());
161 } else if (p instanceof GreaterThanOrEqualPredicate) {
162 parent.addGreaterOrEqualThan(pp, value);
163 } else if (p instanceof GreaterThanPredicate) {
164 parent.addGreaterThan(pp, value);
165 } else if (p instanceof LessThanOrEqualPredicate) {
166 parent.addLessOrEqualThan(pp, value);
167 } else if (p instanceof LessThanPredicate) {
168 parent.addLessThan(pp, value);
169 } else if (p instanceof LikePredicate) {
170
171 parent.addLike(pp, value);
172 } else if (p instanceof NotEqualPredicate) {
173 parent.addNotEqualTo(pp, value);
174 } else if (p instanceof NotEqualIgnoreCasePredicate) {
175 parent.addNotEqualTo(genUpperFunc(pp), ((String) value).toUpperCase());
176 } else if (p instanceof NotLikePredicate) {
177 parent.addNotLike(pp, value);
178 } else {
179 throw new UnsupportedPredicateException(p);
180 }
181 }
182
183
184 private void addMultiValuePredicate(MultiValuedPredicate p, Criteria parent) {
185 final String pp = p.getPropertyPath();
186 if (p instanceof InPredicate) {
187 final Set<?> values = getValsUnsafe(p.getValues());
188 parent.addIn(pp, values);
189 } else if (p instanceof InIgnoreCasePredicate) {
190 final Set<String> values = toUpper(getVals(((InIgnoreCasePredicate) p).getValues()));
191 parent.addIn(genUpperFunc(pp), values);
192 } else if (p instanceof NotInPredicate) {
193 final Set<?> values = getValsUnsafe(p.getValues());
194 parent.addNotIn(pp, values);
195 } else if (p instanceof NotInIgnoreCasePredicate) {
196 final Set<String> values = toUpper(getVals(((NotInIgnoreCasePredicate) p).getValues()));
197 parent.addNotIn(genUpperFunc(pp), values);
198 } else {
199 throw new UnsupportedPredicateException(p);
200 }
201 }
202
203
204 private void addCompositePredicate(final CompositePredicate p, final Criteria parent, LookupCustomizer.Transform<Predicate, Predicate> transform) {
205 for (Predicate ip : p.getPredicates()) {
206 final Criteria inner = new Criteria();
207 addPredicate(ip, inner, transform);
208 if (p instanceof AndPredicate) {
209 parent.addAndCriteria(inner);
210 } else if (p instanceof OrPredicate) {
211 parent.addOrCriteria(inner);
212 } else {
213 throw new UnsupportedPredicateException(p);
214 }
215 }
216 }
217
218 @SuppressWarnings("unchecked")
219 private static <T, U extends CriteriaValue<T>> Set<T> getVals(Set<? extends U> toConv) {
220 return (Set<T>) getValsUnsafe(toConv);
221 }
222
223
224 private static Set<?> getValsUnsafe(Set<? extends CriteriaValue<?>> toConv) {
225 final Set<Object> values = new HashSet<Object>();
226 for (CriteriaValue<?> value : toConv) {
227 values.add(value.getValue());
228 }
229 return values;
230 }
231
232
233 private static Set<String> toUpper(Set<String> strs) {
234 final Set<String> values = new HashSet<String>();
235 for (String value : strs) {
236 values.add(value.toUpperCase());
237 }
238 return values;
239 }
240
241 private String getUpperFunction() {
242 return getDbPlatform().getUpperCaseFunction();
243 }
244
245 private String genUpperFunc(String pp) {
246 return new StringBuilder(getUpperFunction()).append("(").append(pp).append(")").toString();
247 }
248
249
250 private static class UnsupportedPredicateException extends RuntimeException {
251 private UnsupportedPredicateException(Predicate predicate) {
252 super("Unsupported predicate [" + String.valueOf(predicate) + "]");
253 }
254 }
255
256
257 private static class UnsupportedCountFlagException extends RuntimeException {
258 private UnsupportedCountFlagException(CountFlag flag) {
259 super("Unsupported predicate [" + String.valueOf(flag) + "]");
260 }
261 }
262 }