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 two predicates by a logical OR.
090         * If you want to combine multiple predicates see {@link #in(Predicate...)}
091         */
092        public static Predicate or(final Predicate left, final Predicate right) {
093            notNull(left, "left");
094            notNull(right, "right");
095            return new Predicate() {
096                public boolean matches(Exchange exchange) {
097                    return left.matches(exchange) || right.matches(exchange);
098                }
099    
100                @Override
101                public String toString() {
102                    return "(" + left + ") or (" + right + ")";
103                }
104            };
105        }
106    
107        /**
108         * A helper method to return true if any of the predicates matches.
109         */
110        public static Predicate in(final Predicate... predicates) {
111            notNull(predicates, "predicates");
112    
113            return new Predicate() {
114                public boolean matches(Exchange exchange) {
115                    for (Predicate in : predicates) {
116                        if (in.matches(exchange)) {
117                            return true;
118                        }
119                    }
120                    return false;
121                }
122    
123                @Override
124                public String toString() {
125                    return "in (" + Arrays.asList(predicates) + ")";
126                }
127            };
128        }
129    
130        /**
131         * A helper method to return true if any of the predicates matches.
132         */
133        public static Predicate in(List<Predicate> predicates) {
134            return in(predicates.toArray(new Predicate[0]));
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    
434        /**
435         * Concat the given predicates into a single predicate, which
436         * only matches if all the predicates matches.
437         *
438         * @param predicates predicates
439         * @return a single predicate containing all the predicates
440         */
441        public static Predicate and(List<Predicate> predicates) {
442            Predicate answer = null;
443            for (Predicate predicate : predicates) {
444                if (answer == null) {
445                    answer = predicate;
446                } else {
447                    answer = and(answer, predicate);
448                }
449            }
450            return answer;
451        }
452    
453        /**
454         * Concat the given predicates into a single predicate, which only matches
455         * if all the predicates matches.
456         *
457         * @param predicates predicates
458         * @return a single predicate containing all the predicates
459         */
460        public static Predicate and(Predicate... predicates) {
461            return and(Arrays.asList(predicates));
462        }
463    
464        /**
465         * A constant predicate.
466         *
467         * @param answer the constant matches
468         * @return a predicate that always returns the given answer.
469         */
470        public static Predicate constant(final boolean answer) {
471            return new Predicate() {
472                @Override
473                public boolean matches(Exchange exchange) {
474                    return answer;
475                }
476    
477                @Override
478                public String toString() {
479                    return "" + answer;
480                }
481            };
482        }
483    }