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