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