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.text.SimpleDateFormat;
020 import java.util.Collection;
021 import java.util.Collections;
022 import java.util.Comparator;
023 import java.util.Date;
024 import java.util.Iterator;
025 import java.util.List;
026 import java.util.Scanner;
027 import java.util.regex.Pattern;
028
029 import org.apache.camel.Endpoint;
030 import org.apache.camel.Exchange;
031 import org.apache.camel.Expression;
032 import org.apache.camel.Message;
033 import org.apache.camel.NoSuchEndpointException;
034 import org.apache.camel.Producer;
035 import org.apache.camel.impl.ExpressionAdapter;
036 import org.apache.camel.language.bean.BeanLanguage;
037 import org.apache.camel.spi.Language;
038 import org.apache.camel.util.ExchangeHelper;
039 import org.apache.camel.util.ObjectHelper;
040
041 /**
042 * A helper class for working with <a href="http://camel.apache.org/expression.html">expressions</a>.
043 *
044 * @version $Revision: 780937 $
045 */
046 public final class ExpressionBuilder {
047
048 /**
049 * Utility classes should not have a public constructor.
050 */
051 private ExpressionBuilder() {
052 }
053
054 /**
055 * Returns an expression for the header value with the given name
056 *
057 * @param headerName the name of the header the expression will return
058 * @return an expression object which will return the header value
059 */
060 public static Expression headerExpression(final String headerName) {
061 return new ExpressionAdapter() {
062 public Object evaluate(Exchange exchange) {
063 Object header = exchange.getIn().getHeader(headerName);
064 if (header == null) {
065 // fall back on a property
066 header = exchange.getProperty(headerName);
067 }
068 return header;
069 }
070
071 @Override
072 public String toString() {
073 return "header(" + headerName + ")";
074 }
075 };
076 }
077
078 /**
079 * Returns an expression for the inbound message headers
080 *
081 * @return an expression object which will return the inbound headers
082 */
083 public static Expression headersExpression() {
084 return new ExpressionAdapter() {
085 public Object evaluate(Exchange exchange) {
086 return exchange.getIn().getHeaders();
087 }
088
089 @Override
090 public String toString() {
091 return "headers";
092 }
093 };
094 }
095
096 /**
097 * Returns an expression for the out header value with the given name
098 *
099 * @param headerName the name of the header the expression will return
100 * @return an expression object which will return the header value
101 */
102 public static Expression outHeaderExpression(final String headerName) {
103 return new ExpressionAdapter() {
104 public Object evaluate(Exchange exchange) {
105 if (!exchange.hasOut()) {
106 return null;
107 }
108
109 Message out = exchange.getOut();
110 Object header = out.getHeader(headerName);
111 if (header == null) {
112 // lets try the exchange header
113 header = exchange.getProperty(headerName);
114 }
115 return header;
116 }
117
118 @Override
119 public String toString() {
120 return "outHeader(" + headerName + ")";
121 }
122 };
123 }
124
125 /**
126 * Returns an expression for the outbound message headers
127 *
128 * @return an expression object which will return the headers
129 */
130 public static Expression outHeadersExpression() {
131 return new ExpressionAdapter() {
132 public Object evaluate(Exchange exchange) {
133 return exchange.getOut().getHeaders();
134 }
135
136 @Override
137 public String toString() {
138 return "outHeaders";
139 }
140 };
141 }
142
143 /**
144 * Returns an expression for an exception set on the exchange
145 *
146 * @see Exchange#getException()
147 * @return an expression object which will return the exception set on the exchange
148 */
149 public static Expression exchangeExceptionExpression() {
150 return new ExpressionAdapter() {
151 public Object evaluate(Exchange exchange) {
152 Exception exception = exchange.getException();
153 if (exception == null) {
154 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
155 }
156 return exception;
157 }
158
159 @Override
160 public String toString() {
161 return "exchangeException";
162 }
163 };
164 }
165
166 /**
167 * Returns an expression for an exception set on the exchange
168 * <p/>
169 * Is used to get the caused exception that typically have been wrapped in some sort
170 * of Camel wrapper exception
171 * @param type the exception type
172 * @see Exchange#getException(Class)
173 * @return an expression object which will return the exception set on the exchange
174 */
175 public static Expression exchangeExceptionExpression(final Class<Exception> type) {
176 return new ExpressionAdapter() {
177 public Object evaluate(Exchange exchange) {
178 Exception exception = exchange.getException(type);
179 if (exception == null) {
180 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
181 // must use exception iterator to walk it and find the type we are looking for
182 Iterator<Throwable> it = ObjectHelper.createExceptionIterator(exception);
183 while (it.hasNext()) {
184 Throwable e = it.next();
185 if (type.isInstance(e)) {
186 return type.cast(e);
187 }
188 }
189 // not found
190 return null;
191
192 }
193 return exception;
194 }
195
196 @Override
197 public String toString() {
198 return "exchangeException[" + type + "]";
199 }
200 };
201 }
202
203 /**
204 * Returns an expression for the type converter
205 *
206 * @return an expression object which will return the type converter
207 */
208 public static Expression typeConverterExpression() {
209 return new ExpressionAdapter() {
210 public Object evaluate(Exchange exchange) {
211 return exchange.getContext().getTypeConverter();
212 }
213
214 @Override
215 public String toString() {
216 return "typeConverter";
217 }
218 };
219 }
220
221 /**
222 * Returns an expression for an exception message set on the exchange
223 *
224 * @see <tt>Exchange.getException().getMessage()</tt>
225 * @return an expression object which will return the exception message set on the exchange
226 */
227 public static Expression exchangeExceptionMessageExpression() {
228 return new ExpressionAdapter() {
229 public Object evaluate(Exchange exchange) {
230 Exception exception = exchange.getException();
231 if (exception == null) {
232 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
233 }
234 return exception != null ? exception.getMessage() : null;
235 }
236
237 @Override
238 public String toString() {
239 return "exchangeExceptionMessage";
240 }
241 };
242 }
243
244 /**
245 * Returns an expression for the property value of exchange with the given name
246 *
247 * @param propertyName the name of the property the expression will return
248 * @return an expression object which will return the property value
249 */
250 public static Expression propertyExpression(final String propertyName) {
251 return new ExpressionAdapter() {
252 public Object evaluate(Exchange exchange) {
253 return exchange.getProperty(propertyName);
254 }
255
256 @Override
257 public String toString() {
258 return "property(" + propertyName + ")";
259 }
260 };
261 }
262
263 /**
264 * Returns an expression for the properties of exchange
265 *
266 * @return an expression object which will return the properties
267 */
268 public static Expression propertiesExpression() {
269 return new ExpressionAdapter() {
270 public Object evaluate(Exchange exchange) {
271 return exchange.getProperties();
272 }
273
274 @Override
275 public String toString() {
276 return "properties";
277 }
278 };
279 }
280
281 /**
282 * Returns an expression for the properties of the camel context
283 *
284 * @return an expression object which will return the properties
285 */
286 public static Expression camelContextPropertiesExpression() {
287 return new ExpressionAdapter() {
288 public Object evaluate(Exchange exchange) {
289 return exchange.getContext().getProperties();
290 }
291
292 @Override
293 public String toString() {
294 return "camelContextProperties";
295 }
296 };
297 }
298
299 /**
300 * Returns an expression for the property value of the camel context with the given name
301 *
302 * @param propertyName the name of the property the expression will return
303 * @return an expression object which will return the property value
304 */
305 public static Expression camelContextPropertyExpression(final String propertyName) {
306 return new ExpressionAdapter() {
307 public Object evaluate(Exchange exchange) {
308 return exchange.getContext().getProperties().get(propertyName);
309 }
310
311 @Override
312 public String toString() {
313 return "camelContextProperty(" + propertyName + ")";
314 }
315 };
316 }
317
318 /**
319 * Returns an expression for a system property value with the given name
320 *
321 * @param propertyName the name of the system property the expression will return
322 * @return an expression object which will return the system property value
323 */
324 public static Expression systemPropertyExpression(final String propertyName) {
325 return systemPropertyExpression(propertyName, null);
326 }
327
328 /**
329 * Returns an expression for a system property value with the given name
330 *
331 * @param propertyName the name of the system property the expression will return
332 * @param defaultValue default value to return if no system property exists
333 * @return an expression object which will return the system property value
334 */
335 public static Expression systemPropertyExpression(final String propertyName,
336 final String defaultValue) {
337 return new ExpressionAdapter() {
338 public Object evaluate(Exchange exchange) {
339 return System.getProperty(propertyName, defaultValue);
340 }
341
342 @Override
343 public String toString() {
344 return "systemProperty(" + propertyName + ")";
345 }
346 };
347 }
348
349 /**
350 * Returns an expression for the constant value
351 *
352 * @param value the value the expression will return
353 * @return an expression object which will return the constant value
354 */
355 public static Expression constantExpression(final Object value) {
356 return new ExpressionAdapter() {
357 public Object evaluate(Exchange exchange) {
358 return value;
359 }
360
361 @Override
362 public String toString() {
363 return "" + value;
364 }
365 };
366 }
367
368 /**
369 * Returns the expression for the exchanges inbound message body
370 */
371 public static Expression bodyExpression() {
372 return new ExpressionAdapter() {
373 public Object evaluate(Exchange exchange) {
374 return exchange.getIn().getBody();
375 }
376
377 @Override
378 public String toString() {
379 return "body";
380 }
381 };
382 }
383
384 /**
385 * Returns the expression for the exchanges inbound message body converted
386 * to the given type
387 */
388 public static <T> Expression bodyExpression(final Class<T> type) {
389 return new ExpressionAdapter() {
390 public Object evaluate(Exchange exchange) {
391 return exchange.getIn().getBody(type);
392 }
393
394 @Override
395 public String toString() {
396 return "bodyAs[" + type.getName() + "]";
397 }
398 };
399 }
400
401 /**
402 * Returns the expression for the exchanges inbound message body type
403 */
404 public static Expression bodyTypeExpression() {
405 return new ExpressionAdapter() {
406 public Object evaluate(Exchange exchange) {
407 return exchange.getIn().getBody().getClass();
408 }
409
410 @Override
411 public String toString() {
412 return "bodyType";
413 }
414 };
415 }
416
417 /**
418 * Returns the expression for the out messages body
419 */
420 public static Expression outBodyExpression() {
421 return new ExpressionAdapter() {
422 public Object evaluate(Exchange exchange) {
423 if (exchange.hasOut()) {
424 return exchange.getOut().getBody();
425 } else {
426 return null;
427 }
428 }
429
430 @Override
431 public String toString() {
432 return "outBody";
433 }
434 };
435 }
436
437 /**
438 * Returns the expression for the exchanges outbound message body converted
439 * to the given type
440 */
441 public static <T> Expression outBodyExpression(final Class<T> type) {
442 return new ExpressionAdapter() {
443 public Object evaluate(Exchange exchange) {
444 if (exchange.hasOut()) {
445 return exchange.getOut().getBody(type);
446 } else {
447 return null;
448 }
449 }
450
451 @Override
452 public String toString() {
453 return "outBodyAs[" + type.getName() + "]";
454 }
455 };
456 }
457
458 /**
459 * Returns the expression for the fault messages body
460 */
461 public static Expression faultBodyExpression() {
462 return new ExpressionAdapter() {
463 public Object evaluate(Exchange exchange) {
464 return exchange.getFault().getBody();
465 }
466
467 @Override
468 public String toString() {
469 return "faultBody";
470 }
471 };
472 }
473
474 /**
475 * Returns the expression for the exchanges fault message body converted
476 * to the given type
477 */
478 public static <T> Expression faultBodyExpression(final Class<T> type) {
479 return new ExpressionAdapter() {
480 public Object evaluate(Exchange exchange) {
481 return exchange.getFault().getBody(type);
482 }
483
484 @Override
485 public String toString() {
486 return "faultBodyAs[" + type.getName() + "]";
487 }
488 };
489 }
490
491 /**
492 * Returns the expression for the exchange
493 */
494 public static Expression exchangeExpression() {
495 return new ExpressionAdapter() {
496 public Object evaluate(Exchange exchange) {
497 return exchange;
498 }
499
500 @Override
501 public String toString() {
502 return "exchange";
503 }
504 };
505 }
506
507 /**
508 * Returns the expression for the IN message
509 */
510 public static Expression inMessageExpression() {
511 return new ExpressionAdapter() {
512 public Object evaluate(Exchange exchange) {
513 return exchange.getIn();
514 }
515
516 @Override
517 public String toString() {
518 return "inMessage";
519 }
520 };
521 }
522
523 /**
524 * Returns the expression for the OUT message
525 */
526 public static Expression outMessageExpression() {
527 return new ExpressionAdapter() {
528 public Object evaluate(Exchange exchange) {
529 return exchange.getOut();
530 }
531
532 @Override
533 public String toString() {
534 return "outMessage";
535 }
536 };
537 }
538
539 /**
540 * Returns an expression which converts the given expression to the given type
541 */
542 @SuppressWarnings("unchecked")
543 public static Expression convertToExpression(final Expression expression, final Class type) {
544 return new ExpressionAdapter() {
545 public Object evaluate(Exchange exchange) {
546 return expression.evaluate(exchange, type);
547 }
548
549 @Override
550 public String toString() {
551 return "" + expression + ".convertTo(" + type.getCanonicalName() + ".class)";
552 }
553 };
554 }
555
556 /**
557 * Returns an expression which converts the given expression to the given type the type
558 * expression is evaluted to
559 */
560 public static Expression convertToExpression(final Expression expression, final Expression type) {
561 return new ExpressionAdapter() {
562 public Object evaluate(Exchange exchange) {
563 return expression.evaluate(exchange, type.evaluate(exchange, Object.class).getClass());
564 }
565
566 @Override
567 public String toString() {
568 return "" + expression + ".convertToEvaluatedType(" + type + ")";
569 }
570 };
571 }
572
573 /**
574 * Returns a tokenize expression which will tokenize the string with the
575 * given token
576 */
577 public static Expression tokenizeExpression(final Expression expression,
578 final String token) {
579 return new ExpressionAdapter() {
580 public Object evaluate(Exchange exchange) {
581 Object value = expression.evaluate(exchange, Object.class);
582 Scanner scanner = ObjectHelper.getScanner(exchange, value);
583 scanner.useDelimiter(token);
584 return scanner;
585 }
586
587 @Override
588 public String toString() {
589 return "tokenize(" + expression + ", " + token + ")";
590 }
591 };
592 }
593
594 /**
595 * Returns a tokenize expression which will tokenize the string with the
596 * given regex
597 */
598 public static Expression regexTokenizeExpression(final Expression expression,
599 final String regexTokenizer) {
600 final Pattern pattern = Pattern.compile(regexTokenizer);
601 return new ExpressionAdapter() {
602 public Object evaluate(Exchange exchange) {
603 Object value = expression.evaluate(exchange, Object.class);
604 Scanner scanner = ObjectHelper.getScanner(exchange, value);
605 scanner.useDelimiter(regexTokenizer);
606 return scanner;
607 }
608
609 @Override
610 public String toString() {
611 return "regexTokenize(" + expression + ", " + pattern.pattern() + ")";
612 }
613 };
614 }
615
616 /**
617 * Returns a sort expression which will sort the expression with the given comparator.
618 * <p/>
619 * The expression is evaluted as a {@link List} object to allow sorting.
620 */
621 @SuppressWarnings("unchecked")
622 public static Expression sortExpression(final Expression expression, final Comparator comparator) {
623 return new ExpressionAdapter() {
624 public Object evaluate(Exchange exchange) {
625 List list = expression.evaluate(exchange, List.class);
626 Collections.sort(list, comparator);
627 return list;
628 }
629
630 @Override
631 public String toString() {
632 return "sort(" + expression + " by: " + comparator + ")";
633 }
634 };
635 }
636
637 /**
638 * Transforms the expression into a String then performs the regex
639 * replaceAll to transform the String and return the result
640 */
641 public static Expression regexReplaceAll(final Expression expression,
642 final String regex, final String replacement) {
643 final Pattern pattern = Pattern.compile(regex);
644 return new ExpressionAdapter() {
645 public Object evaluate(Exchange exchange) {
646 String text = expression.evaluate(exchange, String.class);
647 if (text == null) {
648 return null;
649 }
650 return pattern.matcher(text).replaceAll(replacement);
651 }
652
653 @Override
654 public String toString() {
655 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")";
656 }
657 };
658 }
659
660 /**
661 * Transforms the expression into a String then performs the regex
662 * replaceAll to transform the String and return the result
663 */
664 public static Expression regexReplaceAll(final Expression expression,
665 final String regex, final Expression replacementExpression) {
666
667 final Pattern pattern = Pattern.compile(regex);
668 return new ExpressionAdapter() {
669 public Object evaluate(Exchange exchange) {
670 String text = expression.evaluate(exchange, String.class);
671 String replacement = replacementExpression.evaluate(exchange, String.class);
672 if (text == null || replacement == null) {
673 return null;
674 }
675 return pattern.matcher(text).replaceAll(replacement);
676 }
677
678 @Override
679 public String toString() {
680 return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")";
681 }
682 };
683 }
684
685 /**
686 * Appends the String evaluations of the two expressions together
687 */
688 public static Expression append(final Expression left, final Expression right) {
689 return new ExpressionAdapter() {
690 public Object evaluate(Exchange exchange) {
691 return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class);
692 }
693
694 @Override
695 public String toString() {
696 return "append(" + left + ", " + right + ")";
697 }
698 };
699 }
700
701 /**
702 * Prepends the String evaluations of the two expressions together
703 */
704 public static Expression prepend(final Expression left, final Expression right) {
705 return new ExpressionAdapter() {
706 public Object evaluate(Exchange exchange) {
707 return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class);
708 }
709
710 @Override
711 public String toString() {
712 return "prepend(" + left + ", " + right + ")";
713 }
714 };
715 }
716
717 /**
718 * Returns an expression which returns the string concatenation value of the various
719 * expressions
720 *
721 * @param expressions the expression to be concatenated dynamically
722 * @return an expression which when evaluated will return the concatenated values
723 */
724 public static Expression concatExpression(final Collection<Expression> expressions) {
725 return concatExpression(expressions, null);
726 }
727
728 /**
729 * Returns an expression which returns the string concatenation value of the various
730 * expressions
731 *
732 * @param expressions the expression to be concatenated dynamically
733 * @param expression the text description of the expression
734 * @return an expression which when evaluated will return the concatenated values
735 */
736 public static Expression concatExpression(final Collection<Expression> expressions, final String expression) {
737 return new ExpressionAdapter() {
738 public Object evaluate(Exchange exchange) {
739 StringBuffer buffer = new StringBuffer();
740 for (Expression expression : expressions) {
741 String text = expression.evaluate(exchange, String.class);
742 if (text != null) {
743 buffer.append(text);
744 }
745 }
746 return buffer.toString();
747 }
748
749 @Override
750 public String toString() {
751 if (expression != null) {
752 return expression;
753 } else {
754 return "concat" + expressions;
755 }
756 }
757 };
758 }
759
760 /**
761 * Returns an Expression for the inbound message id
762 */
763 public static Expression messageIdExpression() {
764 return new ExpressionAdapter() {
765 public Object evaluate(Exchange exchange) {
766 return exchange.getIn().getMessageId();
767 }
768
769 @Override
770 public String toString() {
771 return "messageId";
772 }
773 };
774 }
775
776 public static Expression dateExpression(final String command, final String pattern) {
777 return new ExpressionAdapter() {
778 public Object evaluate(Exchange exchange) {
779 Date date;
780 if ("now".equals(command)) {
781 date = new Date();
782 } else if (command.startsWith("header.") || command.startsWith("in.header.")) {
783 String key = command.substring(command.lastIndexOf('.') + 1);
784 date = exchange.getIn().getHeader(key, Date.class);
785 if (date == null) {
786 throw new IllegalArgumentException("Cannot find java.util.Date object at " + command);
787 }
788 } else if (command.startsWith("out.header.")) {
789 String key = command.substring(command.lastIndexOf('.') + 1);
790 date = exchange.getOut().getHeader(key, Date.class);
791 if (date == null) {
792 throw new IllegalArgumentException("Cannot find java.util.Date object at " + command);
793 }
794 } else {
795 throw new IllegalArgumentException("Command not supported for dateExpression: " + command);
796 }
797
798 SimpleDateFormat df = new SimpleDateFormat(pattern);
799 return df.format(date);
800 }
801
802 @Override
803 public String toString() {
804 return "date(" + command + ":" + pattern + ")";
805 }
806 };
807 }
808
809 public static Expression simpleExpression(final String expression) {
810 return new ExpressionAdapter() {
811 public Object evaluate(Exchange exchange) {
812 // resolve language using context to have a clear separation of packages
813 // must call evalute to return the nested langauge evaluate when evaluating
814 // stacked expressions
815 Language language = exchange.getContext().resolveLanguage("simple");
816 return language.createExpression(expression).evaluate(exchange, Object.class);
817 }
818
819 @Override
820 public String toString() {
821 return "simple(" + expression + ")";
822 }
823 };
824 }
825
826 public static Expression beanExpression(final String expression) {
827 return new ExpressionAdapter() {
828 public Object evaluate(Exchange exchange) {
829 // resolve language using context to have a clear separation of packages
830 // must call evaluate to return the nested language evaluate when evaluating
831 // stacked expressions
832 Language language = exchange.getContext().resolveLanguage("bean");
833 return language.createExpression(expression).evaluate(exchange, Object.class);
834 }
835
836 @Override
837 public String toString() {
838 return "bean(" + expression + ")";
839 }
840 };
841 }
842
843 public static Expression beanExpression(final Class beanType, final String methodName) {
844 return BeanLanguage.bean(beanType, methodName);
845 }
846
847 public static Expression beanExpression(final String beanRef, final String methodName) {
848 String expression = methodName != null ? beanRef + "." + methodName : beanRef;
849 return beanExpression(expression);
850 }
851
852 /**
853 * Returns an expression processing the exchange to the given endpoint uri
854 *
855 * @param uri endpoint uri to send the exchange to
856 * @return an expression object which will return the OUT body
857 */
858 public static Expression toExpression(final String uri) {
859 return new ExpressionAdapter() {
860 public Object evaluate(Exchange exchange) {
861 Endpoint endpoint = exchange.getContext().getEndpoint(uri);
862 if (endpoint == null) {
863 throw new NoSuchEndpointException(uri);
864 }
865
866 Producer producer;
867 try {
868 producer = endpoint.createProducer();
869 producer.start();
870 producer.process(exchange);
871 producer.stop();
872 } catch (Exception e) {
873 throw ObjectHelper.wrapRuntimeCamelException(e);
874 }
875
876 // return the OUT body, but check for exchange pattern
877 if (ExchangeHelper.isOutCapable(exchange)) {
878 return exchange.getOut().getBody();
879 } else {
880 return exchange.getIn().getBody();
881 }
882 }
883
884 @Override
885 public String toString() {
886 return "to(" + uri + ")";
887 }
888 };
889 }
890
891
892 }