This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch mock
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 69b94538860f4bcd8643344fbe73866c4d0a388d
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue Apr 16 11:47:50 2019 +0200

    Move mock component out of camel-core. Work in progress.
---
 .../apache/camel/builder/ExpressionBuilder.java    | 813 --------------------
 .../org/apache/camel/builder/ValueBuilder.java     |   1 +
 .../language/simple/SimpleExpressionBuilder.java   | 851 +++++++++++++++++++++
 .../simple/ast/SimpleFunctionExpression.java       |  71 +-
 4 files changed, 888 insertions(+), 848 deletions(-)

diff --git 
a/core/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java 
b/core/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
index 5901824..18ca79a 100644
--- 
a/core/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
+++ 
b/core/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
@@ -18,21 +18,13 @@ package org.apache.camel.builder;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BiFunction;
 import java.util.function.Function;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.camel.CamelContext;
@@ -42,29 +34,21 @@ import org.apache.camel.Expression;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Message;
 import org.apache.camel.NoSuchLanguageException;
-import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.RuntimeExchangeException;
 import org.apache.camel.model.language.MethodCallExpression;
-import org.apache.camel.spi.ExchangeFormatter;
 import org.apache.camel.spi.Language;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.RouteContext;
 import org.apache.camel.spi.UnitOfWork;
-import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.support.ExpressionAdapter;
 import org.apache.camel.support.GroupIterator;
 import org.apache.camel.support.GroupTokenIterator;
 import org.apache.camel.support.LanguageSupport;
-import org.apache.camel.support.MessageHelper;
-import org.apache.camel.support.processor.DefaultExchangeFormatter;
-import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.OgnlHelper;
 import org.apache.camel.util.Scanner;
-import org.apache.camel.util.SkipIterator;
 import org.apache.camel.util.StringHelper;
 
 /**
@@ -75,8 +59,6 @@ public final class ExpressionBuilder {
     // TODO: Make this possible to have a base class in camel-support, and 
then extend it here, so we can have both
     // and maybe deprecate this and refer to the builder in camel-support
 
-    private static final Pattern OFFSET_PATTERN = 
Pattern.compile("([+-])([^+-]+)");
-
     /**
      * Utility classes should not have a public constructor.
      */
@@ -247,22 +229,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns the expression for the exchanges inbound message header 
invoking methods defined
-     * in a simple OGNL notation
-     *
-     * @param ognl  methods to invoke on the header in a simple OGNL syntax
-     */
-    public static Expression headersOgnlExpression(final String ognl) {
-        return new KeyedOgnlExpressionAdapter(ognl, "headerOgnl(" + ognl + ")",
-            new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() {
-                public Object getKeyedEntity(Exchange exchange, String key) {
-                    String text = simpleExpression(key).evaluate(exchange, 
String.class);
-                    return exchange.getIn().getHeader(text);
-                }
-            });
-    }
-
-    /**
      * Returns an expression for the inbound message headers
      *
      * @return an expression object which will return the inbound headers
@@ -406,36 +372,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns the expression for the exchanges exception invoking methods 
defined
-     * in a simple OGNL notation
-     *
-     * @param ognl  methods to invoke on the body in a simple OGNL syntax
-     */
-    public static Expression exchangeExceptionOgnlExpression(final String 
ognl) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                Object exception = exchange.getException();
-                if (exception == null) {
-                    exception = 
exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
-                }
-
-                if (exception == null) {
-                    return null;
-                }
-
-                // ognl is able to evaluate method name if it contains nested 
functions
-                // so we should not eager evaluate ognl as a string
-                return new MethodCallExpression(exception, 
ognl).evaluate(exchange);
-            }
-
-            @Override
-            public String toString() {
-                return "exchangeExceptionOgnl(" + ognl + ")";
-            }
-        };
-    }
-
-    /**
      * Returns an expression for the type converter
      *
      * @return an expression object which will return the type converter
@@ -529,7 +465,6 @@ public final class ExpressionBuilder {
     /**
      * Returns an expression for an exception message set on the exchange
      *
-     * @see <tt>Exchange.getException().getMessage()</tt>
      * @return an expression object which will return the exception message 
set on the exchange
      */
     public static Expression exchangeExceptionMessageExpression() {
@@ -600,22 +535,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns an expression for the property value of exchange with the given 
name invoking methods defined
-     * in a simple OGNL notation
-     *
-     * @param ognl  methods to invoke on the property in a simple OGNL syntax
-     */
-    public static Expression propertyOgnlExpression(final String ognl) {
-        return new KeyedOgnlExpressionAdapter(ognl, "propertyOgnl(" + ognl + 
")",
-            new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() {
-                public Object getKeyedEntity(Exchange exchange, String key) {
-                    String text = simpleExpression(key).evaluate(exchange, 
String.class);
-                    return exchange.getProperty(text);
-                }
-            });
-    }
-
-    /**
      * Returns an expression for the exchange properties of exchange
      *
      * @return an expression object which will return the exchange properties
@@ -805,69 +724,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns an expression for a type value
-     *
-     * @param name the type name
-     * @return an expression object which will return the type value
-     */
-    public static Expression typeExpression(final String name) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                // it may refer to a class type
-                String text = simpleExpression(name).evaluate(exchange, 
String.class);
-                Class<?> type = 
exchange.getContext().getClassResolver().resolveClass(text);
-                if (type != null) {
-                    return type;
-                }
-
-                int pos = text.lastIndexOf(".");
-                if (pos > 0) {
-                    String before = text.substring(0, pos);
-                    String after = text.substring(pos + 1);
-                    type = 
exchange.getContext().getClassResolver().resolveClass(before);
-                    if (type != null) {
-                        return ObjectHelper.lookupConstantFieldValue(type, 
after);
-                    }
-                }
-
-                throw 
CamelExecutionException.wrapCamelExecutionException(exchange, new 
ClassNotFoundException("Cannot find type " + text));
-            }
-
-            @Override
-            public String toString() {
-                return "type:" + name;
-            }
-        };
-    }
-
-    /**
-     * Returns an expression that caches the evaluation of another expression
-     * and returns the cached value, to avoid re-evaluating the expression.
-     *
-     * @param expression  the target expression to cache
-     * @return the cached value
-     */
-    public static Expression cacheExpression(final Expression expression) {
-        return new ExpressionAdapter() {
-            private final AtomicReference<Object> cache = new 
AtomicReference<>();
-
-            public Object evaluate(Exchange exchange) {
-                Object answer = cache.get();
-                if (answer == null) {
-                    answer = expression.evaluate(exchange, Object.class);
-                    cache.set(answer);
-                }
-                return answer;
-            }
-
-            @Override
-            public String toString() {
-                return expression.toString();
-            }
-        };
-    }
-
-    /**
      * Returns the expression for the exchanges inbound message body
      */
     public static Expression bodyExpression() {
@@ -958,31 +814,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns the expression for the exchanges inbound message body invoking 
methods defined
-     * in a simple OGNL notation
-     *
-     * @param ognl  methods to invoke on the body in a simple OGNL syntax
-     */
-    public static Expression bodyOgnlExpression(final String ognl) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                Object body = exchange.getIn().getBody();
-                if (body == null) {
-                    return null;
-                }
-                // ognl is able to evaluate method name if it contains nested 
functions
-                // so we should not eager evaluate ognl as a string
-                return new MethodCallExpression(body, ognl).evaluate(exchange);
-            }
-
-            @Override
-            public String toString() {
-                return "bodyOgnl(" + ognl + ")";
-            }
-        };
-    }
-
-    /**
      * Returns the expression for invoking a method (support OGNL syntax) on 
the given expression
      *
      * @param exp   the expression to evaluate and invoke the method on its 
result
@@ -1008,52 +839,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns the expression for the exchanges camelContext invoking methods 
defined
-     * in a simple OGNL notation
-     *
-     * @param ognl  methods to invoke on the context in a simple OGNL syntax
-     */
-    public static Expression camelContextOgnlExpression(final String ognl) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                CamelContext context = exchange.getContext();
-                if (context == null) {
-                    return null;
-                }
-                // ognl is able to evaluate method name if it contains nested 
functions
-                // so we should not eager evaluate ognl as a string
-                return new MethodCallExpression(context, 
ognl).evaluate(exchange);
-            }
-
-            @Override
-            public String toString() {
-                return "camelContextOgnl(" + ognl + ")";
-            }
-        };
-    }
-
-    /**
-     * Returns the expression for the exchange invoking methods defined
-     * in a simple OGNL notation
-     *
-     * @param ognl  methods to invoke on the exchange in a simple OGNL syntax
-     */
-    public static Expression exchangeOgnlExpression(final String ognl) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                // ognl is able to evaluate method name if it contains nested 
functions
-                // so we should not eager evaluate ognl as a string
-                return new MethodCallExpression(exchange, 
ognl).evaluate(exchange);
-            }
-
-            @Override
-            public String toString() {
-                return "exchangeOgnl(" + ognl + ")";
-            }
-        };
-    }
-
-    /**
      * Returns the expression for the exchanges inbound message body converted
      * to the given type
      */
