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 isNull(final Expression expression) { 335 return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) { 336 337 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 338 if (leftValue == null) { 339 // the left operator is null so its true 340 return true; 341 } 342 343 return ObjectHelper.typeCoerceEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue); 344 } 345 346 protected String getOperationText() { 347 // leave the operation text as "is not" as Camel will insert right and left expression around it 348 // so it will be displayed as: XXX is null 349 return "is"; 350 } 351 }; 352 } 353 354 public static Predicate isNotNull(final Expression expression) { 355 return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) { 356 357 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 358 if (leftValue != null) { 359 // the left operator is not null so its true 360 return true; 361 } 362 363 return ObjectHelper.typeCoerceNotEquals(exchange.getContext().getTypeConverter(), leftValue, rightValue); 364 } 365 366 protected String getOperationText() { 367 // leave the operation text as "is not" as Camel will insert right and left expression around it 368 // so it will be displayed as: XXX is not null 369 return "is not"; 370 } 371 }; 372 } 373 374 public static Predicate isInstanceOf(final Expression expression, final Class<?> type) { 375 notNull(expression, "expression"); 376 notNull(type, "type"); 377 378 return new Predicate() { 379 public boolean matches(Exchange exchange) { 380 Object value = expression.evaluate(exchange, Object.class); 381 return type.isInstance(value); 382 } 383 384 @Override 385 public String toString() { 386 return expression + " instanceof " + type.getCanonicalName(); 387 } 388 }; 389 } 390 391 public static Predicate startsWith(final Expression left, final Expression right) { 392 return new BinaryPredicateSupport(left, right) { 393 394 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 395 if (leftValue == null && rightValue == null) { 396 // they are equal 397 return true; 398 } else if (leftValue == null || rightValue == null) { 399 // only one of them is null so they are not equal 400 return false; 401 } 402 String leftStr = exchange.getContext().getTypeConverter().convertTo(String.class, leftValue); 403 String rightStr = exchange.getContext().getTypeConverter().convertTo(String.class, rightValue); 404 if (leftStr != null && rightStr != null) { 405 return leftStr.startsWith(rightStr); 406 } else { 407 return false; 408 } 409 } 410 411 protected String getOperationText() { 412 return "startsWith"; 413 } 414 }; 415 } 416 417 public static Predicate endsWith(final Expression left, final Expression right) { 418 return new BinaryPredicateSupport(left, right) { 419 420 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 421 if (leftValue == null && rightValue == null) { 422 // they are equal 423 return true; 424 } else if (leftValue == null || rightValue == null) { 425 // only one of them is null so they are not equal 426 return false; 427 } 428 String leftStr = exchange.getContext().getTypeConverter().convertTo(String.class, leftValue); 429 String rightStr = exchange.getContext().getTypeConverter().convertTo(String.class, rightValue); 430 if (leftStr != null && rightStr != null) { 431 return leftStr.endsWith(rightStr); 432 } else { 433 return false; 434 } 435 } 436 437 protected String getOperationText() { 438 return "endsWith"; 439 } 440 }; 441 } 442 443 /** 444 * Returns a predicate which is true if the expression matches the given 445 * regular expression 446 * 447 * @param expression the expression to evaluate 448 * @param regex the regular expression to match against 449 * @return a new predicate 450 */ 451 public static Predicate regex(final Expression expression, final String regex) { 452 return regex(expression, Pattern.compile(regex)); 453 } 454 455 /** 456 * Returns a predicate which is true if the expression matches the given 457 * regular expression 458 * 459 * @param expression the expression to evaluate 460 * @param pattern the regular expression to match against 461 * @return a new predicate 462 */ 463 public static Predicate regex(final Expression expression, final Pattern pattern) { 464 notNull(expression, "expression"); 465 notNull(pattern, "pattern"); 466 467 return new Predicate() { 468 public boolean matches(Exchange exchange) { 469 String value = expression.evaluate(exchange, String.class); 470 if (value != null) { 471 Matcher matcher = pattern.matcher(value); 472 return matcher.matches(); 473 } 474 return false; 475 } 476 477 @Override 478 public String toString() { 479 return expression + ".matches('" + pattern + "')"; 480 } 481 }; 482 } 483 484 /** 485 * Concat the given predicates into a single predicate, which 486 * only matches if all the predicates matches. 487 * 488 * @param predicates predicates 489 * @return a single predicate containing all the predicates 490 */ 491 public static Predicate and(List<Predicate> predicates) { 492 Predicate answer = null; 493 for (Predicate predicate : predicates) { 494 if (answer == null) { 495 answer = predicate; 496 } else { 497 answer = and(answer, predicate); 498 } 499 } 500 return answer; 501 } 502 503 /** 504 * Concat the given predicates into a single predicate, which only matches 505 * if all the predicates matches. 506 * 507 * @param predicates predicates 508 * @return a single predicate containing all the predicates 509 */ 510 public static Predicate and(Predicate... predicates) { 511 return and(Arrays.asList(predicates)); 512 } 513 514 /** 515 * A constant predicate. 516 * 517 * @param answer the constant matches 518 * @return a predicate that always returns the given answer. 519 */ 520 public static Predicate constant(final boolean answer) { 521 return new Predicate() { 522 @Override 523 public boolean matches(Exchange exchange) { 524 return answer; 525 } 526 527 @Override 528 public String toString() { 529 return "" + answer; 530 } 531 }; 532 } 533}