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: 776194 $
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        /**
342         * Returns a predicate which is true if the expression matches the given
343         * regular expression
344         *
345         * @param expression the expression to evaluate
346         * @param regex the regular expression to match against
347         * @return a new predicate
348         */
349        public static Predicate regex(final Expression expression, final String regex) {
350            return regex(expression, Pattern.compile(regex));
351        }
352    
353        /**
354         * Returns a predicate which is true if the expression matches the given
355         * regular expression
356         *
357         * @param expression the expression to evaluate
358         * @param pattern the regular expression to match against
359         * @return a new predicate
360         */
361        public static Predicate regex(final Expression expression, final Pattern pattern) {
362            notNull(expression, "expression");
363            notNull(pattern, "pattern");
364    
365            return new Predicate() {
366                public boolean matches(Exchange exchange) {
367                    String value = expression.evaluate(exchange, String.class);
368                    if (value != null) {
369                        Matcher matcher = pattern.matcher(value);
370                        return matcher.matches();
371                    }
372                    return false;
373                }
374    
375                @Override
376                public String toString() {
377                    return expression + ".matches('" + pattern + "')";
378                }
379            };
380        }
381    }