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