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