Repository: camel
Updated Branches:
  refs/heads/master bac9ddd4b -> 1c86ed716


CAMEL-11484: Optimise - Simple Language / ExpressionBuilder can use cache of 
frequent used expressions when having nested functions


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/1c86ed71
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/1c86ed71
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/1c86ed71

Branch: refs/heads/master
Commit: 1c86ed71607ee48d7d2726278232905857d0c4f5
Parents: bac9ddd
Author: Claus Ibsen <davscl...@apache.org>
Authored: Fri Jun 30 10:51:59 2017 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Fri Jun 30 11:51:47 2017 +0200

----------------------------------------------------------------------
 .../language/simple/SimpleExpressionParser.java | 14 ++++++++-
 .../camel/language/simple/SimpleLanguage.java   |  8 +++---
 .../language/simple/SimplePredicateParser.java  | 12 +++++++-
 .../simple/ast/SimpleFunctionExpression.java    | 30 ++++++++++++++++++--
 .../simple/ast/SimpleFunctionStart.java         | 12 +++++---
 .../SimpleLanguageTransformRandomTest.java      |  3 ++
 .../camel/itest/jmh/SimpleExpressionTest.java   | 11 +++----
 7 files changed, 71 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionParser.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionParser.java
 
b/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionParser.java
index bf5fe8d..0e2bd9c 100644
--- 
a/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionParser.java
+++ 
b/camel-core/src/main/java/org/apache/camel/language/simple/SimpleExpressionParser.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
 import org.apache.camel.builder.ExpressionBuilder;
 import org.apache.camel.language.simple.ast.LiteralExpression;
 import org.apache.camel.language.simple.ast.LiteralNode;
@@ -32,21 +33,32 @@ import 
org.apache.camel.language.simple.types.SimpleIllegalSyntaxException;
 import org.apache.camel.language.simple.types.SimpleParserException;
 import org.apache.camel.language.simple.types.SimpleToken;
 import org.apache.camel.language.simple.types.TokenType;
