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