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.io.PrintWriter; 020 import java.io.StringWriter; 021 import java.text.SimpleDateFormat; 022 import java.util.Collection; 023 import java.util.Collections; 024 import java.util.Comparator; 025 import java.util.Date; 026 import java.util.Iterator; 027 import java.util.List; 028 import java.util.Scanner; 029 import java.util.regex.Pattern; 030 031 import org.apache.camel.Component; 032 import org.apache.camel.Endpoint; 033 import org.apache.camel.Exchange; 034 import org.apache.camel.Expression; 035 import org.apache.camel.InvalidPayloadException; 036 import org.apache.camel.Message; 037 import org.apache.camel.NoSuchEndpointException; 038 import org.apache.camel.Producer; 039 import org.apache.camel.component.bean.BeanInvocation; 040 import org.apache.camel.component.properties.PropertiesComponent; 041 import org.apache.camel.language.bean.BeanLanguage; 042 import org.apache.camel.model.language.MethodCallExpression; 043 import org.apache.camel.spi.Language; 044 import org.apache.camel.support.ExpressionAdapter; 045 import org.apache.camel.support.TokenPairExpressionIterator; 046 import org.apache.camel.support.TokenXMLPairExpressionIterator; 047 import org.apache.camel.util.ExchangeHelper; 048 import org.apache.camel.util.FileUtil; 049 import org.apache.camel.util.GroupIterator; 050 import org.apache.camel.util.IOHelper; 051 import org.apache.camel.util.ObjectHelper; 052 import org.apache.camel.util.OgnlHelper; 053 054 /** 055 * A helper class for working with <a href="http://camel.apache.org/expression.html">expressions</a>. 056 * 057 * @version 058 */ 059 public final class ExpressionBuilder { 060 061 /** 062 * Utility classes should not have a public constructor. 063 */ 064 private ExpressionBuilder() { 065 } 066 067 /** 068 * Returns an expression for the inbound message attachments 069 * 070 * @return an expression object which will return the inbound message attachments 071 */ 072 public static Expression attachmentsExpression() { 073 return new ExpressionAdapter() { 074 public Object evaluate(Exchange exchange) { 075 return exchange.getIn().getAttachments(); 076 } 077 078 @Override 079 public String toString() { 080 return "attachments"; 081 } 082 }; 083 } 084 085 /** 086 * Returns an expression for the inbound message attachments 087 * 088 * @return an expression object which will return the inbound message attachments 089 */ 090 public static Expression attachmentValuesExpression() { 091 return new ExpressionAdapter() { 092 public Object evaluate(Exchange exchange) { 093 return exchange.getIn().getAttachments().values(); 094 } 095 096 @Override 097 public String toString() { 098 return "attachments"; 099 } 100 }; 101 } 102 103 /** 104 * Returns an expression for the header value with the given name 105 * <p/> 106 * Will fallback and look in properties if not found in headers. 107 * 108 * @param headerName the name of the header the expression will return 109 * @return an expression object which will return the header value 110 */ 111 public static Expression headerExpression(final String headerName) { 112 return new ExpressionAdapter() { 113 public Object evaluate(Exchange exchange) { 114 Object header = exchange.getIn().getHeader(headerName); 115 if (header == null) { 116 // fall back on a property 117 header = exchange.getProperty(headerName); 118 } 119 return header; 120 } 121 122 @Override 123 public String toString() { 124 return "header(" + headerName + ")"; 125 } 126 }; 127 } 128 129 /** 130 * Returns an expression for the header value with the given name converted to the given type 131 * <p/> 132 * Will fallback and look in properties if not found in headers. 133 * 134 * @param headerName the name of the header the expression will return 135 * @param type the type to convert to 136 * @return an expression object which will return the header value 137 */ 138 public static <T> Expression headerExpression(final String headerName, final Class<T> type) { 139 return new ExpressionAdapter() { 140 public Object evaluate(Exchange exchange) { 141 Object header = exchange.getIn().getHeader(headerName, type); 142 if (header == null) { 143 // fall back on a property 144 header = exchange.getProperty(headerName, type); 145 } 146 return header; 147 } 148 149 @Override 150 public String toString() { 151 return "headerAs(" + headerName + ", " + type + ")"; 152 } 153 }; 154 } 155 156 /** 157 * Returns an expression for the header value with the given name converted to the given type 158 * <p/> 159 * Will fallback and look in properties if not found in headers. 160 * 161 * @param headerName the name of the header the expression will return 162 * @param name the type to convert to as a FQN class name 163 * @return an expression object which will return the header value 164 */ 165 public static Expression headerExpression(final String headerName, final String name) { 166 return new ExpressionAdapter() { 167 public Object evaluate(Exchange exchange) { 168 Class<?> type; 169 try { 170 type = exchange.getContext().getClassResolver().resolveMandatoryClass(name); 171 } catch (ClassNotFoundException e) { 172 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 173 } 174 175 Object header = exchange.getIn().getHeader(headerName, type); 176 if (header == null) { 177 // fall back on a property 178 header = exchange.getProperty(headerName, type); 179 } 180 return header; 181 } 182 183 @Override 184 public String toString() { 185 return "headerAs(" + headerName + ", " + name + ")"; 186 } 187 }; 188 } 189 190 /** 191 * Returns the expression for the exchanges inbound message header invoking methods defined 192 * in a simple OGNL notation 193 * 194 * @param ognl methods to invoke on the header in a simple OGNL syntax 195 */ 196 public static Expression headersOgnlExpression(final String ognl) { 197 return new KeyedOgnlExpressionAdapter(ognl, "headerOgnl(" + ognl + ")", 198 new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() { 199 public Object getKeyedEntity(Exchange exchange, String key) { 200 return exchange.getIn().getHeader(key); 201 } 202 }); 203 } 204 205 /** 206 * Returns an expression for the inbound message headers 207 * 208 * @return an expression object which will return the inbound headers 209 */ 210 public static Expression headersExpression() { 211 return new ExpressionAdapter() { 212 public Object evaluate(Exchange exchange) { 213 return exchange.getIn().getHeaders(); 214 } 215 216 @Override 217 public String toString() { 218 return "headers"; 219 } 220 }; 221 } 222 223 /** 224 * Returns an expression for the out header value with the given name 225 * <p/> 226 * Will fallback and look in properties if not found in headers. 227 * 228 * @param headerName the name of the header the expression will return 229 * @return an expression object which will return the header value 230 */ 231 public static Expression outHeaderExpression(final String headerName) { 232 return new ExpressionAdapter() { 233 public Object evaluate(Exchange exchange) { 234 if (!exchange.hasOut()) { 235 return null; 236 } 237 238 Message out = exchange.getOut(); 239 Object header = out.getHeader(headerName); 240 if (header == null) { 241 // let's try the exchange header 242 header = exchange.getProperty(headerName); 243 } 244 return header; 245 } 246 247 @Override 248 public String toString() { 249 return "outHeader(" + headerName + ")"; 250 } 251 }; 252 } 253 254 /** 255 * Returns an expression for the outbound message headers 256 * 257 * @return an expression object which will return the headers, will be <tt>null</tt> if the 258 * exchange is not out capable. 259 */ 260 public static Expression outHeadersExpression() { 261 return new ExpressionAdapter() { 262 public Object evaluate(Exchange exchange) { 263 // only get out headers if the MEP is out capable 264 if (ExchangeHelper.isOutCapable(exchange)) { 265 return exchange.getOut().getHeaders(); 266 } else { 267 return null; 268 } 269 } 270 271 @Override 272 public String toString() { 273 return "outHeaders"; 274 } 275 }; 276 } 277 278 /** 279 * Returns an expression for the exchange pattern 280 * 281 * @see org.apache.camel.Exchange#getPattern() 282 * @return an expression object which will return the exchange pattern 283 */ 284 public static Expression exchangePatternExpression() { 285 return new ExpressionAdapter() { 286 public Object evaluate(Exchange exchange) { 287 return exchange.getPattern(); 288 } 289 290 @Override 291 public String toString() { 292 return "exchangePattern"; 293 } 294 }; 295 } 296 297 /** 298 * Returns an expression for an exception set on the exchange 299 * 300 * @see Exchange#getException() 301 * @return an expression object which will return the exception set on the exchange 302 */ 303 public static Expression exchangeExceptionExpression() { 304 return new ExpressionAdapter() { 305 public Object evaluate(Exchange exchange) { 306 Exception exception = exchange.getException(); 307 if (exception == null) { 308 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 309 } 310 return exception; 311 } 312 313 @Override 314 public String toString() { 315 return "exchangeException"; 316 } 317 }; 318 } 319 320 /** 321 * Returns an expression for an exception set on the exchange 322 * <p/> 323 * Is used to get the caused exception that typically have been wrapped in some sort 324 * of Camel wrapper exception 325 * @param type the exception type 326 * @see Exchange#getException(Class) 327 * @return an expression object which will return the exception set on the exchange 328 */ 329 public static Expression exchangeExceptionExpression(final Class<Exception> type) { 330 return new ExpressionAdapter() { 331 public Object evaluate(Exchange exchange) { 332 Exception exception = exchange.getException(type); 333 if (exception == null) { 334 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 335 return ObjectHelper.getException(type, exception); 336 } 337 return exception; 338 } 339 340 @Override 341 public String toString() { 342 return "exchangeException[" + type + "]"; 343 } 344 }; 345 } 346 347 /** 348 * Returns the expression for the exchanges exception invoking methods defined 349 * in a simple OGNL notation 350 * 351 * @param ognl methods to invoke on the body in a simple OGNL syntax 352 */ 353 public static Expression exchangeExceptionOgnlExpression(final String ognl) { 354 return new ExpressionAdapter() { 355 public Object evaluate(Exchange exchange) { 356 Object exception = exchange.getException(); 357 if (exception == null) { 358 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 359 } 360 361 if (exception == null) { 362 return null; 363 } 364 return new MethodCallExpression(exception, ognl).evaluate(exchange); 365 } 366 367 @Override 368 public String toString() { 369 return "exchangeExceptionOgnl(" + ognl + ")"; 370 } 371 }; 372 } 373 374 /** 375 * Returns an expression for the type converter 376 * 377 * @return an expression object which will return the type converter 378 */ 379 public static Expression typeConverterExpression() { 380 return new ExpressionAdapter() { 381 public Object evaluate(Exchange exchange) { 382 return exchange.getContext().getTypeConverter(); 383 } 384 385 @Override 386 public String toString() { 387 return "typeConverter"; 388 } 389 }; 390 } 391 392 /** 393 * Returns an expression for the {@link org.apache.camel.spi.Registry} 394 * 395 * @return an expression object which will return the registry 396 */ 397 public static Expression registryExpression() { 398 return new ExpressionAdapter() { 399 public Object evaluate(Exchange exchange) { 400 return exchange.getContext().getRegistry(); 401 } 402 403 @Override 404 public String toString() { 405 return "registry"; 406 } 407 }; 408 } 409 410 /** 411 * Returns an expression for lookup a bean in the {@link org.apache.camel.spi.Registry} 412 * 413 * @return an expression object which will return the bean 414 */ 415 public static Expression refExpression(final String ref) { 416 return new ExpressionAdapter() { 417 public Object evaluate(Exchange exchange) { 418 return exchange.getContext().getRegistry().lookup(ref); 419 } 420 421 @Override 422 public String toString() { 423 return "ref(" + ref + ")"; 424 } 425 }; 426 } 427 428 /** 429 * Returns an expression for the {@link org.apache.camel.CamelContext} 430 * 431 * @return an expression object which will return the camel context 432 */ 433 public static Expression camelContextExpression() { 434 return new ExpressionAdapter() { 435 public Object evaluate(Exchange exchange) { 436 return exchange.getContext(); 437 } 438 439 @Override 440 public String toString() { 441 return "camelContext"; 442 } 443 }; 444 } 445 446 /** 447 * Returns an expression for the {@link org.apache.camel.CamelContext} name 448 * 449 * @return an expression object which will return the camel context name 450 */ 451 public static Expression camelContextNameExpression() { 452 return new ExpressionAdapter() { 453 public Object evaluate(Exchange exchange) { 454 return exchange.getContext().getName(); 455 } 456 457 @Override 458 public String toString() { 459 return "camelContextName"; 460 } 461 }; 462 } 463 464 /** 465 * Returns an expression for an exception message set on the exchange 466 * 467 * @see <tt>Exchange.getException().getMessage()</tt> 468 * @return an expression object which will return the exception message set on the exchange 469 */ 470 public static Expression exchangeExceptionMessageExpression() { 471 return new ExpressionAdapter() { 472 public Object evaluate(Exchange exchange) { 473 Exception exception = exchange.getException(); 474 if (exception == null) { 475 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 476 } 477 return exception != null ? exception.getMessage() : null; 478 } 479 480 @Override 481 public String toString() { 482 return "exchangeExceptionMessage"; 483 } 484 }; 485 } 486 487 /** 488 * Returns an expression for an exception stacktrace set on the exchange 489 * 490 * @return an expression object which will return the exception stacktrace set on the exchange 491 */ 492 public static Expression exchangeExceptionStackTraceExpression() { 493 return new ExpressionAdapter() { 494 public Object evaluate(Exchange exchange) { 495 Exception exception = exchange.getException(); 496 if (exception == null) { 497 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 498 } 499 if (exception != null) { 500 StringWriter sw = new StringWriter(); 501 PrintWriter pw = new PrintWriter(sw); 502 exception.printStackTrace(pw); 503 IOHelper.close(pw, sw); 504 return sw.toString(); 505 } else { 506 return null; 507 } 508 } 509 510 @Override 511 public String toString() { 512 return "exchangeExceptionStackTrace"; 513 } 514 }; 515 } 516 517 /** 518 * Returns an expression for the property value of exchange with the given name 519 * 520 * @param propertyName the name of the property the expression will return 521 * @return an expression object which will return the property value 522 */ 523 public static Expression propertyExpression(final String propertyName) { 524 return new ExpressionAdapter() { 525 public Object evaluate(Exchange exchange) { 526 return exchange.getProperty(propertyName); 527 } 528 529 @Override 530 public String toString() { 531 return "property(" + propertyName + ")"; 532 } 533 }; 534 } 535 536 /** 537 * Returns an expression for the property value of exchange with the given name invoking methods defined 538 * in a simple OGNL notation 539 * 540 * @param ognl methods to invoke on the property in a simple OGNL syntax 541 */ 542 public static Expression propertyOgnlExpression(final String ognl) { 543 return new KeyedOgnlExpressionAdapter(ognl, "propertyOgnl(" + ognl + ")", 544 new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() { 545 public Object getKeyedEntity(Exchange exchange, String key) { 546 return exchange.getProperty(key); 547 } 548 }); 549 } 550 551 /** 552 * Returns an expression for the properties of exchange 553 * 554 * @return an expression object which will return the properties 555 */ 556 public static Expression propertiesExpression() { 557 return new ExpressionAdapter() { 558 public Object evaluate(Exchange exchange) { 559 return exchange.getProperties(); 560 } 561 562 @Override 563 public String toString() { 564 return "properties"; 565 } 566 }; 567 } 568 569 /** 570 * Returns an expression for the properties of the camel context 571 * 572 * @return an expression object which will return the properties 573 */ 574 public static Expression camelContextPropertiesExpression() { 575 return new ExpressionAdapter() { 576 public Object evaluate(Exchange exchange) { 577 return exchange.getContext().getProperties(); 578 } 579 580 @Override 581 public String toString() { 582 return "camelContextProperties"; 583 } 584 }; 585 } 586 587 /** 588 * Returns an expression for the property value of the camel context with the given name 589 * 590 * @param propertyName the name of the property the expression will return 591 * @return an expression object which will return the property value 592 */ 593 public static Expression camelContextPropertyExpression(final String propertyName) { 594 return new ExpressionAdapter() { 595 public Object evaluate(Exchange exchange) { 596 return exchange.getContext().getProperties().get(propertyName); 597 } 598 599 @Override 600 public String toString() { 601 return "camelContextProperty(" + propertyName + ")"; 602 } 603 }; 604 } 605 606 /** 607 * Returns an expression for a system property value with the given name 608 * 609 * @param propertyName the name of the system property the expression will return 610 * @return an expression object which will return the system property value 611 */ 612 public static Expression systemPropertyExpression(final String propertyName) { 613 return systemPropertyExpression(propertyName, null); 614 } 615 616 /** 617 * Returns an expression for a system property value with the given name 618 * 619 * @param propertyName the name of the system property the expression will return 620 * @param defaultValue default value to return if no system property exists 621 * @return an expression object which will return the system property value 622 */ 623 public static Expression systemPropertyExpression(final String propertyName, 624 final String defaultValue) { 625 return new ExpressionAdapter() { 626 public Object evaluate(Exchange exchange) { 627 return System.getProperty(propertyName, defaultValue); 628 } 629 630 @Override 631 public String toString() { 632 return "systemProperty(" + propertyName + ")"; 633 } 634 }; 635 } 636 637 /** 638 * Returns an expression for a system environment value with the given name 639 * 640 * @param propertyName the name of the system environment the expression will return 641 * @return an expression object which will return the system property value 642 */ 643 public static Expression systemEnvironmentExpression(final String propertyName) { 644 return systemEnvironmentExpression(propertyName, null); 645 } 646 647 /** 648 * Returns an expression for a system environment value with the given name 649 * 650 * @param propertyName the name of the system environment the expression will return 651 * @param defaultValue default value to return if no system environment exists 652 * @return an expression object which will return the system environment value 653 */ 654 public static Expression systemEnvironmentExpression(final String propertyName, 655 final String defaultValue) { 656 return new ExpressionAdapter() { 657 public Object evaluate(Exchange exchange) { 658 String answer = System.getenv(propertyName); 659 if (answer == null) { 660 answer = defaultValue; 661 } 662 return answer; 663 } 664 665 @Override 666 public String toString() { 667 return "systemEnvironment(" + propertyName + ")"; 668 } 669 }; 670 } 671 672 /** 673 * Returns an expression for the constant value 674 * 675 * @param value the value the expression will return 676 * @return an expression object which will return the constant value 677 */ 678 public static Expression constantExpression(final Object value) { 679 return new ExpressionAdapter() { 680 public Object evaluate(Exchange exchange) { 681 return value; 682 } 683 684 @Override 685 public String toString() { 686 return "" + value; 687 } 688 }; 689 } 690 691 /** 692 * Returns the expression for the exchanges inbound message body 693 */ 694 public static Expression bodyExpression() { 695 return new ExpressionAdapter() { 696 public Object evaluate(Exchange exchange) { 697 return exchange.getIn().getBody(); 698 } 699 700 @Override 701 public String toString() { 702 return "body"; 703 } 704 }; 705 } 706 707 /** 708 * Returns the expression for the exchanges inbound message body invoking methods defined 709 * in a simple OGNL notation 710 * 711 * @param ognl methods to invoke on the body in a simple OGNL syntax 712 */ 713 public static Expression bodyOgnlExpression(final String ognl) { 714 return new ExpressionAdapter() { 715 public Object evaluate(Exchange exchange) { 716 Object body = exchange.getIn().getBody(); 717 if (body == null) { 718 return null; 719 } 720 return new MethodCallExpression(body, ognl).evaluate(exchange); 721 } 722 723 @Override 724 public String toString() { 725 return "bodyOgnl(" + ognl + ")"; 726 } 727 }; 728 } 729 730 /** 731 * Returns the expression for the exchanges inbound message body converted 732 * to the given type 733 */ 734 public static <T> Expression bodyExpression(final Class<T> type) { 735 return new ExpressionAdapter() { 736 public Object evaluate(Exchange exchange) { 737 return exchange.getIn().getBody(type); 738 } 739 740 @Override 741 public String toString() { 742 return "bodyAs[" + type.getName() + "]"; 743 } 744 }; 745 } 746 747 /** 748 * Returns the expression for the exchanges inbound message body converted 749 * to the given type 750 */ 751 public static Expression bodyExpression(final String name) { 752 return new ExpressionAdapter() { 753 public Object evaluate(Exchange exchange) { 754 Class<?> type; 755 try { 756 type = exchange.getContext().getClassResolver().resolveMandatoryClass(name); 757 } catch (ClassNotFoundException e) { 758 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 759 } 760 return exchange.getIn().getBody(type); 761 } 762 763 @Override 764 public String toString() { 765 return "bodyAs[" + name + "]"; 766 } 767 }; 768 } 769 770 /** 771 * Returns the expression for the exchanges inbound message body converted 772 * to the given type 773 */ 774 public static Expression mandatoryBodyExpression(final String name) { 775 return new ExpressionAdapter() { 776 public Object evaluate(Exchange exchange) { 777 Class<?> type; 778 try { 779 type = exchange.getContext().getClassResolver().resolveMandatoryClass(name); 780 } catch (ClassNotFoundException e) { 781 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 782 } 783 try { 784 return exchange.getIn().getMandatoryBody(type); 785 } catch (InvalidPayloadException e) { 786 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 787 } 788 } 789 790 @Override 791 public String toString() { 792 return "mandatoryBodyAs[" + name + "]"; 793 } 794 }; 795 } 796 797 /** 798 * Returns the expression for the current thread name 799 */ 800 public static Expression threadNameExpression() { 801 return new ExpressionAdapter() { 802 public Object evaluate(Exchange exchange) { 803 return Thread.currentThread().getName(); 804 } 805 806 @Override 807 public String toString() { 808 return "threadName"; 809 } 810 }; 811 } 812 813 /** 814 * Returns the expression for the exchanges inbound message body converted 815 * to the given type. 816 * <p/> 817 * Does <b>not</b> allow null bodies. 818 */ 819 public static <T> Expression mandatoryBodyExpression(final Class<T> type) { 820 return mandatoryBodyExpression(type, false); 821 } 822 823 /** 824 * Returns the expression for the exchanges inbound message body converted 825 * to the given type 826 * 827 * @param type the type 828 * @param nullBodyAllowed whether null bodies is allowed and if so a null is returned, 829 * otherwise an exception is thrown 830 */ 831 public static <T> Expression mandatoryBodyExpression(final Class<T> type, final boolean nullBodyAllowed) { 832 return new ExpressionAdapter() { 833 public Object evaluate(Exchange exchange) { 834 if (nullBodyAllowed) { 835 if (exchange.getIn().getBody() == null) { 836 return null; 837 } 838 839 // if its a bean invocation then if it has no arguments then it should be threaded as null body allowed 840 BeanInvocation bi = exchange.getIn().getBody(BeanInvocation.class); 841 if (bi != null && (bi.getArgs() == null || bi.getArgs().length == 0 || bi.getArgs()[0] == null)) { 842 return null; 843 } 844 } 845 846 try { 847 return exchange.getIn().getMandatoryBody(type); 848 } catch (InvalidPayloadException e) { 849 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 850 } 851 } 852 853 @Override 854 public String toString() { 855 return "mandatoryBodyAs[" + type.getName() + "]"; 856 } 857 }; 858 } 859 860 /** 861 * Returns the expression for the exchanges inbound message body type 862 */ 863 public static Expression bodyTypeExpression() { 864 return new ExpressionAdapter() { 865 public Object evaluate(Exchange exchange) { 866 return exchange.getIn().getBody().getClass(); 867 } 868 869 @Override 870 public String toString() { 871 return "bodyType"; 872 } 873 }; 874 } 875 876 /** 877 * Returns the expression for the out messages body 878 */ 879 public static Expression outBodyExpression() { 880 return new ExpressionAdapter() { 881 public Object evaluate(Exchange exchange) { 882 if (exchange.hasOut()) { 883 return exchange.getOut().getBody(); 884 } else { 885 return null; 886 } 887 } 888 889 @Override 890 public String toString() { 891 return "outBody"; 892 } 893 }; 894 } 895 896 /** 897 * Returns the expression for the exchanges outbound message body converted 898 * to the given type 899 */ 900 public static <T> Expression outBodyExpression(final Class<T> type) { 901 return new ExpressionAdapter() { 902 public Object evaluate(Exchange exchange) { 903 if (exchange.hasOut()) { 904 return exchange.getOut().getBody(type); 905 } else { 906 return null; 907 } 908 } 909 910 @Override 911 public String toString() { 912 return "outBodyAs[" + type.getName() + "]"; 913 } 914 }; 915 } 916 917 /** 918 * Returns the expression for the fault messages body 919 */ 920 public static Expression faultBodyExpression() { 921 return new ExpressionAdapter() { 922 public Object evaluate(Exchange exchange) { 923 return exchange.getOut().isFault() ? exchange.getOut().getBody() : null; 924 } 925 926 @Override 927 public String toString() { 928 return "faultBody"; 929 } 930 }; 931 } 932 933 /** 934 * Returns the expression for the exchanges fault message body converted 935 * to the given type 936 */ 937 public static <T> Expression faultBodyExpression(final Class<T> type) { 938 return new ExpressionAdapter() { 939 public Object evaluate(Exchange exchange) { 940 return exchange.getOut().isFault() ? exchange.getOut().getBody(type) : null; 941 } 942 943 @Override 944 public String toString() { 945 return "faultBodyAs[" + type.getName() + "]"; 946 } 947 }; 948 } 949 950 /** 951 * Returns the expression for the exchange 952 */ 953 public static Expression exchangeExpression() { 954 return new ExpressionAdapter() { 955 public Object evaluate(Exchange exchange) { 956 return exchange; 957 } 958 959 @Override 960 public String toString() { 961 return "exchange"; 962 } 963 }; 964 } 965 966 /** 967 * Returns the expression for the IN message 968 */ 969 public static Expression inMessageExpression() { 970 return new ExpressionAdapter() { 971 public Object evaluate(Exchange exchange) { 972 return exchange.getIn(); 973 } 974 975 @Override 976 public String toString() { 977 return "inMessage"; 978 } 979 }; 980 } 981 982 /** 983 * Returns the expression for the OUT message 984 */ 985 public static Expression outMessageExpression() { 986 return new ExpressionAdapter() { 987 public Object evaluate(Exchange exchange) { 988 return exchange.getOut(); 989 } 990 991 @Override 992 public String toString() { 993 return "outMessage"; 994 } 995 }; 996 } 997 998 /** 999 * Returns an expression which converts the given expression to the given type 1000 */ 1001 public static Expression convertToExpression(final Expression expression, final Class<?> type) { 1002 return new ExpressionAdapter() { 1003 public Object evaluate(Exchange exchange) { 1004 if (type != null) { 1005 return expression.evaluate(exchange, type); 1006 } else { 1007 return expression; 1008 } 1009 } 1010 1011 @Override 1012 public String toString() { 1013 return "" + expression; 1014 } 1015 }; 1016 } 1017 1018 /** 1019 * Returns an expression which converts the given expression to the given type the type 1020 * expression is evaluated to 1021 */ 1022 public static Expression convertToExpression(final Expression expression, final Expression type) { 1023 return new ExpressionAdapter() { 1024 public Object evaluate(Exchange exchange) { 1025 Object result = type.evaluate(exchange, Object.class); 1026 if (result != null) { 1027 return expression.evaluate(exchange, result.getClass()); 1028 } else { 1029 return expression; 1030 } 1031 } 1032 1033 @Override 1034 public String toString() { 1035 return "" + expression; 1036 } 1037 }; 1038 } 1039 1040 /** 1041 * Returns a tokenize expression which will tokenize the string with the 1042 * given token 1043 */ 1044 public static Expression tokenizeExpression(final Expression expression, 1045 final String token) { 1046 return new ExpressionAdapter() { 1047 public Object evaluate(Exchange exchange) { 1048 Object value = expression.evaluate(exchange, Object.class); 1049 Scanner scanner = ObjectHelper.getScanner(exchange, value); 1050 scanner.useDelimiter(token); 1051 return scanner; 1052 } 1053 1054 @Override 1055 public String toString() { 1056 return "tokenize(" + expression + ", " + token + ")"; 1057 } 1058 }; 1059 } 1060 1061 /** 1062 * Returns an {@link TokenPairExpressionIterator} expression 1063 */ 1064 public static Expression tokenizePairExpression(String startToken, String endToken, boolean includeTokens) { 1065 return new TokenPairExpressionIterator(startToken, endToken, includeTokens); 1066 } 1067 1068 /** 1069 * Returns an {@link TokenXMLPairExpressionIterator} expression 1070 */ 1071 public static Expression tokenizeXMLExpression(String tagName, String inheritNamespaceTagName) { 1072 ObjectHelper.notEmpty(tagName, "tagName"); 1073 1074 // must be XML tokens 1075 if (!tagName.startsWith("<")) { 1076 tagName = "<" + tagName; 1077 } 1078 if (!tagName.endsWith(">")) { 1079 tagName = tagName + ">"; 1080 } 1081 1082 String endToken = "</" + tagName.substring(1); 1083 1084 if (inheritNamespaceTagName != null) { 1085 if (!inheritNamespaceTagName.startsWith("<")) { 1086 inheritNamespaceTagName = "<" + inheritNamespaceTagName; 1087 } 1088 if (!inheritNamespaceTagName.endsWith(">")) { 1089 inheritNamespaceTagName = inheritNamespaceTagName + ">"; 1090 } 1091 } 1092 1093 return new TokenXMLPairExpressionIterator(tagName, endToken, inheritNamespaceTagName); 1094 } 1095 1096 /** 1097 * Returns a tokenize expression which will tokenize the string with the 1098 * given regex 1099 */ 1100 public static Expression regexTokenizeExpression(final Expression expression, 1101 final String regexTokenizer) { 1102 final Pattern pattern = Pattern.compile(regexTokenizer); 1103 return new ExpressionAdapter() { 1104 public Object evaluate(Exchange exchange) { 1105 Object value = expression.evaluate(exchange, Object.class); 1106 Scanner scanner = ObjectHelper.getScanner(exchange, value); 1107 scanner.useDelimiter(pattern); 1108 return scanner; 1109 } 1110 1111 @Override 1112 public String toString() { 1113 return "regexTokenize(" + expression + ", " + pattern.pattern() + ")"; 1114 } 1115 }; 1116 } 1117 1118 public static Expression groupIteratorExpression(final Expression expression, final String token, final int group) { 1119 return new ExpressionAdapter() { 1120 public Object evaluate(Exchange exchange) { 1121 // evaluate expression as iterator 1122 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1123 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1124 return new GroupIterator(exchange.getContext(), it, token, group); 1125 } 1126 1127 @Override 1128 public String toString() { 1129 return "group " + expression + " " + group + " times"; 1130 } 1131 }; 1132 } 1133 1134 /** 1135 * Returns a sort expression which will sort the expression with the given comparator. 1136 * <p/> 1137 * The expression is evaluated as a {@link List} object to allow sorting. 1138 */ 1139 @SuppressWarnings({"unchecked", "rawtypes"}) 1140 public static Expression sortExpression(final Expression expression, final Comparator comparator) { 1141 return new ExpressionAdapter() { 1142 public Object evaluate(Exchange exchange) { 1143 List<?> list = expression.evaluate(exchange, List.class); 1144 Collections.sort(list, comparator); 1145 return list; 1146 } 1147 1148 @Override 1149 public String toString() { 1150 return "sort(" + expression + " by: " + comparator + ")"; 1151 } 1152 }; 1153 } 1154 1155 /** 1156 * Transforms the expression into a String then performs the regex 1157 * replaceAll to transform the String and return the result 1158 */ 1159 public static Expression regexReplaceAll(final Expression expression, 1160 final String regex, final String replacement) { 1161 final Pattern pattern = Pattern.compile(regex); 1162 return new ExpressionAdapter() { 1163 public Object evaluate(Exchange exchange) { 1164 String text = expression.evaluate(exchange, String.class); 1165 if (text == null) { 1166 return null; 1167 } 1168 return pattern.matcher(text).replaceAll(replacement); 1169 } 1170 1171 @Override 1172 public String toString() { 1173 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1174 } 1175 }; 1176 } 1177 1178 /** 1179 * Transforms the expression into a String then performs the regex 1180 * replaceAll to transform the String and return the result 1181 */ 1182 public static Expression regexReplaceAll(final Expression expression, 1183 final String regex, final Expression replacementExpression) { 1184 1185 final Pattern pattern = Pattern.compile(regex); 1186 return new ExpressionAdapter() { 1187 public Object evaluate(Exchange exchange) { 1188 String text = expression.evaluate(exchange, String.class); 1189 String replacement = replacementExpression.evaluate(exchange, String.class); 1190 if (text == null || replacement == null) { 1191 return null; 1192 } 1193 return pattern.matcher(text).replaceAll(replacement); 1194 } 1195 1196 @Override 1197 public String toString() { 1198 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1199 } 1200 }; 1201 } 1202 1203 /** 1204 * Appends the String evaluations of the two expressions together 1205 */ 1206 public static Expression append(final Expression left, final Expression right) { 1207 return new ExpressionAdapter() { 1208 public Object evaluate(Exchange exchange) { 1209 return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class); 1210 } 1211 1212 @Override 1213 public String toString() { 1214 return "append(" + left + ", " + right + ")"; 1215 } 1216 }; 1217 } 1218 1219 /** 1220 * Prepends the String evaluations of the two expressions together 1221 */ 1222 public static Expression prepend(final Expression left, final Expression right) { 1223 return new ExpressionAdapter() { 1224 public Object evaluate(Exchange exchange) { 1225 return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class); 1226 } 1227 1228 @Override 1229 public String toString() { 1230 return "prepend(" + left + ", " + right + ")"; 1231 } 1232 }; 1233 } 1234 1235 /** 1236 * Returns an expression which returns the string concatenation value of the various 1237 * expressions 1238 * 1239 * @param expressions the expression to be concatenated dynamically 1240 * @return an expression which when evaluated will return the concatenated values 1241 */ 1242 public static Expression concatExpression(final Collection<Expression> expressions) { 1243 return concatExpression(expressions, null); 1244 } 1245 1246 /** 1247 * Returns an expression which returns the string concatenation value of the various 1248 * expressions 1249 * 1250 * @param expressions the expression to be concatenated dynamically 1251 * @param expression the text description of the expression 1252 * @return an expression which when evaluated will return the concatenated values 1253 */ 1254 public static Expression concatExpression(final Collection<Expression> expressions, final String expression) { 1255 return new ExpressionAdapter() { 1256 public Object evaluate(Exchange exchange) { 1257 StringBuilder buffer = new StringBuilder(); 1258 for (Expression expression : expressions) { 1259 String text = expression.evaluate(exchange, String.class); 1260 if (text != null) { 1261 buffer.append(text); 1262 } 1263 } 1264 return buffer.toString(); 1265 } 1266 1267 @Override 1268 public String toString() { 1269 if (expression != null) { 1270 return expression; 1271 } else { 1272 return "concat" + expressions; 1273 } 1274 } 1275 }; 1276 } 1277 1278 /** 1279 * Returns an Expression for the inbound message id 1280 */ 1281 public static Expression messageIdExpression() { 1282 return new ExpressionAdapter() { 1283 public Object evaluate(Exchange exchange) { 1284 return exchange.getIn().getMessageId(); 1285 } 1286 1287 @Override 1288 public String toString() { 1289 return "messageId"; 1290 } 1291 }; 1292 } 1293 1294 /** 1295 * Returns an Expression for the exchange id 1296 */ 1297 public static Expression exchangeIdExpression() { 1298 return new ExpressionAdapter() { 1299 public Object evaluate(Exchange exchange) { 1300 return exchange.getExchangeId(); 1301 } 1302 1303 @Override 1304 public String toString() { 1305 return "exchangeId"; 1306 } 1307 }; 1308 } 1309 1310 public static Expression dateExpression(final String command, final String pattern) { 1311 return new ExpressionAdapter() { 1312 public Object evaluate(Exchange exchange) { 1313 Date date; 1314 if ("now".equals(command)) { 1315 date = new Date(); 1316 } else if (command.startsWith("header.") || command.startsWith("in.header.")) { 1317 String key = command.substring(command.lastIndexOf('.') + 1); 1318 date = exchange.getIn().getHeader(key, Date.class); 1319 if (date == null) { 1320 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1321 } 1322 } else if (command.startsWith("out.header.")) { 1323 String key = command.substring(command.lastIndexOf('.') + 1); 1324 date = exchange.getOut().getHeader(key, Date.class); 1325 if (date == null) { 1326 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1327 } 1328 } else if ("file".equals(command)) { 1329 Long num = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 1330 if (num != null && num > 0) { 1331 date = new Date(num.longValue()); 1332 } else { 1333 date = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class); 1334 if (date == null) { 1335 throw new IllegalArgumentException("Cannot find " + Exchange.FILE_LAST_MODIFIED + " header at command: " + command); 1336 } 1337 } 1338 } else { 1339 throw new IllegalArgumentException("Command not supported for dateExpression: " + command); 1340 } 1341 1342 SimpleDateFormat df = new SimpleDateFormat(pattern); 1343 return df.format(date); 1344 } 1345 1346 @Override 1347 public String toString() { 1348 return "date(" + command + ":" + pattern + ")"; 1349 } 1350 }; 1351 } 1352 1353 public static Expression simpleExpression(final String expression) { 1354 return new ExpressionAdapter() { 1355 public Object evaluate(Exchange exchange) { 1356 // resolve language using context to have a clear separation of packages 1357 // must call evaluate to return the nested language evaluate when evaluating 1358 // stacked expressions 1359 Language language = exchange.getContext().resolveLanguage("simple"); 1360 return language.createExpression(expression).evaluate(exchange, Object.class); 1361 } 1362 1363 @Override 1364 public String toString() { 1365 return "simple(" + expression + ")"; 1366 } 1367 }; 1368 } 1369 1370 public static Expression beanExpression(final String expression) { 1371 return new ExpressionAdapter() { 1372 public Object evaluate(Exchange exchange) { 1373 // resolve language using context to have a clear separation of packages 1374 // must call evaluate to return the nested language evaluate when evaluating 1375 // stacked expressions 1376 Language language = exchange.getContext().resolveLanguage("bean"); 1377 return language.createExpression(expression).evaluate(exchange, Object.class); 1378 } 1379 1380 @Override 1381 public String toString() { 1382 return "bean(" + expression + ")"; 1383 } 1384 }; 1385 } 1386 1387 public static Expression beanExpression(final Class<?> beanType, final String methodName) { 1388 return BeanLanguage.bean(beanType, methodName); 1389 } 1390 1391 public static Expression beanExpression(final Object bean, final String methodName) { 1392 return BeanLanguage.bean(bean, methodName); 1393 } 1394 1395 public static Expression beanExpression(final String beanRef, final String methodName) { 1396 String expression = methodName != null ? beanRef + "." + methodName : beanRef; 1397 return beanExpression(expression); 1398 } 1399 1400 /** 1401 * Returns an expression processing the exchange to the given endpoint uri 1402 * 1403 * @param uri endpoint uri to send the exchange to 1404 * @return an expression object which will return the OUT body 1405 */ 1406 public static Expression toExpression(final String uri) { 1407 return new ExpressionAdapter() { 1408 public Object evaluate(Exchange exchange) { 1409 Endpoint endpoint = exchange.getContext().getEndpoint(uri); 1410 if (endpoint == null) { 1411 throw new NoSuchEndpointException(uri); 1412 } 1413 1414 Producer producer; 1415 try { 1416 producer = endpoint.createProducer(); 1417 producer.start(); 1418 producer.process(exchange); 1419 producer.stop(); 1420 } catch (Exception e) { 1421 throw ObjectHelper.wrapRuntimeCamelException(e); 1422 } 1423 1424 // return the OUT body, but check for exchange pattern 1425 if (ExchangeHelper.isOutCapable(exchange)) { 1426 return exchange.getOut().getBody(); 1427 } else { 1428 return exchange.getIn().getBody(); 1429 } 1430 } 1431 1432 @Override 1433 public String toString() { 1434 return "to(" + uri + ")"; 1435 } 1436 }; 1437 } 1438 1439 public static Expression fileNameExpression() { 1440 return new ExpressionAdapter() { 1441 public Object evaluate(Exchange exchange) { 1442 return exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1443 } 1444 1445 @Override 1446 public String toString() { 1447 return "file:name"; 1448 } 1449 }; 1450 } 1451 1452 public static Expression fileOnlyNameExpression() { 1453 return new ExpressionAdapter() { 1454 public Object evaluate(Exchange exchange) { 1455 String answer = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class); 1456 if (answer == null) { 1457 answer = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1458 answer = FileUtil.stripPath(answer); 1459 } 1460 return answer; 1461 } 1462 1463 @Override 1464 public String toString() { 1465 return "file:onlyname"; 1466 } 1467 }; 1468 } 1469 1470 public static Expression fileNameNoExtensionExpression() { 1471 return new ExpressionAdapter() { 1472 public Object evaluate(Exchange exchange) { 1473 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1474 return FileUtil.stripExt(name); 1475 } 1476 1477 @Override 1478 public String toString() { 1479 return "file:name.noext"; 1480 } 1481 }; 1482 } 1483 1484 public static Expression fileOnlyNameNoExtensionExpression() { 1485 return new ExpressionAdapter() { 1486 public Object evaluate(Exchange exchange) { 1487 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 1488 return FileUtil.stripExt(name); 1489 } 1490 1491 @Override 1492 public String toString() { 1493 return "file:onlyname.noext"; 1494 } 1495 }; 1496 } 1497 1498 public static Expression fileExtensionExpression() { 1499 return new ExpressionAdapter() { 1500 public Object evaluate(Exchange exchange) { 1501 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 1502 if (name != null) { 1503 return name.substring(name.lastIndexOf('.') + 1); 1504 } else { 1505 return null; 1506 } 1507 } 1508 1509 @Override 1510 public String toString() { 1511 return "file:ext"; 1512 } 1513 }; 1514 } 1515 1516 public static Expression fileParentExpression() { 1517 return new ExpressionAdapter() { 1518 public Object evaluate(Exchange exchange) { 1519 return exchange.getIn().getHeader("CamelFileParent", String.class); 1520 } 1521 1522 @Override 1523 public String toString() { 1524 return "file:parent"; 1525 } 1526 }; 1527 } 1528 1529 public static Expression filePathExpression() { 1530 return new ExpressionAdapter() { 1531 public Object evaluate(Exchange exchange) { 1532 return exchange.getIn().getHeader("CamelFilePath", String.class); 1533 } 1534 1535 @Override 1536 public String toString() { 1537 return "file:path"; 1538 } 1539 }; 1540 } 1541 1542 public static Expression fileAbsolutePathExpression() { 1543 return new ExpressionAdapter() { 1544 public Object evaluate(Exchange exchange) { 1545 return exchange.getIn().getHeader("CamelFileAbsolutePath", String.class); 1546 } 1547 1548 @Override 1549 public String toString() { 1550 return "file:absolute.path"; 1551 } 1552 }; 1553 } 1554 1555 public static Expression fileAbsoluteExpression() { 1556 return new ExpressionAdapter() { 1557 public Object evaluate(Exchange exchange) { 1558 return exchange.getIn().getHeader("CamelFileAbsolute", Boolean.class); 1559 } 1560 1561 @Override 1562 public String toString() { 1563 return "file:absolute"; 1564 } 1565 }; 1566 } 1567 1568 public static Expression fileSizeExpression() { 1569 return new ExpressionAdapter() { 1570 public Object evaluate(Exchange exchange) { 1571 return exchange.getIn().getHeader(Exchange.FILE_LENGTH, Long.class); 1572 } 1573 1574 @Override 1575 public String toString() { 1576 return "file:length"; 1577 } 1578 }; 1579 } 1580 1581 public static Expression fileLastModifiedExpression() { 1582 return new ExpressionAdapter() { 1583 public Object evaluate(Exchange exchange) { 1584 return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 1585 } 1586 1587 @Override 1588 public String toString() { 1589 return "file:modified"; 1590 } 1591 }; 1592 } 1593 1594 public static Expression propertiesComponentExpression(final String key, final String locations) { 1595 return new ExpressionAdapter() { 1596 public Object evaluate(Exchange exchange) { 1597 try { 1598 if (locations != null) { 1599 // the properties component is optional as we got locations 1600 // getComponent will create a new component if none already exists 1601 Component component = exchange.getContext().getComponent("properties"); 1602 PropertiesComponent pc = exchange.getContext().getTypeConverter() 1603 .mandatoryConvertTo(PropertiesComponent.class, component); 1604 // enclose key with {{ }} to force parsing 1605 String[] paths = locations.split(","); 1606 return pc.parseUri(pc.getPrefixToken() + key + pc.getSuffixToken(), paths); 1607 } else { 1608 // the properties component is mandatory if no locations provided 1609 Component component = exchange.getContext().hasComponent("properties"); 1610 if (component == null) { 1611 throw new IllegalArgumentException("PropertiesComponent with name properties must be defined" 1612 + " in CamelContext to support property placeholders in expressions"); 1613 } 1614 PropertiesComponent pc = exchange.getContext().getTypeConverter() 1615 .mandatoryConvertTo(PropertiesComponent.class, component); 1616 // enclose key with {{ }} to force parsing 1617 return pc.parseUri(pc.getPrefixToken() + key + pc.getSuffixToken()); 1618 } 1619 } catch (Exception e) { 1620 throw ObjectHelper.wrapRuntimeCamelException(e); 1621 } 1622 } 1623 1624 @Override 1625 public String toString() { 1626 return "properties(" + key + ")"; 1627 } 1628 }; 1629 } 1630 1631 /** 1632 * Expression adapter for OGNL expression from Message Header or Exchange property 1633 */ 1634 private static class KeyedOgnlExpressionAdapter extends ExpressionAdapter { 1635 private final String ognl; 1636 private final String toStringValue; 1637 private final KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy; 1638 1639 public KeyedOgnlExpressionAdapter(String ognl, String toStringValue, 1640 KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy) { 1641 this.ognl = ognl; 1642 this.toStringValue = toStringValue; 1643 this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy; 1644 } 1645 1646 public Object evaluate(Exchange exchange) { 1647 // try with full name first 1648 Object property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl); 1649 if (property != null) { 1650 return property; 1651 } 1652 1653 // Split ognl except when this is not a Map, Array 1654 // and we would like to keep the dots within the key name 1655 List<String> methods = OgnlHelper.splitOgnl(ognl); 1656 1657 // remove any OGNL operators so we got the pure key name 1658 String key = OgnlHelper.removeOperators(methods.get(0)); 1659 1660 property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, key); 1661 if (property == null) { 1662 return null; 1663 } 1664 // the remainder is the rest of the ognl without the key 1665 String remainder = ObjectHelper.after(ognl, key); 1666 return new MethodCallExpression(property, remainder).evaluate(exchange); 1667 } 1668 1669 @Override 1670 public String toString() { 1671 return toStringValue; 1672 } 1673 1674 /** 1675 * Strategy to retrieve the value based on the key 1676 */ 1677 public interface KeyedEntityRetrievalStrategy { 1678 Object getKeyedEntity(Exchange exchange, String key); 1679 } 1680 }; 1681 1682 }