@@ -1095,103 +880,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns the expression for the exchanges inbound message body converted
-     * to the given type and invoking methods on the converted body defined in 
a simple OGNL notation
-     */
-    public static Expression bodyOgnlExpression(final String name, final 
String ognl) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String text = simpleExpression(name).evaluate(exchange, 
String.class);
-                Class<?> type;
-                try {
-                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
-                } catch (ClassNotFoundException e) {
-                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-                }
-                Object body = exchange.getIn().getBody(type);
-                if (body != null) {
-                    // ognl is able to evaluate method name if it contains 
nested functions
-                    // so we should not eager evaluate ognl as a string
-                    MethodCallExpression call = new 
MethodCallExpression(exchange, ognl);
-                    // set the instance to use
-                    call.setInstance(body);
-                    return call.evaluate(exchange);
-                } else {
-                    return null;
-                }
-            }
-
-            @Override
-            public String toString() {
-                return "bodyOgnlAs[" + name + "](" + ognl + ")";
-            }
-        };
-    }
-
-    /**
-     * Returns the expression for the exchanges inbound message body converted
-     * to the given type
-     */
-    public static Expression mandatoryBodyExpression(final String name) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String text = simpleExpression(name).evaluate(exchange, 
String.class);
-                Class<?> type;
-                try {
-                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
-                } catch (ClassNotFoundException e) {
-                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-                }
-                try {
-                    return exchange.getIn().getMandatoryBody(type);
-                } catch (InvalidPayloadException e) {
-                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-                }
-            }
-
-            @Override
-            public String toString() {
-                return "mandatoryBodyAs[" + name + "]";
-            }
-        };
-    }
-
-    /**
-     * Returns the expression for the exchanges inbound message body converted
-     * to the given type and invoking methods on the converted body defined in 
a simple OGNL notation
-     */
-    public static Expression mandatoryBodyOgnlExpression(final String name, 
final String ognl) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String text = simpleExpression(name).evaluate(exchange, 
String.class);
-                Class<?> type;
-                try {
-                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
-                } catch (ClassNotFoundException e) {
-                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-                }
-                Object body;
-                try {
-                    body = exchange.getIn().getMandatoryBody(type);
-                } catch (InvalidPayloadException e) {
-                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-                }
-                // ognl is able to evaluate method name if it contains nested 
functions
-                // so we should not eager evaluate ognl as a string
-                MethodCallExpression call = new MethodCallExpression(exchange, 
ognl);
-                // set the instance to use
-                call.setInstance(body);
-                return call.evaluate(exchange);
-            }
-
-            @Override
-            public String toString() {
-                return "mandatoryBodyAs[" + name + "](" + ognl + ")";
-            }
-        };
-    }
-
-    /**
      * Returns the expression for the current thread name
      */
     public static Expression threadNameExpression() {
@@ -1224,22 +912,6 @@ public final class ExpressionBuilder {
     }
 
     /**
-     * Returns the expression for the {@code null} value
-     */
-    public static Expression nullExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return null;
-            }
-
-            @Override
-            public String toString() {
-                return "null";
-            }
-        };
-    }
-
-    /**
      * Returns the expression for the exchanges inbound message body converted
      * to the given type.
      * <p/>
@@ -1665,22 +1337,6 @@ public final class ExpressionBuilder {
         };
     }
 
-    public static Expression skipIteratorExpression(final Expression 
expression, final int skip) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                // evaluate expression as iterator
-                Iterator<?> it = expression.evaluate(exchange, Iterator.class);
-                ObjectHelper.notNull(it, "expression: " + expression + " 
evaluated on " + exchange + " must return an java.util.Iterator");
-                return new SkipIterator(it, skip);
-            }
-
-            @Override
-            public String toString() {
-                return "skip " + expression + " " + skip + " times";
-            }
-        };
-    }
-
     /**
      * Returns a sort expression which will sort the expression with the given 
comparator.
      * <p/>
@@ -1883,90 +1539,6 @@ public final class ExpressionBuilder {
         };
     }
 
-    public static Expression dateExpression(final String command) {
-        return dateExpression(command, null, null);
-    }
-
-    public static Expression dateExpression(final String command, final String 
pattern) {
-        return dateExpression(command, null, pattern);
-    }
-
-    public static Expression dateExpression(final String commandWithOffsets, 
final String timezone, final String pattern) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                // Capture optional time offsets
-                String command = commandWithOffsets.split("[+-]", 2)[0].trim();
-                List<Long> offsets = new ArrayList<>();
-                Matcher offsetMatcher = 
OFFSET_PATTERN.matcher(commandWithOffsets);
-                while (offsetMatcher.find()) {
-                    try {
-                        long value = 
exchange.getContext().getTypeConverter().mandatoryConvertTo(long.class, 
exchange, offsetMatcher.group(2).trim());
-                        offsets.add(offsetMatcher.group(1).equals("+") ? value 
: -value);
-                    } catch (NoTypeConversionAvailableException e) {
-                        throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-                    }
-                }
-
-                Date date;
-                if ("now".equals(command)) {
-                    date = new Date();
-                } else if (command.startsWith("header.") || 
command.startsWith("in.header.")) {
-                    String key = command.substring(command.lastIndexOf('.') + 
1);
-                    date = exchange.getIn().getHeader(key, Date.class);
-                    if (date == null) {
-                        throw new IllegalArgumentException("Cannot find 
java.util.Date object at command: " + command);
-                    }
-                } else if (command.startsWith("out.header.")) {
-                    String key = command.substring(command.lastIndexOf('.') + 
1);
-                    date = exchange.getOut().getHeader(key, Date.class);
-                    if (date == null) {
-                        throw new IllegalArgumentException("Cannot find 
java.util.Date object at command: " + command);
-                    }
-                } else if (command.startsWith("exchangeProperty.")) {
-                    String key = command.substring(command.lastIndexOf('.') + 
1);
-                    date = exchange.getProperty(key, Date.class);
-                    if (date == null) {
-                        throw new IllegalArgumentException("Cannot find 
java.util.Date object at command: " + command);
-                    }
-                } else if ("file".equals(command)) {
-                    Long num = 
exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class);
-                    if (num != null && num > 0) {
-                        date = new Date(num);
-                    } else {
-                        date = 
exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class);
-                        if (date == null) {
-                            throw new IllegalArgumentException("Cannot find " 
+ Exchange.FILE_LAST_MODIFIED + " header at command: " + command);
-                        }
-                    }
-                } else {
-                    throw new IllegalArgumentException("Command not supported 
for dateExpression: " + command);
-                }
-
-                // Apply offsets
-                long dateAsLong = date.getTime();
-                for (long offset : offsets) {
-                    dateAsLong += offset;
-                }
-                date = new Date(dateAsLong);
-
-                if (pattern != null && !pattern.isEmpty()) {
-                    SimpleDateFormat df = new SimpleDateFormat(pattern);
-                    if (timezone != null && !timezone.isEmpty()) {
-                        df.setTimeZone(TimeZone.getTimeZone(timezone));
-                    }
-                    return df.format(date);
-                } else {
-                    return date;
-                }
-            }
-
-            @Override
-            public String toString() {
-                return "date(" + commandWithOffsets + ":" + pattern + ":" + 
timezone + ")";
-            }
-        };
-    }
-
     public static Expression simpleExpression(final String expression) {
         return new ExpressionAdapter() {
             public Object evaluate(Exchange exchange) {
@@ -2007,199 +1579,6 @@ public final class ExpressionBuilder {
         };
     }
 
-    public static Expression fileNameExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:name";
-            }
-        };
-    }
-
-    public static Expression fileOnlyNameExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String answer = 
exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class);
-                if (answer == null) {
-                    answer = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
-                    answer = FileUtil.stripPath(answer);
-                }
-                return answer;
-            }
-
-            @Override
-            public String toString() {
-                return "file:onlyname";
-            }
-        };
-    }
-
-    public static Expression fileNameNoExtensionExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
-                return FileUtil.stripExt(name);
-            }
-
-            @Override
-            public String toString() {
-                return "file:name.noext";
-            }
-        };
-    }
-
-    public static Expression fileNameNoExtensionSingleExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
-                return FileUtil.stripExt(name, true);
-            }
-
-            @Override
-            public String toString() {
-                return "file:name.noext.single";
-            }
-        };
-    }
-
-    public static Expression fileOnlyNameNoExtensionExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String name = fileOnlyNameExpression().evaluate(exchange, 
String.class);
-                return FileUtil.stripExt(name);
-            }
-
-            @Override
-            public String toString() {
-                return "file:onlyname.noext";
-            }
-        };
-    }
-
-    public static Expression fileOnlyNameNoExtensionSingleExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String name = fileOnlyNameExpression().evaluate(exchange, 
String.class);
-                return FileUtil.stripExt(name, true);
-            }
-
-            @Override
-            public String toString() {
-                return "file:onlyname.noext.single";
-            }
-        };
-    }
-
-    public static Expression fileExtensionExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
-                return FileUtil.onlyExt(name);
-            }
-
-            @Override
-            public String toString() {
-                return "file:ext";
-            }
-        };
-    }
-
-    public static Expression fileExtensionSingleExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
-                return FileUtil.onlyExt(name, true);
-            }
-
-            @Override
-            public String toString() {
-                return "file:ext.single";
-            }
-        };
-    }
-
-    public static Expression fileParentExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader("CamelFileParent", 
String.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:parent";
-            }
-        };
-    }
-
-    public static Expression filePathExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader("CamelFilePath", 
String.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:path";
-            }
-        };
-    }
-
-    public static Expression fileAbsolutePathExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader("CamelFileAbsolutePath", 
String.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:absolute.path";
-            }
-        };
-    }
-
-    public static Expression fileAbsoluteExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader("CamelFileAbsolute", 
Boolean.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:absolute";
-            }
-        };
-    }
-
-    public static Expression fileSizeExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader(Exchange.FILE_LENGTH, 
Long.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:length";
-            }
-        };
-    }
-
-    public static Expression fileLastModifiedExpression() {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, 
Long.class);
-            }
-
-            @Override
-            public String toString() {
-                return "file:modified";
-            }
-        };
-    }
-
     /**
      * Returns Simple expression or fallback to Constant expression if 
expression str is not Simple expression.
      */
