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.Comparator; 025import java.util.Date; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Map; 029import java.util.Random; 030import java.util.Set; 031import java.util.TimeZone; 032import java.util.concurrent.atomic.AtomicReference; 033import java.util.function.BiFunction; 034import java.util.function.Function; 035import java.util.regex.Matcher; 036import java.util.regex.Pattern; 037 038import org.apache.camel.CamelContext; 039import org.apache.camel.Component; 040import org.apache.camel.Endpoint; 041import org.apache.camel.Exchange; 042import org.apache.camel.Expression; 043import org.apache.camel.InvalidPayloadException; 044import org.apache.camel.Message; 045import org.apache.camel.NoSuchEndpointException; 046import org.apache.camel.NoSuchLanguageException; 047import org.apache.camel.NoTypeConversionAvailableException; 048import org.apache.camel.Producer; 049import org.apache.camel.RuntimeExchangeException; 050import org.apache.camel.component.bean.BeanInvocation; 051import org.apache.camel.component.properties.PropertiesComponent; 052import org.apache.camel.language.bean.BeanLanguage; 053import org.apache.camel.language.simple.SimpleLanguage; 054import org.apache.camel.model.language.MethodCallExpression; 055import org.apache.camel.processor.DefaultExchangeFormatter; 056import org.apache.camel.spi.ExchangeFormatter; 057import org.apache.camel.spi.Language; 058import org.apache.camel.spi.RouteContext; 059import org.apache.camel.spi.UnitOfWork; 060import org.apache.camel.support.ExpressionAdapter; 061import org.apache.camel.support.TokenPairExpressionIterator; 062import org.apache.camel.support.TokenXMLExpressionIterator; 063import org.apache.camel.support.XMLTokenExpressionIterator; 064import org.apache.camel.util.CamelContextHelper; 065import org.apache.camel.util.ExchangeHelper; 066import org.apache.camel.util.FileUtil; 067import org.apache.camel.util.GroupIterator; 068import org.apache.camel.util.GroupTokenIterator; 069import org.apache.camel.util.IOHelper; 070import org.apache.camel.util.MessageHelper; 071import org.apache.camel.util.ObjectHelper; 072import org.apache.camel.util.OgnlHelper; 073import org.apache.camel.util.Scanner; 074import org.apache.camel.util.SkipIterator; 075import org.apache.camel.util.StringHelper; 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 * @deprecated use {@link #exchangeExceptionExpression()} instead 651 */ 652 @Deprecated 653 public static Expression propertiesExpression() { 654 return exchangeExceptionExpression(); 655 } 656 657 /** 658 * Returns an expression for the exchange properties of exchange 659 * 660 * @return an expression object which will return the exchange properties 661 */ 662 public static Expression exchangePropertiesExpression() { 663 return new ExpressionAdapter() { 664 public Object evaluate(Exchange exchange) { 665 return exchange.getProperties(); 666 } 667 668 @Override 669 public String toString() { 670 return "exchangeProperties"; 671 } 672 }; 673 } 674 675 /** 676 * Returns an expression for the properties of the camel context 677 * 678 * @return an expression object which will return the properties 679 */ 680 public static Expression camelContextPropertiesExpression() { 681 return new ExpressionAdapter() { 682 public Object evaluate(Exchange exchange) { 683 return exchange.getContext().getGlobalOptions(); 684 } 685 686 @Override 687 public String toString() { 688 return "camelContextProperties"; 689 } 690 }; 691 } 692 693 /** 694 * Returns an expression for the property value of the camel context with the given name 695 * 696 * @param propertyName the name of the property the expression will return 697 * @return an expression object which will return the property value 698 */ 699 public static Expression camelContextPropertyExpression(final String propertyName) { 700 return new ExpressionAdapter() { 701 public Object evaluate(Exchange exchange) { 702 String text = simpleExpression(propertyName).evaluate(exchange, String.class); 703 return exchange.getContext().getGlobalOption(text); 704 } 705 706 @Override 707 public String toString() { 708 return "camelContextProperty(" + propertyName + ")"; 709 } 710 }; 711 } 712 713 /** 714 * Returns an expression for a system property value with the given name 715 * 716 * @param propertyName the name of the system property the expression will return 717 * @return an expression object which will return the system property value 718 */ 719 public static Expression systemPropertyExpression(final String propertyName) { 720 return systemPropertyExpression(propertyName, null); 721 } 722 723 /** 724 * Returns an expression for a system property value with the given name 725 * 726 * @param propertyName the name of the system property the expression will return 727 * @param defaultValue default value to return if no system property exists 728 * @return an expression object which will return the system property value 729 */ 730 public static Expression systemPropertyExpression(final String propertyName, 731 final String defaultValue) { 732 return new ExpressionAdapter() { 733 public Object evaluate(Exchange exchange) { 734 String text = simpleExpression(propertyName).evaluate(exchange, String.class); 735 String text2 = simpleExpression(defaultValue).evaluate(exchange, String.class); 736 return System.getProperty(text, text2); 737 } 738 739 @Override 740 public String toString() { 741 return "systemProperty(" + propertyName + ")"; 742 } 743 }; 744 } 745 746 /** 747 * Returns an expression for a system environment value with the given name 748 * 749 * @param propertyName the name of the system environment the expression will return 750 * @return an expression object which will return the system property value 751 */ 752 public static Expression systemEnvironmentExpression(final String propertyName) { 753 return systemEnvironmentExpression(propertyName, null); 754 } 755 756 /** 757 * Returns an expression for a system environment value with the given name 758 * 759 * @param propertyName the name of the system environment the expression will return 760 * @param defaultValue default value to return if no system environment exists 761 * @return an expression object which will return the system environment value 762 */ 763 public static Expression systemEnvironmentExpression(final String propertyName, 764 final String defaultValue) { 765 return new ExpressionAdapter() { 766 public Object evaluate(Exchange exchange) { 767 String text = simpleExpression(propertyName).evaluate(exchange, String.class); 768 String answer = System.getenv(text.toUpperCase()); 769 if (answer == null) { 770 String text2 = simpleExpression(defaultValue).evaluate(exchange, String.class); 771 answer = text2; 772 } 773 return answer; 774 } 775 776 @Override 777 public String toString() { 778 return "systemEnvironment(" + propertyName + ")"; 779 } 780 }; 781 } 782 783 /** 784 * Returns an expression for the constant value 785 * 786 * @param value the value the expression will return 787 * @return an expression object which will return the constant value 788 */ 789 public static Expression constantExpression(final Object value) { 790 return new ExpressionAdapter() { 791 public Object evaluate(Exchange exchange) { 792 return value; 793 } 794 795 @Override 796 public String toString() { 797 return "" + value; 798 } 799 }; 800 } 801 802 /** 803 * Returns an expression for evaluating the expression/predicate using the given language 804 * 805 * @param expression the expression or predicate 806 * @return an expression object which will evaluate the expression/predicate using the given language 807 */ 808 public static Expression languageExpression(final String language, final String expression) { 809 return new ExpressionAdapter() { 810 public Object evaluate(Exchange exchange) { 811 Language lan = exchange.getContext().resolveLanguage(language); 812 if (lan != null) { 813 return lan.createExpression(expression).evaluate(exchange, Object.class); 814 } else { 815 throw new NoSuchLanguageException(language); 816 } 817 } 818 819 @Override 820 public boolean matches(Exchange exchange) { 821 Language lan = exchange.getContext().resolveLanguage(language); 822 if (lan != null) { 823 return lan.createPredicate(expression).matches(exchange); 824 } else { 825 throw new NoSuchLanguageException(language); 826 } 827 } 828 829 @Override 830 public String toString() { 831 return "language[" + language + ":" + expression + "]"; 832 } 833 }; 834 } 835 836 /** 837 * Returns an expression for a type value 838 * 839 * @param name the type name 840 * @return an expression object which will return the type value 841 */ 842 public static Expression typeExpression(final String name) { 843 return new ExpressionAdapter() { 844 public Object evaluate(Exchange exchange) { 845 // it may refer to a class type 846 String text = simpleExpression(name).evaluate(exchange, String.class); 847 Class<?> type = exchange.getContext().getClassResolver().resolveClass(text); 848 if (type != null) { 849 return type; 850 } 851 852 int pos = text.lastIndexOf("."); 853 if (pos > 0) { 854 String before = text.substring(0, pos); 855 String after = text.substring(pos + 1); 856 type = exchange.getContext().getClassResolver().resolveClass(before); 857 if (type != null) { 858 return ObjectHelper.lookupConstantFieldValue(type, after); 859 } 860 } 861 862 throw ObjectHelper.wrapCamelExecutionException(exchange, new ClassNotFoundException("Cannot find type " + text)); 863 } 864 865 @Override 866 public String toString() { 867 return "type:" + name; 868 } 869 }; 870 } 871 872 /** 873 * Returns an expression that caches the evaluation of another expression 874 * and returns the cached value, to avoid re-evaluating the expression. 875 * 876 * @param expression the target expression to cache 877 * @return the cached value 878 */ 879 public static Expression cacheExpression(final Expression expression) { 880 return new ExpressionAdapter() { 881 private final AtomicReference<Object> cache = new AtomicReference<>(); 882 883 public Object evaluate(Exchange exchange) { 884 Object answer = cache.get(); 885 if (answer == null) { 886 answer = expression.evaluate(exchange, Object.class); 887 cache.set(answer); 888 } 889 return answer; 890 } 891 892 @Override 893 public String toString() { 894 return expression.toString(); 895 } 896 }; 897 } 898 899 /** 900 * Returns the expression for the exchanges inbound message body 901 */ 902 public static Expression bodyExpression() { 903 return new ExpressionAdapter() { 904 public Object evaluate(Exchange exchange) { 905 return exchange.getIn().getBody(); 906 } 907 908 @Override 909 public String toString() { 910 return "body"; 911 } 912 }; 913 } 914 915 /** 916 * Returns a functional expression for the exchanges inbound message body 917 */ 918 public static Expression bodyExpression(final Function<Object, Object> function) { 919 return new ExpressionAdapter() { 920 public Object evaluate(Exchange exchange) { 921 return function.apply( 922 exchange.getIn().getBody() 923 ); 924 } 925 926 @Override 927 public String toString() { 928 return "bodyExpression"; 929 } 930 }; 931 } 932 933 /** 934 * Returns a functional expression for the exchanges inbound message body and headers 935 */ 936 public static Expression bodyExpression(final BiFunction<Object, Map<String, Object>, Object> function) { 937 return new ExpressionAdapter() { 938 public Object evaluate(Exchange exchange) { 939 return function.apply( 940 exchange.getIn().getBody(), 941 exchange.getIn().getHeaders() 942 ); 943 } 944 945 @Override 946 public String toString() { 947 return "bodyExpression"; 948 } 949 }; 950 } 951 952 /** 953 * Returns a functional expression for the exchanges inbound message body converted to a desired type 954 */ 955 public static <T> Expression bodyExpression(final Class<T> bodyType, final Function<T, Object> function) { 956 return new ExpressionAdapter() { 957 public Object evaluate(Exchange exchange) { 958 return function.apply( 959 exchange.getIn().getBody(bodyType) 960 ); 961 } 962 963 @Override 964 public String toString() { 965 return "bodyExpression (" + bodyType + ")"; 966 } 967 }; 968 } 969 970 /** 971 * Returns a functional expression for the exchanges inbound message body converted to a desired type and headers 972 */ 973 public static <T> Expression bodyExpression(final Class<T> bodyType, final BiFunction<T, Map<String, Object>, Object> function) { 974 return new ExpressionAdapter() { 975 public Object evaluate(Exchange exchange) { 976 return function.apply( 977 exchange.getIn().getBody(bodyType), 978 exchange.getIn().getHeaders() 979 ); 980 } 981 982 @Override 983 public String toString() { 984 return "bodyExpression (" + bodyType + ")"; 985 } 986 }; 987 } 988 989 /** 990 * Returns the expression for the exchanges inbound message body invoking methods defined 991 * in a simple OGNL notation 992 * 993 * @param ognl methods to invoke on the body in a simple OGNL syntax 994 */ 995 public static Expression bodyOgnlExpression(final String ognl) { 996 return new ExpressionAdapter() { 997 public Object evaluate(Exchange exchange) { 998 Object body = exchange.getIn().getBody(); 999 if (body == null) { 1000 return null; 1001 } 1002 // ognl is able to evaluate method name if it contains nested functions 1003 // so we should not eager evaluate ognl as a string 1004 return new MethodCallExpression(body, ognl).evaluate(exchange); 1005 } 1006 1007 @Override 1008 public String toString() { 1009 return "bodyOgnl(" + ognl + ")"; 1010 } 1011 }; 1012 } 1013 1014 /** 1015 * Returns the expression for invoking a method (support OGNL syntax) on the given expression 1016 * 1017 * @param exp the expression to evaluate and invoke the method on its result 1018 * @param ognl methods to invoke on the evaluated expression in a simple OGNL syntax 1019 */ 1020 public static Expression ognlExpression(final Expression exp, final String ognl) { 1021 return new ExpressionAdapter() { 1022 public Object evaluate(Exchange exchange) { 1023 Object value = exp.evaluate(exchange, Object.class); 1024 if (value == null) { 1025 return null; 1026 } 1027 // ognl is able to evaluate method name if it contains nested functions 1028 // so we should not eager evaluate ognl as a string 1029 return new MethodCallExpression(value, ognl).evaluate(exchange); 1030 } 1031 1032 @Override 1033 public String toString() { 1034 return "ognl(" + exp + ", " + ognl + ")"; 1035 } 1036 }; 1037 } 1038 1039 /** 1040 * Returns the expression for the exchanges camelContext invoking methods defined 1041 * in a simple OGNL notation 1042 * 1043 * @param ognl methods to invoke on the context in a simple OGNL syntax 1044 */ 1045 public static Expression camelContextOgnlExpression(final String ognl) { 1046 return new ExpressionAdapter() { 1047 public Object evaluate(Exchange exchange) { 1048 CamelContext context = exchange.getContext(); 1049 if (context == null) { 1050 return null; 1051 } 1052 // ognl is able to evaluate method name if it contains nested functions 1053 // so we should not eager evaluate ognl as a string 1054 return new MethodCallExpression(context, ognl).evaluate(exchange); 1055 } 1056 1057 @Override 1058 public String toString() { 1059 return "camelContextOgnl(" + ognl + ")"; 1060 } 1061 }; 1062 } 1063 1064 /** 1065 * Returns the expression for the exchange invoking methods defined 1066 * in a simple OGNL notation 1067 * 1068 * @param ognl methods to invoke on the exchange in a simple OGNL syntax 1069 */ 1070 public static Expression exchangeOgnlExpression(final String ognl) { 1071 return new ExpressionAdapter() { 1072 public Object evaluate(Exchange exchange) { 1073 // ognl is able to evaluate method name if it contains nested functions 1074 // so we should not eager evaluate ognl as a string 1075 return new MethodCallExpression(exchange, ognl).evaluate(exchange); 1076 } 1077 1078 @Override 1079 public String toString() { 1080 return "exchangeOgnl(" + ognl + ")"; 1081 } 1082 }; 1083 } 1084 1085 /** 1086 * Returns the expression for the exchanges inbound message body converted 1087 * to the given type 1088 */ 1089 public static <T> Expression bodyExpression(final Class<T> type) { 1090 return new ExpressionAdapter() { 1091 public Object evaluate(Exchange exchange) { 1092 return exchange.getIn().getBody(type); 1093 } 1094 1095 @Override 1096 public String toString() { 1097 return "bodyAs[" + type.getName() + "]"; 1098 } 1099 }; 1100 } 1101 1102 /** 1103 * Returns the expression for the exchanges inbound message body converted 1104 * to the given type 1105 */ 1106 public static Expression bodyExpression(final String name) { 1107 return new ExpressionAdapter() { 1108 public Object evaluate(Exchange exchange) { 1109 String text = simpleExpression(name).evaluate(exchange, String.class); 1110 Class<?> type; 1111 try { 1112 type = exchange.getContext().getClassResolver().resolveMandatoryClass(text); 1113 } catch (ClassNotFoundException e) { 1114 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1115 } 1116 return exchange.getIn().getBody(type); 1117 } 1118 1119 @Override 1120 public String toString() { 1121 return "bodyAs[" + name + "]"; 1122 } 1123 }; 1124 } 1125 1126 /** 1127 * Returns the expression for the exchanges inbound message body converted 1128 * to the given type and invoking methods on the converted body defined in a simple OGNL notation 1129 */ 1130 public static Expression bodyOgnlExpression(final String name, final String ognl) { 1131 return new ExpressionAdapter() { 1132 public Object evaluate(Exchange exchange) { 1133 String text = simpleExpression(name).evaluate(exchange, String.class); 1134 Class<?> type; 1135 try { 1136 type = exchange.getContext().getClassResolver().resolveMandatoryClass(text); 1137 } catch (ClassNotFoundException e) { 1138 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1139 } 1140 Object body = exchange.getIn().getBody(type); 1141 if (body != null) { 1142 // ognl is able to evaluate method name if it contains nested functions 1143 // so we should not eager evaluate ognl as a string 1144 MethodCallExpression call = new MethodCallExpression(exchange, ognl); 1145 // set the instance to use 1146 call.setInstance(body); 1147 return call.evaluate(exchange); 1148 } else { 1149 return null; 1150 } 1151 } 1152 1153 @Override 1154 public String toString() { 1155 return "bodyOgnlAs[" + name + "](" + ognl + ")"; 1156 } 1157 }; 1158 } 1159 1160 /** 1161 * Returns the expression for the exchanges inbound message body converted 1162 * to the given type 1163 */ 1164 public static Expression mandatoryBodyExpression(final String name) { 1165 return new ExpressionAdapter() { 1166 public Object evaluate(Exchange exchange) { 1167 String text = simpleExpression(name).evaluate(exchange, String.class); 1168 Class<?> type; 1169 try { 1170 type = exchange.getContext().getClassResolver().resolveMandatoryClass(text); 1171 } catch (ClassNotFoundException e) { 1172 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1173 } 1174 try { 1175 return exchange.getIn().getMandatoryBody(type); 1176 } catch (InvalidPayloadException e) { 1177 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1178 } 1179 } 1180 1181 @Override 1182 public String toString() { 1183 return "mandatoryBodyAs[" + name + "]"; 1184 } 1185 }; 1186 } 1187 1188 /** 1189 * Returns the expression for the exchanges inbound message body converted 1190 * to the given type and invoking methods on the converted body defined in a simple OGNL notation 1191 */ 1192 public static Expression mandatoryBodyOgnlExpression(final String name, final String ognl) { 1193 return new ExpressionAdapter() { 1194 public Object evaluate(Exchange exchange) { 1195 String text = simpleExpression(name).evaluate(exchange, String.class); 1196 Class<?> type; 1197 try { 1198 type = exchange.getContext().getClassResolver().resolveMandatoryClass(text); 1199 } catch (ClassNotFoundException e) { 1200 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1201 } 1202 Object body; 1203 try { 1204 body = exchange.getIn().getMandatoryBody(type); 1205 } catch (InvalidPayloadException e) { 1206 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1207 } 1208 // ognl is able to evaluate method name if it contains nested functions 1209 // so we should not eager evaluate ognl as a string 1210 MethodCallExpression call = new MethodCallExpression(exchange, ognl); 1211 // set the instance to use 1212 call.setInstance(body); 1213 return call.evaluate(exchange); 1214 } 1215 1216 @Override 1217 public String toString() { 1218 return "mandatoryBodyAs[" + name + "](" + ognl + ")"; 1219 } 1220 }; 1221 } 1222 1223 /** 1224 * Returns the expression for the current thread name 1225 */ 1226 public static Expression threadNameExpression() { 1227 return new ExpressionAdapter() { 1228 public Object evaluate(Exchange exchange) { 1229 return Thread.currentThread().getName(); 1230 } 1231 1232 @Override 1233 public String toString() { 1234 return "threadName"; 1235 } 1236 }; 1237 } 1238 1239 /** 1240 * Returns the expression for the {@code null} value 1241 */ 1242 public static Expression nullExpression() { 1243 return new ExpressionAdapter() { 1244 public Object evaluate(Exchange exchange) { 1245 return null; 1246 } 1247 1248 @Override 1249 public String toString() { 1250 return "null"; 1251 } 1252 }; 1253 } 1254 1255 /** 1256 * Returns the expression for the exchanges inbound message body converted 1257 * to the given type. 1258 * <p/> 1259 * Does <b>not</b> allow null bodies. 1260 */ 1261 public static <T> Expression mandatoryBodyExpression(final Class<T> type) { 1262 return mandatoryBodyExpression(type, false); 1263 } 1264 1265 /** 1266 * Returns the expression for the exchanges inbound message body converted 1267 * to the given type 1268 * 1269 * @param type the type 1270 * @param nullBodyAllowed whether null bodies is allowed and if so a null is returned, 1271 * otherwise an exception is thrown 1272 */ 1273 public static <T> Expression mandatoryBodyExpression(final Class<T> type, final boolean nullBodyAllowed) { 1274 return new ExpressionAdapter() { 1275 public Object evaluate(Exchange exchange) { 1276 if (nullBodyAllowed) { 1277 if (exchange.getIn().getBody() == null) { 1278 return null; 1279 } 1280 1281 // if its a bean invocation then if it has no arguments then it should be threaded as null body allowed 1282 if (exchange.getIn().getBody() instanceof BeanInvocation) { 1283 // BeanInvocation would be stored directly as the message body 1284 // do not force any type conversion attempts as it would just be unnecessary and cost a bit performance 1285 // so a regular instanceof check is sufficient 1286 BeanInvocation bi = (BeanInvocation) exchange.getIn().getBody(); 1287 if (bi.getArgs() == null || bi.getArgs().length == 0 || bi.getArgs()[0] == null) { 1288 return null; 1289 } 1290 } 1291 } 1292 1293 try { 1294 return exchange.getIn().getMandatoryBody(type); 1295 } catch (InvalidPayloadException e) { 1296 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1297 } 1298 } 1299 1300 @Override 1301 public String toString() { 1302 return "mandatoryBodyAs[" + type.getName() + "]"; 1303 } 1304 }; 1305 } 1306 1307 /** 1308 * Returns the expression for the exchanges inbound message body type 1309 */ 1310 public static Expression bodyTypeExpression() { 1311 return new ExpressionAdapter() { 1312 public Object evaluate(Exchange exchange) { 1313 return exchange.getIn().getBody().getClass(); 1314 } 1315 1316 @Override 1317 public String toString() { 1318 return "bodyType"; 1319 } 1320 }; 1321 } 1322 1323 /** 1324 * Returns the expression for the out messages body 1325 */ 1326 public static Expression outBodyExpression() { 1327 return new ExpressionAdapter() { 1328 public Object evaluate(Exchange exchange) { 1329 if (exchange.hasOut()) { 1330 return exchange.getOut().getBody(); 1331 } else { 1332 return null; 1333 } 1334 } 1335 1336 @Override 1337 public String toString() { 1338 return "outBody"; 1339 } 1340 }; 1341 } 1342 1343 /** 1344 * Returns the expression for the exchanges outbound message body converted 1345 * to the given type 1346 */ 1347 public static <T> Expression outBodyExpression(final Class<T> type) { 1348 return new ExpressionAdapter() { 1349 public Object evaluate(Exchange exchange) { 1350 if (exchange.hasOut()) { 1351 return exchange.getOut().getBody(type); 1352 } else { 1353 return null; 1354 } 1355 } 1356 1357 @Override 1358 public String toString() { 1359 return "outBodyAs[" + type.getName() + "]"; 1360 } 1361 }; 1362 } 1363 1364 /** 1365 * Returns the expression for the fault messages body 1366 */ 1367 public static Expression faultBodyExpression() { 1368 return new ExpressionAdapter() { 1369 public Object evaluate(Exchange exchange) { 1370 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 1371 return msg.isFault() ? msg.getBody() : null; 1372 } 1373 1374 @Override 1375 public String toString() { 1376 return "faultBody"; 1377 } 1378 }; 1379 } 1380 1381 /** 1382 * Returns the expression for the exchanges fault message body converted 1383 * to the given type 1384 */ 1385 public static <T> Expression faultBodyExpression(final Class<T> type) { 1386 return new ExpressionAdapter() { 1387 public Object evaluate(Exchange exchange) { 1388 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 1389 return msg.isFault() ? msg.getBody(type) : null; 1390 } 1391 1392 @Override 1393 public String toString() { 1394 return "faultBodyAs[" + type.getName() + "]"; 1395 } 1396 }; 1397 } 1398 1399 /** 1400 * Returns the expression for the exchange 1401 */ 1402 public static Expression exchangeExpression() { 1403 return new ExpressionAdapter() { 1404 public Object evaluate(Exchange exchange) { 1405 return exchange; 1406 } 1407 1408 @Override 1409 public String toString() { 1410 return "exchange"; 1411 } 1412 }; 1413 } 1414 1415 /** 1416 * Returns a functional expression for the exchange 1417 */ 1418 public static Expression exchangeExpression(final Function<Exchange, Object> function) { 1419 return new ExpressionAdapter() { 1420 public Object evaluate(Exchange exchange) { 1421 return function.apply(exchange); 1422 } 1423 1424 @Override 1425 public String toString() { 1426 return "exchangeExpression"; 1427 } 1428 }; 1429 } 1430 1431 /** 1432 * Returns the expression for the IN message 1433 */ 1434 public static Expression messageExpression() { 1435 return inMessageExpression(); 1436 } 1437 1438 /** 1439 * Returns a functional expression for the IN message 1440 */ 1441 public static Expression messageExpression(final Function<Message, Object> function) { 1442 return inMessageExpression(function); 1443 } 1444 1445 /** 1446 * Returns the expression for the IN message 1447 */ 1448 public static Expression inMessageExpression() { 1449 return new ExpressionAdapter() { 1450 public Object evaluate(Exchange exchange) { 1451 return exchange.getIn(); 1452 } 1453 1454 @Override 1455 public String toString() { 1456 return "inMessage"; 1457 } 1458 }; 1459 } 1460 1461 /** 1462 * Returns a functional expression for the IN message 1463 */ 1464 public static Expression inMessageExpression(final Function<Message, Object> function) { 1465 return new ExpressionAdapter() { 1466 public Object evaluate(Exchange exchange) { 1467 return function.apply(exchange.getIn()); 1468 } 1469 1470 @Override 1471 public String toString() { 1472 return "inMessageExpression"; 1473 } 1474 }; 1475 } 1476 1477 /** 1478 * Returns the expression for the OUT message 1479 */ 1480 public static Expression outMessageExpression() { 1481 return new ExpressionAdapter() { 1482 public Object evaluate(Exchange exchange) { 1483 return exchange.getOut(); 1484 } 1485 1486 @Override 1487 public String toString() { 1488 return "outMessage"; 1489 } 1490 }; 1491 } 1492 1493 /** 1494 * Returns a functional expression for the OUT message 1495 */ 1496 public static Expression outMessageExpression(final Function<Message, Object> function) { 1497 return new ExpressionAdapter() { 1498 public Object evaluate(Exchange exchange) { 1499 return function.apply(exchange.getOut()); 1500 } 1501 1502 @Override 1503 public String toString() { 1504 return "outMessageExpression"; 1505 } 1506 }; 1507 } 1508 1509 /** 1510 * Returns an expression which converts the given expression to the given type 1511 */ 1512 public static Expression convertToExpression(final Expression expression, final Class<?> type) { 1513 return new ExpressionAdapter() { 1514 public Object evaluate(Exchange exchange) { 1515 if (type != null) { 1516 return expression.evaluate(exchange, type); 1517 } else { 1518 return expression; 1519 } 1520 } 1521 1522 @Override 1523 public String toString() { 1524 return "" + expression; 1525 } 1526 }; 1527 } 1528 1529 /** 1530 * Returns an expression which converts the given expression to the given type the type 1531 * expression is evaluated to 1532 */ 1533 public static Expression convertToExpression(final Expression expression, final Expression type) { 1534 return new ExpressionAdapter() { 1535 public Object evaluate(Exchange exchange) { 1536 Object result = type.evaluate(exchange, Object.class); 1537 if (result != null) { 1538 return expression.evaluate(exchange, result.getClass()); 1539 } else { 1540 return expression; 1541 } 1542 } 1543 1544 @Override 1545 public String toString() { 1546 return "" + expression; 1547 } 1548 }; 1549 } 1550 1551 /** 1552 * Returns a tokenize expression which will tokenize the string with the 1553 * given token 1554 */ 1555 public static Expression tokenizeExpression(final Expression expression, 1556 final String token) { 1557 return new ExpressionAdapter() { 1558 public Object evaluate(Exchange exchange) { 1559 String text = simpleExpression(token).evaluate(exchange, String.class); 1560 Object value = expression.evaluate(exchange, Object.class); 1561 Scanner scanner = ObjectHelper.getScanner(exchange, value, text); 1562 return scanner; 1563 } 1564 1565 @Override 1566 public String toString() { 1567 return "tokenize(" + expression + ", " + token + ")"; 1568 } 1569 }; 1570 } 1571 1572 /** 1573 * Returns an expression that skips the first element 1574 */ 1575 public static Expression skipFirstExpression(final Expression expression) { 1576 return new ExpressionAdapter() { 1577 public Object evaluate(Exchange exchange) { 1578 Object value = expression.evaluate(exchange, Object.class); 1579 Iterator it = exchange.getContext().getTypeConverter().tryConvertTo(Iterator.class, exchange, value); 1580 if (it != null) { 1581 // skip first 1582 it.next(); 1583 return it; 1584 } else { 1585 return value; 1586 } 1587 } 1588 1589 @Override 1590 public String toString() { 1591 return "skipFirst(" + expression + ")"; 1592 } 1593 }; 1594 } 1595 1596 /** 1597 * Returns an {@link TokenPairExpressionIterator} expression 1598 */ 1599 public static Expression tokenizePairExpression(String startToken, String endToken, boolean includeTokens) { 1600 return new TokenPairExpressionIterator(startToken, endToken, includeTokens); 1601 } 1602 1603 /** 1604 * Returns an {@link TokenXMLExpressionIterator} expression 1605 */ 1606 public static Expression tokenizeXMLExpression(String tagName, String inheritNamespaceTagName) { 1607 StringHelper.notEmpty(tagName, "tagName"); 1608 return new TokenXMLExpressionIterator(tagName, inheritNamespaceTagName); 1609 } 1610 1611 public static Expression tokenizeXMLAwareExpression(String path, char mode) { 1612 StringHelper.notEmpty(path, "path"); 1613 return new XMLTokenExpressionIterator(path, mode); 1614 } 1615 1616 public static Expression tokenizeXMLAwareExpression(String path, char mode, int group) { 1617 StringHelper.notEmpty(path, "path"); 1618 return new XMLTokenExpressionIterator(path, mode, group); 1619 } 1620 1621 /** 1622 * Returns a tokenize expression which will tokenize the string with the 1623 * given regex 1624 */ 1625 public static Expression regexTokenizeExpression(final Expression expression, 1626 final String regexTokenizer) { 1627 return new ExpressionAdapter() { 1628 public Object evaluate(Exchange exchange) { 1629 Object value = expression.evaluate(exchange, Object.class); 1630 Scanner scanner = ObjectHelper.getScanner(exchange, value, regexTokenizer); 1631 return scanner; 1632 } 1633 1634 @Override 1635 public String toString() { 1636 return "regexTokenize(" + expression + ", " + regexTokenizer + ")"; 1637 } 1638 }; 1639 } 1640 1641 public static Expression groupXmlIteratorExpression(final Expression expression, final String group) { 1642 return new ExpressionAdapter() { 1643 public Object evaluate(Exchange exchange) { 1644 // evaluate expression as iterator 1645 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1646 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1647 // must use GroupTokenIterator in xml mode as we want to concat the xml parts into a single message 1648 // the group can be a simple expression so evaluate it as a number 1649 Integer parts = exchange.getContext().resolveLanguage("simple").createExpression(group).evaluate(exchange, Integer.class); 1650 if (parts == null) { 1651 throw new RuntimeExchangeException("Group evaluated as null, must be evaluated as a positive Integer value from expression: " + group, exchange); 1652 } else if (parts <= 0) { 1653 throw new RuntimeExchangeException("Group must be a positive number, was: " + parts, exchange); 1654 } 1655 return new GroupTokenIterator(exchange, it, null, parts, false); 1656 } 1657 1658 @Override 1659 public String toString() { 1660 return "group " + expression + " " + group + " times"; 1661 } 1662 }; 1663 } 1664 1665 public static Expression groupIteratorExpression(final Expression expression, final String token, final String group, final boolean skipFirst) { 1666 return new ExpressionAdapter() { 1667 public Object evaluate(Exchange exchange) { 1668 // evaluate expression as iterator 1669 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1670 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1671 // the group can be a simple expression so evaluate it as a number 1672 Integer parts = exchange.getContext().resolveLanguage("simple").createExpression(group).evaluate(exchange, Integer.class); 1673 if (parts == null) { 1674 throw new RuntimeExchangeException("Group evaluated as null, must be evaluated as a positive Integer value from expression: " + group, exchange); 1675 } else if (parts <= 0) { 1676 throw new RuntimeExchangeException("Group must be a positive number, was: " + parts, exchange); 1677 } 1678 if (token != null) { 1679 return new GroupTokenIterator(exchange, it, token, parts, skipFirst); 1680 } else { 1681 return new GroupIterator(exchange, it, parts, skipFirst); 1682 } 1683 } 1684 1685 @Override 1686 public String toString() { 1687 return "group " + expression + " " + group + " times"; 1688 } 1689 }; 1690 } 1691 1692 public static Expression skipIteratorExpression(final Expression expression, final int skip) { 1693 return new ExpressionAdapter() { 1694 public Object evaluate(Exchange exchange) { 1695 // evaluate expression as iterator 1696 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1697 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1698 return new SkipIterator(exchange, it, skip); 1699 } 1700 1701 @Override 1702 public String toString() { 1703 return "skip " + expression + " " + skip + " times"; 1704 } 1705 }; 1706 } 1707 1708 /** 1709 * Returns a sort expression which will sort the expression with the given comparator. 1710 * <p/> 1711 * The expression is evaluated as a {@link List} object to allow sorting. 1712 */ 1713 @SuppressWarnings({"unchecked", "rawtypes"}) 1714 public static Expression sortExpression(final Expression expression, final Comparator comparator) { 1715 return new ExpressionAdapter() { 1716 public Object evaluate(Exchange exchange) { 1717 List<?> list = expression.evaluate(exchange, List.class); 1718 list.sort(comparator); 1719 return list; 1720 } 1721 1722 @Override 1723 public String toString() { 1724 return "sort(" + expression + " by: " + comparator + ")"; 1725 } 1726 }; 1727 } 1728 1729 /** 1730 * Transforms the expression into a String then performs the regex 1731 * replaceAll to transform the String and return the result 1732 */ 1733 public static Expression regexReplaceAll(final Expression expression, 1734 final String regex, final String replacement) { 1735 final Pattern pattern = Pattern.compile(regex); 1736 return new ExpressionAdapter() { 1737 public Object evaluate(Exchange exchange) { 1738 String text = expression.evaluate(exchange, String.class); 1739 if (text == null) { 1740 return null; 1741 } 1742 return pattern.matcher(text).replaceAll(replacement); 1743 } 1744 1745 @Override 1746 public String toString() { 1747 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1748 } 1749 }; 1750 } 1751 1752 /** 1753 * Transforms the expression into a String then performs the regex 1754 * replaceAll to transform the String and return the result 1755 */ 1756 public static Expression regexReplaceAll(final Expression expression, 1757 final String regex, final Expression replacementExpression) { 1758 1759 final Pattern pattern = Pattern.compile(regex); 1760 return new ExpressionAdapter() { 1761 public Object evaluate(Exchange exchange) { 1762 String text = expression.evaluate(exchange, String.class); 1763 String replacement = replacementExpression.evaluate(exchange, String.class); 1764 if (text == null || replacement == null) { 1765 return null; 1766 } 1767 return pattern.matcher(text).replaceAll(replacement); 1768 } 1769 1770 @Override 1771 public String toString() { 1772 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1773 } 1774 }; 1775 } 1776 1777 /** 1778 * Appends the String evaluations of the two expressions together 1779 */ 1780 public static Expression append(final Expression left, final Expression right) { 1781 return new ExpressionAdapter() { 1782 public Object evaluate(Exchange exchange) { 1783 return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class); 1784 } 1785 1786 @Override 1787 public String toString() { 1788 return "append(" + left + ", " + right + ")"; 1789 } 1790 }; 1791 } 1792 1793 /** 1794 * Prepends the String evaluations of the two expressions together 1795 */ 1796 public static Expression prepend(final Expression left, final Expression right) { 1797 return new ExpressionAdapter() { 1798 public Object evaluate(Exchange exchange) { 1799 return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class); 1800 } 1801 1802 @Override 1803 public String toString() { 1804 return "prepend(" + left + ", " + right + ")"; 1805 } 1806 }; 1807 } 1808 1809 /** 1810 * Returns an expression which returns the string concatenation value of the various 1811 * expressions 1812 * 1813 * @param expressions the expression to be concatenated dynamically 1814 * @return an expression which when evaluated will return the concatenated values 1815 */ 1816 public static Expression concatExpression(final Collection<Expression> expressions) { 1817 return concatExpression(expressions, null); 1818 } 1819 1820 /** 1821 * Returns an expression which returns the string concatenation value of the various 1822 * expressions 1823 * 1824 * @param expressions the expression to be concatenated dynamically 1825 * @param desription the text description of the expression 1826 * @return an expression which when evaluated will return the concatenated values 1827 */ 1828 public static Expression concatExpression(final Collection<Expression> expressions, final String desription) { 1829 return new ExpressionAdapter() { 1830 public Object evaluate(Exchange exchange) { 1831 StringBuilder buffer = new StringBuilder(); 1832 for (Expression expression : expressions) { 1833 String text = expression.evaluate(exchange, String.class); 1834 if (text != null) { 1835 buffer.append(text); 1836 } 1837 } 1838 return buffer.toString(); 1839 } 1840 1841 @Override 1842 public String toString() { 1843 if (desription != null) { 1844 return desription; 1845 } else { 1846 return "concat" + expressions; 1847 } 1848 } 1849 }; 1850 } 1851 1852 /** 1853 * Returns an Expression for the inbound message id 1854 */ 1855 public static Expression messageIdExpression() { 1856 return new ExpressionAdapter() { 1857 public Object evaluate(Exchange exchange) { 1858 return exchange.getIn().getMessageId(); 1859 } 1860 1861 @Override 1862 public String toString() { 1863 return "messageId"; 1864 } 1865 }; 1866 } 1867 1868 /** 1869 * Returns an Expression for the exchange id 1870 */ 1871 public static Expression exchangeIdExpression() { 1872 return new ExpressionAdapter() { 1873 public Object evaluate(Exchange exchange) { 1874 return exchange.getExchangeId(); 1875 } 1876 1877 @Override 1878 public String toString() { 1879 return "exchangeId"; 1880 } 1881 }; 1882 } 1883 1884 /** 1885 * Returns an Expression for the route id 1886 */ 1887 public static Expression routeIdExpression() { 1888 return new ExpressionAdapter() { 1889 public Object evaluate(Exchange exchange) { 1890 String answer = null; 1891 UnitOfWork uow = exchange.getUnitOfWork(); 1892 RouteContext rc = uow != null ? uow.getRouteContext() : null; 1893 if (rc != null) { 1894 answer = rc.getRoute().getId(); 1895 } 1896 if (answer == null) { 1897 // fallback and get from route id on the exchange 1898 answer = exchange.getFromRouteId(); 1899 } 1900 return answer; 1901 } 1902 1903 @Override 1904 public String toString() { 1905 return "routeId"; 1906 } 1907 }; 1908 } 1909 1910 public static Expression dateExpression(final String command) { 1911 return dateExpression(command, null, null); 1912 } 1913 1914 public static Expression dateExpression(final String command, final String pattern) { 1915 return dateExpression(command, null, pattern); 1916 } 1917 1918 public static Expression dateExpression(final String commandWithOffsets, final String timezone, final String pattern) { 1919 return new ExpressionAdapter() { 1920 public Object evaluate(Exchange exchange) { 1921 // Capture optional time offsets 1922 String command = commandWithOffsets.split("[+-]", 2)[0].trim(); 1923 List<Long> offsets = new ArrayList<>(); 1924 Matcher offsetMatcher = OFFSET_PATTERN.matcher(commandWithOffsets); 1925 while (offsetMatcher.find()) { 1926 try { 1927 long value = exchange.getContext().getTypeConverter().mandatoryConvertTo(long.class, exchange, offsetMatcher.group(2).trim()); 1928 offsets.add(offsetMatcher.group(1).equals("+") ? value : -value); 1929 } catch (NoTypeConversionAvailableException e) { 1930 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1931 } 1932 } 1933 1934 Date date; 1935 if ("now".equals(command)) { 1936 date = new Date(); 1937 } else if (command.startsWith("header.") || command.startsWith("in.header.")) { 1938 String key = command.substring(command.lastIndexOf('.') + 1); 1939 date = exchange.getIn().getHeader(key, Date.class); 1940 if (date == null) { 1941 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1942 } 1943 } else if (command.startsWith("out.header.")) { 1944 String key = command.substring(command.lastIndexOf('.') + 1); 1945 date = exchange.getOut().getHeader(key, Date.class); 1946 if (date == null) { 1947 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1948 } 1949 } else if (command.startsWith("property.") || command.startsWith("exchangeProperty.")) { 1950 String key = command.substring(command.lastIndexOf('.') + 1); 1951 date = exchange.getProperty(key, Date.class); 1952 if (date == null) { 1953 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1954 } 1955 } else if ("file".equals(command)) { 1956 Long num = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 1957 if (num != null && num > 0) { 1958 date = new Date(num); 1959 } else { 1960 date = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class); 1961 if (date == null) { 1962 throw new IllegalArgumentException("Cannot find " + Exchange.FILE_LAST_MODIFIED + " header at command: " + command); 1963 } 1964 } 1965 } else { 1966 throw new IllegalArgumentException("Command not supported for dateExpression: " + command); 1967 } 1968 1969 // Apply offsets 1970 long dateAsLong = date.getTime(); 1971 for (long offset : offsets) { 1972 dateAsLong += offset; 1973 } 1974 date = new Date(dateAsLong); 1975 1976 if (pattern != null && !pattern.isEmpty()) { 1977 SimpleDateFormat df = new SimpleDateFormat(pattern); 1978 if (timezone != null && !timezone.isEmpty()) { 1979 df.setTimeZone(TimeZone.getTimeZone(timezone)); 1980 } 1981 return df.format(date); 1982 } else { 1983 return date; 1984 } 1985 } 1986 1987 @Override 1988 public String toString() { 1989 return "date(" + commandWithOffsets + ":" + pattern + ":" + timezone + ")"; 1990 } 1991 }; 1992 } 1993 1994 public static Expression simpleExpression(final String expression) { 1995 return new ExpressionAdapter() { 1996 public Object evaluate(Exchange exchange) { 1997 if (SimpleLanguage.hasSimpleFunction(expression)) { 1998 // resolve language using context to have a clear separation of packages 1999 // must call evaluate to return the nested language evaluate when evaluating 2000 // stacked expressions 2001 Language language = exchange.getContext().resolveLanguage("simple"); 2002 return language.createExpression(expression).evaluate(exchange, Object.class); 2003 } else { 2004 return expression; 2005 } 2006 } 2007 2008 @Override 2009 public String toString() { 2010 return "simple(" + expression + ")"; 2011 } 2012 }; 2013 } 2014 2015 public static Expression beanExpression(final String expression) { 2016 return new ExpressionAdapter() { 2017 public Object evaluate(Exchange exchange) { 2018 // bean is able to evaluate method name if it contains nested functions 2019 // so we should not eager evaluate expression as a string 2020 // resolve language using context to have a clear separation of packages 2021 // must call evaluate to return the nested language evaluate when evaluating 2022 // stacked expressions 2023 Language language = exchange.getContext().resolveLanguage("bean"); 2024 return language.createExpression(expression).evaluate(exchange, Object.class); 2025 } 2026 2027 @Override 2028 public String toString() { 2029 return "bean(" + expression + ")"; 2030 } 2031 }; 2032 } 2033 2034 public static Expression beanExpression(final Class<?> beanType, final String methodName) { 2035 return BeanLanguage.bean(beanType, methodName); 2036 } 2037 2038 public static Expression beanExpression(final Object bean, final String methodName) { 2039 return BeanLanguage.bean(bean, methodName); 2040 } 2041 2042 public static Expression beanExpression(final String beanRef, final String methodName) { 2043 String expression = methodName != null ? beanRef + "." + methodName : beanRef; 2044 return beanExpression(expression); 2045 } 2046 2047 /** 2048 * Returns an expression processing the exchange to the given endpoint uri 2049 * 2050 * @param uri endpoint uri to send the exchange to 2051 * @return an expression object which will return the OUT body 2052 * @deprecated not in use, and not available in XML DSL 2053 */ 2054 @Deprecated 2055 public static Expression toExpression(final String uri) { 2056 return new ExpressionAdapter() { 2057 public Object evaluate(Exchange exchange) { 2058 String text = simpleExpression(uri).evaluate(exchange, String.class); 2059 Endpoint endpoint = exchange.getContext().getEndpoint(text); 2060 if (endpoint == null) { 2061 throw new NoSuchEndpointException(text); 2062 } 2063 2064 Producer producer; 2065 try { 2066 producer = endpoint.createProducer(); 2067 producer.start(); 2068 producer.process(exchange); 2069 producer.stop(); 2070 } catch (Exception e) { 2071 throw ObjectHelper.wrapRuntimeCamelException(e); 2072 } 2073 2074 // return the OUT body, but check for exchange pattern 2075 if (ExchangeHelper.isOutCapable(exchange)) { 2076 return exchange.getOut().getBody(); 2077 } else { 2078 return exchange.getIn().getBody(); 2079 } 2080 } 2081 2082 @Override 2083 public String toString() { 2084 return "to(" + uri + ")"; 2085 } 2086 }; 2087 } 2088 2089 public static Expression fileNameExpression() { 2090 return new ExpressionAdapter() { 2091 public Object evaluate(Exchange exchange) { 2092 return exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2093 } 2094 2095 @Override 2096 public String toString() { 2097 return "file:name"; 2098 } 2099 }; 2100 } 2101 2102 public static Expression fileOnlyNameExpression() { 2103 return new ExpressionAdapter() { 2104 public Object evaluate(Exchange exchange) { 2105 String answer = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class); 2106 if (answer == null) { 2107 answer = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2108 answer = FileUtil.stripPath(answer); 2109 } 2110 return answer; 2111 } 2112 2113 @Override 2114 public String toString() { 2115 return "file:onlyname"; 2116 } 2117 }; 2118 } 2119 2120 public static Expression fileNameNoExtensionExpression() { 2121 return new ExpressionAdapter() { 2122 public Object evaluate(Exchange exchange) { 2123 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2124 return FileUtil.stripExt(name); 2125 } 2126 2127 @Override 2128 public String toString() { 2129 return "file:name.noext"; 2130 } 2131 }; 2132 } 2133 2134 public static Expression fileNameNoExtensionSingleExpression() { 2135 return new ExpressionAdapter() { 2136 public Object evaluate(Exchange exchange) { 2137 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2138 return FileUtil.stripExt(name, true); 2139 } 2140 2141 @Override 2142 public String toString() { 2143 return "file:name.noext.single"; 2144 } 2145 }; 2146 } 2147 2148 public static Expression fileOnlyNameNoExtensionExpression() { 2149 return new ExpressionAdapter() { 2150 public Object evaluate(Exchange exchange) { 2151 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 2152 return FileUtil.stripExt(name); 2153 } 2154 2155 @Override 2156 public String toString() { 2157 return "file:onlyname.noext"; 2158 } 2159 }; 2160 } 2161 2162 public static Expression fileOnlyNameNoExtensionSingleExpression() { 2163 return new ExpressionAdapter() { 2164 public Object evaluate(Exchange exchange) { 2165 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 2166 return FileUtil.stripExt(name, true); 2167 } 2168 2169 @Override 2170 public String toString() { 2171 return "file:onlyname.noext.single"; 2172 } 2173 }; 2174 } 2175 2176 public static Expression fileExtensionExpression() { 2177 return new ExpressionAdapter() { 2178 public Object evaluate(Exchange exchange) { 2179 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2180 return FileUtil.onlyExt(name); 2181 } 2182 2183 @Override 2184 public String toString() { 2185 return "file:ext"; 2186 } 2187 }; 2188 } 2189 2190 public static Expression fileExtensionSingleExpression() { 2191 return new ExpressionAdapter() { 2192 public Object evaluate(Exchange exchange) { 2193 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2194 return FileUtil.onlyExt(name, true); 2195 } 2196 2197 @Override 2198 public String toString() { 2199 return "file:ext.single"; 2200 } 2201 }; 2202 } 2203 2204 public static Expression fileParentExpression() { 2205 return new ExpressionAdapter() { 2206 public Object evaluate(Exchange exchange) { 2207 return exchange.getIn().getHeader("CamelFileParent", String.class); 2208 } 2209 2210 @Override 2211 public String toString() { 2212 return "file:parent"; 2213 } 2214 }; 2215 } 2216 2217 public static Expression filePathExpression() { 2218 return new ExpressionAdapter() { 2219 public Object evaluate(Exchange exchange) { 2220 return exchange.getIn().getHeader("CamelFilePath", String.class); 2221 } 2222 2223 @Override 2224 public String toString() { 2225 return "file:path"; 2226 } 2227 }; 2228 } 2229 2230 public static Expression fileAbsolutePathExpression() { 2231 return new ExpressionAdapter() { 2232 public Object evaluate(Exchange exchange) { 2233 return exchange.getIn().getHeader("CamelFileAbsolutePath", String.class); 2234 } 2235 2236 @Override 2237 public String toString() { 2238 return "file:absolute.path"; 2239 } 2240 }; 2241 } 2242 2243 public static Expression fileAbsoluteExpression() { 2244 return new ExpressionAdapter() { 2245 public Object evaluate(Exchange exchange) { 2246 return exchange.getIn().getHeader("CamelFileAbsolute", Boolean.class); 2247 } 2248 2249 @Override 2250 public String toString() { 2251 return "file:absolute"; 2252 } 2253 }; 2254 } 2255 2256 public static Expression fileSizeExpression() { 2257 return new ExpressionAdapter() { 2258 public Object evaluate(Exchange exchange) { 2259 return exchange.getIn().getHeader(Exchange.FILE_LENGTH, Long.class); 2260 } 2261 2262 @Override 2263 public String toString() { 2264 return "file:length"; 2265 } 2266 }; 2267 } 2268 2269 public static Expression fileLastModifiedExpression() { 2270 return new ExpressionAdapter() { 2271 public Object evaluate(Exchange exchange) { 2272 return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 2273 } 2274 2275 @Override 2276 public String toString() { 2277 return "file:modified"; 2278 } 2279 }; 2280 } 2281 2282 /** 2283 * Returns Simple expression or fallback to Constant expression if expression str is not Simple expression. 2284 */ 2285 public static Expression parseSimpleOrFallbackToConstantExpression(String str, CamelContext camelContext) { 2286 if (StringHelper.hasStartToken(str, "simple")) { 2287 return camelContext.resolveLanguage("simple").createExpression(str); 2288 } 2289 return constantExpression(str); 2290 } 2291 2292 public static Expression propertiesComponentExpression(final String key, final String locations, final String defaultValue) { 2293 return new ExpressionAdapter() { 2294 public Object evaluate(Exchange exchange) { 2295 String text = simpleExpression(key).evaluate(exchange, String.class); 2296 String text2 = simpleExpression(locations).evaluate(exchange, String.class); 2297 try { 2298 if (text2 != null) { 2299 // the properties component is optional as we got locations 2300 // getComponent will create a new component if none already exists 2301 Component component = exchange.getContext().getComponent("properties"); 2302 PropertiesComponent pc = exchange.getContext().getTypeConverter() 2303 .mandatoryConvertTo(PropertiesComponent.class, component); 2304 // enclose key with {{ }} to force parsing 2305 String[] paths = text2.split(","); 2306 return pc.parseUri(pc.getPrefixToken() + text + pc.getSuffixToken(), paths); 2307 } else { 2308 // the properties component is mandatory if no locations provided 2309 Component component = exchange.getContext().hasComponent("properties"); 2310 if (component == null) { 2311 throw new IllegalArgumentException("PropertiesComponent with name properties must be defined" 2312 + " in CamelContext to support property placeholders in expressions"); 2313 } 2314 PropertiesComponent pc = exchange.getContext().getTypeConverter() 2315 .mandatoryConvertTo(PropertiesComponent.class, component); 2316 // enclose key with {{ }} to force parsing 2317 return pc.parseUri(pc.getPrefixToken() + text + pc.getSuffixToken()); 2318 } 2319 } catch (Exception e) { 2320 // property with key not found, use default value if provided 2321 if (defaultValue != null) { 2322 return defaultValue; 2323 } 2324 throw ObjectHelper.wrapRuntimeCamelException(e); 2325 } 2326 } 2327 2328 @Override 2329 public String toString() { 2330 return "properties(" + key + ")"; 2331 } 2332 }; 2333 } 2334 2335 /** 2336 * Returns a random number between 0 and max (exclusive) 2337 */ 2338 public static Expression randomExpression(final int max) { 2339 return randomExpression(0, max); 2340 } 2341 2342 /** 2343 * Returns a random number between min and max (exclusive) 2344 */ 2345 public static Expression randomExpression(final int min, final int max) { 2346 return new ExpressionAdapter() { 2347 public Object evaluate(Exchange exchange) { 2348 Random random = new Random(); 2349 int randomNum = random.nextInt(max - min) + min; 2350 return randomNum; 2351 } 2352 2353 @Override 2354 public String toString() { 2355 return "random(" + min + "," + max + ")"; 2356 } 2357 }; 2358 } 2359 2360 /** 2361 * Returns a random number between min and max (exclusive) 2362 */ 2363 public static Expression randomExpression(final String min, final String max) { 2364 return new ExpressionAdapter() { 2365 public Object evaluate(Exchange exchange) { 2366 int num1 = simpleExpression(min).evaluate(exchange, Integer.class); 2367 int num2 = simpleExpression(max).evaluate(exchange, Integer.class); 2368 Random random = new Random(); 2369 int randomNum = random.nextInt(num2 - num1) + num1; 2370 return randomNum; 2371 } 2372 2373 @Override 2374 public String toString() { 2375 return "random(" + min + "," + max + ")"; 2376 } 2377 }; 2378 } 2379 2380 /** 2381 * Returns an iterator to skip (iterate) the given expression 2382 */ 2383 public static Expression skipExpression(final String expression, final int number) { 2384 return new ExpressionAdapter() { 2385 public Object evaluate(Exchange exchange) { 2386 // use simple language 2387 Expression exp = exchange.getContext().resolveLanguage("simple").createExpression(expression); 2388 return ExpressionBuilder.skipIteratorExpression(exp, number).evaluate(exchange, Object.class); 2389 } 2390 2391 @Override 2392 public String toString() { 2393 return "skip(" + expression + "," + number + ")"; 2394 } 2395 }; 2396 } 2397 2398 /** 2399 * Returns an iterator to collate (iterate) the given expression 2400 */ 2401 public static Expression collateExpression(final String expression, final int group) { 2402 return new ExpressionAdapter() { 2403 public Object evaluate(Exchange exchange) { 2404 // use simple language 2405 Expression exp = exchange.getContext().resolveLanguage("simple").createExpression(expression); 2406 return ExpressionBuilder.groupIteratorExpression(exp, null, "" + group, false).evaluate(exchange, Object.class); 2407 } 2408 2409 @Override 2410 public String toString() { 2411 return "collate(" + expression + "," + group + ")"; 2412 } 2413 }; 2414 } 2415 2416 /** 2417 * Returns the message history (including exchange details or not) 2418 */ 2419 public static Expression messageHistoryExpression(final boolean detailed) { 2420 return new ExpressionAdapter() { 2421 2422 private ExchangeFormatter formatter; 2423 2424 public Object evaluate(Exchange exchange) { 2425 ExchangeFormatter ef = null; 2426 if (detailed) { 2427 // use the exchange formatter to log exchange details 2428 ef = getOrCreateExchangeFormatter(exchange.getContext()); 2429 } 2430 return MessageHelper.dumpMessageHistoryStacktrace(exchange, ef, false); 2431 } 2432 2433 private ExchangeFormatter getOrCreateExchangeFormatter(CamelContext camelContext) { 2434 if (formatter == null) { 2435 Set<ExchangeFormatter> formatters = camelContext.getRegistry().findByType(ExchangeFormatter.class); 2436 if (formatters != null && formatters.size() == 1) { 2437 formatter = formatters.iterator().next(); 2438 } else { 2439 // setup exchange formatter to be used for message history dump 2440 DefaultExchangeFormatter def = new DefaultExchangeFormatter(); 2441 def.setShowExchangeId(true); 2442 def.setMultiline(true); 2443 def.setShowHeaders(true); 2444 def.setStyle(DefaultExchangeFormatter.OutputStyle.Fixed); 2445 try { 2446 Integer maxChars = CamelContextHelper.parseInteger(camelContext, camelContext.getGlobalOption(Exchange.LOG_DEBUG_BODY_MAX_CHARS)); 2447 if (maxChars != null) { 2448 def.setMaxChars(maxChars); 2449 } 2450 } catch (Exception e) { 2451 throw ObjectHelper.wrapRuntimeCamelException(e); 2452 } 2453 formatter = def; 2454 } 2455 } 2456 return formatter; 2457 } 2458 2459 @Override 2460 public String toString() { 2461 return "messageHistory(" + detailed + ")"; 2462 } 2463 }; 2464 } 2465 2466 /** 2467 * Expression adapter for OGNL expression from Message Header or Exchange property 2468 */ 2469 private static class KeyedOgnlExpressionAdapter extends ExpressionAdapter { 2470 private final String ognl; 2471 private final String toStringValue; 2472 private final KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy; 2473 2474 KeyedOgnlExpressionAdapter(String ognl, String toStringValue, 2475 KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy) { 2476 this.ognl = ognl; 2477 this.toStringValue = toStringValue; 2478 this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy; 2479 } 2480 2481 public Object evaluate(Exchange exchange) { 2482 // try with full name first 2483 Object property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl); 2484 if (property != null) { 2485 return property; 2486 } 2487 2488 2489 // Split ognl except when this is not a Map, Array 2490 // and we would like to keep the dots within the key name 2491 List<String> methods = OgnlHelper.splitOgnl(ognl); 2492 2493 String key = methods.get(0); 2494 String keySuffix = ""; 2495 // if ognl starts with a key inside brackets (eg: [foo.bar]) 2496 // remove starting and ending brackets from key 2497 if (key.startsWith("[") && key.endsWith("]")) { 2498 key = StringHelper.removeLeadingAndEndingQuotes(key.substring(1, key.length() - 1)); 2499 keySuffix = StringHelper.after(methods.get(0), key); 2500 } 2501 // remove any OGNL operators so we got the pure key name 2502 key = OgnlHelper.removeOperators(key); 2503 2504 2505 property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, key); 2506 if (property == null) { 2507 return null; 2508 } 2509 // the remainder is the rest of the ognl without the key 2510 String remainder = StringHelper.after(ognl, key + keySuffix); 2511 return new MethodCallExpression(property, remainder).evaluate(exchange); 2512 } 2513 2514 @Override 2515 public String toString() { 2516 return toStringValue; 2517 } 2518 2519 /** 2520 * Strategy to retrieve the value based on the key 2521 */ 2522 public interface KeyedEntityRetrievalStrategy { 2523 Object getKeyedEntity(Exchange exchange, String key); 2524 } 2525 } 2526 2527}