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.Scanner; 031import java.util.Set; 032import java.util.TimeZone; 033import java.util.concurrent.atomic.AtomicReference; 034import java.util.function.BiFunction; 035import java.util.function.Function; 036import java.util.regex.Matcher; 037import java.util.regex.Pattern; 038 039import org.apache.camel.CamelContext; 040import org.apache.camel.Component; 041import org.apache.camel.Endpoint; 042import org.apache.camel.Exchange; 043import org.apache.camel.Expression; 044import org.apache.camel.InvalidPayloadException; 045import org.apache.camel.Message; 046import org.apache.camel.NoSuchEndpointException; 047import org.apache.camel.NoSuchLanguageException; 048import org.apache.camel.NoTypeConversionAvailableException; 049import org.apache.camel.Producer; 050import org.apache.camel.RuntimeExchangeException; 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.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); 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<Object>(); 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); 1562 scanner.useDelimiter(text); 1563 return scanner; 1564 } 1565 1566 @Override 1567 public String toString() { 1568 return "tokenize(" + expression + ", " + token + ")"; 1569 } 1570 }; 1571 } 1572 1573 /** 1574 * Returns an expression that skips the first element 1575 */ 1576 public static Expression skipFirstExpression(final Expression expression) { 1577 return new ExpressionAdapter() { 1578 public Object evaluate(Exchange exchange) { 1579 Object value = expression.evaluate(exchange, Object.class); 1580 Iterator it = exchange.getContext().getTypeConverter().tryConvertTo(Iterator.class, exchange, value); 1581 if (it != null) { 1582 // skip first 1583 it.next(); 1584 return it; 1585 } else { 1586 return value; 1587 } 1588 } 1589 1590 @Override 1591 public String toString() { 1592 return "skipFirst(" + expression + ")"; 1593 } 1594 }; 1595 } 1596 1597 /** 1598 * Returns an {@link TokenPairExpressionIterator} expression 1599 */ 1600 public static Expression tokenizePairExpression(String startToken, String endToken, boolean includeTokens) { 1601 return new TokenPairExpressionIterator(startToken, endToken, includeTokens); 1602 } 1603 1604 /** 1605 * Returns an {@link TokenXMLExpressionIterator} expression 1606 */ 1607 public static Expression tokenizeXMLExpression(String tagName, String inheritNamespaceTagName) { 1608 ObjectHelper.notEmpty(tagName, "tagName"); 1609 return new TokenXMLExpressionIterator(tagName, inheritNamespaceTagName); 1610 } 1611 1612 public static Expression tokenizeXMLAwareExpression(String path, char mode) { 1613 ObjectHelper.notEmpty(path, "path"); 1614 return new XMLTokenExpressionIterator(path, mode); 1615 } 1616 1617 public static Expression tokenizeXMLAwareExpression(String path, char mode, int group) { 1618 ObjectHelper.notEmpty(path, "path"); 1619 return new XMLTokenExpressionIterator(path, mode, group); 1620 } 1621 1622 /** 1623 * Returns a tokenize expression which will tokenize the string with the 1624 * given regex 1625 */ 1626 public static Expression regexTokenizeExpression(final Expression expression, 1627 final String regexTokenizer) { 1628 final Pattern pattern = Pattern.compile(regexTokenizer); 1629 return new ExpressionAdapter() { 1630 public Object evaluate(Exchange exchange) { 1631 Object value = expression.evaluate(exchange, Object.class); 1632 Scanner scanner = ObjectHelper.getScanner(exchange, value); 1633 scanner.useDelimiter(pattern); 1634 return scanner; 1635 } 1636 1637 @Override 1638 public String toString() { 1639 return "regexTokenize(" + expression + ", " + pattern.pattern() + ")"; 1640 } 1641 }; 1642 } 1643 1644 public static Expression groupXmlIteratorExpression(final Expression expression, final String group) { 1645 return new ExpressionAdapter() { 1646 public Object evaluate(Exchange exchange) { 1647 // evaluate expression as iterator 1648 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1649 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1650 // must use GroupTokenIterator in xml mode as we want to concat the xml parts into a single message 1651 // the group can be a simple expression so evaluate it as a number 1652 Integer parts = exchange.getContext().resolveLanguage("simple").createExpression(group).evaluate(exchange, Integer.class); 1653 if (parts == null) { 1654 throw new RuntimeExchangeException("Group evaluated as null, must be evaluated as a positive Integer value from expression: " + group, exchange); 1655 } else if (parts <= 0) { 1656 throw new RuntimeExchangeException("Group must be a positive number, was: " + parts, exchange); 1657 } 1658 return new GroupTokenIterator(exchange, it, null, parts, false); 1659 } 1660 1661 @Override 1662 public String toString() { 1663 return "group " + expression + " " + group + " times"; 1664 } 1665 }; 1666 } 1667 1668 public static Expression groupIteratorExpression(final Expression expression, final String token, final String group, final boolean skipFirst) { 1669 return new ExpressionAdapter() { 1670 public Object evaluate(Exchange exchange) { 1671 // evaluate expression as iterator 1672 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1673 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1674 // the group can be a simple expression so evaluate it as a number 1675 Integer parts = exchange.getContext().resolveLanguage("simple").createExpression(group).evaluate(exchange, Integer.class); 1676 if (parts == null) { 1677 throw new RuntimeExchangeException("Group evaluated as null, must be evaluated as a positive Integer value from expression: " + group, exchange); 1678 } else if (parts <= 0) { 1679 throw new RuntimeExchangeException("Group must be a positive number, was: " + parts, exchange); 1680 } 1681 if (token != null) { 1682 return new GroupTokenIterator(exchange, it, token, parts, skipFirst); 1683 } else { 1684 return new GroupIterator(exchange, it, parts, skipFirst); 1685 } 1686 } 1687 1688 @Override 1689 public String toString() { 1690 return "group " + expression + " " + group + " times"; 1691 } 1692 }; 1693 } 1694 1695 public static Expression skipIteratorExpression(final Expression expression, final int skip) { 1696 return new ExpressionAdapter() { 1697 public Object evaluate(Exchange exchange) { 1698 // evaluate expression as iterator 1699 Iterator<?> it = expression.evaluate(exchange, Iterator.class); 1700 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator"); 1701 return new SkipIterator(exchange, it, skip); 1702 } 1703 1704 @Override 1705 public String toString() { 1706 return "skip " + expression + " " + skip + " times"; 1707 } 1708 }; 1709 } 1710 1711 /** 1712 * Returns a sort expression which will sort the expression with the given comparator. 1713 * <p/> 1714 * The expression is evaluated as a {@link List} object to allow sorting. 1715 */ 1716 @SuppressWarnings({"unchecked", "rawtypes"}) 1717 public static Expression sortExpression(final Expression expression, final Comparator comparator) { 1718 return new ExpressionAdapter() { 1719 public Object evaluate(Exchange exchange) { 1720 List<?> list = expression.evaluate(exchange, List.class); 1721 list.sort(comparator); 1722 return list; 1723 } 1724 1725 @Override 1726 public String toString() { 1727 return "sort(" + expression + " by: " + comparator + ")"; 1728 } 1729 }; 1730 } 1731 1732 /** 1733 * Transforms the expression into a String then performs the regex 1734 * replaceAll to transform the String and return the result 1735 */ 1736 public static Expression regexReplaceAll(final Expression expression, 1737 final String regex, final String replacement) { 1738 final Pattern pattern = Pattern.compile(regex); 1739 return new ExpressionAdapter() { 1740 public Object evaluate(Exchange exchange) { 1741 String text = expression.evaluate(exchange, String.class); 1742 if (text == null) { 1743 return null; 1744 } 1745 return pattern.matcher(text).replaceAll(replacement); 1746 } 1747 1748 @Override 1749 public String toString() { 1750 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1751 } 1752 }; 1753 } 1754 1755 /** 1756 * Transforms the expression into a String then performs the regex 1757 * replaceAll to transform the String and return the result 1758 */ 1759 public static Expression regexReplaceAll(final Expression expression, 1760 final String regex, final Expression replacementExpression) { 1761 1762 final Pattern pattern = Pattern.compile(regex); 1763 return new ExpressionAdapter() { 1764 public Object evaluate(Exchange exchange) { 1765 String text = expression.evaluate(exchange, String.class); 1766 String replacement = replacementExpression.evaluate(exchange, String.class); 1767 if (text == null || replacement == null) { 1768 return null; 1769 } 1770 return pattern.matcher(text).replaceAll(replacement); 1771 } 1772 1773 @Override 1774 public String toString() { 1775 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")"; 1776 } 1777 }; 1778 } 1779 1780 /** 1781 * Appends the String evaluations of the two expressions together 1782 */ 1783 public static Expression append(final Expression left, final Expression right) { 1784 return new ExpressionAdapter() { 1785 public Object evaluate(Exchange exchange) { 1786 return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class); 1787 } 1788 1789 @Override 1790 public String toString() { 1791 return "append(" + left + ", " + right + ")"; 1792 } 1793 }; 1794 } 1795 1796 /** 1797 * Prepends the String evaluations of the two expressions together 1798 */ 1799 public static Expression prepend(final Expression left, final Expression right) { 1800 return new ExpressionAdapter() { 1801 public Object evaluate(Exchange exchange) { 1802 return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class); 1803 } 1804 1805 @Override 1806 public String toString() { 1807 return "prepend(" + left + ", " + right + ")"; 1808 } 1809 }; 1810 } 1811 1812 /** 1813 * Returns an expression which returns the string concatenation value of the various 1814 * expressions 1815 * 1816 * @param expressions the expression to be concatenated dynamically 1817 * @return an expression which when evaluated will return the concatenated values 1818 */ 1819 public static Expression concatExpression(final Collection<Expression> expressions) { 1820 return concatExpression(expressions, null); 1821 } 1822 1823 /** 1824 * Returns an expression which returns the string concatenation value of the various 1825 * expressions 1826 * 1827 * @param expressions the expression to be concatenated dynamically 1828 * @param desription the text description of the expression 1829 * @return an expression which when evaluated will return the concatenated values 1830 */ 1831 public static Expression concatExpression(final Collection<Expression> expressions, final String desription) { 1832 return new ExpressionAdapter() { 1833 public Object evaluate(Exchange exchange) { 1834 StringBuilder buffer = new StringBuilder(); 1835 for (Expression expression : expressions) { 1836 String text = expression.evaluate(exchange, String.class); 1837 if (text != null) { 1838 buffer.append(text); 1839 } 1840 } 1841 return buffer.toString(); 1842 } 1843 1844 @Override 1845 public String toString() { 1846 if (desription != null) { 1847 return desription; 1848 } else { 1849 return "concat" + expressions; 1850 } 1851 } 1852 }; 1853 } 1854 1855 /** 1856 * Returns an Expression for the inbound message id 1857 */ 1858 public static Expression messageIdExpression() { 1859 return new ExpressionAdapter() { 1860 public Object evaluate(Exchange exchange) { 1861 return exchange.getIn().getMessageId(); 1862 } 1863 1864 @Override 1865 public String toString() { 1866 return "messageId"; 1867 } 1868 }; 1869 } 1870 1871 /** 1872 * Returns an Expression for the exchange id 1873 */ 1874 public static Expression exchangeIdExpression() { 1875 return new ExpressionAdapter() { 1876 public Object evaluate(Exchange exchange) { 1877 return exchange.getExchangeId(); 1878 } 1879 1880 @Override 1881 public String toString() { 1882 return "exchangeId"; 1883 } 1884 }; 1885 } 1886 1887 /** 1888 * Returns an Expression for the route id 1889 */ 1890 public static Expression routeIdExpression() { 1891 return new ExpressionAdapter() { 1892 public Object evaluate(Exchange exchange) { 1893 String answer = null; 1894 UnitOfWork uow = exchange.getUnitOfWork(); 1895 RouteContext rc = uow != null ? uow.getRouteContext() : null; 1896 if (rc != null) { 1897 answer = rc.getRoute().getId(); 1898 } 1899 if (answer == null) { 1900 // fallback and get from route id on the exchange 1901 answer = exchange.getFromRouteId(); 1902 } 1903 return answer; 1904 } 1905 1906 @Override 1907 public String toString() { 1908 return "routeId"; 1909 } 1910 }; 1911 } 1912 1913 public static Expression dateExpression(final String command) { 1914 return dateExpression(command, null, null); 1915 } 1916 1917 public static Expression dateExpression(final String command, final String pattern) { 1918 return dateExpression(command, null, pattern); 1919 } 1920 1921 public static Expression dateExpression(final String commandWithOffsets, final String timezone, final String pattern) { 1922 return new ExpressionAdapter() { 1923 public Object evaluate(Exchange exchange) { 1924 // Capture optional time offsets 1925 String command = commandWithOffsets.split("[+-]", 2)[0].trim(); 1926 List<Long> offsets = new ArrayList<>(); 1927 Matcher offsetMatcher = OFFSET_PATTERN.matcher(commandWithOffsets); 1928 while (offsetMatcher.find()) { 1929 try { 1930 long value = exchange.getContext().getTypeConverter().mandatoryConvertTo(long.class, exchange, offsetMatcher.group(2).trim()); 1931 offsets.add(offsetMatcher.group(1).equals("+") ? value : -value); 1932 } catch (NoTypeConversionAvailableException e) { 1933 throw ObjectHelper.wrapCamelExecutionException(exchange, e); 1934 } 1935 } 1936 1937 Date date; 1938 if ("now".equals(command)) { 1939 date = new Date(); 1940 } else if (command.startsWith("header.") || command.startsWith("in.header.")) { 1941 String key = command.substring(command.lastIndexOf('.') + 1); 1942 date = exchange.getIn().getHeader(key, Date.class); 1943 if (date == null) { 1944 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1945 } 1946 } else if (command.startsWith("out.header.")) { 1947 String key = command.substring(command.lastIndexOf('.') + 1); 1948 date = exchange.getOut().getHeader(key, Date.class); 1949 if (date == null) { 1950 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1951 } 1952 } else if (command.startsWith("property.")) { 1953 String key = command.substring(command.lastIndexOf('.') + 1); 1954 date = exchange.getProperty(key, Date.class); 1955 if (date == null) { 1956 throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command); 1957 } 1958 } else if ("file".equals(command)) { 1959 Long num = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 1960 if (num != null && num > 0) { 1961 date = new Date(num); 1962 } else { 1963 date = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class); 1964 if (date == null) { 1965 throw new IllegalArgumentException("Cannot find " + Exchange.FILE_LAST_MODIFIED + " header at command: " + command); 1966 } 1967 } 1968 } else { 1969 throw new IllegalArgumentException("Command not supported for dateExpression: " + command); 1970 } 1971 1972 // Apply offsets 1973 long dateAsLong = date.getTime(); 1974 for (long offset : offsets) { 1975 dateAsLong += offset; 1976 } 1977 date = new Date(dateAsLong); 1978 1979 if (pattern != null && !pattern.isEmpty()) { 1980 SimpleDateFormat df = new SimpleDateFormat(pattern); 1981 if (timezone != null && !timezone.isEmpty()) { 1982 df.setTimeZone(TimeZone.getTimeZone(timezone)); 1983 } 1984 return df.format(date); 1985 } else { 1986 return date; 1987 } 1988 } 1989 1990 @Override 1991 public String toString() { 1992 return "date(" + commandWithOffsets + ":" + pattern + ":" + timezone + ")"; 1993 } 1994 }; 1995 } 1996 1997 public static Expression simpleExpression(final String expression) { 1998 return new ExpressionAdapter() { 1999 public Object evaluate(Exchange exchange) { 2000 if (SimpleLanguage.hasSimpleFunction(expression)) { 2001 // resolve language using context to have a clear separation of packages 2002 // must call evaluate to return the nested language evaluate when evaluating 2003 // stacked expressions 2004 Language language = exchange.getContext().resolveLanguage("simple"); 2005 return language.createExpression(expression).evaluate(exchange, Object.class); 2006 } else { 2007 return expression; 2008 } 2009 } 2010 2011 @Override 2012 public String toString() { 2013 return "simple(" + expression + ")"; 2014 } 2015 }; 2016 } 2017 2018 public static Expression beanExpression(final String expression) { 2019 return new ExpressionAdapter() { 2020 public Object evaluate(Exchange exchange) { 2021 // bean is able to evaluate method name if it contains nested functions 2022 // so we should not eager evaluate expression as a string 2023 // resolve language using context to have a clear separation of packages 2024 // must call evaluate to return the nested language evaluate when evaluating 2025 // stacked expressions 2026 Language language = exchange.getContext().resolveLanguage("bean"); 2027 return language.createExpression(expression).evaluate(exchange, Object.class); 2028 } 2029 2030 @Override 2031 public String toString() { 2032 return "bean(" + expression + ")"; 2033 } 2034 }; 2035 } 2036 2037 public static Expression beanExpression(final Class<?> beanType, final String methodName) { 2038 return BeanLanguage.bean(beanType, methodName); 2039 } 2040 2041 public static Expression beanExpression(final Object bean, final String methodName) { 2042 return BeanLanguage.bean(bean, methodName); 2043 } 2044 2045 public static Expression beanExpression(final String beanRef, final String methodName) { 2046 String expression = methodName != null ? beanRef + "." + methodName : beanRef; 2047 return beanExpression(expression); 2048 } 2049 2050 /** 2051 * Returns an expression processing the exchange to the given endpoint uri 2052 * 2053 * @param uri endpoint uri to send the exchange to 2054 * @return an expression object which will return the OUT body 2055 */ 2056 public static Expression toExpression(final String uri) { 2057 return new ExpressionAdapter() { 2058 public Object evaluate(Exchange exchange) { 2059 String text = simpleExpression(uri).evaluate(exchange, String.class); 2060 Endpoint endpoint = exchange.getContext().getEndpoint(text); 2061 if (endpoint == null) { 2062 throw new NoSuchEndpointException(text); 2063 } 2064 2065 Producer producer; 2066 try { 2067 producer = endpoint.createProducer(); 2068 producer.start(); 2069 producer.process(exchange); 2070 producer.stop(); 2071 } catch (Exception e) { 2072 throw ObjectHelper.wrapRuntimeCamelException(e); 2073 } 2074 2075 // return the OUT body, but check for exchange pattern 2076 if (ExchangeHelper.isOutCapable(exchange)) { 2077 return exchange.getOut().getBody(); 2078 } else { 2079 return exchange.getIn().getBody(); 2080 } 2081 } 2082 2083 @Override 2084 public String toString() { 2085 return "to(" + uri + ")"; 2086 } 2087 }; 2088 } 2089 2090 public static Expression fileNameExpression() { 2091 return new ExpressionAdapter() { 2092 public Object evaluate(Exchange exchange) { 2093 return exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2094 } 2095 2096 @Override 2097 public String toString() { 2098 return "file:name"; 2099 } 2100 }; 2101 } 2102 2103 public static Expression fileOnlyNameExpression() { 2104 return new ExpressionAdapter() { 2105 public Object evaluate(Exchange exchange) { 2106 String answer = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class); 2107 if (answer == null) { 2108 answer = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2109 answer = FileUtil.stripPath(answer); 2110 } 2111 return answer; 2112 } 2113 2114 @Override 2115 public String toString() { 2116 return "file:onlyname"; 2117 } 2118 }; 2119 } 2120 2121 public static Expression fileNameNoExtensionExpression() { 2122 return new ExpressionAdapter() { 2123 public Object evaluate(Exchange exchange) { 2124 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2125 return FileUtil.stripExt(name); 2126 } 2127 2128 @Override 2129 public String toString() { 2130 return "file:name.noext"; 2131 } 2132 }; 2133 } 2134 2135 public static Expression fileNameNoExtensionSingleExpression() { 2136 return new ExpressionAdapter() { 2137 public Object evaluate(Exchange exchange) { 2138 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2139 return FileUtil.stripExt(name, true); 2140 } 2141 2142 @Override 2143 public String toString() { 2144 return "file:name.noext.single"; 2145 } 2146 }; 2147 } 2148 2149 public static Expression fileOnlyNameNoExtensionExpression() { 2150 return new ExpressionAdapter() { 2151 public Object evaluate(Exchange exchange) { 2152 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 2153 return FileUtil.stripExt(name); 2154 } 2155 2156 @Override 2157 public String toString() { 2158 return "file:onlyname.noext"; 2159 } 2160 }; 2161 } 2162 2163 public static Expression fileOnlyNameNoExtensionSingleExpression() { 2164 return new ExpressionAdapter() { 2165 public Object evaluate(Exchange exchange) { 2166 String name = fileOnlyNameExpression().evaluate(exchange, String.class); 2167 return FileUtil.stripExt(name, true); 2168 } 2169 2170 @Override 2171 public String toString() { 2172 return "file:onlyname.noext.single"; 2173 } 2174 }; 2175 } 2176 2177 public static Expression fileExtensionExpression() { 2178 return new ExpressionAdapter() { 2179 public Object evaluate(Exchange exchange) { 2180 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2181 return FileUtil.onlyExt(name); 2182 } 2183 2184 @Override 2185 public String toString() { 2186 return "file:ext"; 2187 } 2188 }; 2189 } 2190 2191 public static Expression fileExtensionSingleExpression() { 2192 return new ExpressionAdapter() { 2193 public Object evaluate(Exchange exchange) { 2194 String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); 2195 return FileUtil.onlyExt(name, true); 2196 } 2197 2198 @Override 2199 public String toString() { 2200 return "file:ext.single"; 2201 } 2202 }; 2203 } 2204 2205 public static Expression fileParentExpression() { 2206 return new ExpressionAdapter() { 2207 public Object evaluate(Exchange exchange) { 2208 return exchange.getIn().getHeader("CamelFileParent", String.class); 2209 } 2210 2211 @Override 2212 public String toString() { 2213 return "file:parent"; 2214 } 2215 }; 2216 } 2217 2218 public static Expression filePathExpression() { 2219 return new ExpressionAdapter() { 2220 public Object evaluate(Exchange exchange) { 2221 return exchange.getIn().getHeader("CamelFilePath", String.class); 2222 } 2223 2224 @Override 2225 public String toString() { 2226 return "file:path"; 2227 } 2228 }; 2229 } 2230 2231 public static Expression fileAbsolutePathExpression() { 2232 return new ExpressionAdapter() { 2233 public Object evaluate(Exchange exchange) { 2234 return exchange.getIn().getHeader("CamelFileAbsolutePath", String.class); 2235 } 2236 2237 @Override 2238 public String toString() { 2239 return "file:absolute.path"; 2240 } 2241 }; 2242 } 2243 2244 public static Expression fileAbsoluteExpression() { 2245 return new ExpressionAdapter() { 2246 public Object evaluate(Exchange exchange) { 2247 return exchange.getIn().getHeader("CamelFileAbsolute", Boolean.class); 2248 } 2249 2250 @Override 2251 public String toString() { 2252 return "file:absolute"; 2253 } 2254 }; 2255 } 2256 2257 public static Expression fileSizeExpression() { 2258 return new ExpressionAdapter() { 2259 public Object evaluate(Exchange exchange) { 2260 return exchange.getIn().getHeader(Exchange.FILE_LENGTH, Long.class); 2261 } 2262 2263 @Override 2264 public String toString() { 2265 return "file:length"; 2266 } 2267 }; 2268 } 2269 2270 public static Expression fileLastModifiedExpression() { 2271 return new ExpressionAdapter() { 2272 public Object evaluate(Exchange exchange) { 2273 return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class); 2274 } 2275 2276 @Override 2277 public String toString() { 2278 return "file:modified"; 2279 } 2280 }; 2281 } 2282 2283 /** 2284 * Returns Simple expression or fallback to Constant expression if expression str is not Simple expression. 2285 */ 2286 public static Expression parseSimpleOrFallbackToConstantExpression(String str, CamelContext camelContext) { 2287 if (StringHelper.hasStartToken(str, "simple")) { 2288 return camelContext.resolveLanguage("simple").createExpression(str); 2289 } 2290 return constantExpression(str); 2291 } 2292 2293 public static Expression propertiesComponentExpression(final String key, final String locations, final String defaultValue) { 2294 return new ExpressionAdapter() { 2295 public Object evaluate(Exchange exchange) { 2296 String text = simpleExpression(key).evaluate(exchange, String.class); 2297 String text2 = simpleExpression(locations).evaluate(exchange, String.class); 2298 try { 2299 if (text2 != null) { 2300 // the properties component is optional as we got locations 2301 // getComponent will create a new component if none already exists 2302 Component component = exchange.getContext().getComponent("properties"); 2303 PropertiesComponent pc = exchange.getContext().getTypeConverter() 2304 .mandatoryConvertTo(PropertiesComponent.class, component); 2305 // enclose key with {{ }} to force parsing 2306 String[] paths = text2.split(","); 2307 return pc.parseUri(pc.getPrefixToken() + text + pc.getSuffixToken(), paths); 2308 } else { 2309 // the properties component is mandatory if no locations provided 2310 Component component = exchange.getContext().hasComponent("properties"); 2311 if (component == null) { 2312 throw new IllegalArgumentException("PropertiesComponent with name properties must be defined" 2313 + " in CamelContext to support property placeholders in expressions"); 2314 } 2315 PropertiesComponent pc = exchange.getContext().getTypeConverter() 2316 .mandatoryConvertTo(PropertiesComponent.class, component); 2317 // enclose key with {{ }} to force parsing 2318 return pc.parseUri(pc.getPrefixToken() + text + pc.getSuffixToken()); 2319 } 2320 } catch (Exception e) { 2321 // property with key not found, use default value if provided 2322 if (defaultValue != null) { 2323 return defaultValue; 2324 } 2325 throw ObjectHelper.wrapRuntimeCamelException(e); 2326 } 2327 } 2328 2329 @Override 2330 public String toString() { 2331 return "properties(" + key + ")"; 2332 } 2333 }; 2334 } 2335 2336 /** 2337 * Returns a random number between 0 and max (exclusive) 2338 */ 2339 public static Expression randomExpression(final int max) { 2340 return randomExpression(0, max); 2341 } 2342 2343 /** 2344 * Returns a random number between min and max (exclusive) 2345 */ 2346 public static Expression randomExpression(final int min, final int max) { 2347 return new ExpressionAdapter() { 2348 public Object evaluate(Exchange exchange) { 2349 Random random = new Random(); 2350 int randomNum = random.nextInt(max - min) + min; 2351 return randomNum; 2352 } 2353 2354 @Override 2355 public String toString() { 2356 return "random(" + min + "," + max + ")"; 2357 } 2358 }; 2359 } 2360 2361 /** 2362 * Returns a random number between min and max (exclusive) 2363 */ 2364 public static Expression randomExpression(final String min, final String max) { 2365 return new ExpressionAdapter() { 2366 public Object evaluate(Exchange exchange) { 2367 int num1 = simpleExpression(min).evaluate(exchange, Integer.class); 2368 int num2 = simpleExpression(max).evaluate(exchange, Integer.class); 2369 Random random = new Random(); 2370 int randomNum = random.nextInt(num2 - num1) + num1; 2371 return randomNum; 2372 } 2373 2374 @Override 2375 public String toString() { 2376 return "random(" + min + "," + max + ")"; 2377 } 2378 }; 2379 } 2380 2381 /** 2382 * Returns an iterator to skip (iterate) the given expression 2383 */ 2384 public static Expression skipExpression(final String expression, final int number) { 2385 return new ExpressionAdapter() { 2386 public Object evaluate(Exchange exchange) { 2387 // use simple language 2388 Expression exp = exchange.getContext().resolveLanguage("simple").createExpression(expression); 2389 return ExpressionBuilder.skipIteratorExpression(exp, number).evaluate(exchange, Object.class); 2390 } 2391 2392 @Override 2393 public String toString() { 2394 return "skip(" + expression + "," + number + ")"; 2395 } 2396 }; 2397 } 2398 2399 /** 2400 * Returns an iterator to collate (iterate) the given expression 2401 */ 2402 public static Expression collateExpression(final String expression, final int group) { 2403 return new ExpressionAdapter() { 2404 public Object evaluate(Exchange exchange) { 2405 // use simple language 2406 Expression exp = exchange.getContext().resolveLanguage("simple").createExpression(expression); 2407 return ExpressionBuilder.groupIteratorExpression(exp, null, "" + group, false).evaluate(exchange, Object.class); 2408 } 2409 2410 @Override 2411 public String toString() { 2412 return "collate(" + expression + "," + group + ")"; 2413 } 2414 }; 2415 } 2416 2417 /** 2418 * Returns the message history (including exchange details or not) 2419 */ 2420 public static Expression messageHistoryExpression(final boolean detailed) { 2421 return new ExpressionAdapter() { 2422 2423 private ExchangeFormatter formatter; 2424 2425 public Object evaluate(Exchange exchange) { 2426 ExchangeFormatter ef = null; 2427 if (detailed) { 2428 // use the exchange formatter to log exchange details 2429 ef = getOrCreateExchangeFormatter(exchange.getContext()); 2430 } 2431 return MessageHelper.dumpMessageHistoryStacktrace(exchange, ef, false); 2432 } 2433 2434 private ExchangeFormatter getOrCreateExchangeFormatter(CamelContext camelContext) { 2435 if (formatter == null) { 2436 Set<ExchangeFormatter> formatters = camelContext.getRegistry().findByType(ExchangeFormatter.class); 2437 if (formatters != null && formatters.size() == 1) { 2438 formatter = formatters.iterator().next(); 2439 } else { 2440 // setup exchange formatter to be used for message history dump 2441 DefaultExchangeFormatter def = new DefaultExchangeFormatter(); 2442 def.setShowExchangeId(true); 2443 def.setMultiline(true); 2444 def.setShowHeaders(true); 2445 def.setStyle(DefaultExchangeFormatter.OutputStyle.Fixed); 2446 try { 2447 Integer maxChars = CamelContextHelper.parseInteger(camelContext, camelContext.getGlobalOption(Exchange.LOG_DEBUG_BODY_MAX_CHARS)); 2448 if (maxChars != null) { 2449 def.setMaxChars(maxChars); 2450 } 2451 } catch (Exception e) { 2452 throw ObjectHelper.wrapRuntimeCamelException(e); 2453 } 2454 formatter = def; 2455 } 2456 } 2457 return formatter; 2458 } 2459 2460 @Override 2461 public String toString() { 2462 return "messageHistory(" + detailed + ")"; 2463 } 2464 }; 2465 } 2466 2467 /** 2468 * Expression adapter for OGNL expression from Message Header or Exchange property 2469 */ 2470 private static class KeyedOgnlExpressionAdapter extends ExpressionAdapter { 2471 private final String ognl; 2472 private final String toStringValue; 2473 private final KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy; 2474 2475 KeyedOgnlExpressionAdapter(String ognl, String toStringValue, 2476 KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy) { 2477 this.ognl = ognl; 2478 this.toStringValue = toStringValue; 2479 this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy; 2480 } 2481 2482 public Object evaluate(Exchange exchange) { 2483 // try with full name first 2484 Object property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl); 2485 if (property != null) { 2486 return property; 2487 } 2488 2489 2490 // Split ognl except when this is not a Map, Array 2491 // and we would like to keep the dots within the key name 2492 List<String> methods = OgnlHelper.splitOgnl(ognl); 2493 2494 String key = methods.get(0); 2495 String keySuffix = ""; 2496 // if ognl starts with a key inside brackets (eg: [foo.bar]) 2497 // remove starting and ending brackets from key 2498 if (key.startsWith("[") && key.endsWith("]")) { 2499 key = StringHelper.removeLeadingAndEndingQuotes(key.substring(1, key.length() - 1)); 2500 keySuffix = StringHelper.after(methods.get(0), key); 2501 } 2502 // remove any OGNL operators so we got the pure key name 2503 key = OgnlHelper.removeOperators(key); 2504 2505 2506 property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, key); 2507 if (property == null) { 2508 return null; 2509 } 2510 // the remainder is the rest of the ognl without the key 2511 String remainder = ObjectHelper.after(ognl, key + keySuffix); 2512 return new MethodCallExpression(property, remainder).evaluate(exchange); 2513 } 2514 2515 @Override 2516 public String toString() { 2517 return toStringValue; 2518 } 2519 2520 /** 2521 * Strategy to retrieve the value based on the key 2522 */ 2523 public interface KeyedEntityRetrievalStrategy { 2524 Object getKeyedEntity(Exchange exchange, String key); 2525 } 2526 } 2527 2528}