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.text.SimpleDateFormat; 020 import java.util.Collection; 021 import java.util.Collections; 022 import java.util.Comparator; 023 import java.util.Date; 024 import java.util.Iterator; 025 import java.util.List; 026 import java.util.Scanner; 027 import java.util.regex.Pattern; 028 029 import org.apache.camel.Endpoint; 030 import org.apache.camel.Exchange; 031 import org.apache.camel.Expression; 032 import org.apache.camel.Message; 033 import org.apache.camel.NoSuchEndpointException; 034 import org.apache.camel.Producer; 035 import org.apache.camel.impl.ExpressionAdapter; 036 import org.apache.camel.language.bean.BeanLanguage; 037 import org.apache.camel.spi.Language; 038 import org.apache.camel.util.ExchangeHelper; 039 import org.apache.camel.util.ObjectHelper; 040 041 /** 042 * A helper class for working with <a href="http://camel.apache.org/expression.html">expressions</a>. 043 * 044 * @version $Revision: 780937 $ 045 */ 046 public final class ExpressionBuilder { 047 048 /** 049 * Utility classes should not have a public constructor. 050 */ 051 private ExpressionBuilder() { 052 } 053 054 /** 055 * Returns an expression for the header value with the given name 056 * 057 * @param headerName the name of the header the expression will return 058 * @return an expression object which will return the header value 059 */ 060 public static Expression headerExpression(final String headerName) { 061 return new ExpressionAdapter() { 062 public Object evaluate(Exchange exchange) { 063 Object header = exchange.getIn().getHeader(headerName); 064 if (header == null) { 065 // fall back on a property 066 header = exchange.getProperty(headerName); 067 } 068 return header; 069 } 070 071 @Override 072 public String toString() { 073 return "header(" + headerName + ")"; 074 } 075 }; 076 } 077 078 /** 079 * Returns an expression for the inbound message headers 080 * 081 * @return an expression object which will return the inbound headers 082 */ 083 public static Expression headersExpression() { 084 return new ExpressionAdapter() { 085 public Object evaluate(Exchange exchange) { 086 return exchange.getIn().getHeaders(); 087 } 088 089 @Override 090 public String toString() { 091 return "headers"; 092 } 093 }; 094 } 095 096 /** 097 * Returns an expression for the out header value with the given name 098 * 099 * @param headerName the name of the header the expression will return 100 * @return an expression object which will return the header value 101 */ 102 public static Expression outHeaderExpression(final String headerName) { 103 return new ExpressionAdapter() { 104 public Object evaluate(Exchange exchange) { 105 if (!exchange.hasOut()) { 106 return null; 107 } 108 109 Message out = exchange.getOut(); 110 Object header = out.getHeader(headerName); 111 if (header == null) { 112 // lets try the exchange header 113 header = exchange.getProperty(headerName); 114 } 115 return header; 116 } 117 118 @Override 119 public String toString() { 120 return "outHeader(" + headerName + ")"; 121 } 122 }; 123 } 124 125 /** 126 * Returns an expression for the outbound message headers 127 * 128 * @return an expression object which will return the headers 129 */ 130 public static Expression outHeadersExpression() { 131 return new ExpressionAdapter() { 132 public Object evaluate(Exchange exchange) { 133 return exchange.getOut().getHeaders(); 134 } 135 136 @Override 137 public String toString() { 138 return "outHeaders"; 139 } 140 }; 141 } 142 143 /** 144 * Returns an expression for an exception set on the exchange 145 * 146 * @see Exchange#getException() 147 * @return an expression object which will return the exception set on the exchange 148 */ 149 public static Expression exchangeExceptionExpression() { 150 return new ExpressionAdapter() { 151 public Object evaluate(Exchange exchange) { 152 Exception exception = exchange.getException(); 153 if (exception == null) { 154 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 155 } 156 return exception; 157 } 158 159 @Override 160 public String toString() { 161 return "exchangeException"; 162 } 163 }; 164 } 165 166 /** 167 * Returns an expression for an exception set on the exchange 168 * <p/> 169 * Is used to get the caused exception that typically have been wrapped in some sort 170 * of Camel wrapper exception 171 * @param type the exception type 172 * @see Exchange#getException(Class) 173 * @return an expression object which will return the exception set on the exchange 174 */ 175 public static Expression exchangeExceptionExpression(final Class<Exception> type) { 176 return new ExpressionAdapter() { 177 public Object evaluate(Exchange exchange) { 178 Exception exception = exchange.getException(type); 179 if (exception == null) { 180 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 181 // must use exception iterator to walk it and find the type we are looking for 182 Iterator<Throwable> it = ObjectHelper.createExceptionIterator(exception); 183 while (it.hasNext()) { 184 Throwable e = it.next(); 185 if (type.isInstance(e)) { 186 return type.cast(e); 187 } 188 } 189 // not found 190 return null; 191 192 } 193 return exception; 194 } 195 196 @Override 197 public String toString() { 198 return "exchangeException[" + type + "]"; 199 } 200 }; 201 } 202 203 /** 204 * Returns an expression for the type converter 205 * 206 * @return an expression object which will return the type converter 207 */ 208 public static Expression typeConverterExpression() { 209 return new ExpressionAdapter() { 210 public Object evaluate(Exchange exchange) { 211 return exchange.getContext().getTypeConverter(); 212 } 213 214 @Override 215 public String toString() { 216 return "typeConverter"; 217 } 218 }; 219 } 220 221 /** 222 * Returns an expression for an exception message set on the exchange 223 * 224 * @see <tt>Exchange.getException().getMessage()</tt> 225 * @return an expression object which will return the exception message set on the exchange 226 */ 227 public static Expression exchangeExceptionMessageExpression() { 228 return new ExpressionAdapter() { 229 public Object evaluate(Exchange exchange) { 230 Exception exception = exchange.getException(); 231 if (exception == null) { 232 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 233 } 234 return exception != null ? exception.getMessage() : null; 235 } 236 237 @Override 238 public String toString() { 239 return "exchangeExceptionMessage"; 240 } 241 }; 242 } 243 244 /** 245 * Returns an expression for the property value of exchange with the given name 246 * 247 * @param propertyName the name of the property the expression will return 248 * @return an expression object which will return the property value 249 */ 250 public static Expression propertyExpression(final String propertyName) { 251 return new ExpressionAdapter() { 252 public Object evaluate(Exchange exchange) { 253 return exchange.getProperty(propertyName); 254 } 255 256 @Override 257 public String toString() { 258 return "property(" + propertyName + ")"; 259 } 260 }; 261 } 262 263 /** 264 * Returns an expression for the properties of exchange 265 * 266 * @return an expression object which will return the properties 267 */ 268 public static Expression propertiesExpression() { 269 return new ExpressionAdapter() { 270 public Object evaluate(Exchange exchange) { 271 return exchange.getProperties(); 272 } 273 274 @Override 275 public String toString() { 276 return "properties"; 277 } 278 }; 279 } 280 281 /** 282 * Returns an expression for the properties of the camel context 283 * 284 * @return an expression object which will return the properties 285 */ 286 public static Expression camelContextPropertiesExpression() { 287 return new ExpressionAdapter() { 288 public Object evaluate(Exchange exchange) { 289 return exchange.getContext().getProperties(); 290 } 291 292 @Override 293 public String toString() { 294 return "camelContextProperties"; 295 } 296 }; 297 } 298 299 /** 300 * Returns an expression for the property value of the camel context with the given name 301 * 302 * @param propertyName the name of the property the expression will return 303 * @return an expression object which will return the property value 304 */ 305 public static Expression camelContextPropertyExpression(final String propertyName) { 306 return new ExpressionAdapter() { 307 public Object evaluate(Exchange exchange) { 308 return exchange.getContext().getProperties().get(propertyName); 309 } 310 311 @Override 312 public String toString() { 313 return "camelContextProperty(" + propertyName + ")"; 314 } 315 }; 316 } 317 318 /** 319 * Returns an expression for a system property value with the given name 320 * 321 * @param propertyName the name of the system property the expression will return 322 * @return an expression object which will return the system property value 323 */ 324 public static Expression systemPropertyExpression(final String propertyName) { 325 return systemPropertyExpression(propertyName, null); 326 } 327 328 /** 329 * Returns an expression for a system property value with the given name 330 * 331 * @param propertyName the name of the system property the expression will return 332 * @param defaultValue default value to return if no system property exists 333 * @return an expression object which will return the system property value 334 */ 335 public static Expression systemPropertyExpression(final String propertyName, 336 final String defaultValue) { 337 return new ExpressionAdapter() { 338 public Object evaluate(Exchange exchange) { 339 return System.getProperty(propertyName, defaultValue); 340 } 341 342 @Override 343 public String toString() { 344 return "systemProperty(" + propertyName + ")"; 345 } 346 }; 347 } 348 349 /** 350 * Returns an expression for the constant value 351 * 352 * @param value the value the expression will return 353 * @return an expression object which will return the constant value 354 */ 355 public static Expression constantExpression(final Object value) { 356 return new ExpressionAdapter() { 357 public Object evaluate(Exchange exchange) { 358 return value; 359 } 360 361 @Override 362 public String toString() { 363 return "" + value; 364 } 365 }; 366 } 367 368 /** 369 * Returns the expression for the exchanges inbound message body 370 */ 371 public static Expression bodyExpression() { 372 return new ExpressionAdapter() { 373 public Object evaluate(Exchange exchange) { 374 return exchange.getIn().getBody(); 375 } 376 377 @Override 378 public String toString() { 379 return "body"; 380 } 381 }; 382 } 383 384 /** 385 * Returns the expression for the exchanges inbound message body converted 386 * to the given type 387 */ 388 public static <T> Expression bodyExpression(final Class<T> type) { 389 return new ExpressionAdapter() { 390 public Object evaluate(Exchange exchange) { 391 return exchange.getIn().getBody(type); 392 } 393 394 @Override 395 public String toString() { 396 return "bodyAs[" + type.getName() + "]"; 397 } 398 }; 399 } 400 401 /** 402 * Returns the expression for the exchanges inbound message body type 403 */ 404 public static Expression bodyTypeExpression() { 405 return new ExpressionAdapter() { 406 public Object evaluate(Exchange exchange) { 407 return exchange.getIn().getBody().getClass(); 408 } 409 410 @Override 411 public String toString() { 412 return "bodyType"; 413 } 414 }; 415 } 416 417 /** 418 * Returns the expression for the out messages body 419 */ 420 public static Expression outBodyExpression() { 421 return new ExpressionAdapter() { 422 public Object evaluate(Exchange exchange) { 423 if (exchange.hasOut()) { 424 return exchange.getOut().getBody(); 425 } else { 426 return null; 427 } 428 } 429 430 @Override 431 public String toString() { 432 return "outBody"; 433 } 434 }; 435 } 436 437 /** 438 * Returns the expression for the exchanges outbound message body converted 439 * to the given type 440 */ 441 public static <T> Expression outBodyExpression(final Class<T> type) { 442 return new ExpressionAdapter() { 443 public Object evaluate(Exchange exchange) { 444 if (exchange.hasOut()) { 445 return exchange.getOut().getBody(type); 446 } else { 447 return null; 448 } 449 } 450 451 @Override 452 public String toString() { 453 return "outBodyAs[" + type.getName() + "]"; 454 } 455 }; 456 } 457 458 /** 459 * Returns the expression for the fault messages body 460 */ 461 public static Expression faultBodyExpression() { 462 return new ExpressionAdapter() { 463 public Object evaluate(Exchange exchange) { 464 return exchange.getFault().getBody(); 465 } 466 467 @Override 468 public String toString() { 469 return "faultBody"; 470 } 471 }; 472 } 473 474 /** 475 * Returns the expression for the exchanges fault message body converted 476 * to the given type 477 */ 478 public static <T> Expression faultBodyExpression(final Class<T> type) { 479 return new ExpressionAdapter() { 480 public Object evaluate(Exchange exchange) { 481 return exchange.getFault().getBody(type); 482 } 483 484 @Override 485 public String toString() { 486 return "faultBodyAs[" + type.getName() + "]"; 487 } 488 }; 489 } 490 491 /** 492 * Returns the expression for the exchange 493 */ 494 public static Expression exchangeExpression() { 495 return new ExpressionAdapter() { 496 public Object evaluate(Exchange exchange) { 497 return exchange; 498 } 499 500 @Override 501 public String toString() { 502 return "exchange"; 503 } 504 }; 505 } 506 507 /** 508 * Returns the expression for the IN message 509 */ 510 public static Expression inMessageExpression() { 511 return new ExpressionAdapter() { 512 public Object evaluate(Exchange exchange) { 513 return exchange.getIn(); 514 } 515 516 @Override 517 public String toString() { 518 return "inMessage"; 519 } 520 }; 521 } 522 523 /** 524 * Returns the expression for the OUT message 525 */ 526 public static Expression outMessageExpression() { 527 return new ExpressionAdapter() { 528 public Object evaluate(Exchange exchange) { 529 return exchange.getOut(); 530 } 531 532 @Override 533 public String toString() { 534 return "outMessage"; 535 } 536 }; 537 } 538 539 /** 540 * Returns an expression which converts the given expression to the given type 541 */ 542 @SuppressWarnings("unchecked") 543 public static Expression convertToExpression(final Expression expression, final Class type) { 544 return new ExpressionAdapter() { 545 public Object evaluate(Exchange exchange) { 546 return expression.evaluate(exchange, type); 547 } 548 549 @Override 550 public String toString() { 551 return "" + expression + ".convertTo(" + type.getCanonicalName() + ".class)"; 552 } 553 }; 554 } 555 556 /** 557 * Returns an expression which converts the given expression to the given type the type 558 * expression is evaluted to 559 */ 560 public static Expression convertToExpression(final Expression expression, final Expression type) { 561 return new ExpressionAdapter() { 562 public Object evaluate(Exchange exchange) { 563 return expression.evaluate(exchange, type.evaluate(exchange, Object.class).getClass()); 564 } 565 566 @Override 567 public String toString() { 568 return "" + expression + ".convertToEvaluatedType(" + type + ")"; 569 } 570 }; 571 } 572 573 /** 574 * Returns a tokenize expression which will tokenize the string with the 575 * given token 576 */ 577 public static Expression tokenizeExpression(final Expression expression, 578 final String token) { 579 return new ExpressionAdapter() { 580 public Object evaluate(Exchange exchange) { 581 Object value = expression.evaluate(exchange, Object.class); 582 Scanner scanner = ObjectHelper.getScanner(exchange, value); 583 scanner.useDelimiter(token); 584 return scanner; 585 } 586 587 @Override 588 public String toString() { 589 return "tokenize(" + expression + ", " + token + ")"; 590 } 591 }; 592 } 593 594 /** 595 * Returns a tokenize expression which will tokenize the string with the 596 * given regex 597 */ 598 public static Expression regexTokenizeExpression(final Expression expression, 599 final String regexTokenizer) { 600 final Pattern pattern = Pattern.compile(regexTokenizer); 601 return new ExpressionAdapter() { 602 public Object evaluate(Exchange exchange) { 603 Object value = expression.evaluate(exchange, Object.class); 604 Scanner scanner = ObjectHelper.getScanner(exchange, value); 605 scanner.useDelimiter(regexTokenizer); 606 return scanner; 607 } 608 609 @Override 610 public String toString() { 611 return "regexTokenize(" + expression + ", " + pattern.pattern() + ")"; 612 } 613 }; 614 } 615 616 /** 617 * Returns a sort expression which will sort the expression with the given comparator. 618 * <p/> 619 * The expression is evaluted as a {@link List} object to allow sorting. 620 */ 621 @SuppressWarnings("unchecked") 622 public static Expression sortExpression(final Expression expression, final Comparator comparator) { 623 return new ExpressionAdapter() { 624 public Object evaluate(Exchange exchange) { 625 List list = expression.evaluate(exchange, List.class); 626 Collections.sort(list, comparator); 627 return list; 628 } 629 630 @Override 631 public String toString() { 632 return "sort(" + expression + " by: " + comparator + ")"; 633 } 634 }; 635 } 636 637 /** 638 * Transforms the expression into a String then performs the regex 639 * replaceAll to transform the String and return the result 640 */ 641 public static Expression regexReplaceAll(final Expression expression, 642 final String regex, final String replacement) { 643 final Pattern pattern = Pattern.compile(regex); 644 return new ExpressionAdapter() { 645 public Object evaluate(Exchange exchange) { 646 String text = expression.evaluate(exchange, String.class); 647 if (text == null) { 648 return null; 649 } 650 return pattern.matcher(text).replaceAll(replacement); 651 } 652 653 @Override 654 public String toString() { 655 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 656 } 657 }; 658 } 659 660 /** 661 * Transforms the expression into a String then performs the regex 662 * replaceAll to transform the String and return the result 663 */ 664 public static Expression regexReplaceAll(final Expression expression, 665 final String regex, final Expression replacementExpression) { 666 667 final Pattern pattern = Pattern.compile(regex); 668 return new ExpressionAdapter() { 669 public Object evaluate(Exchange exchange) { 670 String text = expression.evaluate(exchange, String.class); 671 String replacement = replacementExpression.evaluate(exchange, String.class); 672 if (text == null || replacement == null) { 673 return null; 674 } 675 return pattern.matcher(text).replaceAll(replacement); 676 } 677 678 @Override 679 public String toString() { 680 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 681 } 682 }; 683 } 684 685 /** 686 * Appends the String evaluations of the two expressions together 687 */ 688 public static Expression append(final Expression left, final Expression right) { 689 return new ExpressionAdapter() { 690 public Object evaluate(Exchange exchange) { 691 return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class); 692 } 693 694 @Override 695 public String toString() { 696 return "append(" + left + ", " + right + ")"; 697 } 698 }; 699 } 700 701 /** 702 * Prepends the String evaluations of the two expressions together 703 */ 704 public static Expression prepend(final Expression left, final Expression right) { 705 return new ExpressionAdapter() { 706 public Object evaluate(Exchange exchange) { 707 return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class); 708 } 709 710 @Override 711 public String toString() { 712 return "prepend(" + left + ", " + right + ")"; 713 } 714 }; 715 } 716 717 /** 718 * Returns an expression which returns the string concatenation value of the various 719 * expressions 720 * 721 * @param expressions the expression to be concatenated dynamically 722 * @return an expression which when evaluated will return the concatenated values 723 */ 724 public static Expression concatExpression(final Collection<Expression> expressions) { 725 return concatExpression(expressions, null); 726 } 727 728 /** 729 * Returns an expression which returns the string concatenation value of the various 730 * expressions 731 * 732 * @param expressions the expression to be concatenated dynamically 733 * @param expression the text description of the expression 734 * @return an expression which when evaluated will return the concatenated values 735 */ 736 public static Expression concatExpression(final Collection<Expression> expressions, final String expression) { 737 return new ExpressionAdapter() { 738 public Object evaluate(Exchange exchange) { 739 StringBuffer buffer = new StringBuffer(); 740 for (Expression expression : expressions) { 741 String text = expression.evaluate(exchange, String.class); 742 if (text != null) { 743 buffer.append(text); 744 } 745 } 746 return buffer.toString(); 747 } 748 749 @Override 750 public String toString() { 751 if (expression != null) { 752 return expression; 753 } else { 754 return "concat" + expressions; 755 } 756 } 757 }; 758 } 759 760 /** 761 * Returns an Expression for the inbound message id 762 */ 763 public static Expression messageIdExpression() { 764 return new ExpressionAdapter() { 765 public Object evaluate(Exchange exchange) { 766 return exchange.getIn().getMessageId(); 767 } 768 769 @Override 770 public String toString() { 771 return "messageId"; 772 } 773 }; 774 } 775 776 public static Expression dateExpression(final String command, final String pattern) { 777 return new ExpressionAdapter() { 778 public Object evaluate(Exchange exchange) { 779 Date date; 780 if ("now".equals(command)) { 781 date = new Date(); 782 } else if (command.startsWith("header.") || command.startsWith("in.header.")) { 783 String key = command.substring(command.lastIndexOf('.') + 1); 784 date = exchange.getIn().getHeader(key, Date.class); 785 if (date == null) { 786 throw new IllegalArgumentException("Cannot find java.util.Date object at " + command); 787 } 788 } else if (command.startsWith("out.header.")) { 789 String key = command.substring(command.lastIndexOf('.') + 1); 790 date = exchange.getOut().getHeader(key, Date.class); 791 if (date == null) { 792 throw new IllegalArgumentException("Cannot find java.util.Date object at " + command); 793 } 794 } else { 795 throw new IllegalArgumentException("Command not supported for dateExpression: " + command); 796 } 797 798 SimpleDateFormat df = new SimpleDateFormat(pattern); 799 return df.format(date); 800 } 801 802 @Override 803 public String toString() { 804 return "date(" + command + ":" + pattern + ")"; 805 } 806 }; 807 } 808 809 public static Expression simpleExpression(final String expression) { 810 return new ExpressionAdapter() { 811 public Object evaluate(Exchange exchange) { 812 // resolve language using context to have a clear separation of packages 813 // must call evalute to return the nested langauge evaluate when evaluating 814 // stacked expressions 815 Language language = exchange.getContext().resolveLanguage("simple"); 816 return language.createExpression(expression).evaluate(exchange, Object.class); 817 } 818 819 @Override 820 public String toString() { 821 return "simple(" + expression + ")"; 822 } 823 }; 824 } 825 826 public static Expression beanExpression(final String expression) { 827 return new ExpressionAdapter() { 828 public Object evaluate(Exchange exchange) { 829 // resolve language using context to have a clear separation of packages 830 // must call evaluate to return the nested language evaluate when evaluating 831 // stacked expressions 832 Language language = exchange.getContext().resolveLanguage("bean"); 833 return language.createExpression(expression).evaluate(exchange, Object.class); 834 } 835 836 @Override 837 public String toString() { 838 return "bean(" + expression + ")"; 839 } 840 }; 841 } 842 843 public static Expression beanExpression(final Class beanType, final String methodName) { 844 return BeanLanguage.bean(beanType, methodName); 845 } 846 847 public static Expression beanExpression(final String beanRef, final String methodName) { 848 String expression = methodName != null ? beanRef + "." + methodName : beanRef; 849 return beanExpression(expression); 850 } 851 852 /** 853 * Returns an expression processing the exchange to the given endpoint uri 854 * 855 * @param uri endpoint uri to send the exchange to 856 * @return an expression object which will return the OUT body 857 */ 858 public static Expression toExpression(final String uri) { 859 return new ExpressionAdapter() { 860 public Object evaluate(Exchange exchange) { 861 Endpoint endpoint = exchange.getContext().getEndpoint(uri); 862 if (endpoint == null) { 863 throw new NoSuchEndpointException(uri); 864 } 865 866 Producer producer; 867 try { 868 producer = endpoint.createProducer(); 869 producer.start(); 870 producer.process(exchange); 871 producer.stop(); 872 } catch (Exception e) { 873 throw ObjectHelper.wrapRuntimeCamelException(e); 874 } 875 876 // return the OUT body, but check for exchange pattern 877 if (ExchangeHelper.isOutCapable(exchange)) { 878 return exchange.getOut().getBody(); 879 } else { 880 return exchange.getIn().getBody(); 881 } 882 } 883 884 @Override 885 public String toString() { 886 return "to(" + uri + ")"; 887 } 888 }; 889 } 890 891 892 }