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