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