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.io.PrintWriter; 020import java.io.StringWriter; 021import java.text.SimpleDateFormat; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.Date; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Random; 029import java.util.Scanner; 030import java.util.Set; 031import java.util.concurrent.atomic.AtomicReference; 032import java.util.regex.Pattern; 033 034import org.apache.camel.CamelContext; 035import org.apache.camel.Component; 036import org.apache.camel.Endpoint; 037import org.apache.camel.Exchange; 038import org.apache.camel.Expression; 039import org.apache.camel.InvalidPayloadException; 040import org.apache.camel.Message; 041import org.apache.camel.NoSuchEndpointException; 042import org.apache.camel.NoSuchLanguageException; 043import org.apache.camel.Producer; 044import org.apache.camel.component.bean.BeanInvocation; 045import org.apache.camel.component.properties.PropertiesComponent; 046import org.apache.camel.language.bean.BeanLanguage; 047import org.apache.camel.model.language.MethodCallExpression; 048import org.apache.camel.processor.DefaultExchangeFormatter; 049import org.apache.camel.spi.ExchangeFormatter; 050import org.apache.camel.spi.Language; 051import org.apache.camel.spi.RouteContext; 052import org.apache.camel.spi.UnitOfWork; 053import org.apache.camel.support.ExpressionAdapter; 054import org.apache.camel.support.TokenPairExpressionIterator; 055import org.apache.camel.support.TokenXMLExpressionIterator; 056import org.apache.camel.support.XMLTokenExpressionIterator; 057import org.apache.camel.util.CamelContextHelper; 058import org.apache.camel.util.ExchangeHelper; 059import org.apache.camel.util.FileUtil; 060import org.apache.camel.util.GroupIterator; 061import org.apache.camel.util.GroupTokenIterator; 062import org.apache.camel.util.IOHelper; 063import org.apache.camel.util.MessageHelper; 064import org.apache.camel.util.ObjectHelper; 065import org.apache.camel.util.OgnlHelper; 066import org.apache.camel.util.StringHelper; 067 068 069/** 070 * A helper class for working with <a href="http://camel.apache.org/expression.html">expressions</a>. 071 * 072 * @version 073 */ 074public final class ExpressionBuilder { 075 076 /** 077 * Utility classes should not have a public constructor. 078 */ 079 private ExpressionBuilder() { 080 } 081 082 /** 083 * Returns an expression for the inbound message attachments 084 * 085 * @return an expression object which will return the inbound message attachments 086 */ 087 public static Expression attachmentsExpression() { 088 return new ExpressionAdapter() { 089 public Object evaluate(Exchange exchange) { 090 return exchange.getIn().getAttachments(); 091 } 092 093 @Override 094 public String toString() { 095 return "attachments"; 096 } 097 }; 098 } 099 100 /** 101 * Returns an expression for the inbound message attachments 102 * 103 * @return an expression object which will return the inbound message attachments 104 */ 105 public static Expression attachmentValuesExpression() { 106 return new ExpressionAdapter() { 107 public Object evaluate(Exchange exchange) { 108 return exchange.getIn().getAttachments().values(); 109 } 110 111 @Override 112 public String toString() { 113 return "attachments"; 114 } 115 }; 116 } 117 118 /** 119 * Returns an expression for the header value with the given name 120 * <p/> 121 * Will fallback and look in properties if not found in headers. 122 * 123 * @param headerName the name of the header the expression will return 124 * @return an expression object which will return the header value 125 */ 126 public static Expression headerExpression(final String headerName) { 127 return new ExpressionAdapter() { 128 public Object evaluate(Exchange exchange) { 129 Object header = exchange.getIn().getHeader(headerName); 130 if (header == null) { 131 // fall back on a property 132 header = exchange.getProperty(headerName); 133 } 134 return header; 135 } 136 137 @Override 138 public String toString() { 139 return "header(" + headerName + ")"; 140 } 141 }; 142 } 143 144 /** 145 * Returns an expression for the header value with the given name converted to the given type 146 * <p/> 147 * Will fallback and look in properties if not found in headers. 148 * 149 * @param headerName the name of the header the expression will return 150 * @param type the type to convert to 151 * @return an expression object which will return the header value 152 */ 153 public static <T> Expression headerExpression(final String headerName, final Class<T> type) { 154 return new ExpressionAdapter() { 155 public Object evaluate(Exchange exchange) { 156 Object header = exchange.getIn().getHeader(headerName, type); 157 if (header == null) { 158 // fall back on a property 159 header = exchange.getProperty(headerName, type); 160 } 161 return header; 162 } 163 164 @Override 165 public String toString() { 166 return "headerAs(" + headerName + ", " + type + ")"; 167 } 168 }; 169 } 170 171 /** 172 * Returns an expression for the header value with the given name converted to the given type 173 * <p/> 174 * Will fallback and look in properties if not found in headers. 175 * 176 * @param headerName the name of the header the expression will return 177 * @param name the type to convert to as a FQN class name 178 * @return an expression object which will return the header value 179 */ 180 public static Expression headerExpression(final String headerName, final String name) { 181 return new ExpressionAdapter() { 182 public Object evaluate(Exchange exchange) { 183 Class<?> type; 184 try { 185 type = exchange.getContext().getClassResolver().resolveMandatoryClass(name); 186 } catch (ClassNotFoundException e) { 187 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 188 } 189 190 Object header = exchange.getIn().getHeader(headerName, type); 191 if (header == null) { 192 // fall back on a property 193 header = exchange.getProperty(headerName, type); 194 } 195 return header; 196 } 197 198 @Override 199 public String toString() { 200 return "headerAs(" + headerName + ", " + name + ")"; 201 } 202 }; 203 } 204 205 /** 206 * Returns the expression for the exchanges inbound message header invoking methods defined 207 * in a simple OGNL notation 208 * 209 * @param ognl methods to invoke on the header in a simple OGNL syntax 210 */ 211 public static Expression headersOgnlExpression(final String ognl) { 212 return new KeyedOgnlExpressionAdapter(ognl, "headerOgnl(" + ognl + ")", 213 new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() { 214 public Object getKeyedEntity(Exchange exchange, String key) { 215 return exchange.getIn().getHeader(key); 216 } 217 }); 218 } 219 220 /** 221 * Returns an expression for the inbound message headers 222 * 223 * @return an expression object which will return the inbound headers 224 */ 225 public static Expression headersExpression() { 226 return new ExpressionAdapter() { 227 public Object evaluate(Exchange exchange) { 228 return exchange.getIn().getHeaders(); 229 } 230 231 @Override 232 public String toString() { 233 return "headers"; 234 } 235 }; 236 } 237 238 /** 239 * Returns an expression for the out header value with the given name 240 * <p/> 241 * Will fallback and look in properties if not found in headers. 242 * 243 * @param headerName the name of the header the expression will return 244 * @return an expression object which will return the header value 245 */ 246 public static Expression outHeaderExpression(final String headerName) { 247 return new ExpressionAdapter() { 248 public Object evaluate(Exchange exchange) { 249 if (!exchange.hasOut()) { 250 return null; 251 } 252 253 Message out = exchange.getOut(); 254 Object header = out.getHeader(headerName); 255 if (header == null) { 256 // let's try the exchange header 257 header = exchange.getProperty(headerName); 258 } 259 return header; 260 } 261 262 @Override 263 public String toString() { 264 return "outHeader(" + headerName + ")"; 265 } 266 }; 267 } 268 269 /** 270 * Returns an expression for the outbound message headers 271 * 272 * @return an expression object which will return the headers, will be <tt>null</tt> if the 273 * exchange is not out capable. 274 */ 275 public static Expression outHeadersExpression() { 276 return new ExpressionAdapter() { 277 public Object evaluate(Exchange exchange) { 278 // only get out headers if the MEP is out capable 279 if (ExchangeHelper.isOutCapable(exchange)) { 280 return exchange.getOut().getHeaders(); 281 } else { 282 return null; 283 } 284 } 285 286 @Override 287 public String toString() { 288 return "outHeaders"; 289 } 290 }; 291 } 292 293 /** 294 * Returns an expression for the exchange pattern 295 * 296 * @see org.apache.camel.Exchange#getPattern() 297 * @return an expression object which will return the exchange pattern 298 */ 299 public static Expression exchangePatternExpression() { 300 return new ExpressionAdapter() { 301 public Object evaluate(Exchange exchange) { 302 return exchange.getPattern(); 303 } 304 305 @Override 306 public String toString() { 307 return "exchangePattern"; 308 } 309 }; 310 } 311 312 /** 313 * Returns an expression for an exception set on the exchange 314 * 315 * @see Exchange#getException() 316 * @return an expression object which will return the exception set on the exchange 317 */ 318 public static Expression exchangeExceptionExpression() { 319 return new ExpressionAdapter() { 320 public Object evaluate(Exchange exchange) { 321 Exception exception = exchange.getException(); 322 if (exception == null) { 323 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 324 } 325 return exception; 326 } 327 328 @Override 329 public String toString() { 330 return "exchangeException"; 331 } 332 }; 333 } 334 335 /** 336 * Returns an expression for an exception set on the exchange 337 * <p/> 338 * Is used to get the caused exception that typically have been wrapped in some sort 339 * of Camel wrapper exception 340 * @param type the exception type 341 * @see Exchange#getException(Class) 342 * @return an expression object which will return the exception set on the exchange 343 */ 344 public static Expression exchangeExceptionExpression(final Class<Exception> type) { 345 return new ExpressionAdapter() { 346 public Object evaluate(Exchange exchange) { 347 Exception exception = exchange.getException(type); 348 if (exception == null) { 349 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 350 return ObjectHelper.getException(type, exception); 351 } 352 return exception; 353 } 354 355 @Override 356 public String toString() { 357 return "exchangeException[" + type + "]"; 358 } 359 }; 360 } 361 362 /** 363 * Returns the expression for the exchanges exception invoking methods defined 364 * in a simple OGNL notation 365 * 366 * @param ognl methods to invoke on the body in a simple OGNL syntax 367 */ 368 public static Expression exchangeExceptionOgnlExpression(final String ognl) { 369 return new ExpressionAdapter() { 370 public Object evaluate(Exchange exchange) { 371 Object exception = exchange.getException(); 372 if (exception == null) { 373 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 374 } 375 376 if (exception == null) { 377 return null; 378 } 379 return new MethodCallExpression(exception, ognl).evaluate(exchange); 380 } 381 382 @Override 383 public String toString() { 384 return "exchangeExceptionOgnl(" + ognl + ")"; 385 } 386 }; 387 } 388 389 /** 390 * Returns an expression for the type converter 391 * 392 * @return an expression object which will return the type converter 393 */ 394 public static Expression typeConverterExpression() { 395 return new ExpressionAdapter() { 396 public Object evaluate(Exchange exchange) { 397 return exchange.getContext().getTypeConverter(); 398 } 399 400 @Override 401 public String toString() { 402 return "typeConverter"; 403 } 404 }; 405 } 406 407 /** 408 * Returns an expression for the {@link org.apache.camel.spi.Registry} 409 * 410 * @return an expression object which will return the registry 411 */ 412 public static Expression registryExpression() { 413 return new ExpressionAdapter() { 414 public Object evaluate(Exchange exchange) { 415 return exchange.getContext().getRegistry(); 416 } 417 418 @Override 419 public String toString() { 420 return "registry"; 421 } 422 }; 423 } 424 425 /** 426 * Returns an expression for lookup a bean in the {@link org.apache.camel.spi.Registry} 427 * 428 * @return an expression object which will return the bean 429 */ 430 public static Expression refExpression(final String ref) { 431 return new ExpressionAdapter() { 432 public Object evaluate(Exchange exchange) { 433 return exchange.getContext().getRegistry().lookupByName(ref); 434 } 435 436 @Override 437 public String toString() { 438 return "ref(" + ref + ")"; 439 } 440 }; 441 } 442 443 /** 444 * Returns an expression for the {@link org.apache.camel.CamelContext} 445 * 446 * @return an expression object which will return the camel context 447 */ 448 public static Expression camelContextExpression() { 449 return new ExpressionAdapter() { 450 public Object evaluate(Exchange exchange) { 451 return exchange.getContext(); 452 } 453 454 @Override 455 public String toString() { 456 return "camelContext"; 457 } 458 }; 459 } 460 461 /** 462 * Returns an expression for the {@link org.apache.camel.CamelContext} name 463 * 464 * @return an expression object which will return the camel context name 465 */ 466 public static Expression camelContextNameExpression() { 467 return new ExpressionAdapter() { 468 public Object evaluate(Exchange exchange) { 469 return exchange.getContext().getName(); 470 } 471 472 @Override 473 public String toString() { 474 return "camelContextName"; 475 } 476 }; 477 } 478 479 /** 480 * Returns an expression for an exception message set on the exchange 481 * 482 * @see <tt>Exchange.getException().getMessage()</tt> 483 * @return an expression object which will return the exception message set on the exchange 484 */ 485 public static Expression exchangeExceptionMessageExpression() { 486 return new ExpressionAdapter() { 487 public Object evaluate(Exchange exchange) { 488 Exception exception = exchange.getException(); 489 if (exception == null) { 490 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 491 } 492 return exception != null ? exception.getMessage() : null; 493 } 494 495 @Override 496 public String toString() { 497 return "exchangeExceptionMessage"; 498 } 499 }; 500 } 501 502 /** 503 * Returns an expression for an exception stacktrace set on the exchange 504 * 505 * @return an expression object which will return the exception stacktrace set on the exchange 506 */ 507 public static Expression exchangeExceptionStackTraceExpression() { 508 return new ExpressionAdapter() { 509 public Object evaluate(Exchange exchange) { 510 Exception exception = exchange.getException(); 511 if (exception == null) { 512 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 513 } 514 if (exception != null) { 515 StringWriter sw = new StringWriter(); 516 PrintWriter pw = new PrintWriter(sw); 517 exception.printStackTrace(pw); 518 IOHelper.close(pw, sw); 519 return sw.toString(); 520 } else { 521 return null; 522 } 523 } 524 525 @Override 526 public String toString() { 527 return "exchangeExceptionStackTrace"; 528 } 529 }; 530 } 531 532 /** 533 * Returns an expression for the property value of exchange with the given name 534 * 535 * @param propertyName the name of the property the expression will return 536 * @return an expression object which will return the property value 537 * @deprecated use {@link #exchangePropertyExpression(String)} instead 538 */ 539 @Deprecated 540 public static Expression propertyExpression(final String propertyName) { 541 return new ExpressionAdapter() { 542 public Object evaluate(Exchange exchange) { 543 return exchange.getProperty(propertyName); 544 } 545 546 @Override 547 public String toString() { 548 return "exchangeProperty(" + propertyName + ")"; 549 } 550 }; 551 } 552 553 /** 554 * Returns an expression for the property value of exchange with the given name 555 * 556 * @param propertyName the name of the property the expression will return 557 * @return an expression object which will return the property value 558 */ 559 public static Expression exchangePropertyExpression(final String propertyName) { 560 return new ExpressionAdapter() { 561 public Object evaluate(Exchange exchange) { 562 return exchange.getProperty(propertyName); 563 } 564 565 @Override 566 public String toString() { 567 return "exchangeProperty(" + propertyName + ")"; 568 } 569 }; 570 } 571 572 /** 573 * Returns an expression for the property value of exchange with the given name invoking methods defined 574 * in a simple OGNL notation 575 * 576 * @param ognl methods to invoke on the property in a simple OGNL syntax 577 */ 578 public static Expression propertyOgnlExpression(final String ognl) { 579 return new KeyedOgnlExpressionAdapter(ognl, "propertyOgnl(" + ognl + ")", 580 new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() { 581 public Object getKeyedEntity(Exchange exchange, String key) { 582 return exchange.getProperty(key); 583 } 584 }); 585 } 586 587 /** 588 * Returns an expression for the properties of exchange 589 * 590 * @return an expression object which will return the properties 591 */ 592 public static Expression propertiesExpression() { 593 return new ExpressionAdapter() { 594 public Object evaluate(Exchange exchange) { 595 return exchange.getProperties(); 596 } 597 598 @Override 599 public String toString() { 600 return "properties"; 601 } 602 }; 603 } 604 605 /** 606 * Returns an expression for the properties of the camel context 607 * 608 * @return an expression object which will return the properties 609 */ 610 public static Expression camelContextPropertiesExpression() { 611 return new ExpressionAdapter() { 612 public Object evaluate(Exchange exchange) { 613 return exchange.getContext().getProperties(); 614 } 615 616 @Override 617 public String toString() { 618 return "camelContextProperties"; 619 } 620 }; 621 } 622 623 /** 624 * Returns an expression for the property value of the camel context with the given name 625 * 626 * @param propertyName the name of the property the expression will return 627 * @return an expression object which will return the property value 628 */ 629 public static Expression camelContextPropertyExpression(final String propertyName) { 630 return new ExpressionAdapter() { 631 public Object evaluate(Exchange exchange) { 632 return exchange.getContext().getProperty(propertyName); 633 } 634 635 @Override 636 public String toString() { 637 return "camelContextProperty(" + propertyName + ")"; 638 } 639 }; 640 } 641 642 /** 643 * Returns an expression for a system property value with the given name 644 * 645 * @param propertyName the name of the system property the expression will return 646 * @return an expression object which will return the system property value 647 */ 648 public static Expression systemPropertyExpression(final String propertyName) { 649 return systemPropertyExpression(propertyName, null); 650 } 651 652 /** 653 * Returns an expression for a system property value with the given name 654 * 655 * @param propertyName the name of the system property the expression will return 656 * @param defaultValue default value to return if no system property exists 657 * @return an expression object which will return the system property value 658 */ 659 public static Expression systemPropertyExpression(final String propertyName, 660 final String defaultValue) { 661 return new ExpressionAdapter() { 662 public Object evaluate(Exchange exchange) { 663 return System.getProperty(propertyName, defaultValue); 664 } 665 666 @Override 667 public String toString() { 668 return "systemProperty(" + propertyName + ")"; 669 } 670 }; 671 } 672 673 /** 674 * Returns an expression for a system environment value with the given name 675 * 676 * @param propertyName the name of the system environment the expression will return 677 * @return an expression object which will return the system property value 678 */ 679 public static Expression systemEnvironmentExpression(final String propertyName) { 680 return systemEnvironmentExpression(propertyName, null); 681 } 682 683 /** 684 * Returns an expression for a system environment value with the given name 685 * 686 * @param propertyName the name of the system environment the expression will return 687 * @param defaultValue default value to return if no system environment exists 688 * @return an expression object which will return the system environment value 689 */ 690 public static Expression systemEnvironmentExpression(final String propertyName, 691 final String defaultValue) { 692 return new ExpressionAdapter() { 693 public Object evaluate(Exchange exchange) { 694 String answer = System.getenv(propertyName); 695 if (answer == null) { 696 answer = defaultValue; 697 } 698 return answer; 699 } 700 701 @Override 702 public String toString() { 703 return "systemEnvironment(" + propertyName + ")"; 704 } 705 }; 706 } 707 708 /** 709 * Returns an expression for the constant value 710 * 711 * @param value the value the expression will return 712 * @return an expression object which will return the constant value 713 */ 714 public static Expression constantExpression(final Object value) { 715 return new ExpressionAdapter() { 716 public Object evaluate(Exchange exchange) { 717 return value; 718 } 719 720 @Override 721 public String toString() { 722 return "" + value; 723 } 724 }; 725 } 726 727 /** 728 * Returns an expression for evaluating the expression/predicate using the given language 729 * 730 * @param expression the expression or predicate 731 * @return an expression object which will evaluate the expression/predicate using the given language 732 */ 733 public static Expression languageExpression(final String language, final String expression) { 734 return new ExpressionAdapter() { 735 public Object evaluate(Exchange exchange) { 736 Language lan = exchange.getContext().resolveLanguage(language); 737 if (lan != null) { 738 return lan.createExpression(expression).evaluate(exchange, Object.class); 739 } else { 740 throw new NoSuchLanguageException(language); 741 } 742 } 743 744 @Override 745 public boolean matches(Exchange exchange) { 746 Language lan = exchange.getContext().resolveLanguage(language); 747 if (lan != null) { 748 return lan.createPredicate(expression).matches(exchange); 749 } else { 750 throw new NoSuchLanguageException(language); 751 } 752 } 753 754 @Override 755 public String toString() { 756 return "language[" + language + ":" + expression + "]"; 757 } 758 }; 759 } 760 761 /** 762 * Returns an expression for a type value 763 * 764 * @param name the type name 765 * @return an expression object which will return the type value 766 */ 767 public static Expression typeExpression(final String name) { 768 return new ExpressionAdapter() { 769 public Object evaluate(Exchange exchange) { 770 // it may refer to a class type 771 Class<?> type = exchange.getContext().getClassResolver().resolveClass(name); 772 if (type != null) { 773 return type; 774 } 775 776 int pos = name.lastIndexOf("."); 777 if (pos > 0) { 778 String before = name.substring(0, pos); 779 String after = name.substring(pos + 1); 780 type = exchange.getContext().getClassResolver().resolveClass(before); 781 if (type != null) { 782 return ObjectHelper.lookupConstantFieldValue(type, after); 783 } 784 } 785 786 throw ObjectHelper.wrapCamelExecutionException(exchange, new ClassNotFoundException("Cannot find type " + name)); 787 } 788 789 @Override 790 public String toString() { 791 return "type:" + name; 792 } 793 }; 794 } 795 796 /** 797 * Returns an expression that caches the evaluation of another expression 798 * and returns the cached value, to avoid re-evaluating the expression. 799 * 800 * @param expression the target expression to cache 801 * @return the cached value 802 */ 803 public static Expression cacheExpression(final Expression expression) { 804 return new ExpressionAdapter() { 805 private final AtomicReference<Object> cache = new AtomicReference<Object>(); 806 807 public Object evaluate(Exchange exchange) { 808 Object answer = cache.get(); 809 if (answer == null) { 810 answer = expression.evaluate(exchange, Object.class); 811 cache.set(answer); 812 } 813 return answer; 814 } 815 816 @Override 817 public String toString() { 818 return expression.toString(); 819 } 820 }; 821 } 822 823 /** 824 * Returns the expression for the exchanges inbound message body 825 */ 826 public static Expression bodyExpression() { 827 return new ExpressionAdapter() { 828 public Object evaluate(Exchange exchange) { 829 return exchange.getIn().getBody(); 830 } 831 832 @Override 833 public String toString() { 834 return "body"; 835 } 836 }; 837 } 838 839 /** 840 * Returns the expression for the exchanges inbound message body invoking methods defined 841 * in a simple OGNL notation 842 * 843 * @param ognl methods to invoke on the body in a simple OGNL syntax 844 */ 845 public static Expression bodyOgnlExpression(final String ognl) { 846 return new ExpressionAdapter() { 847 public Object evaluate(Exchange exchange) { 848 Object body = exchange.getIn().getBody(); 849 if (body == null) { 850 return null; 851 } 852 return new MethodCallExpression(body, ognl).evaluate(exchange); 853 } 854 855 @Override 856 public String toString() { 857 return "bodyOgnl(" + ognl + ")"; 858 } 859 }; 860 } 861 862 /** 863 * Returns the expression for invoking a method (support OGNL syntax) on the given expression 864 * 865 * @param exp the expression to evaluate and invoke the method on its result 866 * @param ognl methods to invoke on the evaluated expression in a simple OGNL syntax 867 */ 868 public static Expression ognlExpression(final Expression exp, final String ognl) { 869 return new ExpressionAdapter() { 870 public Object evaluate(Exchange exchange) { 871 Object value = exp.evaluate(exchange, Object.class); 872 if (value == null) { 873 return null; 874 } 875 return new MethodCallExpression(value, ognl).evaluate(exchange); 876 } 877 878 @Override 879 public String toString() { 880 return "ognl(" + exp + ", " + ognl + ")"; 881 } 882 }; 883 } 884 885 /** 886 * Returns the expression for the exchanges camelContext invoking methods defined 887 * in a simple OGNL notation 888 * 889 * @param ognl methods to invoke on the context in a simple OGNL syntax 890 */ 891 public static Expression camelContextOgnlExpression(final String ognl) { 892 return new ExpressionAdapter() { 893 public Object evaluate(Exchange exchange) { 894 CamelContext context = exchange.getContext(); 895 if (context == null) { 896 return null; 897 } 898 return new MethodCallExpression(context, ognl).evaluate(exchange); 899 } 900 901 @Override 902 public String toString() { 903 return "camelContextOgnl(" + ognl + ")"; 904 } 905 }; 906 } 907 908 /** 909 * Returns the expression for the exchange invoking methods defined 910 * in a simple OGNL notation 911 * 912 * @param ognl methods to invoke on the exchange in a simple OGNL syntax 913 */ 914 public static Expression exchangeOgnlExpression(final String ognl) { 915 return new ExpressionAdapter() { 916 public Object evaluate(Exchange exchange) { 917 return new MethodCallExpression(exchange, ognl).evaluate(exchange); 918 } 919 920 @Override 921 public String toString() { 922 return "exchangeOgnl(" + ognl + ")"; 923 } 924 }; 925 } 926 927 /** 928 * Returns the expression for the exchanges inbound message body converted 929 * to the given type 930 */ 931 public static <T> Expression bodyExpression(final Class<T> type) { 932 return new ExpressionAdapter() { 933 public Object evaluate(Exchange exchange) { 934 return exchange.getIn().getBody(type); 935 } 936 937 @Override 938 public String toString() { 939 return "bodyAs[" + type.getName() + "]"; 940 } 941 }; 942 } 943 944 /** 945 * Returns the expression for the exchanges inbound message body converted 946 * to the given type 947 */ 948 public static Expression bodyExpression(final String name) { 949 return new ExpressionAdapter() { 950 public Object evaluate(Exchange exchange) { 951 Class<?> type; 952 try { 953 type = exchange.getContext().getClassResolver().resolveMandatoryClass(name); 954 } catch (ClassNotFoundException e) { 955 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 956 } 957 return exchange.getIn().getBody(type); 958 } 959 960 @Override 961 public String toString() { 962 return "bodyAs[" + name + "]"; 963 } 964 }; 965 } 966 967 /** 968 * Returns the expression for the exchanges inbound message body converted 969 * to the given type 970 */ 971 public static Expression mandatoryBodyExpression(final String name) { 972 return new ExpressionAdapter() { 973 public Object evaluate(Exchange exchange) { 974 Class<?> type; 975 try { 976 type = exchange.getContext().getClassResolver().resolveMandatoryClass(name); 977 } catch (ClassNotFoundException e) { 978 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 979 } 980 try { 981 return exchange.getIn().getMandatoryBody(type); 982 } catch (InvalidPayloadException e) { 983 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 984 } 985 } 986 987 @Override 988 public String toString() { 989 return "mandatoryBodyAs[" + name + "]"; 990 } 991 }; 992 } 993 994 /** 995 * Returns the expression for the current thread name 996 */ 997 public static Expression threadNameExpression() { 998 return new ExpressionAdapter() { 999 public Object evaluate(Exchange exchange) { 1000 return Thread.currentThread().getName(); 1001 } 1002 1003 @Override 1004 public String toString() { 1005 return "threadName"; 1006 } 1007 }; 1008 } 1009 1010 /** 1011 * Returns the expression for the {@code null} value 1012 */ 1013 public static Expression nullExpression() { 1014 return new ExpressionAdapter() { 1015 public Object evaluate(Exchange exchange) { 1016 return null; 1017 } 1018 1019 @Override 1020 public String toString() { 1021 return "null"; 1022 } 1023 }; 1024 } 1025 1026 /** 1027 * Returns the expression for the exchanges inbound message body converted 1028 * to the given type. 1029 * <p/> 1030 * Does <b>not</b> allow null bodies. 1031 */ 1032 public static <T> Expression mandatoryBodyExpression(final Class<T> type) { 1033 return mandatoryBodyExpression(type, false); 1034 } 1035 1036 /** 1037 * Returns the expression for the exchanges inbound message body converted 1038 * to the given type 1039 * 1040 * @param type the type 1041 * @param nullBodyAllowed whether null bodies is allowed and if so a null is returned, 1042 * otherwise an exception is thrown 1043 */ 1044 public static <T> Expression mandatoryBodyExpression(final Class<T> type, final boolean nullBodyAllowed) { 1045 return new ExpressionAdapter() { 1046 public Object evaluate(Exchange exchange) { 1047 if (nullBodyAllowed) { 1048 if (exchange.getIn().getBody() == null) { 1049 return null; 1050 } 1051 1052 // if its a bean invocation then if it has no arguments then it should be threaded as null body allowed 1053 if (exchange.getIn().getBody() instanceof BeanInvocation) { 1054 // BeanInvocation would be stored directly as the message body 1055 // do not force any type conversion attempts as it would just be unnecessary and cost a bit performance 1056 // so a regular instanceof check is sufficient 1057 BeanInvocation bi = (BeanInvocation) exchange.getIn().getBody(); 1058 if (bi.getArgs() == null || bi.getArgs().length == 0 || bi.getArgs()[0] == null) { 1059 return null; 1060 } 1061 } 1062 } 1063 1064 try { 1065 return exchange.getIn().getMandatoryBody(type); 1066 } catch (InvalidPayloadException e) { 1067 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1068 } 1069 } 1070 1071 @Override 1072 public String toString() { 1073 return "mandatoryBodyAs[" + type.getName() + "]"; 1074 } 1075 }; 1076 } 1077 1078 /** 1079 * Returns the expression for the exchanges inbound message body type 1080 */ 1081 public static Expression bodyTypeExpression() { 1082 return new ExpressionAdapter() { 1083 public Object evaluate(Exchange exchange) { 1084 return exchange.getIn().getBody().getClass(); 1085 } 1086 1087 @Override 1088 public String toString() { 1089 return "bodyType"; 1090 } 1091 }; 1092 } 1093 1094 /** 1095 * Returns the expression for the out messages body 1096 */ 1097 public static Expression outBodyExpression() { 1098 return new ExpressionAdapter() { 1099 public Object evaluate(Exchange exchange) { 1100 if (exchange.hasOut()) { 1101 return exchange.getOut().getBody(); 1102 } else { 1103 return null; 1104 } 1105 } 1106 1107 @Override 1108 public String toString() { 1109 return "outBody"; 1110 } 1111 }; 1112 } 1113 1114 /** 1115 * Returns the expression for the exchanges outbound message body converted 1116 * to the given type 1117 */ 1118 public static <T> Expression outBodyExpression(final Class<T> type) { 1119 return new ExpressionAdapter() { 1120 public Object evaluate(Exchange exchange) { 1121 if (exchange.hasOut()) { 1122 return exchange.getOut().getBody(type); 1123 } else { 1124 return null; 1125 } 1126 } 1127 1128 @Override 1129 public String toString() { 1130 return "outBodyAs[" + type.getName() + "]"; 1131 } 1132 }; 1133 } 1134 1135 /** 1136 * Returns the expression for the fault messages body 1137 */ 1138 public static Expression faultBodyExpression() { 1139 return new ExpressionAdapter() { 1140 public Object evaluate(Exchange exchange) { 1141 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 1142 return msg.isFault() ? msg.getBody() : null; 1143 } 1144 1145 @Override 1146 public String toString() { 1147 return "faultBody"; 1148 } 1149 }; 1150 } 1151 1152 /** 1153 * Returns the expression for the exchanges fault message body converted 1154 * to the given type 1155 */ 1156 public static <T> Expression faultBodyExpression(final Class<T> type) { 1157 return new ExpressionAdapter() { 1158 public Object evaluate(Exchange exchange) { 1159 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 1160 return msg.isFault() ? msg.getBody(type) : null; 1161 } 1162 1163 @Override 1164 public String toString() { 1165 return "faultBodyAs[" + type.getName() + "]"; 1166 } 1167 }; 1168 } 1169 1170 /** 1171 * Returns the expression for the exchange 1172 */ 1173 public static Expression exchangeExpression() { 1174 return new ExpressionAdapter() { 1175 public Object evaluate(Exchange exchange) { 1176 return exchange; 1177 } 1178 1179 @Override 1180 public String toString() { 1181 return "exchange"; 1182 } 1183 }; 1184 } 1185 1186 /** 1187 * Returns the expression for the IN message 1188 */ 1189 public static Expression inMessageExpression() { 1190 return new ExpressionAdapter() { 1191 public Object evaluate(Exchange exchange) { 1192 return exchange.getIn(); 1193 } 1194 1195 @Override 1196 public String toString() { 1197 return "inMessage"; 1198 } 1199 }; 1200 } 1201 1202 /** 1203 * Returns the expression for the OUT message 1204 */ 1205 public static Expression outMessageExpression() { 1206 return new ExpressionAdapter() { 1207 public Object evaluate(Exchange exchange) { 1208 return exchange.getOut(); 1209 } 1210 1211 @Override 1212 public String toString() { 1213 return "outMessage"; 1214 } 1215 }; 1216 } 1217 1218 /** 1219 * Returns an expression which converts the given expression to the given type 1220 */ 1221 public static Expression convertToExpression(final Expression expression, final Class<?> type) { 1222 return new ExpressionAdapter() { 1223 public Object evaluate(Exchange exchange) { 1224 if (type != null) { 1225 return expression.evaluate(exchange, type); 1226 } else { 1227 return expression; 1228 } 1229 } 1230 1231 @Override 1232 public String toString() { 1233 return "" + expression; 1234 } 1235 }; 1236 } 1237 1238 /** 1239 * Returns an expression which converts the given expression to the given type the type 1240 * expression is evaluated to 1241 */ 1242 public static Expression convertToExpression(final Expression expression, final Expression type) { 1243 return new ExpressionAdapter() { 1244 public Object evaluate(Exchange exchange) { 1245 Object result = type.evaluate(exchange, Object.class); 1246 if (result != null) { 1247 return expression.evaluate(exchange, result.getClass()); 1248 } else { 1249 return expression; 1250 } 1251 } 1252 1253 @Override 1254 public String toString() { 1255 return "" + expression; 1256 } 1257 }; 1258 } 1259 1260 /** 1261 * Returns a tokenize expression which will tokenize the string with the 1262 * given token 1263 */ 1264 public static Expression tokenizeExpression(final Expression expression, 1265 final String token) { 1266 return new ExpressionAdapter() { 1267 public Object evaluate(Exchange exchange) { 1268 Object value = expression.evaluate(exchange, Object.class); 1269 Scanner scanner = ObjectHelper.getScanner(exchange, value); 1270 scanner.useDelimiter(token); 1271 return scanner; 1272 } 1273 1274 @Override 1275 public String toString() { 1276 return "tokenize(" + expression + ", " + token + ")"; 1277 } 1278 }; 1279 } 1280 1281 /** 1282 * Returns an expression that skips the first element 1283 */ 1284 public static Expression skipFirstExpression(final Expression expression) { 1285 return new ExpressionAdapter() { 1286 public Object evaluate(Exchange exchange) { 1287 Object value = expression.evaluate(exchange, Object.class); 1288 Iterator it = exchange.getContext().getTypeConverter().tryConvertTo(Iterator.class, exchange, value); 1289 if (it != null) { 1290 // skip first 1291 it.next(); 1292 return it; 1293 } else { 1294 return value; 1295 } 1296 } 1297 1298 @Override 1299 public String toString() { 1300 return "skipFirst(" + expression + ")"; 1301 } 1302 }; 1303 } 1304 1305 /** 1306 * Returns an {@link TokenPairExpressionIterator} expression 1307 */ 1308 public static Expression tokenizePairExpression(String startToken, String endToken, boolean includeTokens) { 1309 return new TokenPairExpressionIterator(startToken, endToken, includeTokens); 1310 } 1311 1312 /** 1313 * Returns an {@link TokenXMLExpressionIterator} expression 1314 */ 1315 public static Expression tokenizeXMLExpression(String tagName, String inheritNamespaceTagName) { 1316 ObjectHelper.notEmpty(tagName, "tagName"); 1317 1318 // must be XML tokens 1319 if (!tagName.startsWith("<")) { 1320 tagName = "<" + tagName; 1321 } 1322 if (!tagName.endsWith(">")) { 1323 tagName = tagName + ">"; 1324 } 1325 1326 if (inheritNamespaceTagName != null) { 1327 if (!inheritNamespaceTagName.startsWith("<")) { 1328 inheritNamespaceTagName = "<" + inheritNamespaceTagName; 1329 } 1330 if (!inheritNamespaceTagName.endsWith(">")) { 1331 inheritNamespaceTagName = inheritNamespaceTagName + ">"; 1332 } 1333 } 1334 return new TokenXMLExpressionIterator(tagName, inheritNamespaceTagName); 1335 } 1336 1337 public static Expression tokenizeXMLAwareExpression(String path, char mode) { 1338 ObjectHelper.notEmpty(path, "path"); 1339 1340 return new XMLTokenExpressionIterator(path, mode); 1341 } 1342 1343 public static Expression tokenizeXMLAwareExpression(String path, char mode, int group) { 1344 ObjectHelper.notEmpty(path, "path"); 1345 1346 return new XMLTokenExpressionIterator(path, mode, group); 1347 } 1348 1349 /** 1350 * Returns a tokenize expression which will tokenize the string with the 1351 * given regex 1352 */ 1353 public static Expression regexTokenizeExpression(final Expression expression, 1354 final String regexTokenizer) { 1355 final Pattern pattern = Pattern.compile(regexTokenizer); 1356 return new ExpressionAdapter() { 1357 public Object evaluate(Exchange exchange) { 1358 Object value = expression.evaluate(exchange, Object.class); 1359 Scanner scanner = ObjectHelper.getScanner(exchange, value); 1360 scanner.useDelimiter(pattern); 1361 return scanner; 1362 } 1363 1364 @Override 1365 public String toString() { 1366 return "regexTokenize(" + expression + ", " + pattern.pattern() + ")"; 1367 } 1368 }; 1369 } 1370 1371 public static Expression groupXmlIteratorExpression(final Expression expression, final int group) { 1372 return new ExpressionAdapter() { 1373 public Object evaluate(Exchange exchange) { 1374 // evaluate expression as iterator 1375 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1376 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1377 // must use GroupTokenIterator in xml mode as we want to concat the xml parts into a single message 1378 return new GroupTokenIterator(exchange, it, null, group, false); 1379 } 1380 1381 @Override 1382 public String toString() { 1383 return "group " + expression + " " + group + " times"; 1384 } 1385 }; 1386 } 1387 1388 public static Expression groupIteratorExpression(final Expression expression, final String token, final int group, final boolean skipFirst) { 1389 return new ExpressionAdapter() { 1390 public Object evaluate(Exchange exchange) { 1391 // evaluate expression as iterator 1392 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1393 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1394 if (token != null) { 1395 return new GroupTokenIterator(exchange, it, token, group, skipFirst); 1396 } else { 1397 return new GroupIterator(exchange, it, group, skipFirst); 1398 } 1399 } 1400 1401 @Override 1402 public String toString() { 1403 return "group " + expression + " " + group + " times"; 1404 } 1405 }; 1406 } 1407 1408 /** 1409 * Returns a sort expression which will sort the expression with the given comparator. 1410 * <p/> 1411 * The expression is evaluated as a {@link List} object to allow sorting. 1412 */ 1413 @SuppressWarnings({"unchecked", "rawtypes"}) 1414 public static Expression sortExpression(final Expression expression, final Comparator comparator) { 1415 return new ExpressionAdapter() { 1416 public Object evaluate(Exchange exchange) { 1417 List<?> list = expression.evaluate(exchange, List.class); 1418 Collections.sort(list, comparator); 1419 return list; 1420 } 1421 1422 @Override 1423 public String toString() { 1424 return "sort(" + expression + " by: " + comparator + ")"; 1425 } 1426 }; 1427 } 1428 1429 /** 1430 * Transforms the expression into a String then performs the regex 1431 * replaceAll to transform the String and return the result 1432 */ 1433 public static Expression regexReplaceAll(final Expression expression, 1434 final String regex, final String replacement) { 1435 final Pattern pattern = Pattern.compile(regex); 1436 return new ExpressionAdapter() { 1437 public Object evaluate(Exchange exchange) { 1438 String text = expression.evaluate(exchange, String.class); 1439 if (text == null) { 1440 return null; 1441 } 1442 return pattern.matcher(text).replaceAll(replacement); 1443 } 1444 1445 @Override 1446 public String toString() { 1447 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1448 } 1449 }; 1450 } 1451 1452 /** 1453 * Transforms the expression into a String then performs the regex 1454 * replaceAll to transform the String and return the result 1455 */ 1456 public static Expression regexReplaceAll(final Expression expression, 1457 final String regex, final Expression replacementExpression) { 1458 1459 final Pattern pattern = Pattern.compile(regex); 1460 return new ExpressionAdapter() { 1461 public Object evaluate(Exchange exchange) { 1462 String text = expression.evaluate(exchange, String.class); 1463 String replacement = replacementExpression.evaluate(exchange, String.class); 1464 if (text == null || replacement == null) { 1465 return null; 1466 } 1467 return pattern.matcher(text).replaceAll(replacement); 1468 } 1469 1470 @Override 1471 public String toString() { 1472 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1473 } 1474 }; 1475 } 1476 1477 /** 1478 * Appends the String evaluations of the two expressions together 1479 */ 1480 public static Expression append(final Expression left, final Expression right) { 1481 return new ExpressionAdapter() { 1482 public Object evaluate(Exchange exchange) { 1483 return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class); 1484 } 1485 1486 @Override 1487 public String toString() { 1488 return "append(" + left + ", " + right + ")"; 1489 } 1490 }; 1491 } 1492 1493 /** 1494 * Prepends the String evaluations of the two expressions together 1495 */ 1496 public static Expression prepend(final Expression left, final Expression right) { 1497 return new ExpressionAdapter() { 1498 public Object evaluate(Exchange exchange) { 1499 return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class); 1500 } 1501 1502 @Override 1503 public String toString() { 1504 return "prepend(" + left + ", " + right + ")"; 1505 } 1506 }; 1507 } 1508 1509 /** 1510 * Returns an expression which returns the string concatenation value of the various 1511 * expressions 1512 * 1513 * @param expressions the expression to be concatenated dynamically 1514 * @return an expression which when evaluated will return the concatenated values 1515 */ 1516 public static Expression concatExpression(final Collection<Expression> expressions) { 1517 return concatExpression(expressions, null); 1518 } 1519 1520 /** 1521 * Returns an expression which returns the string concatenation value of the various 1522 * expressions 1523 * 1524 * @param expressions the expression to be concatenated dynamically 1525 * @param expression the text description of the expression 1526 * @return an expression which when evaluated will return the concatenated values 1527 */ 1528 public static Expression concatExpression(final Collection<Expression> expressions, final String expression) { 1529 return new ExpressionAdapter() { 1530 public Object evaluate(Exchange exchange) { 1531 StringBuilder buffer = new StringBuilder(); 1532 for (Expression expression : expressions) { 1533 String text = expression.evaluate(exchange, String.class); 1534 if (text != null) { 1535 buffer.append(text); 1536 } 1537 } 1538 return buffer.toString(); 1539 } 1540 1541 @Override 1542 public String toString() { 1543 if (expression != null) { 1544 return expression; 1545 } else { 1546 return "concat" + expressions; 1547 } 1548 } 1549 }; 1550 } 1551 1552 /** 1553 * Returns an Expression for the inbound message id 1554 */ 1555 public static Expression messageIdExpression() { 1556 return new ExpressionAdapter() { 1557 public Object evaluate(Exchange exchange) { 1558 return exchange.getIn().getMessageId(); 1559 } 1560 1561 @Override 1562 public String toString() { 1563 return "messageId"; 1564 } 1565 }; 1566 } 1567 1568 /** 1569 * Returns an Expression for the exchange id 1570 */ 1571 public static Expression exchangeIdExpression() { 1572 return new ExpressionAdapter() { 1573 public Object evaluate(Exchange exchange) { 1574 return exchange.getExchangeId(); 1575 } 1576 1577 @Override 1578 public String toString() { 1579 return "exchangeId"; 1580 } 1581 }; 1582 } 1583 1584 /** 1585 * Returns an Expression for the route id 1586 */ 1587 public static Expression routeIdExpression() { 1588 return new ExpressionAdapter() { 1589 public Object evaluate(Exchange exchange) { 1590 String answer = null; 1591 UnitOfWork uow = exchange.getUnitOfWork(); 1592 RouteContext rc = uow != null ? uow.getRouteContext() : null; 1593 if (rc != null) { 1594 answer = rc.getRoute().getId(); 1595 } 1596 if (answer == null) { 1597 // fallback and get from route id on the exchange 1598 answer = exchange.getFromRouteId(); 1599 } 1600 return answer; 1601 } 1602 1603 @Override 1604 public String toString() { 1605 return "routeId"; 1606 } 1607 }; 1608 } 1609 1610 public static Expression dateExpression(final String command, final String pattern) { 1611 return new ExpressionAdapter() { 1612 public Object evaluate(Exchange exchange) { 1613 Date date; 1614 if ("now".equals(command)) { 1615 date = new Date(); 1616 } else if (command.startsWith("header.") || command.startsWith("in.header.")) { 1617 String key = command.substring(command.lastIndexOf('.') + 1); 1618 date = exchange.getIn().getHeader(key, Date.class); 1619 if (date == null) { 1620 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1621 } 1622 } else if (command.startsWith("out.header.")) { 1623 String key = command.substring(command.lastIndexOf('.') + 1); 1624 date = exchange.getOut().getHeader(key, Date.class); 1625 if (date == null) { 1626 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1627 } 1628 } else if ("file".equals(command)) { 1629 Long num = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 1630 if (num != null && num > 0) { 1631 date = new Date(num.longValue()); 1632 } else { 1633 date = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class); 1634 if (date == null) { 1635 throw new IllegalArgumentException("Cannot find " + Exchange.FILE_LAST_MODIFIED + " header at command: " + command); 1636 } 1637 } 1638 } else { 1639 throw new IllegalArgumentException("Command not supported for dateExpression: " + command); 1640 } 1641 1642 SimpleDateFormat df = new SimpleDateFormat(pattern); 1643 return df.format(date); 1644 } 1645 1646 @Override 1647 public String toString() { 1648 return "date(" + command + ":" + pattern + ")"; 1649 } 1650 }; 1651 } 1652 1653 public static Expression simpleExpression(final String expression) { 1654 return new ExpressionAdapter() { 1655 public Object evaluate(Exchange exchange) { 1656 // resolve language using context to have a clear separation of packages 1657 // must call evaluate to return the nested language evaluate when evaluating 1658 // stacked expressions 1659 Language language = exchange.getContext().resolveLanguage("simple"); 1660 return language.createExpression(expression).evaluate(exchange, Object.class); 1661 } 1662 1663 @Override 1664 public String toString() { 1665 return "simple(" + expression + ")"; 1666 } 1667 }; 1668 } 1669 1670 public static Expression beanExpression(final String expression) { 1671 return new ExpressionAdapter() { 1672 public Object evaluate(Exchange exchange) { 1673 // resolve language using context to have a clear separation of packages 1674 // must call evaluate to return the nested language evaluate when evaluating 1675 // stacked expressions 1676 Language language = exchange.getContext().resolveLanguage("bean"); 1677 return language.createExpression(expression).evaluate(exchange, Object.class); 1678 } 1679 1680 @Override 1681 public String toString() { 1682 return "bean(" + expression + ")"; 1683 } 1684 }; 1685 } 1686 1687 public static Expression beanExpression(final Class<?> beanType, final String methodName) { 1688 return BeanLanguage.bean(beanType, methodName); 1689 } 1690 1691 public static Expression beanExpression(final Object bean, final String methodName) { 1692 return BeanLanguage.bean(bean, methodName); 1693 } 1694 1695 public static Expression beanExpression(final String beanRef, final String methodName) { 1696 String expression = methodName != null ? beanRef + "." + methodName : beanRef; 1697 return beanExpression(expression); 1698 } 1699 1700 /** 1701 * Returns an expression processing the exchange to the given endpoint uri 1702 * 1703 * @param uri endpoint uri to send the exchange to 1704 * @return an expression object which will return the OUT body 1705 */ 1706 public static Expression toExpression(final String uri) { 1707 return new ExpressionAdapter() { 1708 public Object evaluate(Exchange exchange) { 1709 Endpoint endpoint = exchange.getContext().getEndpoint(uri); 1710 if (endpoint == null) { 1711 throw new NoSuchEndpointException(uri); 1712 } 1713 1714 Producer producer; 1715 try { 1716 producer = endpoint.createProducer(); 1717 producer.start(); 1718 producer.process(exchange); 1719 producer.stop(); 1720 } catch (Exception e) { 1721 throw ObjectHelper.wrapRuntimeCamelException(e); 1722 } 1723 1724 // return the OUT body, but check for exchange pattern 1725 if (ExchangeHelper.isOutCapable(exchange)) { 1726 return exchange.getOut().getBody(); 1727 } else { 1728 return exchange.getIn().getBody(); 1729 } 1730 } 1731 1732 @Override 1733 public String toString() { 1734 return "to(" + uri + ")"; 1735 } 1736 }; 1737 } 1738 1739 public static Expression fileNameExpression() { 1740 return new ExpressionAdapter() { 1741 public Object evaluate(Exchange exchange) { 1742 return exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1743 } 1744 1745 @Override 1746 public String toString() { 1747 return "file:name"; 1748 } 1749 }; 1750 } 1751 1752 public static Expression fileOnlyNameExpression() { 1753 return new ExpressionAdapter() { 1754 public Object evaluate(Exchange exchange) { 1755 String answer = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class); 1756 if (answer == null) { 1757 answer = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1758 answer = FileUtil.stripPath(answer); 1759 } 1760 return answer; 1761 } 1762 1763 @Override 1764 public String toString() { 1765 return "file:onlyname"; 1766 } 1767 }; 1768 } 1769 1770 public static Expression fileNameNoExtensionExpression() { 1771 return new ExpressionAdapter() { 1772 public Object evaluate(Exchange exchange) { 1773 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1774 return FileUtil.stripExt(name); 1775 } 1776 1777 @Override 1778 public String toString() { 1779 return "file:name.noext"; 1780 } 1781 }; 1782 } 1783 1784 public static Expression fileNameNoExtensionSingleExpression() { 1785 return new ExpressionAdapter() { 1786 public Object evaluate(Exchange exchange) { 1787 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1788 return FileUtil.stripExt(name, true); 1789 } 1790 1791 @Override 1792 public String toString() { 1793 return "file:name.noext.single"; 1794 } 1795 }; 1796 } 1797 1798 public static Expression fileOnlyNameNoExtensionExpression() { 1799 return new ExpressionAdapter() { 1800 public Object evaluate(Exchange exchange) { 1801 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 1802 return FileUtil.stripExt(name); 1803 } 1804 1805 @Override 1806 public String toString() { 1807 return "file:onlyname.noext"; 1808 } 1809 }; 1810 } 1811 1812 public static Expression fileOnlyNameNoExtensionSingleExpression() { 1813 return new ExpressionAdapter() { 1814 public Object evaluate(Exchange exchange) { 1815 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 1816 return FileUtil.stripExt(name, true); 1817 } 1818 1819 @Override 1820 public String toString() { 1821 return "file:onlyname.noext.single"; 1822 } 1823 }; 1824 } 1825 1826 public static Expression fileExtensionExpression() { 1827 return new ExpressionAdapter() { 1828 public Object evaluate(Exchange exchange) { 1829 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1830 return FileUtil.onlyExt(name); 1831 } 1832 1833 @Override 1834 public String toString() { 1835 return "file:ext"; 1836 } 1837 }; 1838 } 1839 1840 public static Expression fileExtensionSingleExpression() { 1841 return new ExpressionAdapter() { 1842 public Object evaluate(Exchange exchange) { 1843 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1844 return FileUtil.onlyExt(name, true); 1845 } 1846 1847 @Override 1848 public String toString() { 1849 return "file:ext.single"; 1850 } 1851 }; 1852 } 1853 1854 public static Expression fileParentExpression() { 1855 return new ExpressionAdapter() { 1856 public Object evaluate(Exchange exchange) { 1857 return exchange.getIn().getHeader("CamelFileParent", String.class); 1858 } 1859 1860 @Override 1861 public String toString() { 1862 return "file:parent"; 1863 } 1864 }; 1865 } 1866 1867 public static Expression filePathExpression() { 1868 return new ExpressionAdapter() { 1869 public Object evaluate(Exchange exchange) { 1870 return exchange.getIn().getHeader("CamelFilePath", String.class); 1871 } 1872 1873 @Override 1874 public String toString() { 1875 return "file:path"; 1876 } 1877 }; 1878 } 1879 1880 public static Expression fileAbsolutePathExpression() { 1881 return new ExpressionAdapter() { 1882 public Object evaluate(Exchange exchange) { 1883 return exchange.getIn().getHeader("CamelFileAbsolutePath", String.class); 1884 } 1885 1886 @Override 1887 public String toString() { 1888 return "file:absolute.path"; 1889 } 1890 }; 1891 } 1892 1893 public static Expression fileAbsoluteExpression() { 1894 return new ExpressionAdapter() { 1895 public Object evaluate(Exchange exchange) { 1896 return exchange.getIn().getHeader("CamelFileAbsolute", Boolean.class); 1897 } 1898 1899 @Override 1900 public String toString() { 1901 return "file:absolute"; 1902 } 1903 }; 1904 } 1905 1906 public static Expression fileSizeExpression() { 1907 return new ExpressionAdapter() { 1908 public Object evaluate(Exchange exchange) { 1909 return exchange.getIn().getHeader(Exchange.FILE_LENGTH, Long.class); 1910 } 1911 1912 @Override 1913 public String toString() { 1914 return "file:length"; 1915 } 1916 }; 1917 } 1918 1919 public static Expression fileLastModifiedExpression() { 1920 return new ExpressionAdapter() { 1921 public Object evaluate(Exchange exchange) { 1922 return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 1923 } 1924 1925 @Override 1926 public String toString() { 1927 return "file:modified"; 1928 } 1929 }; 1930 } 1931 1932 /** 1933 * Returns Simple expression or fallback to Constant expression if expression str is not Simple expression. 1934 */ 1935 public static Expression parseSimpleOrFallbackToConstantExpression(String str, CamelContext camelContext) { 1936 if (StringHelper.hasStartToken(str, "simple")) { 1937 return camelContext.resolveLanguage("simple").createExpression(str); 1938 } 1939 return constantExpression(str); 1940 } 1941 1942 public static Expression propertiesComponentExpression(final String key, final String locations) { 1943 return new ExpressionAdapter() { 1944 public Object evaluate(Exchange exchange) { 1945 try { 1946 if (locations != null) { 1947 // the properties component is optional as we got locations 1948 // getComponent will create a new component if none already exists 1949 Component component = exchange.getContext().getComponent("properties"); 1950 PropertiesComponent pc = exchange.getContext().getTypeConverter() 1951 .mandatoryConvertTo(PropertiesComponent.class, component); 1952 // enclose key with {{ }} to force parsing 1953 String[] paths = locations.split(","); 1954 return pc.parseUri(pc.getPrefixToken() + key + pc.getSuffixToken(), paths); 1955 } else { 1956 // the properties component is mandatory if no locations provided 1957 Component component = exchange.getContext().hasComponent("properties"); 1958 if (component == null) { 1959 throw new IllegalArgumentException("PropertiesComponent with name properties must be defined" 1960 + " in CamelContext to support property placeholders in expressions"); 1961 } 1962 PropertiesComponent pc = exchange.getContext().getTypeConverter() 1963 .mandatoryConvertTo(PropertiesComponent.class, component); 1964 // enclose key with {{ }} to force parsing 1965 return pc.parseUri(pc.getPrefixToken() + key + pc.getSuffixToken()); 1966 } 1967 } catch (Exception e) { 1968 throw ObjectHelper.wrapRuntimeCamelException(e); 1969 } 1970 } 1971 1972 @Override 1973 public String toString() { 1974 return "properties(" + key + ")"; 1975 } 1976 }; 1977 } 1978 1979 /** 1980 * Returns a random number between min and max 1981 */ 1982 public static Expression randomExpression(final int min, final int max) { 1983 return new ExpressionAdapter() { 1984 public Object evaluate(Exchange exchange) { 1985 Random random = new Random(); 1986 int randomNum = random.nextInt(max - min) + min; 1987 return randomNum; 1988 } 1989 1990 @Override 1991 public String toString() { 1992 return "random"; 1993 } 1994 }; 1995 } 1996 1997 /** 1998 * Returns a random number between 0 and upperbound (exclusive) 1999 */ 2000 public static Expression randomExpression(final int upperbound) { 2001 return new ExpressionAdapter() { 2002 public Object evaluate(Exchange exchange) { 2003 Random random = new Random(); 2004 int randomNum = random.nextInt(upperbound); 2005 return randomNum; 2006 } 2007 2008 @Override 2009 public String toString() { 2010 return "random"; 2011 } 2012 }; 2013 } 2014 2015 /** 2016 * Returns an iterator to collate (iterate) the given expression 2017 */ 2018 public static Expression collateExpression(final String expression, final int group) { 2019 return new ExpressionAdapter() { 2020 public Object evaluate(Exchange exchange) { 2021 // use simple language 2022 Expression exp = exchange.getContext().resolveLanguage("simple").createExpression(expression); 2023 return ExpressionBuilder.groupIteratorExpression(exp, null, group, false).evaluate(exchange, Object.class); 2024 } 2025 2026 @Override 2027 public String toString() { 2028 return "collate(" + expression + "," + group + ")"; 2029 } 2030 }; 2031 } 2032 2033 /** 2034 * Returns the message history (including exchange details or not) 2035 */ 2036 public static Expression messageHistoryExpression(final boolean detailed) { 2037 return new ExpressionAdapter() { 2038 2039 private ExchangeFormatter formatter; 2040 2041 public Object evaluate(Exchange exchange) { 2042 ExchangeFormatter ef = null; 2043 if (detailed) { 2044 // use the exchange formatter to log exchange details 2045 ef = getOrCreateExchangeFormatter(exchange.getContext()); 2046 } 2047 return MessageHelper.dumpMessageHistoryStacktrace(exchange, ef, false); 2048 } 2049 2050 private ExchangeFormatter getOrCreateExchangeFormatter(CamelContext camelContext) { 2051 if (formatter == null) { 2052 Set<ExchangeFormatter> formatters = camelContext.getRegistry().findByType(ExchangeFormatter.class); 2053 if (formatters != null && formatters.size() == 1) { 2054 formatter = formatters.iterator().next(); 2055 } else { 2056 // setup exchange formatter to be used for message history dump 2057 DefaultExchangeFormatter def = new DefaultExchangeFormatter(); 2058 def.setShowExchangeId(true); 2059 def.setMultiline(true); 2060 def.setShowHeaders(true); 2061 def.setStyle(DefaultExchangeFormatter.OutputStyle.Fixed); 2062 try { 2063 Integer maxChars = CamelContextHelper.parseInteger(camelContext, camelContext.getProperty(Exchange.LOG_DEBUG_BODY_MAX_CHARS)); 2064 if (maxChars != null) { 2065 def.setMaxChars(maxChars); 2066 } 2067 } catch (Exception e) { 2068 throw ObjectHelper.wrapRuntimeCamelException(e); 2069 } 2070 formatter = def; 2071 } 2072 } 2073 return formatter; 2074 } 2075 2076 @Override 2077 public String toString() { 2078 return "messageHistory(" + detailed + ")"; 2079 } 2080 }; 2081 } 2082 2083 /** 2084 * Expression adapter for OGNL expression from Message Header or Exchange property 2085 */ 2086 private static class KeyedOgnlExpressionAdapter extends ExpressionAdapter { 2087 private final String ognl; 2088 private final String toStringValue; 2089 private final KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy; 2090 2091 KeyedOgnlExpressionAdapter(String ognl, String toStringValue, 2092 KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy) { 2093 this.ognl = ognl; 2094 this.toStringValue = toStringValue; 2095 this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy; 2096 } 2097 2098 public Object evaluate(Exchange exchange) { 2099 // try with full name first 2100 Object property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl); 2101 if (property != null) { 2102 return property; 2103 } 2104 2105 // Split ognl except when this is not a Map, Array 2106 // and we would like to keep the dots within the key name 2107 List<String> methods = OgnlHelper.splitOgnl(ognl); 2108 2109 // remove any OGNL operators so we got the pure key name 2110 String key = OgnlHelper.removeOperators(methods.get(0)); 2111 2112 property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, key); 2113 if (property == null) { 2114 return null; 2115 } 2116 // the remainder is the rest of the ognl without the key 2117 String remainder = ObjectHelper.after(ognl, key); 2118 return new MethodCallExpression(property, remainder).evaluate(exchange); 2119 } 2120 2121 @Override 2122 public String toString() { 2123 return toStringValue; 2124 } 2125 2126 /** 2127 * Strategy to retrieve the value based on the key 2128 */ 2129 public interface KeyedEntityRetrievalStrategy { 2130 Object getKeyedEntity(Exchange exchange, String key); 2131 } 2132 }; 2133 2134}