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