You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/10/02 08:50:43 UTC

[camel] 03/14: CAMEL-15605: Languages should be singleton for better performance.

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

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

commit 3f0349f79be94141afacb4edfd44a25b7deb2296
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Oct 1 17:06:04 2020 +0200

    CAMEL-15605: Languages should be singleton for better performance.
---
 .../language/TokenizerExpressionReifier.java       | 41 ++++++-----
 .../language/XMLTokenizerExpressionReifier.java    | 37 +++++++---
 .../camel/language/tokenizer/TokenizeLanguage.java | 82 +++++++---------------
 .../apache/camel/language/LanguageServiceTest.java | 18 -----
 .../org/apache/camel/language/TokenizerTest.java   |  4 +-
 .../org/apache/camel/support/CustomizersTest.java  |  8 ++-
 .../support/PredicateToExpressionAdapter.java      |  3 +
 .../language/xtokenizer/XMLTokenizeLanguage.java   | 21 ++++--
 8 files changed, 103 insertions(+), 111 deletions(-)

diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/TokenizerExpressionReifier.java b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/TokenizerExpressionReifier.java
index 0f12413..02576d4 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/TokenizerExpressionReifier.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/TokenizerExpressionReifier.java
@@ -29,32 +29,29 @@ import org.apache.camel.support.ExpressionToPredicateAdapter;
 
 public class TokenizerExpressionReifier extends ExpressionReifier<TokenizerExpression> {
 
-    // TODO: Update me
-
     public TokenizerExpressionReifier(CamelContext camelContext, ExpressionDefinition definition) {
         super(camelContext, (TokenizerExpression) definition);
     }
 
-    @Override
-    protected void configureLanguage(Language language) {
-        Map<String, Object> props = new HashMap<>();
+    protected Map<String, Object> createProperties() {
+        Map<String, Object> properties = new HashMap<>(10);
         // special for new line tokens, if defined from XML then its 2
         // characters, so we replace that back to a single char
         String token = definition.getToken();
         if (token.startsWith("\\n")) {
             token = '\n' + token.substring(2);
         }
-        props.put("token", token);
-        props.put("endToken", definition.getEndToken());
-        props.put("inheritNamespaceTagName", definition.getInheritNamespaceTagName());
-        props.put("headerName", definition.getHeaderName());
-        props.put("groupDelimiter", definition.getGroupDelimiter());
-        props.put("regex", definition.getRegex());
-        props.put("xml", definition.getXml());
-        props.put("includeTokens", definition.getIncludeTokens());
-        props.put("group", definition.getGroup());
-        props.put("skipFirst", definition.getSkipFirst());
-        setProperties(language, props);
+        properties.put("token", token);
+        properties.put("endToken", definition.getEndToken());
+        properties.put("inheritNamespaceTagName", definition.getInheritNamespaceTagName());
+        properties.put("headerName", definition.getHeaderName());
+        properties.put("groupDelimiter", definition.getGroupDelimiter());
+        properties.put("regex", definition.getRegex());
+        properties.put("xml", definition.getXml());
+        properties.put("includeTokens", definition.getIncludeTokens());
+        properties.put("group", definition.getGroup());
+        properties.put("skipFirst", definition.getSkipFirst());
+        return properties;
     }
 
     @Override
@@ -63,4 +60,16 @@ public class TokenizerExpressionReifier extends ExpressionReifier<TokenizerExpre
         return ExpressionToPredicateAdapter.toPredicate(exp);
     }
 
+    @Override
+    protected Expression createExpression(Language language, String exp) {
+        // method call does not use the string exp so its not in use
+        return language.createExpression(createProperties());
+    }
+
+    @Override
+    protected Predicate createPredicate(Language language, String exp) {
+        // method call does not use the string exp so its not in use
+        return language.createPredicate(createProperties());
+    }
+
 }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XMLTokenizerExpressionReifier.java b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XMLTokenizerExpressionReifier.java
index aac9085..331a075 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XMLTokenizerExpressionReifier.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/language/XMLTokenizerExpressionReifier.java
@@ -24,28 +24,42 @@ import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
 import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.model.language.XMLTokenizerExpression;