@@ -2249,196 +1628,4 @@ public final class ExpressionBuilder {
         };
     }
 
-    /**
-     * Returns a random number between 0 and max (exclusive)
-     */
-    public static Expression randomExpression(final int max) {
-        return randomExpression(0, max);
-    }
-
-    /**
-     * Returns a random number between min and max (exclusive)
-     */
-    public static Expression randomExpression(final int min, final int max) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                Random random = new Random();
-                int randomNum = random.nextInt(max - min) + min;
-                return randomNum;
-            }
-
-            @Override
-            public String toString() {
-                return "random(" + min + "," + max + ")";
-            }
-        };
-    }
-
-    /**
-     * Returns a random number between min and max (exclusive)
-     */
-    public static Expression randomExpression(final String min, final String 
max) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                int num1 = simpleExpression(min).evaluate(exchange, 
Integer.class);
-                int num2 = simpleExpression(max).evaluate(exchange, 
Integer.class);
-                Random random = new Random();
-                int randomNum = random.nextInt(num2 - num1) + num1;
-                return randomNum;
-            }
-
-            @Override
-            public String toString() {
-                return "random(" + min + "," + max + ")";
-            }
-        };
-    }
-
-    /**
-     * Returns an iterator to skip (iterate) the given expression
-     */
-    public static Expression skipExpression(final String expression, final int 
number) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                // use simple language
-                Expression exp = 
exchange.getContext().resolveLanguage("simple").createExpression(expression);
-                return ExpressionBuilder.skipIteratorExpression(exp, 
number).evaluate(exchange, Object.class);
-            }
-
-            @Override
-            public String toString() {
-                return "skip(" + expression + "," + number + ")";
-            }
-        };
-    }
-
-    /**
-     * Returns an iterator to collate (iterate) the given expression
-     */
-    public static Expression collateExpression(final String expression, final 
int group) {
-        return new ExpressionAdapter() {
-            public Object evaluate(Exchange exchange) {
-                // use simple language
-                Expression exp = 
exchange.getContext().resolveLanguage("simple").createExpression(expression);
-                return ExpressionBuilder.groupIteratorExpression(exp, null, "" 
+ group, false).evaluate(exchange, Object.class);
-            }
-
-            @Override
-            public String toString() {
-                return "collate(" + expression + "," + group + ")";
-            }
-        };
-    }
-
-    /**
-     * Returns the message history (including exchange details or not)
-     */
-    public static Expression messageHistoryExpression(final boolean detailed) {
-        return new ExpressionAdapter() {
-
-            private ExchangeFormatter formatter;
-
-            public Object evaluate(Exchange exchange) {
-                ExchangeFormatter ef = null;
-                if (detailed) {
-                    // use the exchange formatter to log exchange details
-                    ef = getOrCreateExchangeFormatter(exchange.getContext());
-                }
-                return MessageHelper.dumpMessageHistoryStacktrace(exchange, 
ef, false);
-            }
-
-            private ExchangeFormatter 
getOrCreateExchangeFormatter(CamelContext camelContext) {
-                if (formatter == null) {
-                    Set<ExchangeFormatter> formatters = 
camelContext.getRegistry().findByType(ExchangeFormatter.class);
-                    if (formatters != null && formatters.size() == 1) {
-                        formatter = formatters.iterator().next();
-                    } else {
-                        // setup exchange formatter to be used for message 
history dump
-                        DefaultExchangeFormatter def = new 
DefaultExchangeFormatter();
-                        def.setShowExchangeId(true);
-                        def.setMultiline(true);
-                        def.setShowHeaders(true);
-                        
def.setStyle(DefaultExchangeFormatter.OutputStyle.Fixed);
-                        try {
-                            Integer maxChars = 
CamelContextHelper.parseInteger(camelContext, 
camelContext.getGlobalOption(Exchange.LOG_DEBUG_BODY_MAX_CHARS));
-                            if (maxChars != null) {
-                                def.setMaxChars(maxChars);
-                            }
-                        } catch (Exception e) {
-                            throw 
RuntimeCamelException.wrapRuntimeCamelException(e);
-                        }
-                        formatter = def;
-                    }
-                }
-                return formatter;
-            }
-
-            @Override
-            public String toString() {
-                return "messageHistory(" + detailed + ")";
-            }
-        };
-    }
-
-    /**
-     * Expression adapter for OGNL expression from Message Header or Exchange 
property
-     */
-    private static class KeyedOgnlExpressionAdapter extends ExpressionAdapter {
-        private final String ognl;
-        private final String toStringValue;
-        private final KeyedEntityRetrievalStrategy 
keyedEntityRetrievalStrategy;
-
-        KeyedOgnlExpressionAdapter(String ognl, String toStringValue,
-                                   KeyedEntityRetrievalStrategy 
keyedEntityRetrievalStrategy) {
-            this.ognl = ognl;
-            this.toStringValue = toStringValue;
-            this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy;
-        }
-
-        public Object evaluate(Exchange exchange) {
-            // try with full name first
-            Object property = 
keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl);
-            if (property != null) {
-                return property;
-            }
-
-
-            // Split ognl except when this is not a Map, Array
-            // and we would like to keep the dots within the key name
-            List<String> methods = OgnlHelper.splitOgnl(ognl);
-
-            String key = methods.get(0);
-            String keySuffix = "";
-            // if ognl starts with a key inside brackets (eg: [foo.bar])
-            // remove starting and ending brackets from key
-            if (key.startsWith("[") && key.endsWith("]")) {
-                key = 
StringHelper.removeLeadingAndEndingQuotes(key.substring(1, key.length() - 1));
-                keySuffix = StringHelper.after(methods.get(0), key);
-            }
-            // remove any OGNL operators so we got the pure key name
-            key = OgnlHelper.removeOperators(key);
-
-
-            property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, 
key);
-            if (property == null) {
-                return null;
-            }
-            // the remainder is the rest of the ognl without the key
-            String remainder = StringHelper.after(ognl, key + keySuffix);
-            return new MethodCallExpression(property, 
remainder).evaluate(exchange);
-        }
-
-        @Override
-        public String toString() {
-            return toStringValue;
-        }
-
-        /**
-         * Strategy to retrieve the value based on the key
-         */
-        public interface KeyedEntityRetrievalStrategy {
-            Object getKeyedEntity(Exchange exchange, String key);
-        }
-    }
-
 }
