You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pp...@apache.org on 2020/12/03 11:23:41 UTC

[camel] branch master updated: csimple language: support fully pre-compiled use case

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8f332aa  csimple language: support fully pre-compiled use case
8f332aa is described below

commit 8f332aa8d5c22c56208504f30631a21be8858273
Author: Peter Palaga <pp...@redhat.com>
AuthorDate: Tue Dec 1 22:40:47 2020 +0100

    csimple language: support fully pre-compiled use case
---
 .../camel/language/csimple/CSimpleLanguage.java    | 349 +++++++++++++--------
 1 file changed, 217 insertions(+), 132 deletions(-)

diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleLanguage.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleLanguage.java
index 2ff2ca6..4c8eec4 100644
--- a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleLanguage.java
+++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleLanguage.java
@@ -20,7 +20,9 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -49,19 +51,34 @@ public class CSimpleLanguage extends LanguageSupport implements StaticService {
 
     private static final Logger LOG = LoggerFactory.getLogger(CSimpleLanguage.class);
 
-    private final Map<String, CSimpleExpression> compiled = new ConcurrentHashMap<>();
-    private CSimpleCompiler compiler;
+    private final Map<String, CSimpleExpression> compiled;
+    /**
+     * If set, this implementation attempts to compile those expressions at runtime, that are not yet available in
+     * {@link #compiled}; otherwise no compilation attempts will be made at runtime
+     */
+    private final CompilationSupport compilationSupport;
 
-    private String configResource = "camel-csimple.properties";
-    private Set<String> imports = new TreeSet<>();
-    private Map<String, String> aliases = new HashMap<>();
+    public CSimpleLanguage() {
+        this.compiled = new ConcurrentHashMap<>();
+        this.compilationSupport = new CompilationSupport();
+    }
+
+    /**
+     * For 100% pre-compiled use cases
+     *
+     * @param compiled the compiled
+     */
+    private CSimpleLanguage(Map<String, CSimpleExpression> compiled) {
+        this.compiled = compiled;
+        this.compilationSupport = null;
+    }
 
     public String getConfigResource() {
-        return configResource;
+        return compilationSupport().configResource;
     }
 
     public void setConfigResource(String configResource) {
-        this.configResource = configResource;
+        compilationSupport().configResource = configResource;
     }
 
     /**
@@ -70,14 +87,7 @@ public class CSimpleLanguage extends LanguageSupport implements StaticService {
      * @param imports import such as com.foo.MyClass
      */
     public void addImport(String imports) {
-        if (!imports.startsWith("import ")) {
-            imports = "import " + imports;
-        }
-        if (compiler != null) {
-            compiler.addImport(imports);
-        } else {
-            this.imports.add(imports);
-        }
+        compilationSupport().addImport(imports);
     }
 
     /**
@@ -87,132 +97,27 @@ public class CSimpleLanguage extends LanguageSupport implements StaticService {
      * @param value the value
      */
     public void addAliases(String key, String value) {
-        if (compiler != null) {
-            compiler.addAliases(key, value);
-        } else {
-            this.aliases.put(key, value);
-        }
+        compilationSupport().addAliases(key, value);
     }
 
     @Override
     public void init() {
-        // load pre compiled first
-        loadPreCompiled();
-
-        // load optional configuration file
-        loadConfiguration();
-
-        // detect custom compiler (camel-csimple-joor)
-        ExtendedCamelContext ecc = getCamelContext().adapt(ExtendedCamelContext.class);
-        Optional<Class<?>> clazz = ecc.getBootstrapFactoryFinder().findClass(CSimpleCompiler.FACTORY);
-        if (clazz.isPresent()) {
-            compiler = (CSimpleCompiler) ecc.getInjector().newInstance(clazz.get(), false);
-            if (compiler != null) {
-                LOG.info("Detected camel-csimple-joor compiler");
-                if (imports != null) {
-                    imports.forEach(compiler::addImport);
-                }
-                if (aliases != null) {
-                    aliases.forEach(compiler::addAliases);
-                }
-            }
-            ServiceHelper.initService(compiler);
+        if (compilationSupport != null) {
+            compilationSupport.init();
         }
     }
 
     @Override
     public void start() {
-        ServiceHelper.startService(compiler);
+        if (compilationSupport != null) {
+            ServiceHelper.startService(compilationSupport.compiler);
+        }
     }
 
     @Override
     public void stop() {
-        ServiceHelper.stopService(compiler);
-    }
-
-    private void loadPreCompiled() {
-        ExtendedCamelContext ecc = getCamelContext().adapt(ExtendedCamelContext.class);
-        InputStream is = ecc.getClassResolver().loadResourceAsStream(PRE_COMPILED_FILE);
-        if (is != null) {
-            try {
-                String text = IOHelper.loadText(is);
-                String[] lines = text.split("\n");
-                for (String fqn : lines) {
-                    // skip comments
-                    fqn = fqn.trim();
-                    if (fqn.startsWith("#") || fqn.isEmpty()) {
-                        continue;
-                    }
-                    // load class
-                    Class<CSimpleExpression> clazz = ecc.getClassResolver().resolveMandatoryClass(fqn, CSimpleExpression.class);
-                    CSimpleExpression ce = clazz.getConstructor(CamelContext.class).newInstance(getCamelContext());
-                    compiled.put(ce.getText(), ce);
-                }
-            } catch (Exception e) {
-                throw new RuntimeCamelException("Error initializing csimple language", e);
-            } finally {
-                IOHelper.close(is);
-            }
-            if (!compiled.isEmpty()) {
-                LOG.info("Loaded and initialized {} csimple expressions from classpath", compiled.size());
-            }
-        }
-    }
-
-    private void loadConfiguration() {
-        InputStream is;
-        String loaded;
-        is = getCamelContext().getClassResolver().loadResourceAsStream(CONFIG_FILE);
-        try {
-            if (is == null) {
-                // load from file system
-                File file = new File(configResource);
-                if (file.exists()) {
-                    is = new FileInputStream(file);
-                }
-            }
-            if (is == null) {
-                return;
-            }
-            loaded = IOHelper.loadText(is);
-        } catch (IOException e) {
-            throw new RuntimeCamelException("Cannot load " + CONFIG_FILE + " from classpath");
-
-        }
-        IOHelper.close(is);
-
-        int counter1 = 0;
-        int counter2 = 0;
-        String[] lines = loaded.split("\n");
-        for (String line : lines) {
-            line = line.trim();
-            // skip comments
-            if (line.startsWith("#")) {
-                continue;
-            }
-            // imports
-            if (line.startsWith("import ")) {
-                imports.add(line);
-                counter1++;
-                continue;
-            }
-            // aliases as key=value
-            String key = StringHelper.before(line, "=");
-            String value = StringHelper.after(line, "=");
-            if (key != null) {
-                key = key.trim();
-            }
-            if (value != null) {
-                value = value.trim();
-            }
-            if (key != null && value != null) {
-                this.aliases.put(key, value);
-                counter2++;
-            }
-        }
-        if (counter1 > 0 || counter2 > 0) {
-            LOG.info("Loaded csimple language imports: {} and aliases: {} from configuration: {}", counter1, counter2,
-                    configResource);
+        if (compilationSupport != null) {
+            ServiceHelper.stopService(compilationSupport.compiler);
         }
     }
 
@@ -226,8 +131,8 @@ public class CSimpleLanguage extends LanguageSupport implements StaticService {
         text = text.trim();
 
         Predicate answer = compiled.get(text);
-        if (answer == null && compiler != null) {
-            CSimpleExpression exp = compiler.compilePredicate(getCamelContext(), expression);
+        if (answer == null && compilationSupport != null) {
+            CSimpleExpression exp = compilationSupport.compilePredicate(getCamelContext(), expression);
             if (exp != null) {
                 compiled.put(text, exp);
                 answer = exp;
@@ -249,8 +154,8 @@ public class CSimpleLanguage extends LanguageSupport implements StaticService {
         text = text.trim();
 
         Expression answer = compiled.get(text);
-        if (answer == null && compiler != null) {
-            CSimpleExpression exp = compiler.compileExpression(getCamelContext(), expression);
+        if (answer == null && compilationSupport != null) {
+            CSimpleExpression exp = compilationSupport.compileExpression(getCamelContext(), expression);
             if (exp != null) {
                 compiled.put(text, exp);
                 answer = exp;
@@ -262,4 +167,184 @@ public class CSimpleLanguage extends LanguageSupport implements StaticService {
         return answer;
     }
 
+    private CompilationSupport compilationSupport() {
+        if (compilationSupport == null) {
+            throw new IllegalStateException(
+                    "Runtime Compilation is not supported with this " + CSimpleLanguage.class.getSimpleName());
+        }
+        return compilationSupport;
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private Map<String, CSimpleExpression> compiled = new LinkedHashMap<String, CSimpleExpression>();
+
+        public CSimpleLanguage build() {
+            final Map<String, CSimpleExpression> cmpl = Collections.unmodifiableMap(compiled);
+            compiled = null; // invalidate the builder to prevent leaking the mutable collection
+            return new CSimpleLanguage(cmpl);
+        }
+
+        public Builder expression(CSimpleExpression expression) {
+            compiled.put(expression.getText(), expression);
+            return this;
+        }
+    }
+
+    class CompilationSupport {
+        private CSimpleCompiler compiler;
+        private String configResource = "camel-csimple.properties";
+        private final Set<String> imports = new TreeSet<>();
+        private final Map<String, String> aliases = new HashMap<>();
+
+        public void addImport(String imports) {
+            if (!imports.startsWith("import ")) {
+                imports = "import " + imports;
+            }
+            if (compiler != null) {
+                compiler.addImport(imports);
+            } else {
+                this.imports.add(imports);
+            }
+        }
+
+        public void init() {
+            // load pre compiled first
+            loadPreCompiled();
+
+            // load optional configuration file
+            loadConfiguration();
+
+            // detect custom compiler (camel-csimple-joor)
+            ExtendedCamelContext ecc = getCamelContext().adapt(ExtendedCamelContext.class);
+            Optional<Class<?>> clazz = ecc.getBootstrapFactoryFinder().findClass(CSimpleCompiler.FACTORY);
+            if (clazz.isPresent()) {
+                compiler = (CSimpleCompiler) ecc.getInjector().newInstance(clazz.get(), false);
+                if (compiler != null) {
+                    LOG.info("Detected camel-csimple-joor compiler");
+                    if (imports != null) {
+                        imports.forEach(compiler::addImport);
+                    }
+                    if (aliases != null) {
+                        aliases.forEach(compiler::addAliases);
+                    }
+                }
+                ServiceHelper.initService(compiler);
+            }
+        }
+
+        public CSimpleExpression compilePredicate(CamelContext camelContext, String expression) {
+            if (compiler != null) {
+                return compiler.compilePredicate(camelContext, expression);
+            }
+            return null;
+        }
+
+        public CSimpleExpression compileExpression(CamelContext camelContext, String expression) {
+            if (compiler != null) {
+                return compiler.compileExpression(camelContext, expression);
+            }
+            return null;
+        }
+
+        public void addAliases(String key, String value) {
+            if (compiler != null) {
+                compiler.addAliases(key, value);
+            } else {
+                this.aliases.put(key, value);
+            }
+        }
+
+        private void loadPreCompiled() {
+            ExtendedCamelContext ecc = getCamelContext().adapt(ExtendedCamelContext.class);
+            InputStream is = ecc.getClassResolver().loadResourceAsStream(PRE_COMPILED_FILE);
+            if (is != null) {
+                try {
+                    String text = IOHelper.loadText(is);
+                    String[] lines = text.split("\n");
+                    for (String fqn : lines) {
+                        // skip comments
+                        fqn = fqn.trim();
+                        if (fqn.startsWith("#") || fqn.isEmpty()) {
+                            continue;
+                        }
+                        // load class
+                        Class<CSimpleExpression> clazz
+                                = ecc.getClassResolver().resolveMandatoryClass(fqn, CSimpleExpression.class);
+                        CSimpleExpression ce = clazz.getConstructor(CamelContext.class).newInstance(getCamelContext());
+                        compiled.put(ce.getText(), ce);
+                    }
+                } catch (Exception e) {
+                    throw new RuntimeCamelException("Error initializing csimple language", e);
+                } finally {
+                    IOHelper.close(is);
+                }
+                if (!compiled.isEmpty()) {
+                    LOG.info("Loaded and initialized {} csimple expressions from classpath", compiled.size());
+                }
+            }
+        }
+
+        private void loadConfiguration() {
+            InputStream is;
+            String loaded;
+            is = getCamelContext().getClassResolver().loadResourceAsStream(CONFIG_FILE);
+            try {
+                if (is == null) {
+                    // load from file system
+                    File file = new File(configResource);
+                    if (file.exists()) {
+                        is = new FileInputStream(file);
+                    }
+                }
+                if (is == null) {
+                    return;
+                }
+                loaded = IOHelper.loadText(is);
+            } catch (IOException e) {
+                throw new RuntimeCamelException("Cannot load " + CONFIG_FILE + " from classpath");
+
+            }
+            IOHelper.close(is);
+
+            int counter1 = 0;
+            int counter2 = 0;
+            String[] lines = loaded.split("\n");
+            for (String line : lines) {
+                line = line.trim();
+                // skip comments
+                if (line.startsWith("#")) {
+                    continue;
+                }
+                // imports
+                if (line.startsWith("import ")) {
+                    imports.add(line);
+                    counter1++;
+                    continue;
+                }
+                // aliases as key=value
+                String key = StringHelper.before(line, "=");
+                String value = StringHelper.after(line, "=");
+                if (key != null) {
+                    key = key.trim();
+                }
+                if (value != null) {
+                    value = value.trim();
+                }
+                if (key != null && value != null) {
+                    this.aliases.put(key, value);
+                    counter2++;
+                }
+            }
+            if (counter1 > 0 || counter2 > 0) {
+                LOG.info("Loaded csimple language imports: {} and aliases: {} from configuration: {}", counter1, counter2,
+                        configResource);
+            }
+        }
+
+    }
+
 }