+import org.apache.camel.spi.Language;
 import org.apache.camel.spi.NamespaceAware;
+import org.apache.camel.support.ExpressionToPredicateAdapter;
 
 public class XMLTokenizerExpressionReifier extends ExpressionReifier<XMLTokenizerExpression> {
 
-    // TODO: Update me
-
     public XMLTokenizerExpressionReifier(CamelContext camelContext, ExpressionDefinition definition) {
         super(camelContext, (XMLTokenizerExpression) definition);
     }
 
     @Override
-    protected void configureExpression(Expression expression) {
-        bindProperties(expression);
-        configureNamespaceAware(expression);
-        super.configureExpression(expression);
+    public Predicate createPredicate() {
+        Expression exp = createExpression();
+        return ExpressionToPredicateAdapter.toPredicate(exp);
+    }
+
+    @Override
+    protected Expression createExpression(Language language, String exp) {
+        // method call does not use the string exp so its not in use
+        return language.createExpression(createProperties());
+    }
+
+    @Override
+    protected Predicate createPredicate(Language language, String exp) {
+        // method call does not use the string exp so its not in use
+        return language.createPredicate(createProperties());
     }
 
     @Override
     protected void configurePredicate(Predicate predicate) {
-        bindProperties(predicate);
         configureNamespaceAware(predicate);
-        super.configurePredicate(predicate);
+    }
+
+    @Override
+    protected void configureExpression(Expression expression) {
+        configureNamespaceAware(expression);
     }
 
     protected void configureNamespaceAware(Object builder) {
@@ -55,12 +69,13 @@ public class XMLTokenizerExpressionReifier extends ExpressionReifier<XMLTokenize
         }
     }
 
-    protected void bindProperties(Object target) {
-        Map<String, Object> properties = new HashMap<>();
+    protected Map<String, Object> createProperties() {
+        Map<String, Object> properties = new HashMap<>(3);
         properties.put("headerName", definition.getHeaderName());
         properties.put("mode", definition.getMode());
         properties.put("group", definition.getGroup());
-        setProperties(target, properties);
+        properties.put("path", definition.getExpression());
+        return properties;
     }
 
 }
diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
index 20df970..aa087ae 100644
--- a/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
+++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
@@ -16,15 +16,13 @@
  */
 package org.apache.camel.language.tokenizer;
 
-import org.apache.camel.CamelContext;
+import java.util.Map;
+
 import org.apache.camel.Expression;
-import org.apache.camel.IsSingleton;
 import org.apache.camel.Predicate;
-import org.apache.camel.spi.Language;
-import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.support.ExpressionToPredicateAdapter;
+import org.apache.camel.support.LanguageSupport;
 import org.apache.camel.support.builder.ExpressionBuilder;
-import org.apache.camel.support.component.PropertyConfigurerSupport;
 import org.apache.camel.util.ObjectHelper;
 
 /**
@@ -40,7 +38,7 @@ import org.apache.camel.util.ObjectHelper;
  * <tt>token</tt> and <tt>endToken</tt>. And the <tt>xml</tt> mode supports the <tt>inheritNamespaceTagName</tt> option.
  */
 @org.apache.camel.spi.annotations.Language("tokenize")
-public class TokenizeLanguage implements Language, IsSingleton, PropertyConfigurer {
+public class TokenizeLanguage extends LanguageSupport {
 
     private String token;
     private String endToken;
@@ -93,53 +91,6 @@ public class TokenizeLanguage implements Language, IsSingleton, PropertyConfigur
     }
 
     @Override
-    public boolean configure(CamelContext camelContext, Object target, String name, Object value, boolean ignoreCase) {
-        if (target != this) {
-            throw new IllegalStateException("Can only configure our own instance !");
-        }
-        switch (ignoreCase ? name.toLowerCase() : name) {
-            case "token":
-                setToken(PropertyConfigurerSupport.property(camelContext, String.class, value));
-                return true;
-            case "endtoken":
-            case "endToken":
-                setEndToken(PropertyConfigurerSupport.property(camelContext, String.class, value));
-                return true;
-            case "inheritnamespacetagname":
-            case "inheritNamespaceTagName":
-                setInheritNamespaceTagName(PropertyConfigurerSupport.property(camelContext, String.class, value));
-                return true;
-            case "headername":
-            case "headerName":
-                setHeaderName(PropertyConfigurerSupport.property(camelContext, String.class, value));
-                return true;
-            case "regex":
-                setRegex(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
-                return true;
-            case "xml":
-                setXml(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
-                return true;
-            case "includetokens":
-            case "includeTokens":
-                setIncludeTokens(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
-                return true;
-            case "group":
-                setGroup(PropertyConfigurerSupport.property(camelContext, String.class, value));
-                return true;
-            case "groupdelimiter":
-            case "groupDelimiter":
-                setGroupDelimiter(PropertyConfigurerSupport.property(camelContext, String.class, value));
-                return true;
-            case "skipfirst":
-            case "skipFirst":
-                setSkipFirst(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    @Override
     public Predicate createPredicate(String expression) {
         return ExpressionToPredicateAdapter.toPredicate(createExpression(expression));
     }
@@ -201,6 +152,27 @@ public class TokenizeLanguage implements Language, IsSingleton, PropertyConfigur
         return createExpression();
     }
 
+    @Override
+    public Predicate createPredicate(Map<String, Object> properties) {
+        return ExpressionToPredicateAdapter.toPredicate(createExpression(properties));
+    }
+
+    @Override
+    public Expression createExpression(Map<String, Object> properties) {
+        TokenizeLanguage answer = new TokenizeLanguage();
+        answer.setInheritNamespaceTagName(property(String.class, properties, "inheritNamespaceTagName", null));
+        answer.setToken(property(String.class, properties, "token", null));
+        answer.setEndToken(property(String.class, properties, "endToken", null));
+        answer.setHeaderName(property(String.class, properties, "headerName", null));
+        answer.setRegex(property(boolean.class, properties, "regex", false));
+        answer.setXml(property(boolean.class, properties, "xml", false));
+        answer.setIncludeTokens(property(boolean.class, properties, "includeTokens", false));
+        answer.setGroup(property(String.class, properties, "group", null));
+        answer.setGroupDelimiter(property(String.class, properties, "groupDelimiter", null));
+        answer.setSkipFirst(property(boolean.class, properties, "skipFirst", false));
+        return answer.createExpression();
+    }
+
     public String getToken() {
         return token;
     }
@@ -281,8 +253,4 @@ public class TokenizeLanguage implements Language, IsSingleton, PropertyConfigur
         this.skipFirst = skipFirst;
     }
 
-    @Override
-    public boolean isSingleton() {
-        return false;
-    }
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/language/LanguageServiceTest.java b/core/camel-core/src/test/java/org/apache/camel/language/LanguageServiceTest.java
index 6eb339a..fe5d3d0 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/LanguageServiceTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/LanguageServiceTest.java
@@ -61,24 +61,6 @@ public class LanguageServiceTest extends ContextTestSupport {
         assertTrue(context.getLanguageNames().isEmpty());
     }
 
-    @Test
-    public void testNonSingletonLanguage() throws Exception {
-        Language tol = context.resolveLanguage("tokenize");
-        assertNotNull(tol);
-        // simple language is resolved by default hence why there is 2
-        assertEquals(2, context.getLanguageNames().size());
-
-        // resolve again, should find another instance
-        Language tol2 = context.resolveLanguage("tokenize");
-        assertNotNull(tol2);
-        assertNotSame(tol, tol2);
-        // simple language is resolved by default hence why there is 2
-        assertEquals(2, context.getLanguageNames().size());
-
-        context.stop();
-        assertTrue(context.getLanguageNames().isEmpty());
-    }
-
     public class MyLanguage extends ServiceSupport implements Language, IsSingleton {
 
         private String state;
diff --git a/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java b/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
index 3931b72..40debe8 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
@@ -37,7 +37,7 @@ public class TokenizerTest extends ExchangeTestSupport {
     }
 
     @Test
-    public void testTokenizeHeaderWithStringContructor() throws Exception {
+    public void testTokenizeHeaderWithStringConstructor() throws Exception {
         TokenizerExpression definition = new TokenizerExpression(",");
         definition.setHeaderName("names");
 
@@ -119,7 +119,7 @@ public class TokenizerTest extends ExchangeTestSupport {
         assertEquals("names", lan.getHeaderName());
         assertEquals(",", lan.getToken());
         assertEquals(false, lan.isRegex());
-        assertEquals(false, lan.isSingleton());
+        assertEquals(true, lan.isSingleton());
     }
 
     @Test
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java b/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java
index 151f67d..d978540 100644
--- a/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java
@@ -351,15 +351,16 @@ public class CustomizersTest {
                 "tokenize-customizer",
                 LanguageCustomizer.forType(TokenizeLanguage.class, target -> target.setGroup("" + counter.incrementAndGet())));
 
+        // singleton language so its customized once
         Language l1 = context.resolveLanguage("tokenize");
         assertTrue(l1 instanceof TokenizeLanguage);
         assertEquals("1", ((TokenizeLanguage) l1).getGroup());
 
         Language l2 = context.resolveLanguage("tokenize");
         assertTrue(l2 instanceof TokenizeLanguage);
-        assertEquals("2", ((TokenizeLanguage) l2).getGroup());
+        assertEquals("1", ((TokenizeLanguage) l2).getGroup());
 
-        assertNotSame(l1, l2);
+        assertSame(l1, l2);
     }
 
     @Test
@@ -374,6 +375,7 @@ public class CustomizersTest {
                 "tokenize-customizer",
                 LanguageCustomizer.forType(TokenizeLanguage.class, target -> target.setGroup("" + counter.incrementAndGet())));
 
+        // singleton language so its customized once
         Language l1 = context.resolveLanguage("tokenize");
         assertTrue(l1 instanceof TokenizeLanguage);
         assertNull(((TokenizeLanguage) l1).getGroup());
@@ -382,7 +384,7 @@ public class CustomizersTest {
         assertTrue(l2 instanceof TokenizeLanguage);
         assertNull(((TokenizeLanguage) l2).getGroup());
 
-        assertNotSame(l1, l2);
+        assertSame(l1, l2);
     }
 
     @ParameterizedTest
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/PredicateToExpressionAdapter.java b/core/camel-support/src/main/java/org/apache/camel/support/PredicateToExpressionAdapter.java
index 6e6f138..13f8b16 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/PredicateToExpressionAdapter.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/PredicateToExpressionAdapter.java
@@ -45,6 +45,9 @@ public final class PredicateToExpressionAdapter implements Expression {
      * Converts the given predicate into an {@link org.apache.camel.Expression}
      */
     public static Expression toExpression(final Predicate predicate) {
+        if (predicate instanceof Expression) {
+            return (Expression) predicate;
+        }
         return new PredicateToExpressionAdapter(predicate);
     }
 
diff --git a/core/camel-xml-jaxp/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java b/core/camel-xml-jaxp/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
index 50fbeef..876957a 100644
--- a/core/camel-xml-jaxp/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
+++ b/core/camel-xml-jaxp/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.language.xtokenizer;
 
+import java.util.Map;
+
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
 import org.apache.camel.spi.annotations.Language;
@@ -87,6 +89,21 @@ public class XMLTokenizeLanguage extends LanguageSupport {
         return expr;
     }
 
+    @Override
+    public Predicate createPredicate(Map<String, Object> properties) {
+        return ExpressionToPredicateAdapter.toPredicate(createExpression(properties));
+    }
+
+    @Override
+    public Expression createExpression(Map<String, Object> properties) {
+        XMLTokenizeLanguage answer = new XMLTokenizeLanguage();
+        answer.setHeaderName(property(String.class, properties, "headerName", null));
+        answer.setMode(property(char.class, properties, "mode", 'i'));
+        answer.setGroup(property(int.class, properties, "group", 1));
+        String path = property(String.class, properties, "path", null);
+        return answer.createExpression(path);
+    }
+
     public String getHeaderName() {
         return headerName;
     }
@@ -127,8 +144,4 @@ public class XMLTokenizeLanguage extends LanguageSupport {
         this.namespaces = namespaces;
     }
 
-    @Override
-    public boolean isSingleton() {
-        return false;
-    }
 }