001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.builder;
018
019 import java.util.Arrays;
020 import java.util.List;
021 import java.util.regex.Matcher;
022 import java.util.regex.Pattern;
023
024 import org.apache.camel.Exchange;
025 import org.apache.camel.Expression;
026 import org.apache.camel.Predicate;
027 import org.apache.camel.util.ExpressionToPredicateAdapter;
028 import org.apache.camel.util.ObjectHelper;
029
030 import static org.apache.camel.util.ObjectHelper.notNull;
031
032
033 /**
034 * A helper class for working with predicates
035 *
036 * @version
037 */
038 public final class PredicateBuilder {
039
040 /**
041 * Utility classes should not have a public constructor.
042 */
043 private PredicateBuilder() {
044 }
045
046 /**
047 * Converts the given expression into an {@link Predicate}
048 */
049 public static Predicate toPredicate(final Expression expression) {
050 return ExpressionToPredicateAdapter.toPredicate(expression);
051 }
052
053 /**
054 * A helper method to return the logical not of the given predicate
055 */
056 public static Predicate not(final Predicate predicate) {
057 notNull(predicate, "predicate");
058 return new Predicate() {
059 public boolean matches(Exchange exchange) {
060 return !predicate.matches(exchange);
061 }
062
063 @Override
064 public String toString() {
065 return "not (" + predicate + ")";
066 }
067 };
068 }
069
070 /**
071 * A helper method to combine multiple predicates by a logical AND
072 */
073 public static Predicate and(final Predicate left, final Predicate right) {
074 notNull(left, "left");
075 notNull(right, "right");
076 return new Predicate() {
077 public boolean matches(Exchange exchange) {
078 return left.matches(exchange) && right.matches(exchange);
079 }
080
081 @Override
082 public String toString() {
083 return "(" + left + ") and (" + right + ")";
084 }
085 };
086 }
087
088 /**
089 * A helper method to combine multiple predicates by a logical OR
090 */
091 public static Predicate or(final Predicate left, final Predicate right) {
092 notNull(left, "left");
093 notNull(right, "right");
094 return new Predicate() {
095 public boolean matches(Exchange exchange) {
096 return left.matches(exchange) || right.matches(exchange);
097 }
098
099 @Override
100 public String toString() {
101 return "(" + left + ") or (" + right + ")";
102 }
103 };
104 }
105
106 /**
107 * A helper method to return true if any of the predicates matches.
108 */
109 public static Predicate in(final Predicate... predicates) {
110 notNull(predicates, "predicates");
111
112 return new Predicate() {
113 public boolean matches(Exchange exchange) {
114 for (Predicate in : predicates) {
115 if (in.matches(exchange)) {
116 return true;
117 }
118 }
119 return false;
120 }
121
122 @Override
123 public String toString() {
124 return "in (" + Arrays.asList(predicates) + ")";
125 }
126 };
127 }
128
129 public static Predicate isEqualTo(final Expression left, final Expression right) {
130 return new BinaryPredicateSupport(left, right) {
131
132 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
133 if (leftValue == null && rightValue == null) {
134 // they are equal
135 return true;
136 } else if (leftValue == null || rightValue == null) {
137 // only one of them is null so they are not equal
138 return false;
139 }
140
141 return ObjectHelper.typeCoerceEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue);
142 }
143
144 protected String getOperationText() {
145 return "==";
146 }
147 };
148 }
149
150 public static Predicate isNotEqualTo(final Expression left, final Expression right) {
151 return new BinaryPredicateSupport(left, right) {
152
153 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
154 if (leftValue == null && rightValue == null) {
155 // they are equal
156 return false;
157 } else if (leftValue == null || rightValue == null) {
158 // only one of them is null so they are not equal
159 return true;
160 }
161
162 return ObjectHelper.typeCoerceNotEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue);
163 }
164
165 protected String getOperationText() {
166 return "!=";
167 }
168 };
169 }
170
171 public static Predicate isLessThan(final Expression left, final Expression right) {
172 return new BinaryPredicateSupport(left, right) {
173
174 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
175 if (leftValue == null && rightValue == null) {
176 // they are equal
177 return true;
178 } else if (leftValue == null || rightValue == null) {
179 // only one of them is null so they are not equal
180 return false;
181 }
182
183 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) < 0;
184 }
185
186 protected String getOperationText() {
187 return "<";
188 }
189 };
190 }
191
192 public static Predicate isLessThanOrEqualTo(final Expression left, final Expression right) {
193 return new BinaryPredicateSupport(left, right) {
194
195 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
196 if (leftValue == null && rightValue == null) {
197 // they are equal
198 return true;
199 } else if (leftValue == null || rightValue == null) {
200 // only one of them is null so they are not equal
201 return false;
202 }
203
204 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) <= 0;
205 }
206
207 protected String getOperationText() {
208 return "<=";
209 }
210 };
211 }
212
213 public static Predicate isGreaterThan(final Expression left, final Expression right) {
214 return new BinaryPredicateSupport(left, right) {
215
216 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
217 if (leftValue == null && rightValue == null) {
218 // they are equal
219 return false;
220 } else if (leftValue == null || rightValue == null) {
221 // only one of them is null so they are not equal
222 return false;
223 }
224
225 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) > 0;
226 }
227
228 protected String getOperationText() {
229 return ">";
230 }
231 };
232 }
233
234 public static Predicate isGreaterThanOrEqualTo(final Expression left, final Expression right) {
235 return new BinaryPredicateSupport(left, right) {
236
237 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
238 if (leftValue == null && rightValue == null) {
239 // they are equal
240 return true;
241 } else if (leftValue == null || rightValue == null) {
242 // only one of them is null so they are not equal
243 return false;
244 }
245
246 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) >= 0;
247 }
248
249 protected String getOperationText() {
250 return ">=";
251 }
252 };
253 }
254
255 public static Predicate contains(final Expression left, final Expression right) {
256 return new BinaryPredicateSupport(left, right) {
257
258 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
259 if (leftValue == null && rightValue == null) {
260 // they are equal
261 return true;
262 } else if (leftValue == null || rightValue == null) {
263 // only one of them is null so they are not equal
264 return false;
265 }
266
267 return ObjectHelper.contains(leftValue, rightValue);
268 }
269
270 protected String getOperationText() {
271 return "contains";
272 }
273 };
274 }
275
276 public static Predicate isNull(final Expression expression) {
277 return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) {
278
279 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
280 if (leftValue == null) {
281 // the left operator is null so its true
282 return true;
283 }
284
285 return ObjectHelper.typeCoerceEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue);
286 }
287
288 protected String getOperationText() {
289 // leave the operation text as "is not" as Camel will insert right and left expression around it
290 // so it will be displayed as: XXX is null
291 return "is";
292 }
293 };
294 }
295
296 public static Predicate isNotNull(final Expression expression) {
297 return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) {
298
299 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
300 if (leftValue != null) {
301 // the left operator is not null so its true
302 return true;
303 }
304
305 return ObjectHelper.typeCoerceNotEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue);
306 }
307
308 protected String getOperationText() {
309 // leave the operation text as "is not" as Camel will insert right and left expression around it
310 // so it will be displayed as: XXX is not null
311 return "is not";
312 }
313 };
314 }
315
316 public static Predicate isInstanceOf(final Expression expression, final Class<?> type) {
317 notNull(expression, "expression");
318 notNull(type, "type");
319
320 return new Predicate() {
321 public boolean matches(Exchange exchange) {
322 Object value = expression.evaluate(exchange, Object.class);
323 return type.isInstance(value);
324 }
325
326 @Override
327 public String toString() {
328 return expression + " instanceof " + type.getCanonicalName();
329 }
330 };
331 }
332
333 public static Predicate startsWith(final Expression left, final Expression right) {
334 return new BinaryPredicateSupport(left, right) {
335
336 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
337 if (leftValue == null && rightValue == null) {
338 // they are equal
339 return true;
340 } else if (leftValue == null || rightValue == null) {
341 // only one of them is null so they are not equal
342 return false;
343 }
344 String leftStr = exchange.getContext().getTypeConverter().convertTo(String.class, leftValue);
345 String rightStr = exchange.getContext().getTypeConverter().convertTo(String.class, rightValue);
346 if (leftStr != null && rightStr != null) {
347 return leftStr.startsWith(rightStr);
348 } else {
349 return false;
350 }
351 }
352
353 protected String getOperationText() {
354 return "startsWith";
355 }
356 };
357 }
358
359 public static Predicate endsWith(final Expression left, final Expression right) {
360 return new BinaryPredicateSupport(left, right) {
361
362 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
363 if (leftValue == null && rightValue == null) {
364 // they are equal
365 return true;
366 } else if (leftValue == null || rightValue == null) {
367 // only one of them is null so they are not equal
368 return false;
369 }
370 String leftStr = exchange.getContext().getTypeConverter().convertTo(String.class, leftValue);
371 String rightStr = exchange.getContext().getTypeConverter().convertTo(String.class, rightValue);
372 if (leftStr != null && rightStr != null) {
373 return leftStr.endsWith(rightStr);
374 } else {
375 return false;
376 }
377 }
378
379 protected String getOperationText() {
380 return "endsWith";
381 }
382 };
383 }
384
385 /**
386 * Returns a predicate which is true if the expression matches the given
387 * regular expression
388 *
389 * @param expression the expression to evaluate
390 * @param regex the regular expression to match against
391 * @return a new predicate
392 */
393 public static Predicate regex(final Expression expression, final String regex) {
394 return regex(expression, Pattern.compile(regex));
395 }
396
397 /**
398 * Returns a predicate which is true if the expression matches the given
399 * regular expression
400 *
401 * @param expression the expression to evaluate
402 * @param pattern the regular expression to match against
403 * @return a new predicate
404 */
405 public static Predicate regex(final Expression expression, final Pattern pattern) {
406 notNull(expression, "expression");
407 notNull(pattern, "pattern");
408
409 return new Predicate() {
410 public boolean matches(Exchange exchange) {
411 String value = expression.evaluate(exchange, String.class);
412 if (value != null) {
413 Matcher matcher = pattern.matcher(value);
414 return matcher.matches();
415 }
416 return false;
417 }
418
419 @Override
420 public String toString() {
421 return expression + ".matches('" + pattern + "')";
422 }
423 };
424 }
425
426 /**
427 * Concat the given predicates into a single predicate, which
428 * only matches if all the predicates matches.
429 *
430 * @param predicates predicates
431 * @return a single predicate containing all the predicates
432 */
433 public static Predicate and(List<Predicate> predicates) {
434 Predicate answer = null;
435 for (Predicate predicate : predicates) {
436 if (answer == null) {
437 answer = predicate;
438 } else {
439 answer = and(answer, predicate);
440 }
441 }
442 return answer;
443 }
444
445 /**
446 * A constant predicate.
447 *
448 * @param answer the constant matches
449 * @return a predicate that always returns the given answer.
450 */
451 public static Predicate constant(final boolean answer) {
452 return new Predicate() {
453 @Override
454 public boolean matches(Exchange exchange) {
455 return answer;
456 }
457
458 @Override
459 public String toString() {
460 return "" + answer;
461 }
462 };
463 }
464 }