+import org.apache.camel.util.LRUCache;
 
 /**
  * A parser to parse simple language as a Camel {@link Expression}
  */
 public class SimpleExpressionParser extends BaseSimpleParser {
 
+    // use caches to avoid re-parsing the same expressions over and over again
+    private LRUCache<String, Expression> cacheExpression;
+
     @Deprecated
     public SimpleExpressionParser(String expression) {
         super(expression, true);
     }
 
+    @Deprecated
     public SimpleExpressionParser(String expression, boolean allowEscape) {
         super(expression, allowEscape);
     }
 
+    public SimpleExpressionParser(String expression, boolean allowEscape,
+                                  LRUCache<String, Expression> 
cacheExpression) {
+        super(expression, allowEscape);
+        this.cacheExpression = cacheExpression;
+    }
+
     public Expression parseExpression() {
         clear();
         try {
@@ -141,7 +153,7 @@ public class SimpleExpressionParser extends 
BaseSimpleParser {
         if (token.getType().isFunctionStart()) {
             // starting a new function
             functions.incrementAndGet();
-            return new SimpleFunctionStart(token);
+            return new SimpleFunctionStart(token, cacheExpression);
         } else if (functions.get() > 0 && token.getType().isFunctionEnd()) {
             // there must be a start function already, to let this be a end 
function
             functions.decrementAndGet();

http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java 
b/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
index d62e909..1767dc3 100644
--- 
a/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
+++ 
b/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
@@ -155,10 +155,10 @@ public class SimpleLanguage extends LanguageSupport 
implements StaticService {
             answer = 
SimpleBackwardsCompatibleParser.parsePredicate(expression, allowEscape);
             if (answer == null) {
                 // use the new parser
-                SimplePredicateParser parser = new 
SimplePredicateParser(expression, allowEscape);
+                SimplePredicateParser parser = new 
SimplePredicateParser(expression, allowEscape, cacheExpression);
                 answer = parser.parsePredicate();
             }
-            if (cachePredicate != null) {
+            if (cachePredicate != null && answer != null) {
                 cachePredicate.put(expression, answer);
             }
         }
@@ -179,10 +179,10 @@ public class SimpleLanguage extends LanguageSupport 
implements StaticService {
             answer = 
SimpleBackwardsCompatibleParser.parseExpression(expression, allowEscape);
             if (answer == null) {
                 // use the new parser
-                SimpleExpressionParser parser = new 
SimpleExpressionParser(expression, allowEscape);
+                SimpleExpressionParser parser = new 
SimpleExpressionParser(expression, allowEscape, cacheExpression);
                 answer = parser.parseExpression();
             }
-            if (cacheExpression != null) {
+            if (cacheExpression != null && answer != null) {
                 cacheExpression.put(expression, answer);
             }
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/camel-core/src/main/java/org/apache/camel/language/simple/SimplePredicateParser.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/language/simple/SimplePredicateParser.java
 
b/camel-core/src/main/java/org/apache/camel/language/simple/SimplePredicateParser.java
index a9576b1..a127f4a 100644
--- 
a/camel-core/src/main/java/org/apache/camel/language/simple/SimplePredicateParser.java
+++ 
b/camel-core/src/main/java/org/apache/camel/language/simple/SimplePredicateParser.java
@@ -47,21 +47,31 @@ import 
org.apache.camel.language.simple.types.SimpleParserException;
 import org.apache.camel.language.simple.types.SimpleToken;
 import org.apache.camel.language.simple.types.TokenType;
 import org.apache.camel.util.ExpressionToPredicateAdapter;
+import org.apache.camel.util.LRUCache;
 
 /**
  * A parser to parse simple language as a Camel {@link Predicate}
  */
 public class SimplePredicateParser extends BaseSimpleParser {
 
+    // use caches to avoid re-parsing the same expressions over and over again
+    private LRUCache<String, Expression> cacheExpression;
+
     @Deprecated
     public SimplePredicateParser(String expression) {
         super(expression, true);
     }
 
+    @Deprecated
     public SimplePredicateParser(String expression, boolean allowEscape) {
         super(expression, allowEscape);
     }
 
+    public SimplePredicateParser(String expression, boolean allowEscape, 
LRUCache<String, Expression> cacheExpression) {
+        super(expression, allowEscape);
+        this.cacheExpression = cacheExpression;
+    }
+
     public Predicate parsePredicate() {
         clear();
         try {
@@ -223,7 +233,7 @@ public class SimplePredicateParser extends BaseSimpleParser 
{
                                   AtomicBoolean startFunction) {
         if (token.getType().isFunctionStart()) {
             startFunction.set(true);
-            return new SimpleFunctionStart(token);
+            return new SimpleFunctionStart(token, cacheExpression);
         } else if (token.getType().isFunctionEnd()) {
             startFunction.set(false);
             return new SimpleFunctionEnd(token);

http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 5affb51..7c4caf3 100644
--- 
a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -20,6 +20,7 @@ import org.apache.camel.Expression;
 import org.apache.camel.builder.ExpressionBuilder;
 import org.apache.camel.language.simple.types.SimpleParserException;
 import org.apache.camel.language.simple.types.SimpleToken;
+import org.apache.camel.util.LRUCache;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.OgnlHelper;
 import org.apache.camel.util.StringHelper;
@@ -30,10 +31,19 @@ import org.apache.camel.util.StringHelper;
  */
 public class SimpleFunctionExpression extends LiteralExpression {
 
+    // use caches to avoid re-parsing the same expressions over and over again
+    private LRUCache<String, Expression> cacheExpression;
+
+    @Deprecated
     public SimpleFunctionExpression(SimpleToken token) {
         super(token);
     }
 
+    public SimpleFunctionExpression(SimpleToken token, LRUCache<String, 
Expression> cacheExpression) {
+        super(token);
+        this.cacheExpression = cacheExpression;
+    }
+
     /**
      * Creates a Camel {@link Expression} based on this model.
      *
@@ -42,7 +52,15 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
     @Override
     public Expression createExpression(String expression) {
         String function = text.toString();
-        return createSimpleExpression(function, true);
+
+        Expression answer = cacheExpression != null ? 
cacheExpression.get(function) : null;
+        if (answer == null) {
+            answer = createSimpleExpression(function, true);
+            if (cacheExpression != null && answer != null) {
+                cacheExpression.put(function, answer);
+            }
+        }
+        return answer;
     }
 
     /**
@@ -57,7 +75,15 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
      */
     public Expression createExpression(String expression, boolean strict) {
         String function = text.toString();
-        return createSimpleExpression(function, strict);
+
+        Expression answer = cacheExpression != null ? 
cacheExpression.get(function) : null;
+        if (answer == null) {
+            answer = createSimpleExpression(function, strict);
+            if (cacheExpression != null && answer != null) {
+                cacheExpression.put(function, answer);
+            }
+        }
+        return answer;
     }
 
     private Expression createSimpleExpression(String function, boolean strict) 
{

http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionStart.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionStart.java
 
b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionStart.java
index e505548..5198789 100644
--- 
a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionStart.java
+++ 
b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionStart.java
@@ -21,6 +21,7 @@ import org.apache.camel.Expression;
 import org.apache.camel.language.simple.types.SimpleIllegalSyntaxException;
 import org.apache.camel.language.simple.types.SimpleParserException;
 import org.apache.camel.language.simple.types.SimpleToken;
+import org.apache.camel.util.LRUCache;
 import org.apache.camel.util.StringHelper;
 
 /**
@@ -28,11 +29,14 @@ import org.apache.camel.util.StringHelper;
  */
 public class SimpleFunctionStart extends BaseSimpleNode implements BlockStart {
 
-    private CompositeNodes block;
+    // use caches to avoid re-parsing the same expressions over and over again
+    private final LRUCache<String, Expression> cacheExpression;
+    private final CompositeNodes block;
 
-    public SimpleFunctionStart(SimpleToken token) {
+    public SimpleFunctionStart(SimpleToken token, LRUCache<String, Expression> 
cacheExpression) {
         super(token);
         this.block = new CompositeNodes(token);
+        this.cacheExpression = cacheExpression;
     }
 
     public boolean lazyEval(SimpleNode child) {
@@ -58,7 +62,7 @@ public class SimpleFunctionStart extends BaseSimpleNode 
implements BlockStart {
     }
 
     private Expression doCreateLiteralExpression(final String expression) {
-        SimpleFunctionExpression function = new 
SimpleFunctionExpression(this.getToken());
+        SimpleFunctionExpression function = new 
SimpleFunctionExpression(this.getToken(), cacheExpression);
         LiteralNode literal = (LiteralNode) block.getChildren().get(0);
         function.addText(literal.getText());
         return function.createExpression(expression);
@@ -109,7 +113,7 @@ public class SimpleFunctionStart extends BaseSimpleNode 
implements BlockStart {
                 // we have now concat the block as a String which contains the 
function expression
                 // which we then need to evaluate as a function
                 String exp = sb.toString();
-                SimpleFunctionExpression function = new 
SimpleFunctionExpression(token);
+                SimpleFunctionExpression function = new 
SimpleFunctionExpression(token, cacheExpression);
                 function.addText(exp);
                 try {
                     return function.createExpression(exp).evaluate(exchange, 
type);

http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/camel-core/src/test/java/org/apache/camel/language/SimpleLanguageTransformRandomTest.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/language/SimpleLanguageTransformRandomTest.java
 
b/camel-core/src/test/java/org/apache/camel/language/SimpleLanguageTransformRandomTest.java
index 6280f4c..1642318 100644
--- 
a/camel-core/src/test/java/org/apache/camel/language/SimpleLanguageTransformRandomTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/language/SimpleLanguageTransformRandomTest.java
@@ -30,6 +30,9 @@ public class SimpleLanguageTransformRandomTest extends 
ContextTestSupport {
 
         out = template.requestBodyAndHeader("direct:start", "Random number", 
"max", "20", int.class);
         assertTrue(out <= 20);
+
+        out = template.requestBodyAndHeader("direct:start", "Random number", 
"max", "30", int.class);
+        assertTrue(out <= 30);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/1c86ed71/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/SimpleExpressionTest.java
----------------------------------------------------------------------
diff --git 
a/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/SimpleExpressionTest.java
 
b/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/SimpleExpressionTest.java
index 1c45768..8968af7 100644
--- 
a/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/SimpleExpressionTest.java
+++ 
b/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/SimpleExpressionTest.java
@@ -20,10 +20,9 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
-import org.apache.camel.Expression;
-import org.apache.camel.builder.ExpressionBuilder;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.spi.Language;
 import org.junit.Test;
 import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.Level;
@@ -73,6 +72,7 @@ public class SimpleExpressionTest {
         CamelContext camel;
         String expression = "Hello ${body}";
         Exchange exchange;
+        Language simple;
 
         @Setup(Level.Trial)
         public void initialize() {
@@ -81,9 +81,7 @@ public class SimpleExpressionTest {
                 camel.start();
                 exchange = new DefaultExchange(camel);
                 exchange.getIn().setBody("World");
-
-                // warm up as we use cache on simple expression
-                ExpressionBuilder.simpleExpression(expression);
+                simple = camel.resolveLanguage("simple");
 
             } catch (Exception e) {
                 // ignore
@@ -104,8 +102,7 @@ public class SimpleExpressionTest {
     @Benchmark
     @Measurement(batchSize = 1000)
     public void simpleExpression(BenchmarkState state, Blackhole bh) {
-        Expression simple = 
ExpressionBuilder.simpleExpression(state.expression);
-        String out = simple.evaluate(state.exchange, String.class);
+        String out = 
state.simple.createExpression(state.expression).evaluate(state.exchange, 
String.class);
         if (!out.equals("Hello World")) {
             throw new IllegalArgumentException("Evaluation failed");
         }

Reply via email to