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: 756318 $
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 of exchange 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         * Returns an expression for the properties of exchange with the given name
161         *
162         * @see Exchange#getProperties()
163         * @return an expression object which will return the properties
164         */
165        public static <E extends Exchange> Expression<E> propertiesExpression() {
166            return new Expression<E>() {
167                public Object evaluate(E exchange) {
168                    return exchange.getProperties();
169                }
170    
171                @Override
172                public String toString() {
173                    return "properties";
174                }
175            };
176        }
177        
178        /**
179         * Returns an expression for the properties of exchange with the given name
180         *
181         * @see Exchange#getProperties()
182         * @return an expression object which will return the properties
183         */
184        public static <E extends Exchange> Expression<E> camelContextPropertiesExpression() {
185            return new Expression<E>() {
186                public Object evaluate(E exchange) {
187                    return exchange.getContext().getProperties();
188                }
189    
190                @Override
191                public String toString() {
192                    return "camelContextProperties";
193                }
194            };
195        }
196        
197        /**
198         * Returns an expression for the property value of the camel context with the given name
199         *
200         * @see Exchange#getProperty(String)
201         * @param propertyName the name of the property the expression will return
202         * @return an expression object which will return the property value
203         */
204        public static <E extends Exchange> Expression<E> camelContextPropertyExpression(final String propertyName) {
205            return new Expression<E>() {
206                public Object evaluate(E exchange) {
207                    return exchange.getContext().getProperties().get(propertyName);
208                }
209    
210                @Override
211                public String toString() {
212                    return "camelContextProperty(" + propertyName + ")";
213                }
214            };
215        }
216    
217        /**
218         * Returns an expression for a system property value with the given name
219         *
220         * @param propertyName the name of the system property the expression will
221         *                return
222         * @return an expression object which will return the system property value
223         */
224        public static <E extends Exchange> Expression<E> systemPropertyExpression(final String propertyName) {
225            return systemPropertyExpression(propertyName, null);
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
232         *                return
233         * @return an expression object which will return the system property value
234         */
235        public static <E extends Exchange> Expression<E> systemPropertyExpression(final String propertyName,
236                                                                                  final String defaultValue) {
237            return new Expression<E>() {
238                public Object evaluate(E exchange) {
239                    return System.getProperty(propertyName, defaultValue);
240                }
241    
242                @Override
243                public String toString() {
244                    return "systemProperty(" + propertyName + ")";
245                }
246            };
247        }
248    
249        /**
250         * Returns an expression for the constant value
251         *
252         * @param value the value the expression will return
253         * @return an expression object which will return the constant value
254         */
255        public static <E extends Exchange> Expression<E> constantExpression(final Object value) {
256            return new Expression<E>() {
257                public Object evaluate(E exchange) {
258                    return value;
259                }
260    
261                @Override
262                public String toString() {
263                    return "" + value;
264                }
265            };
266        }
267    
268        /**
269         * Returns the expression for the exchanges inbound message body
270         */
271        public static <E extends Exchange> Expression<E> bodyExpression() {
272            return new Expression<E>() {
273                public Object evaluate(E exchange) {
274                    return exchange.getIn().getBody();
275                }
276    
277                @Override
278                public String toString() {
279                    return "body";
280                }
281            };
282        }
283    
284        /**
285         * Returns the expression for the exchanges inbound message body converted
286         * to the given type
287         */
288        public static <E extends Exchange, T> Expression<E> bodyExpression(final Class<T> type) {
289            return new Expression<E>() {
290                public Object evaluate(E exchange) {
291                    return exchange.getIn().getBody(type);
292                }
293    
294                @Override
295                public String toString() {
296                    return "bodyAs[" + type.getName() + "]";
297                }
298            };
299        }
300    
301        /**
302         * Returns the expression for the out messages body
303         */
304        public static <E extends Exchange> Expression<E> outBodyExpression() {
305            return new Expression<E>() {
306                public Object evaluate(E exchange) {
307                    Message out = exchange.getOut(false);
308                    if (out == null) {
309                        return null;
310                    }
311                    return out.getBody();
312                }
313    
314                @Override
315                public String toString() {
316                    return "outBody";
317                }
318            };
319        }
320    
321        /**
322         * Returns the expression for the exchanges outbound message body converted
323         * to the given type
324         */
325        public static <E extends Exchange, T> Expression<E> outBodyExpression(final Class<T> type) {
326            return new Expression<E>() {
327                public Object evaluate(E exchange) {
328                    Message out = exchange.getOut(false);
329                    if (out == null) {
330                        return null;
331                    }
332                    return out.getBody(type);
333                }
334    
335                @Override
336                public String toString() {
337                    return "outBodyAs[" + type.getName() + "]";
338                }
339            };
340        }
341    
342        /**
343         * Returns the expression for the fault messages body
344         */
345        public static <E extends Exchange> Expression<E> faultBodyExpression() {
346            return new Expression<E>() {
347                public Object evaluate(E exchange) {
348                    return exchange.getFault().getBody();
349                }
350    
351                @Override
352                public String toString() {
353                    return "faultBody";
354                }
355            };
356        }
357    
358        /**
359         * Returns the expression for the exchanges fault message body converted
360         * to the given type
361         */
362        public static <E extends Exchange, T> Expression<E> faultBodyExpression(final Class<T> type) {
363            return new Expression<E>() {
364                public Object evaluate(E exchange) {
365                    return exchange.getFault().getBody(type);
366                }
367    
368                @Override
369                public String toString() {
370                    return "faultBodyAs[" + type.getName() + "]";
371                }
372            };
373        }
374    
375        /**
376         * Returns the expression for the exchange
377         */
378        public static <E extends Exchange> Expression<E> exchangeExpression() {
379            return new Expression<E>() {
380                public Object evaluate(E exchange) {
381                    return exchange;
382                }
383    
384                @Override
385                public String toString() {
386                    return "exchange";
387                }
388            };
389        }
390    
391        /**
392         * Returns the expression for the IN message
393         */
394        public static <E extends Exchange> Expression<E> inMessageExpression() {
395            return new Expression<E>() {
396                public Object evaluate(E exchange) {
397                    return exchange.getIn();
398                }
399    
400                @Override
401                public String toString() {
402                    return "inMessage";
403                }
404            };
405        }
406    
407        /**
408         * Returns the expression for the OUT message
409         */
410        public static <E extends Exchange> Expression<E> outMessageExpression() {
411            return new Expression<E>() {
412                public Object evaluate(E exchange) {
413                    return exchange.getOut();
414                }
415    
416                @Override
417                public String toString() {
418                    return "outMessage";
419                }
420            };
421        }
422    
423        /**
424         * Returns an expression which converts the given expression to the given
425         * type
426         */
427        public static <E extends Exchange> Expression<E> convertTo(final Expression expression, final Class type) {
428            return new Expression<E>() {
429                public Object evaluate(E exchange) {
430                    Object value = expression.evaluate(exchange);
431                    return exchange.getContext().getTypeConverter().convertTo(type, exchange, value);
432                }
433    
434                @Override
435                public String toString() {
436                    return "" + expression + ".convertTo(" + type.getName() + ".class)";
437                }
438            };
439        }
440    
441        /**
442         * Returns a tokenize expression which will tokenize the string with the
443         * given token
444         */
445        public static <E extends Exchange> Expression<E> tokenizeExpression(final Expression<E> expression,
446                                                                            final String token) {
447            return new Expression<E>() {
448                public Object evaluate(E exchange) {
449                    Object value = expression.evaluate(exchange);
450                    Scanner scanner = getScanner(exchange, value);
451                    scanner.useDelimiter(token);
452                    return scanner;
453                }
454    
455                @Override
456                public String toString() {
457                    return "tokenize(" + expression + ", " + token + ")";
458                }
459            };
460        }
461    
462        /**
463         * Returns a tokenize expression which will tokenize the string with the
464         * given regex
465         */
466        public static <E extends Exchange> Expression<E> regexTokenize(final Expression<E> expression,
467                                                                       final String regexTokenizer) {
468            final Pattern pattern = Pattern.compile(regexTokenizer);
469            return new Expression<E>() {
470                public Object evaluate(E exchange) {
471                    Object value = expression.evaluate(exchange);
472                    Scanner scanner = getScanner(exchange, value);
473                    scanner.useDelimiter(regexTokenizer);
474                    return scanner;
475                }
476    
477                @Override
478                public String toString() {
479                    return "regexTokenize(" + expression + ", " + pattern.pattern() + ")";
480                }
481            };
482        }
483    
484        private static Scanner getScanner(Exchange exchange, Object value) {
485            String charset = exchange.getProperty(Exchange.CHARSET_NAME, String.class);
486    
487            Scanner scanner = null;
488            if (value instanceof Readable) {
489                scanner = new Scanner((Readable)value);
490            } else if (value instanceof InputStream) {
491                scanner = charset == null ? new Scanner((InputStream)value)
492                    : new Scanner((InputStream)value, charset);
493            } else if (value instanceof File) {
494                try {
495                    scanner = charset == null ? new Scanner((File)value) : new Scanner((File)value, charset);
496                } catch (FileNotFoundException e) {
497                    throw new RuntimeCamelException(e);
498                }
499            } else if (value instanceof String) {
500                scanner = new Scanner((String)value);
501            } else if (value instanceof ReadableByteChannel) {
502                scanner = charset == null ? new Scanner((ReadableByteChannel)value)
503                    : new Scanner((ReadableByteChannel)value, charset);
504            }
505    
506            if (scanner == null) {
507                // value is not a suitable type, try to convert value to a string
508                String text = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, value);
509                if (text != null) {
510                    scanner = new Scanner(text);
511                }
512            }
513            
514            if (scanner == null) {
515                scanner = new Scanner("");
516            }
517            return scanner;
518        }
519    
520        /**
521         * Transforms the expression into a String then performs the regex
522         * replaceAll to transform the String and return the result
523         */
524        public static <E extends Exchange> Expression<E> regexReplaceAll(final Expression<E> expression,
525                                                                         final String regex, final String replacement) {
526            final Pattern pattern = Pattern.compile(regex);
527            return new Expression<E>() {
528                public Object evaluate(E exchange) {
529                    String text = evaluateStringExpression(expression, exchange);
530                    if (text == null) {
531                        return null;
532                    }
533                    return pattern.matcher(text).replaceAll(replacement);
534                }
535    
536                @Override
537                public String toString() {
538                    return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")";
539                }
540            };
541        }
542    
543        /**
544         * Transforms the expression into a String then performs the regex
545         * replaceAll to transform the String and return the result
546         */
547        public static <E extends Exchange> Expression<E> regexReplaceAll(final Expression<E> expression,
548                                                                         String regex,
549                                                                         final Expression<E> replacementExpression) {
550            final Pattern pattern = Pattern.compile(regex);
551            return new Expression<E>() {
552                public Object evaluate(E exchange) {
553                    String text = evaluateStringExpression(expression, exchange);
554                    String replacement = evaluateStringExpression(replacementExpression, exchange);
555                    if (text == null || replacement == null) {
556                        return null;
557                    }
558                    return pattern.matcher(text).replaceAll(replacement);
559                }
560    
561                @Override
562                public String toString() {
563                    return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")";
564                }
565            };
566        }
567    
568        /**
569         * Appends the String evaluations of the two expressions together
570         */
571        public static <E extends Exchange> Expression<E> append(final Expression<E> left,
572                                                                final Expression<E> right) {
573            return new Expression<E>() {
574                public Object evaluate(E exchange) {
575                    return evaluateStringExpression(left, exchange) + evaluateStringExpression(right, exchange);
576                }
577    
578                @Override
579                public String toString() {
580                    return "append(" + left + ", " + right + ")";
581                }
582            };
583        }
584    
585        /**
586         * Evaluates the expression on the given exchange and returns the String
587         * representation
588         *
589         * @param expression the expression to evaluate
590         * @param exchange the exchange to use to evaluate the expression
591         * @return the String representation of the expression or null if it could
592         *         not be evaluated
593         */
594        public static <E extends Exchange> String evaluateStringExpression(Expression<E> expression, E exchange) {
595            Object value = expression.evaluate(exchange);
596            return exchange.getContext().getTypeConverter().convertTo(String.class, exchange, value);
597        }
598    
599        /**
600         * Returns an expression for the given system property
601         */
602        public static <E extends Exchange> Expression<E> systemProperty(final String name) {
603            return systemProperty(name, null);
604        }
605    
606        /**
607         * Returns an expression for the given system property
608         */
609        public static <E extends Exchange> Expression<E> systemProperty(final String name,
610                                                                        final String defaultValue) {
611            return new Expression<E>() {
612                public Object evaluate(E exchange) {
613                    return System.getProperty(name, defaultValue);
614                }
615            };
616        }
617    
618        /**
619         * Returns an expression which returns the string concatenation value of the various
620         * expressions
621         *
622         * @param expressions the expression to be concatenated dynamically
623         * @return an expression which when evaluated will return the concatenated values
624         */
625        public static <E extends Exchange> Expression<E> concatExpression(final Collection<Expression> expressions) {
626            return concatExpression(expressions, null);
627        }
628    
629        /**
630         * Returns an expression which returns the string concatenation value of the various
631         * expressions
632         *
633         * @param expressions the expression to be concatenated dynamically
634         * @param expression the text description of the expression
635         * @return an expression which when evaluated will return the concatenated values
636         */
637        public static <E extends Exchange> Expression<E> concatExpression(final Collection<Expression> expressions, final String expression) {
638            return new Expression<E>() {
639                public Object evaluate(E exchange) {
640                    StringBuffer buffer = new StringBuffer();
641                    for (Expression<E> expression : expressions) {
642                        String text = evaluateStringExpression(expression, exchange);
643                        if (text != null) {
644                            buffer.append(text);
645                        }
646                    }
647                    return buffer.toString();
648                }
649    
650                @Override
651                public String toString() {
652                    if (expression != null) {
653                        return expression;
654                    } else {
655                        return "concat" + expressions;
656                    }
657                }
658            };
659        }
660    
661        /**
662         * Returns an Expression for the inbound message id
663         */
664        public static <E extends Exchange> Expression<E> messageIdExpression() {
665            return new Expression<E>() {
666                public Object evaluate(E exchange) {
667                    return exchange.getIn().getMessageId();
668                }
669    
670                @Override
671                public String toString() {
672                    return "messageId";
673                }
674            };
675        }
676    
677        public static <E extends Exchange> Expression<E> dateExpression(final String command, final String pattern) {
678            return new Expression<E>() {
679                public Object evaluate(E exchange) {
680                    Date date;
681                    if ("now".equals(command)) {
682                        date = new Date();
683                    } else if (command.startsWith("header.") || command.startsWith("in.header.")) {
684                        String key = command.substring(command.lastIndexOf(".") + 1);
685                        date = exchange.getIn().getHeader(key, Date.class);
686                        if (date == null) {
687                            throw new IllegalArgumentException("Could not find java.util.Date object at " + command);
688                        }
689                    } else if (command.startsWith("out.header.")) {
690                        String key = command.substring(command.lastIndexOf(".") + 1);
691                        date = exchange.getOut().getHeader(key, Date.class);
692                        if (date == null) {
693                            throw new IllegalArgumentException("Could not find java.util.Date object at " + command);
694                        }
695                    } else {
696                        throw new IllegalArgumentException("Command not supported for dateExpression: " + command);
697                    }
698    
699                    SimpleDateFormat df = new SimpleDateFormat(pattern);
700                    return df.format(date);
701                }
702    
703                @Override
704                public String toString() {
705                    return "date(" + command + ":" + pattern + ")";
706                }
707            };
708        }
709    
710        public static <E extends Exchange> Expression<E> simpleExpression(final String simple) {
711            return new Expression<E>() {
712                public Object evaluate(E exchange) {
713                    // must call evalute to return the nested langauge evaluate when evaluating
714                    // stacked expressions
715                    return SimpleLanguage.simple(simple).evaluate(exchange);
716                }
717    
718                @Override
719                public String toString() {
720                    return "simple(" + simple + ")";
721                }
722            };
723        }
724    
725        public static <E extends Exchange> Expression<E> beanExpression(final String bean) {
726            return new Expression<E>() {
727                public Object evaluate(E exchange) {
728                    // must call evalute to return the nested langauge evaluate when evaluating
729                    // stacked expressions
730                    return BeanLanguage.bean(bean).evaluate(exchange);
731                }
732    
733                @Override
734                public String toString() {
735                    return "bean(" + bean + ")";
736                }
737            };
738        }
739    
740    }