diff --git 
a/core/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java 
b/core/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
index a37d742..c8ac6cb 100644
--- a/core/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
+++ b/core/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
@@ -343,6 +343,7 @@ public class ValueBuilder implements Expression, Predicate {
      * @return the current builder
      */
     public ValueBuilder method(String methodName) {
+        // TODO: find alternative
         Expression newExp = ExpressionBuilder.ognlExpression(expression, 
methodName);
         return onNewValueBuilder(newExp);
     }
diff --git 
a/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
 
b/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
new file mode 100644
index 0000000..8189149
--- /dev/null
+++ 
b/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
@@ -0,0 +1,851 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.ExpressionBuilder;
+import org.apache.camel.model.language.MethodCallExpression;
+import org.apache.camel.spi.ExchangeFormatter;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.ExpressionAdapter;
+import org.apache.camel.support.MessageHelper;
+import org.apache.camel.support.processor.DefaultExchangeFormatter;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OgnlHelper;
+import org.apache.camel.util.SkipIterator;
+import org.apache.camel.util.StringHelper;
+
+/**
+ * Expression builder used by the simple language.
+ */
+public class SimpleExpressionBuilder {
+
+    private static final Pattern OFFSET_PATTERN = 
Pattern.compile("([+-])([^+-]+)");
+
+    /**
+     * Returns the expression for the exchanges inbound message header 
invoking methods defined
+     * in a simple OGNL notation
+     *
+     * @param ognl  methods to invoke on the header in a simple OGNL syntax
+     */
+    public static Expression headersOgnlExpression(final String ognl) {
+        return new KeyedOgnlExpressionAdapter(ognl, "headerOgnl(" + ognl + ")",
+            new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() {
+                public Object getKeyedEntity(Exchange exchange, String key) {
+                    String text = 
ExpressionBuilder.simpleExpression(key).evaluate(exchange, String.class);
+                    return exchange.getIn().getHeader(text);
+                }
+            });
+    }
+
+    /**
+     * Returns the message history (including exchange details or not)
+     */
+    public static Expression messageHistoryExpression(final boolean detailed) {
+        return new ExpressionAdapter() {
+
+            private ExchangeFormatter formatter;
+
+            public Object evaluate(Exchange exchange) {
+                ExchangeFormatter ef = null;
+                if (detailed) {
+                    // use the exchange formatter to log exchange details
+                    ef = getOrCreateExchangeFormatter(exchange.getContext());
+                }
+                return MessageHelper.dumpMessageHistoryStacktrace(exchange, 
ef, false);
+            }
+
+            private ExchangeFormatter 
getOrCreateExchangeFormatter(CamelContext camelContext) {
+                if (formatter == null) {
+                    Set<ExchangeFormatter> formatters = 
camelContext.getRegistry().findByType(ExchangeFormatter.class);
+                    if (formatters != null && formatters.size() == 1) {
+                        formatter = formatters.iterator().next();
+                    } else {
+                        // setup exchange formatter to be used for message 
history dump
+                        DefaultExchangeFormatter def = new 
DefaultExchangeFormatter();
+                        def.setShowExchangeId(true);
+                        def.setMultiline(true);
+                        def.setShowHeaders(true);
+                        
def.setStyle(DefaultExchangeFormatter.OutputStyle.Fixed);
+                        try {
+                            Integer maxChars = 
CamelContextHelper.parseInteger(camelContext, 
camelContext.getGlobalOption(Exchange.LOG_DEBUG_BODY_MAX_CHARS));
+                            if (maxChars != null) {
+                                def.setMaxChars(maxChars);
+                            }
+                        } catch (Exception e) {
+                            throw 
RuntimeCamelException.wrapRuntimeCamelException(e);
+                        }
+                        formatter = def;
+                    }
+                }
+                return formatter;
+            }
+
+            @Override
+            public String toString() {
+                return "messageHistory(" + detailed + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns an iterator to collate (iterate) the given expression
+     */
+    public static Expression collateExpression(final String expression, final 
int group) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                // use simple language
+                Expression exp = 
exchange.getContext().resolveLanguage("simple").createExpression(expression);
+                return ExpressionBuilder.groupIteratorExpression(exp, null, "" 
+ group, false).evaluate(exchange, Object.class);
+            }
+
+            @Override
+            public String toString() {
+                return "collate(" + expression + "," + group + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns an iterator to skip (iterate) the given expression
+     */
+    public static Expression skipExpression(final String expression, final int 
number) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                // use simple language
+                Expression exp = 
exchange.getContext().resolveLanguage("simple").createExpression(expression);
+                return skipIteratorExpression(exp, number).evaluate(exchange, 
Object.class);
+            }
+
+            @Override
+            public String toString() {
+                return "skip(" + expression + "," + number + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns a random number between min and max (exclusive)
+     */
+    public static Expression randomExpression(final String min, final String 
max) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                int num1 = 
ExpressionBuilder.simpleExpression(min).evaluate(exchange, Integer.class);
+                int num2 = 
ExpressionBuilder.simpleExpression(max).evaluate(exchange, Integer.class);
+                Random random = new Random();
+                int randomNum = random.nextInt(num2 - num1) + num1;
+                return randomNum;
+            }
+
+            @Override
+            public String toString() {
+                return "random(" + min + "," + max + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns a random number between 0 and max (exclusive)
+     */
+    public static Expression randomExpression(final int max) {
+        return randomExpression(0, max);
+    }
+
+    /**
+     * Returns a random number between min and max (exclusive)
+     */
+    public static Expression randomExpression(final int min, final int max) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                Random random = new Random();
+                int randomNum = random.nextInt(max - min) + min;
+                return randomNum;
+            }
+
+            @Override
+            public String toString() {
+                return "random(" + min + "," + max + ")";
+            }
+        };
+    }
+
+    public static Expression fileNameExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:name";
+            }
+        };
+    }
+
+    public static Expression fileOnlyNameExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String answer = 
exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class);
+                if (answer == null) {
+                    answer = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+                    answer = FileUtil.stripPath(answer);
+                }
+                return answer;
+            }
+
+            @Override
+            public String toString() {
+                return "file:onlyname";
+            }
+        };
+    }
+
+    public static Expression fileNameNoExtensionExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+                return FileUtil.stripExt(name);
+            }
+
+            @Override
+            public String toString() {
+                return "file:name.noext";
+            }
+        };
+    }
+
+    public static Expression fileNameNoExtensionSingleExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+                return FileUtil.stripExt(name, true);
+            }
+
+            @Override
+            public String toString() {
+                return "file:name.noext.single";
+            }
+        };
+    }
+
+    public static Expression fileOnlyNameNoExtensionExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String name = fileOnlyNameExpression().evaluate(exchange, 
String.class);
+                return FileUtil.stripExt(name);
+            }
+
+            @Override
+            public String toString() {
+                return "file:onlyname.noext";
+            }
+        };
+    }
+
+    public static Expression fileOnlyNameNoExtensionSingleExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String name = fileOnlyNameExpression().evaluate(exchange, 
String.class);
+                return FileUtil.stripExt(name, true);
+            }
+
+            @Override
+            public String toString() {
+                return "file:onlyname.noext.single";
+            }
+        };
+    }
+
+    public static Expression fileExtensionExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+                return FileUtil.onlyExt(name);
+            }
+
+            @Override
+            public String toString() {
+                return "file:ext";
+            }
+        };
+    }
+
+    public static Expression fileExtensionSingleExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String name = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+                return FileUtil.onlyExt(name, true);
+            }
+
+            @Override
+            public String toString() {
+                return "file:ext.single";
+            }
+        };
+    }
+
+    public static Expression fileParentExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader("CamelFileParent", 
String.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:parent";
+            }
+        };
+    }
+
+    public static Expression filePathExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader("CamelFilePath", 
String.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:path";
+            }
+        };
+    }
+
+    public static Expression fileAbsolutePathExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader("CamelFileAbsolutePath", 
String.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:absolute.path";
+            }
+        };
+    }
+
+    public static Expression fileAbsoluteExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader("CamelFileAbsolute", 
Boolean.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:absolute";
+            }
+        };
+    }
+
+    public static Expression fileSizeExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader(Exchange.FILE_LENGTH, 
Long.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:length";
+            }
+        };
+    }
+
+    public static Expression fileLastModifiedExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, 
Long.class);
+            }
+
+            @Override
+            public String toString() {
+                return "file:modified";
+            }
+        };
+    }
+
+    public static Expression dateExpression(final String command) {
+        return dateExpression(command, null, null);
+    }
+
+    public static Expression dateExpression(final String command, final String 
pattern) {
+        return dateExpression(command, null, pattern);
+    }
+
+    public static Expression dateExpression(final String commandWithOffsets, 
final String timezone, final String pattern) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                // Capture optional time offsets
+                String command = commandWithOffsets.split("[+-]", 2)[0].trim();
+                List<Long> offsets = new ArrayList<>();
+                Matcher offsetMatcher = 
OFFSET_PATTERN.matcher(commandWithOffsets);
+                while (offsetMatcher.find()) {
+                    try {
+                        long value = 
exchange.getContext().getTypeConverter().mandatoryConvertTo(long.class, 
exchange, offsetMatcher.group(2).trim());
+                        offsets.add(offsetMatcher.group(1).equals("+") ? value 
: -value);
+                    } catch (NoTypeConversionAvailableException e) {
+                        throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                    }
+                }
+
+                Date date;
+                if ("now".equals(command)) {
+                    date = new Date();
+                } else if (command.startsWith("header.") || 
command.startsWith("in.header.")) {
+                    String key = command.substring(command.lastIndexOf('.') + 
1);
+                    date = exchange.getIn().getHeader(key, Date.class);
+                    if (date == null) {
+                        throw new IllegalArgumentException("Cannot find 
java.util.Date object at command: " + command);
+                    }
+                } else if (command.startsWith("out.header.")) {
+                    String key = command.substring(command.lastIndexOf('.') + 
1);
+                    date = exchange.getOut().getHeader(key, Date.class);
+                    if (date == null) {
+                        throw new IllegalArgumentException("Cannot find 
java.util.Date object at command: " + command);
+                    }
+                } else if (command.startsWith("exchangeProperty.")) {
+                    String key = command.substring(command.lastIndexOf('.') + 
1);
+                    date = exchange.getProperty(key, Date.class);
+                    if (date == null) {
+                        throw new IllegalArgumentException("Cannot find 
java.util.Date object at command: " + command);
+                    }
+                } else if ("file".equals(command)) {
+                    Long num = 
exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Long.class);
+                    if (num != null && num > 0) {
+                        date = new Date(num);
+                    } else {
+                        date = 
exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class);
+                        if (date == null) {
+                            throw new IllegalArgumentException("Cannot find " 
+ Exchange.FILE_LAST_MODIFIED + " header at command: " + command);
+                        }
+                    }
+                } else {
+                    throw new IllegalArgumentException("Command not supported 
for dateExpression: " + command);
+                }
+
+                // Apply offsets
+                long dateAsLong = date.getTime();
+                for (long offset : offsets) {
+                    dateAsLong += offset;
+                }
+                date = new Date(dateAsLong);
+
+                if (pattern != null && !pattern.isEmpty()) {
+                    SimpleDateFormat df = new SimpleDateFormat(pattern);
+                    if (timezone != null && !timezone.isEmpty()) {
+                        df.setTimeZone(TimeZone.getTimeZone(timezone));
+                    }
+                    return df.format(date);
+                } else {
+                    return date;
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "date(" + commandWithOffsets + ":" + pattern + ":" + 
timezone + ")";
+            }
+        };
+    }
+
+    public static Expression skipIteratorExpression(final Expression 
expression, final int skip) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                // evaluate expression as iterator
+                Iterator<?> it = expression.evaluate(exchange, Iterator.class);
+                ObjectHelper.notNull(it, "expression: " + expression + " 
evaluated on " + exchange + " must return an java.util.Iterator");
+                return new SkipIterator(it, skip);
+            }
+
+            @Override
+            public String toString() {
+                return "skip " + expression + " " + skip + " times";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the {@code null} value
+     */
+    public static Expression nullExpression() {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                return null;
+            }
+
+            @Override
+            public String toString() {
+                return "null";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchanges inbound message body converted
+     * to the given type and invoking methods on the converted body defined in 
a simple OGNL notation
+     */
+    public static Expression mandatoryBodyOgnlExpression(final String name, 
final String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String text = 
ExpressionBuilder.simpleExpression(name).evaluate(exchange, String.class);
+                Class<?> type;
+                try {
+                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
+                } catch (ClassNotFoundException e) {
+                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                }
+                Object body;
+                try {
+                    body = exchange.getIn().getMandatoryBody(type);
+                } catch (InvalidPayloadException e) {
+                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                }
+                // ognl is able to evaluate method name if it contains nested 
functions
+                // so we should not eager evaluate ognl as a string
+                MethodCallExpression call = new MethodCallExpression(exchange, 
ognl);
+                // set the instance to use
+                call.setInstance(body);
+                return call.evaluate(exchange);
+            }
+
+            @Override
+            public String toString() {
+                return "mandatoryBodyAs[" + name + "](" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchanges inbound message body converted
+     * to the given type
+     */
+    public static Expression mandatoryBodyExpression(final String name) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String text = 
ExpressionBuilder.simpleExpression(name).evaluate(exchange, String.class);
+                Class<?> type;
+                try {
+                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
+                } catch (ClassNotFoundException e) {
+                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                }
+                try {
+                    return exchange.getIn().getMandatoryBody(type);
+                } catch (InvalidPayloadException e) {
+                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "mandatoryBodyAs[" + name + "]";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchanges inbound message body converted
+     * to the given type and invoking methods on the converted body defined in 
a simple OGNL notation
+     */
+    public static Expression bodyOgnlExpression(final String name, final 
String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String text = 
ExpressionBuilder.simpleExpression(name).evaluate(exchange, String.class);
+                Class<?> type;
+                try {
+                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
+                } catch (ClassNotFoundException e) {
+                    throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                }
+                Object body = exchange.getIn().getBody(type);
+                if (body != null) {
+                    // ognl is able to evaluate method name if it contains 
nested functions
+                    // so we should not eager evaluate ognl as a string
+                    MethodCallExpression call = new 
MethodCallExpression(exchange, ognl);
+                    // set the instance to use
+                    call.setInstance(body);
+                    return call.evaluate(exchange);
+                } else {
+                    return null;
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "bodyOgnlAs[" + name + "](" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchange invoking methods defined
+     * in a simple OGNL notation
+     *
+     * @param ognl  methods to invoke on the exchange in a simple OGNL syntax
+     */
+    public static Expression exchangeOgnlExpression(final String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                // ognl is able to evaluate method name if it contains nested 
functions
+                // so we should not eager evaluate ognl as a string
+                return new MethodCallExpression(exchange, 
ognl).evaluate(exchange);
+            }
+
+            @Override
+            public String toString() {
+                return "exchangeOgnl(" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchanges camelContext invoking methods 
defined
+     * in a simple OGNL notation
+     *
+     * @param ognl  methods to invoke on the context in a simple OGNL syntax
+     */
+    public static Expression camelContextOgnlExpression(final String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                CamelContext context = exchange.getContext();
+                if (context == null) {
+                    return null;
+                }
+                // ognl is able to evaluate method name if it contains nested 
functions
+                // so we should not eager evaluate ognl as a string
+                return new MethodCallExpression(context, 
ognl).evaluate(exchange);
+            }
+
+            @Override
+            public String toString() {
+                return "camelContextOgnl(" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchanges inbound message body invoking 
methods defined
+     * in a simple OGNL notation
+     *
+     * @param ognl  methods to invoke on the body in a simple OGNL syntax
+     */
+    public static Expression bodyOgnlExpression(final String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                Object body = exchange.getIn().getBody();
+                if (body == null) {
+                    return null;
+                }
+                // ognl is able to evaluate method name if it contains nested 
functions
+                // so we should not eager evaluate ognl as a string
+                return new MethodCallExpression(body, ognl).evaluate(exchange);
+            }
+
+            @Override
+            public String toString() {
+                return "bodyOgnl(" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns an expression that caches the evaluation of another expression
+     * and returns the cached value, to avoid re-evaluating the expression.
+     *
+     * @param expression  the target expression to cache
+     * @return the cached value
+     */
+    public static Expression cacheExpression(final Expression expression) {
+        return new ExpressionAdapter() {
+            private final AtomicReference<Object> cache = new 
AtomicReference<>();
+
+            public Object evaluate(Exchange exchange) {
+                Object answer = cache.get();
+                if (answer == null) {
+                    answer = expression.evaluate(exchange, Object.class);
+                    cache.set(answer);
+                }
+                return answer;
+            }
+
+            @Override
+            public String toString() {
+                return expression.toString();
+            }
+        };
+    }
+
+    /**
+     * Returns an expression for a type value
+     *
+     * @param name the type name
+     * @return an expression object which will return the type value
+     */
+    public static Expression typeExpression(final String name) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                // it may refer to a class type
+                String text = 
ExpressionBuilder.simpleExpression(name).evaluate(exchange, String.class);
+                Class<?> type = 
exchange.getContext().getClassResolver().resolveClass(text);
+                if (type != null) {
+                    return type;
+                }
+
+                int pos = text.lastIndexOf(".");
+                if (pos > 0) {
+                    String before = text.substring(0, pos);
+                    String after = text.substring(pos + 1);
+                    type = 
exchange.getContext().getClassResolver().resolveClass(before);
+                    if (type != null) {
+                        return ObjectHelper.lookupConstantFieldValue(type, 
after);
+                    }
+                }
+
+                throw 
CamelExecutionException.wrapCamelExecutionException(exchange, new 
ClassNotFoundException("Cannot find type " + text));
+            }
+
+            @Override
+            public String toString() {
+                return "type:" + name;
+            }
+        };
+    }
+
+    /**
+     * Returns an expression for the property value of exchange with the given 
name invoking methods defined
+     * in a simple OGNL notation
+     *
+     * @param ognl  methods to invoke on the property in a simple OGNL syntax
+     */
+    public static Expression propertyOgnlExpression(final String ognl) {
+        return new KeyedOgnlExpressionAdapter(ognl, "propertyOgnl(" + ognl + 
")",
+            new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() {
+                public Object getKeyedEntity(Exchange exchange, String key) {
+                    String text = 
ExpressionBuilder.simpleExpression(key).evaluate(exchange, String.class);
+                    return exchange.getProperty(text);
+                }
+            });
+    }
+
+    /**
+     * Returns the expression for the exchanges exception invoking methods 
defined
+     * in a simple OGNL notation
+     *
+     * @param ognl  methods to invoke on the body in a simple OGNL syntax
+     */
+    public static Expression exchangeExceptionOgnlExpression(final String 
ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                Object exception = exchange.getException();
+                if (exception == null) {
+                    exception = 
exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
+                }
+
+                if (exception == null) {
+                    return null;
+                }
+
+                // ognl is able to evaluate method name if it contains nested 
functions
+                // so we should not eager evaluate ognl as a string
+                return new MethodCallExpression(exception, 
ognl).evaluate(exchange);
+            }
+
+            @Override
+            public String toString() {
+                return "exchangeExceptionOgnl(" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Expression adapter for OGNL expression from Message Header or Exchange 
property
+     */
+    public static class KeyedOgnlExpressionAdapter extends ExpressionAdapter {
+        private final String ognl;
+        private final String toStringValue;
+        private final KeyedEntityRetrievalStrategy 
keyedEntityRetrievalStrategy;
+
+        KeyedOgnlExpressionAdapter(String ognl, String toStringValue,
+                                   KeyedEntityRetrievalStrategy 
keyedEntityRetrievalStrategy) {
+            this.ognl = ognl;
+            this.toStringValue = toStringValue;
+            this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy;
+        }
+
+        public Object evaluate(Exchange exchange) {
+            // try with full name first
+            Object property = 
keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl);
+            if (property != null) {
+                return property;
+            }
+
+
+            // Split ognl except when this is not a Map, Array
+            // and we would like to keep the dots within the key name
+            List<String> methods = OgnlHelper.splitOgnl(ognl);
+
+            String key = methods.get(0);
+            String keySuffix = "";
+            // if ognl starts with a key inside brackets (eg: [foo.bar])
+            // remove starting and ending brackets from key
+            if (key.startsWith("[") && key.endsWith("]")) {
+                key = 
StringHelper.removeLeadingAndEndingQuotes(key.substring(1, key.length() - 1));
+                keySuffix = StringHelper.after(methods.get(0), key);
+            }
+            // remove any OGNL operators so we got the pure key name
+            key = OgnlHelper.removeOperators(key);
+
+
+            property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, 
key);
+            if (property == null) {
+                return null;
+            }
+            // the remainder is the rest of the ognl without the key
+            String remainder = StringHelper.after(ognl, key + keySuffix);
+            return new MethodCallExpression(property, 
remainder).evaluate(exchange);
+        }
+
+        @Override
+        public String toString() {
+            return toStringValue;
+        }
+
+        /**
+         * Strategy to retrieve the value based on the key
+         */
+        public interface KeyedEntityRetrievalStrategy {
+            Object getKeyedEntity(Exchange exchange, String key);
+        }
+    }
+}
diff --git 
a/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 01b58c0..4337273 100644
--- 
a/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -20,6 +20,7 @@ import java.util.Map;
 
 import org.apache.camel.Expression;
 import org.apache.camel.builder.ExpressionBuilder;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
 import org.apache.camel.language.simple.types.SimpleParserException;
 import org.apache.camel.language.simple.types.SimpleToken;
 import org.apache.camel.util.ObjectHelper;
@@ -102,7 +103,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             if (invalid) {
                 throw new SimpleParserException("Valid syntax: 
${camelContext.OGNL} was: " + function, token.getIndex());
             }
-            return ExpressionBuilder.camelContextOgnlExpression(remainder);
+            return 
SimpleExpressionBuilder.camelContextOgnlExpression(remainder);
         }
 
         // Exception OGNL
@@ -112,7 +113,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             if (invalid) {
                 throw new SimpleParserException("Valid syntax: 
${exception.OGNL} was: " + function, token.getIndex());
             }
-            return 
ExpressionBuilder.exchangeExceptionOgnlExpression(remainder);
+            return 
SimpleExpressionBuilder.exchangeExceptionOgnlExpression(remainder);
         }
 
         // exchange property
@@ -135,7 +136,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
 
             if (OgnlHelper.isValidOgnlExpression(remainder)) {
                 // ognl based property
-                return ExpressionBuilder.propertyOgnlExpression(remainder);
+                return 
SimpleExpressionBuilder.propertyOgnlExpression(remainder);
             } else {
                 // regular property
                 return ExpressionBuilder.exchangePropertyExpression(remainder);
@@ -159,7 +160,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             if (invalid) {
                 throw new SimpleParserException("Valid syntax: 
${exchange.OGNL} was: " + function, token.getIndex());
             }
-            return ExpressionBuilder.exchangeOgnlExpression(remainder);
+            return SimpleExpressionBuilder.exchangeOgnlExpression(remainder);
         }
 
         // file: prefix
@@ -176,9 +177,9 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         if (remainder != null) {
             String[] parts = remainder.split(":", 2);
             if (parts.length == 1) {
-                return ExpressionBuilder.dateExpression(parts[0]);
+                return SimpleExpressionBuilder.dateExpression(parts[0]);
             } else if (parts.length == 2) {
-                return ExpressionBuilder.dateExpression(parts[0], parts[1]);
+                return SimpleExpressionBuilder.dateExpression(parts[0], 
parts[1]);
             }
         }
 
@@ -189,7 +190,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             if (parts.length < 3) {
                 throw new SimpleParserException("Valid syntax: 
${date-with-timezone:command:timezone:pattern} was: " + function, 
token.getIndex());
             }
-            return ExpressionBuilder.dateExpression(parts[0], parts[1], 
parts[2]);
+            return SimpleExpressionBuilder.dateExpression(parts[0], parts[1], 
parts[2]);
         }
 
         // bean: prefix
@@ -241,9 +242,9 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         // const: prefix
         remainder = ifStartsWithReturnRemainder("type:", function);
         if (remainder != null) {
-            Expression exp = ExpressionBuilder.typeExpression(remainder);
+            Expression exp = SimpleExpressionBuilder.typeExpression(remainder);
             // we want to cache this expression so we wont re-evaluate it as 
the type/constant wont change
-            return ExpressionBuilder.cacheExpression(exp);
+            return SimpleExpressionBuilder.cacheExpression(exp);
         }
 
         // miscellaneous functions
@@ -274,7 +275,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 if (invalid) {
                     throw new SimpleParserException("Valid syntax: 
${bodyAs(type).OGNL} was: " + function, token.getIndex());
                 }
-                return ExpressionBuilder.bodyOgnlExpression(type, remainder);
+                return SimpleExpressionBuilder.bodyOgnlExpression(type, 
remainder);
             } else {
                 return ExpressionBuilder.bodyExpression(type);
             }
@@ -294,9 +295,9 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 if (invalid) {
                     throw new SimpleParserException("Valid syntax: 
${mandatoryBodyAs(type).OGNL} was: " + function, token.getIndex());
                 }
-                return ExpressionBuilder.mandatoryBodyOgnlExpression(type, 
remainder);
+                return 
SimpleExpressionBuilder.mandatoryBodyOgnlExpression(type, remainder);
             } else {
-                return ExpressionBuilder.mandatoryBodyExpression(type);
+                return SimpleExpressionBuilder.mandatoryBodyExpression(type);
             }
         }
 
@@ -312,7 +313,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             if (invalid) {
                 throw new SimpleParserException("Valid syntax: ${body.OGNL} 
was: " + function, token.getIndex());
             }
-            return ExpressionBuilder.bodyOgnlExpression(remainder);
+            return SimpleExpressionBuilder.bodyOgnlExpression(remainder);
         }
 
         // headerAs
@@ -370,7 +371,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
 
             if (OgnlHelper.isValidOgnlExpression(key)) {
                 // ognl based header
-                return ExpressionBuilder.headersOgnlExpression(key);
+                return SimpleExpressionBuilder.headersOgnlExpression(key);
             } else {
                 // regular header
                 return ExpressionBuilder.headerExpression(key);
@@ -415,7 +416,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         } else if (ObjectHelper.equal(expression, "stepId")) {
             return ExpressionBuilder.stepIdExpression();
         } else if (ObjectHelper.equal(expression, "null")) {
-            return ExpressionBuilder.nullExpression();
+            return SimpleExpressionBuilder.nullExpression();
         }
 
         return null;
@@ -423,33 +424,33 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
 
     private Expression createSimpleFileExpression(String remainder, boolean 
strict) {
         if (ObjectHelper.equal(remainder, "name")) {
-            return ExpressionBuilder.fileNameExpression();
+            return SimpleExpressionBuilder.fileNameExpression();
         } else if (ObjectHelper.equal(remainder, "name.noext")) {
-            return ExpressionBuilder.fileNameNoExtensionExpression();
+            return SimpleExpressionBuilder.fileNameNoExtensionExpression();
         } else if (ObjectHelper.equal(remainder, "name.noext.single")) {
-            return ExpressionBuilder.fileNameNoExtensionSingleExpression();
+            return 
SimpleExpressionBuilder.fileNameNoExtensionSingleExpression();
         } else if (ObjectHelper.equal(remainder, "name.ext") || 
ObjectHelper.equal(remainder, "ext")) {
-            return ExpressionBuilder.fileExtensionExpression();
+            return SimpleExpressionBuilder.fileExtensionExpression();
         } else if (ObjectHelper.equal(remainder, "name.ext.single")) {
-            return ExpressionBuilder.fileExtensionSingleExpression();
+            return SimpleExpressionBuilder.fileExtensionSingleExpression();
         } else if (ObjectHelper.equal(remainder, "onlyname")) {
-            return ExpressionBuilder.fileOnlyNameExpression();
+            return SimpleExpressionBuilder.fileOnlyNameExpression();
         } else if (ObjectHelper.equal(remainder, "onlyname.noext")) {
-            return ExpressionBuilder.fileOnlyNameNoExtensionExpression();
+            return SimpleExpressionBuilder.fileOnlyNameNoExtensionExpression();
         } else if (ObjectHelper.equal(remainder, "onlyname.noext.single")) {
-            return ExpressionBuilder.fileOnlyNameNoExtensionSingleExpression();
+            return 
SimpleExpressionBuilder.fileOnlyNameNoExtensionSingleExpression();
         } else if (ObjectHelper.equal(remainder, "parent")) {
-            return ExpressionBuilder.fileParentExpression();
+            return SimpleExpressionBuilder.fileParentExpression();
         } else if (ObjectHelper.equal(remainder, "path")) {
-            return ExpressionBuilder.filePathExpression();
+            return SimpleExpressionBuilder.filePathExpression();
         } else if (ObjectHelper.equal(remainder, "absolute")) {
-            return ExpressionBuilder.fileAbsoluteExpression();
+            return SimpleExpressionBuilder.fileAbsoluteExpression();
         } else if (ObjectHelper.equal(remainder, "absolute.path")) {
-            return ExpressionBuilder.fileAbsolutePathExpression();
+            return SimpleExpressionBuilder.fileAbsolutePathExpression();
         } else if (ObjectHelper.equal(remainder, "length") || 
ObjectHelper.equal(remainder, "size")) {
-            return ExpressionBuilder.fileSizeExpression();
+            return SimpleExpressionBuilder.fileSizeExpression();
         } else if (ObjectHelper.equal(remainder, "modified")) {
-            return ExpressionBuilder.fileLastModifiedExpression();
+            return SimpleExpressionBuilder.fileLastModifiedExpression();
         }
         if (strict) {
             throw new SimpleParserException("Unknown file language syntax: " + 
remainder, token.getIndex());
@@ -472,9 +473,9 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 if (tokens.length > 2) {
                     throw new SimpleParserException("Valid syntax: 
${random(min,max)} or ${random(max)} was: " + function, token.getIndex());
                 }
-                return ExpressionBuilder.randomExpression(tokens[0].trim(), 
tokens[1].trim());
+                return 
SimpleExpressionBuilder.randomExpression(tokens[0].trim(), tokens[1].trim());
             } else {
-                return ExpressionBuilder.randomExpression("0", values.trim());
+                return SimpleExpressionBuilder.randomExpression("0", 
values.trim());
             }
         }
 
@@ -487,7 +488,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
             String exp = "${body}";
             int num = Integer.parseInt(values.trim());
-            return ExpressionBuilder.skipExpression(exp, num);
+            return SimpleExpressionBuilder.skipExpression(exp, num);
         }
 
         // collate function
@@ -499,7 +500,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
             String exp = "${body}";
             int num = Integer.parseInt(values.trim());
-            return ExpressionBuilder.collateExpression(exp, num);
+            return SimpleExpressionBuilder.collateExpression(exp, num);
         }
 
         // messageHistory function
@@ -512,9 +513,9 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             } else {
                 detailed = Boolean.valueOf(values);
             }
-            return ExpressionBuilder.messageHistoryExpression(detailed);
+            return SimpleExpressionBuilder.messageHistoryExpression(detailed);
         } else if (ObjectHelper.equal(function, "messageHistory")) {
-            return ExpressionBuilder.messageHistoryExpression(true);
+            return SimpleExpressionBuilder.messageHistoryExpression(true);
         }
         return null;
     }

Reply via email to