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 }