1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.core.api.search;
17
18 import com.google.common.base.Function;
19 import com.google.common.base.Joiner;
20 import com.google.common.collect.Iterables;
21 import org.apache.commons.lang.StringUtils;
22 import org.kuali.rice.core.api.criteria.Predicate;
23
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.regex.Pattern;
32
33 import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
34
35
36
37
38
39 public class SearchExpressionUtils {
40
41
42
43 static final Collection<SearchOperator> BINARY_RANGE_OPERATORS =
44 Collections.unmodifiableCollection(Arrays.asList(SearchOperator.BETWEEN, SearchOperator.BETWEEN_EXCLUSIVE_LOWER, SearchOperator.BETWEEN_EXCLUSIVE_UPPER,
45 SearchOperator.BETWEEN_EXCLUSIVE_UPPER2, SearchOperator.BETWEEN_EXCLUSIVE));
46
47
48
49
50 public static final Collection<SearchOperator> CLAUSE_OPERATORS = Collections.unmodifiableCollection(Arrays.asList(SearchOperator.AND, SearchOperator.OR));
51 private static final Pattern CLAUSE_OPERATORS_PATTERN = generateSplitPattern(CLAUSE_OPERATORS);
52
53
54
55
56 private final Collection<SearchOperator> PREFIX_UNARY_OPERATORS =
57 Collections.unmodifiableCollection(Arrays.asList(SearchOperator.GREATER_THAN, SearchOperator.LESS_THAN, SearchOperator.GREATER_THAN_EQUAL, SearchOperator.LESS_THAN_EQUAL,
58 SearchOperator.NOT));
59
60
61
62 private final Collection<SearchOperator> POSTFIX_UNARY_OPERATORS =
63 Collections.unmodifiableCollection(Arrays.asList(SearchOperator.LIKE_ONE, SearchOperator.LIKE_MANY, SearchOperator.LIKE_MANY_P));
64
65
66 private SearchExpressionUtils() {
67 throw new UnsupportedOperationException("do not call");
68 }
69
70 public static String parsePrefixUnaryOperatorValue(SearchOperator operator, String expression) {
71 return StringUtils.removeStart(expression.trim(), operator.op()).trim();
72 }
73
74 public static String parsePostfixUnaryOperatorValue(SearchOperator operator, String expression) {
75 return StringUtils.removeEnd(expression.trim(), operator.op()).trim();
76 }
77
78 public static String[] parseBinaryOperatorValues(SearchOperator operator, String expression) {
79 return StringUtils.splitByWholeSeparator(expression.trim(), operator.op(), 2);
80 }
81
82
83
84
85
86
87 private static Pattern generateSplitPattern(Collection<SearchOperator> operators) {
88 return Pattern.compile(Joiner.on("|").join(Iterables.transform(operators,
89 new Function<SearchOperator, String>() {
90 public String apply(SearchOperator op) { return "(?:\\s*" + Pattern.quote(op.op()) + "\\s*)"; }
91 })));
92 }
93
94
95
96
97
98
99 public static String[] splitOnClauses(String expression) {
100 return CLAUSE_OPERATORS_PATTERN.split(expression);
101 }
102
103
104
105
106
107
108 public static String stripClauseOperators(String expression) {
109 return CLAUSE_OPERATORS_PATTERN.matcher(expression).replaceAll("");
110 }
111
112
113
114
115
116
117 public static String[] splitOnOperators(String expression, Collection<SearchOperator> operators) {
118 return generateSplitPattern(operators).split(expression);
119 }
120
121
122
123
124
125
126 public static String[] splitOnOperators(String expression, SearchOperator... operators) {
127 return generateSplitPattern(Arrays.asList(operators)).split(expression);
128 }
129
130
131
132
133
134
135 public static String stripOperators(String expression, Collection<SearchOperator> operators) {
136 return generateSplitPattern(operators).matcher(expression).replaceAll("");
137 }
138
139
140
141
142
143
144 public static String stripOperators(String expression, SearchOperator... operators) {
145 return generateSplitPattern(Arrays.asList(operators)).matcher(expression).replaceAll("");
146 }
147
148 public static Range parseRange(String rangeString) {
149 if (StringUtils.isBlank(rangeString)) {
150 throw new IllegalArgumentException("rangeString was null or blank");
151 }
152 Range range = new Range();
153 rangeString = rangeString.trim();
154 if (rangeString.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
155 rangeString = parsePrefixUnaryOperatorValue(SearchOperator.LESS_THAN_EQUAL, rangeString);
156 range.setUpperBoundValue(rangeString);
157 range.setUpperBoundInclusive(true);
158 } else if (rangeString.startsWith(SearchOperator.LESS_THAN.op())) {
159 rangeString = parsePrefixUnaryOperatorValue(SearchOperator.LESS_THAN, rangeString);
160 range.setUpperBoundValue(rangeString);
161 range.setUpperBoundInclusive(false);
162 } else if (rangeString.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
163 rangeString = parsePrefixUnaryOperatorValue(SearchOperator.GREATER_THAN_EQUAL, rangeString);
164 range.setLowerBoundValue(rangeString);
165 range.setLowerBoundInclusive(true);
166 } else if (rangeString.startsWith(SearchOperator.GREATER_THAN.op())) {
167 rangeString = parsePrefixUnaryOperatorValue(SearchOperator.GREATER_THAN, rangeString);
168 range.setLowerBoundValue(rangeString);
169 range.setLowerBoundInclusive(false);
170
171
172 } else if (rangeString.contains(SearchOperator.BETWEEN_EXCLUSIVE.op())) {
173 String[] rangeBounds = parseBinaryOperatorValues(SearchOperator.BETWEEN_EXCLUSIVE, rangeString);
174 range.setLowerBoundValue(rangeBounds[0]);
175 range.setLowerBoundInclusive(false);
176 range.setUpperBoundValue(rangeBounds[1]);
177 range.setUpperBoundInclusive(false);
178 } else if (rangeString.contains(SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op())) {
179 String[] rangeBounds = parseBinaryOperatorValues(SearchOperator.BETWEEN_EXCLUSIVE_UPPER, rangeString);
180 range.setLowerBoundValue(rangeBounds[0]);
181 range.setLowerBoundInclusive(true);
182 range.setUpperBoundValue(rangeBounds[1]);
183 range.setUpperBoundInclusive(false);
184 } else if (rangeString.contains(SearchOperator.BETWEEN_EXCLUSIVE_UPPER2.op())) {
185 String[] rangeBounds = parseBinaryOperatorValues(SearchOperator.BETWEEN_EXCLUSIVE_UPPER2, rangeString);
186 range.setLowerBoundValue(rangeBounds[0]);
187 range.setLowerBoundInclusive(true);
188 range.setUpperBoundValue(rangeBounds[1]);
189 range.setUpperBoundInclusive(false);
190 } else if (rangeString.contains(SearchOperator.BETWEEN_EXCLUSIVE_LOWER.op())) {
191 String[] rangeBounds = parseBinaryOperatorValues(SearchOperator.BETWEEN_EXCLUSIVE_LOWER, rangeString);
192 range.setLowerBoundValue(rangeBounds[0]);
193 range.setLowerBoundInclusive(false);
194 range.setUpperBoundValue(rangeBounds[1]);
195 range.setUpperBoundInclusive(true);
196 } else if (rangeString.contains(SearchOperator.BETWEEN.op())) {
197 String[] rangeBounds = parseBinaryOperatorValues(SearchOperator.BETWEEN, rangeString);
198 range.setLowerBoundValue(rangeBounds[0]);
199 range.setLowerBoundInclusive(true);
200 range.setUpperBoundValue(rangeBounds[1]);
201 range.setUpperBoundInclusive(true);
202 } else {
203
204 return null;
205 }
206 return range;
207 }
208
209 public static Predicate parsePredicates(String expression, String property) {
210 Set<Predicate> ored_predicates = new HashSet<Predicate>();
211 for (String or_clause: splitOnOperators(expression, SearchOperator.OR)) {
212 Set<Predicate> anded_predicates = new HashSet<Predicate>();
213 for (String and_clause: splitOnOperators(or_clause, SearchOperator.AND)) {
214 anded_predicates.add(parseSimplePredicate(property, and_clause));
215 }
216 ored_predicates.add(and(anded_predicates.toArray(new Predicate[0])));
217 }
218 return or(ored_predicates.toArray(new Predicate[0]));
219 }
220
221 public static Predicate parseSimplePredicate(String property, String value) {
222 if (value.contains(SearchOperator.NULL.op())) {
223 if (isNot(value)) {
224 return isNotNull(property);
225 } else {
226 return isNull(property);
227 }
228 } else if (value.contains(SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op())) {
229 String[] betweenVals = parseBinaryOperatorValues(SearchOperator.BETWEEN_EXCLUSIVE_UPPER, value);
230 return and(greaterThanOrEqual(property, betweenVals[0]), lessThan(property, betweenVals[1]));
231 } else if (value.contains(SearchOperator.BETWEEN.op())) {
232 String[] betweenVals = parseBinaryOperatorValues(SearchOperator.BETWEEN, value);
233 return and(greaterThanOrEqual(property, betweenVals[0]), lessThanOrEqual(property, betweenVals[1]));
234 } else if (value.contains(SearchOperator.GREATER_THAN_EQUAL.op())) {
235 return greaterThanOrEqual(property, stripOperators(value, SearchOperator.GREATER_THAN_EQUAL));
236 } else if (value.contains(SearchOperator.LESS_THAN_EQUAL.op())) {
237 return lessThanOrEqual(property, stripOperators(value, SearchOperator.LESS_THAN_EQUAL));
238 } else if (value.contains(SearchOperator.GREATER_THAN.op())) {
239 return greaterThan(property, stripOperators(value, SearchOperator.GREATER_THAN));
240 } else if (value.contains(SearchOperator.LESS_THAN.op())) {
241 return lessThan(property, stripOperators(value, SearchOperator.LESS_THAN));
242 } else if (value.contains(SearchOperator.NOT.op())) {
243 String[] notValues = splitOnOperators(value, SearchOperator.NOT);
244 List<Predicate> notPreds = new ArrayList<Predicate>(notValues.length);
245 for (String notValue : notValues) {
246 notPreds.add(notEqual(property, SearchExpressionUtils.stripOperators(notValue, SearchOperator.NOT)));
247 }
248 return and(notPreds.toArray(new Predicate[notPreds.size()]));
249 } else if (value.contains(SearchOperator.LIKE_MANY.op()) || (value.contains(SearchOperator.LIKE_ONE.op()))) {
250 if (isNot(value)) {
251 return notLike(property, value);
252 } else {
253 return like(property, value );
254 }
255 } else {
256 if (isNot(value)) {
257 return notEqual(property, value);
258 } else {
259 return equal(property, value);
260 }
261 }
262 }
263
264 private static boolean isNot(String value) {
265 if (value == null) {
266 return false;
267 }
268 return value.contains(SearchOperator.NOT.op());
269 }
270
271
272
273
274
275
276
277 private static List<String> getSearchableValues(String valueEntered) {
278 List<String> lRet = new ArrayList<String>();
279 getSearchableValueRecursive(valueEntered, lRet);
280 return lRet;
281 }
282
283 private static void getSearchableValueRecursive(String valueEntered, List lRet) {
284 if(valueEntered == null) {
285 return;
286 }
287
288 valueEntered = valueEntered.trim();
289
290 if(lRet == null){
291 throw new NullPointerException("The list passed in is by reference and should never be null.");
292 }
293
294 if (StringUtils.contains(valueEntered, SearchOperator.BETWEEN.op())) {
295 List<String> l = Arrays.asList(SearchExpressionUtils.parseBinaryOperatorValues(SearchOperator.BETWEEN, valueEntered));
296 for(String value : l){
297 getSearchableValueRecursive(value,lRet);
298 }
299 return;
300 }
301 if (StringUtils.contains(valueEntered, SearchOperator.OR.op())) {
302 List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.OR.op()));
303 for(String value : l){
304 getSearchableValueRecursive(value,lRet);
305 }
306 return;
307 }
308 if (StringUtils.contains(valueEntered, SearchOperator.AND.op())) {
309
310 List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.AND.op()));
311 for(String value : l){
312 getSearchableValueRecursive(value,lRet);
313 }
314 return;
315 }
316
317
318 lRet.add(valueEntered);
319 }
320 }