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 */ 017package org.apache.camel.builder; 018 019import java.util.Arrays; 020import java.util.List; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024import org.apache.camel.Exchange; 025import org.apache.camel.Expression; 026import org.apache.camel.Predicate; 027import org.apache.camel.util.ExpressionToPredicateAdapter; 028import org.apache.camel.util.ObjectHelper; 029 030import static org.apache.camel.util.ObjectHelper.notNull; 031 032/** 033 * A helper class for working with predicates 034 * 035 * @version 036 */ 037public final class PredicateBuilder { 038 039 /** 040 * Utility classes should not have a public constructor. 041 */ 042 private PredicateBuilder() { 043 } 044 045 /** 046 * Converts the given expression into an {@link Predicate} 047 */ 048 public static Predicate toPredicate(final Expression expression) { 049 return ExpressionToPredicateAdapter.toPredicate(expression); 050 } 051 052 /** 053 * A helper method to return the logical not of the given predicate 054 */ 055 public static Predicate not(final Predicate predicate) { 056 notNull(predicate, "predicate"); 057 return new Predicate() { 058 public boolean matches(Exchange exchange) { 059 return !predicate.matches(exchange); 060 } 061 062 @Override 063 public String toString() { 064 return "not (" + predicate + ")"; 065 } 066 }; 067 } 068 069 /** 070 * A helper method to combine multiple predicates by a logical AND 071 */ 072 public static Predicate and(final Predicate left, final Predicate right) { 073 notNull(left, "left"); 074 notNull(right, "right"); 075 return new Predicate() { 076 public boolean matches(Exchange exchange) { 077 return left.matches(exchange) && right.matches(exchange); 078 } 079 080 @Override 081 public String toString() { 082 return "(" + left + ") and (" + right + ")"; 083 } 084 }; 085 } 086 087 /** 088 * A helper method to combine two predicates by a logical OR. 089 * If you want to combine multiple predicates see {@link #in(Predicate...)} 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 * Concat the given predicates into a single predicate, which matches 108 * if at least one predicates matches. 109 * 110 * @param predicates predicates 111 * @return a single predicate containing all the predicates 112 */ 113 public static Predicate or(List<Predicate> predicates) { 114 Predicate answer = null; 115 for (Predicate predicate : predicates) { 116 if (answer == null) { 117 answer = predicate; 118 } else { 119 answer = or(answer, predicate); 120 } 121 } 122 return answer; 123 } 124 125 /** 126 * Concat the given predicates into a single predicate, which matches 127 * if at least one predicates matches. 128 * 129 * @param predicates predicates 130 * @return a single predicate containing all the predicates 131 */ 132 public static Predicate or(Predicate... predicates) { 133 return or(Arrays.asList(predicates)); 134 } 135 136 /** 137 * A helper method to return true if any of the predicates matches. 138 */ 139 public static Predicate in(final Predicate... predicates) { 140 notNull(predicates, "predicates"); 141 142 return new Predicate() { 143 public boolean matches(Exchange exchange) { 144 for (Predicate in : predicates) { 145 if (in.matches(exchange)) { 146 return true; 147 } 148 } 149 return false; 150 } 151 152 @Override 153 public String toString() { 154 return "in (" + Arrays.asList(predicates) + ")"; 155 } 156 }; 157 } 158 159 /** 160 * A helper method to return true if any of the predicates matches. 161 */ 162 public static Predicate in(List<Predicate> predicates) { 163 return in(predicates.toArray(new Predicate[0])); 164 } 165 166 public static Predicate isEqualTo(final Expression left, final Expression right) { 167 return new BinaryPredicateSupport(left, right) { 168 169 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 170 if (leftValue == null && rightValue == null) { 171 // they are equal 172 return true; 173 } else if (leftValue == null || rightValue == null) { 174 // only one of them is null so they are not equal 175 return false; 176 } 177 178 return ObjectHelper.typeCoerceEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue); 179 } 180 181 protected String getOperationText() { 182 return "=="; 183 } 184 }; 185 } 186 187 public static Predicate isEqualToIgnoreCase(final Expression left, final Expression right) { 188 return new BinaryPredicateSupport(left, right) { 189 190 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 191 if (leftValue == null && rightValue == null) { 192 // they are equal 193 return true; 194 } else if (leftValue == null || rightValue == null) { 195 // only one of them is null so they are not equal 196 return false; 197 } 198 199 return ObjectHelper.typeCoerceEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue, true); 200 } 201 202 protected String getOperationText() { 203 return "=~"; 204 } 205 }; 206 } 207 208 public static Predicate isNotEqualTo(final Expression left, final Expression right) { 209 return new BinaryPredicateSupport(left, right) { 210 211 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 212 if (leftValue == null && rightValue == null) { 213 // they are equal 214 return false; 215 } else if (leftValue == null || rightValue == null) { 216 // only one of them is null so they are not equal 217 return true; 218 } 219 220 return ObjectHelper.typeCoerceNotEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue); 221 } 222 223 protected String getOperationText() { 224 return "!="; 225 } 226 }; 227 } 228 229 public static Predicate isLessThan(final Expression left, final Expression right) { 230 return new BinaryPredicateSupport(left, right) { 231 232 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 233 if (leftValue == null && rightValue == null) { 234 // they are equal 235 return true; 236 } else if (leftValue == null || rightValue == null) { 237 // only one of them is null so they are not equal 238 return false; 239 } 240 241 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) < 0; 242 } 243 244 protected String getOperationText() { 245 return "<"; 246 } 247 }; 248 } 249 250 public static Predicate isLessThanOrEqualTo(final Expression left, final Expression right) { 251 return new BinaryPredicateSupport(left, right) { 252 253 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 254 if (leftValue == null && rightValue == null) { 255 // they are equal 256 return true; 257 } else if (leftValue == null || rightValue == null) { 258 // only one of them is null so they are not equal 259 return false; 260 } 261 262 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) <= 0; 263 } 264 265 protected String getOperationText() { 266 return "<="; 267 } 268 }; 269 } 270 271 public static Predicate isGreaterThan(final Expression left, final Expression right) { 272 return new BinaryPredicateSupport(left, right) { 273 274 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 275 if (leftValue == null && rightValue == null) { 276 // they are equal 277 return false; 278 } else if (leftValue == null || rightValue == null) { 279 // only one of them is null so they are not equal 280 return false; 281 } 282 283 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) > 0; 284 } 285 286 protected String getOperationText() { 287 return ">"; 288 } 289 }; 290 } 291 292 public static Predicate isGreaterThanOrEqualTo(final Expression left, final Expression right) { 293 return new BinaryPredicateSupport(left, right) { 294 295 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 296 if (leftValue == null && rightValue == null) { 297 // they are equal 298 return true; 299 } else if (leftValue == null || rightValue == null) { 300 // only one of them is null so they are not equal 301 return false; 302 } 303 304 return ObjectHelper.typeCoerceCompare(exchange.getContext().getTypeConverter(), leftValue, rightValue) >= 0; 305 } 306 307 protected String getOperationText() { 308 return ">="; 309 } 310 }; 311 } 312 313 public static Predicate contains(final Expression left, final Expression right) { 314 return new BinaryPredicateSupport(left, right) { 315 316 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 317 if (leftValue == null && rightValue == null) { 318 // they are equal 319 return true; 320 } else if (leftValue == null || rightValue == null) { 321 // only one of them is null so they are not equal 322 return false; 323 } 324 325 return ObjectHelper.contains(leftValue, rightValue); 326 } 327 328 protected String getOperationText() { 329 return "contains"; 330 } 331 }; 332 } 333 334 public static Predicate containsIgnoreCase(final Expression left, final Expression right) { 335 return new BinaryPredicateSupport(left, right) { 336 337 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 338 if (leftValue == null && rightValue == null) { 339 // they are equal 340 return true; 341 } else if (leftValue == null || rightValue == null) { 342 // only one of them is null so they are not equal 343 return false; 344 } 345 346 return ObjectHelper.containsIgnoreCase(leftValue, rightValue); 347 } 348 349 protected String getOperationText() { 350 return "~~"; 351 } 352 }; 353 } 354 355 public static Predicate isNull(final Expression expression) { 356 return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) { 357 358 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 359 if (leftValue == null) { 360 // the left operator is null so its true 361 return true; 362 } 363 364 return ObjectHelper.typeCoerceEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue); 365 } 366 367 protected String getOperationText() { 368 // leave the operation text as "is not" as Camel will insert right and left expression around it 369 // so it will be displayed as: XXX is null 370 return "is"; 371 } 372 }; 373 } 374 375 public static Predicate isNotNull(final Expression expression) { 376 return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) { 377 378 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 379 if (leftValue != null) { 380 // the left operator is not null so its true 381 return true; 382 } 383 384 return ObjectHelper.typeCoerceNotEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue); 385 } 386 387 protected String getOperationText() { 388 // leave the operation text as "is not" as Camel will insert right and left expression around it 389 // so it will be displayed as: XXX is not null 390 return "is not"; 391 } 392 }; 393 } 394 395 public static Predicate isInstanceOf(final Expression expression, final Class<?> type) { 396 notNull(expression, "expression"); 397 notNull(type, "type"); 398 399 return new Predicate() { 400 public boolean matches(Exchange exchange) { 401 Object value = expression.evaluate(exchange, Object.class); 402 return type.isInstance(value); 403 } 404 405 @Override 406 public String toString() { 407 return expression + " instanceof " + type.getCanonicalName(); 408 } 409 }; 410 } 411 412 public static Predicate startsWith(final Expression left, final Expression right) { 413 return new BinaryPredicateSupport(left, right) { 414 415 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 416 if (leftValue == null && rightValue == null) { 417 // they are equal 418 return true; 419 } else if (leftValue == null || rightValue == null) { 420 // only one of them is null so they are not equal 421 return false; 422 } 423 String leftStr = exchange.getContext().getTypeConverter().convertTo(String.class, leftValue); 424 String rightStr = exchange.getContext().getTypeConverter().convertTo(String.class, rightValue); 425 if (leftStr != null && rightStr != null) { 426 return leftStr.startsWith(rightStr); 427 } else { 428 return false; 429 } 430 } 431 432 protected String getOperationText() { 433 return "startsWith"; 434 } 435 }; 436 } 437 438 public static Predicate endsWith(final Expression left, final Expression right) { 439 return new BinaryPredicateSupport(left, right) { 440 441 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 442 if (leftValue == null && rightValue == null) { 443 // they are equal 444 return true; 445 } else if (leftValue == null || rightValue == null) { 446 // only one of them is null so they are not equal 447 return false; 448 } 449 String leftStr = exchange.getContext().getTypeConverter().convertTo(String.class, leftValue); 450 String rightStr = exchange.getContext().getTypeConverter().convertTo(String.class, rightValue); 451 if (leftStr != null && rightStr != null) { 452 return leftStr.endsWith(rightStr); 453 } else { 454 return false; 455 } 456 } 457 458 protected String getOperationText() { 459 return "endsWith"; 460 } 461 }; 462 } 463 464 /** 465 * Returns a predicate which is true if the expression matches the given 466 * regular expression 467 * 468 * @param expression the expression to evaluate 469 * @param regex the regular expression to match against 470 * @return a new predicate 471 */ 472 public static Predicate regex(final Expression expression, final String regex) { 473 return regex(expression, Pattern.compile(regex)); 474 } 475 476 /** 477 * Returns a predicate which is true if the expression matches the given 478 * regular expression 479 * 480 * @param expression the expression to evaluate 481 * @param pattern the regular expression to match against 482 * @return a new predicate 483 */ 484 public static Predicate regex(final Expression expression, final Pattern pattern) { 485 notNull(expression, "expression"); 486 notNull(pattern, "pattern"); 487 488 return new Predicate() { 489 public boolean matches(Exchange exchange) { 490 String value = expression.evaluate(exchange, String.class); 491 if (value != null) { 492 Matcher matcher = pattern.matcher(value); 493 return matcher.matches(); 494 } 495 return false; 496 } 497 498 @Override 499 public String toString() { 500 return expression + ".matches('" + pattern + "')"; 501 } 502 }; 503 } 504 505 /** 506 * Concat the given predicates into a single predicate, which 507 * only matches if all the predicates matches. 508 * 509 * @param predicates predicates 510 * @return a single predicate containing all the predicates 511 */ 512 public static Predicate and(List<Predicate> predicates) { 513 Predicate answer = null; 514 for (Predicate predicate : predicates) { 515 if (answer == null) { 516 answer = predicate; 517 } else { 518 answer = and(answer, predicate); 519 } 520 } 521 return answer; 522 } 523 524 /** 525 * Concat the given predicates into a single predicate, which only matches 526 * if all the predicates matches. 527 * 528 * @param predicates predicates 529 * @return a single predicate containing all the predicates 530 */ 531 public static Predicate and(Predicate... predicates) { 532 return and(Arrays.asList(predicates)); 533 } 534 535 /** 536 * A constant predicate. 537 * 538 * @param answer the constant matches 539 * @return a predicate that always returns the given answer. 540 */ 541 public static Predicate constant(final boolean answer) { 542 return new Predicate() { 543 @Override 544 public boolean matches(Exchange exchange) { 545 return answer; 546 } 547 548 @Override 549 public String toString() { 550 return "" + answer; 551 } 552 }; 553 } 554}