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 2022/04/27 17:39:53 UTC

[camel] 02/02: CAMEL-18081: camel-main/camel-java-dsl - Add option to compile to disk to pre-load on next run

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

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

commit e9064257c793af050108570ee7124e10dd96e6b2
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Apr 27 19:39:31 2022 +0200

    CAMEL-18081: camel-main/camel-java-dsl - Add option to compile to disk to pre-load on next run
---
 .../org/apache/camel/spi/RoutesBuilderLoader.java  |  7 ---
 .../java/org/apache/camel/spi/RoutesLoader.java    |  9 +++
 .../camel/impl/engine/DefaultRoutesLoader.java     | 10 +--
 .../dsl/java/joor/ClassRoutesBuilderLoader.java    |  2 +
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     | 49 +++++++++++++++
 .../dsl/java/joor/JavaJoorSaveToDiskTest.java      | 71 ++++++++++++++++++++++
 6 files changed, 133 insertions(+), 15 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java
index 3f11b1350f6..379ab0ced16 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java
@@ -64,11 +64,4 @@ public interface RoutesBuilderLoader extends StaticService, CamelContextAware {
         // noop
     }
 
-    /**
-     * Optional initializes the routes loader from the given set of options
-     *
-     * @param options options as key values
-     */
-    default void init(Map<String, Object> options) {
-    }
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
index 38b9bc5a9ad..d2e09295299 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
@@ -34,6 +34,15 @@ public interface RoutesLoader extends CamelContextAware {
      */
     String FACTORY = "routes-loader";
 
+    /**
+     * Looks up a {@link RoutesBuilderLoader} in the registry or fallback to a factory finder mechanism if none found.
+     *
+     * @param  extension                the file extension for which a loader should be found.
+     * @return                          a {@link RoutesBuilderLoader}
+     * @throws IllegalArgumentException if no {@link RoutesBuilderLoader} can be found for the given file extension
+     */
+    RoutesBuilderLoader getRoutesLoader(String extension) throws Exception;
+
     /**
      * Loads {@link RoutesBuilder} from the give list of {@link Resource} into the current
      * {@link org.apache.camel.CamelContext}.
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
index 7c2063a6cdf..1e3506621e0 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
@@ -137,14 +137,8 @@ public class DefaultRoutesLoader extends ServiceSupport implements RoutesLoader,
         resolveRoutesBuilderLoader(resource).preParseRoute(resource);
     }
 
-    /**
-     * Looks up a {@link RoutesBuilderLoader} in the registry or fallback to a factory finder mechanism if none found.
-     *
-     * @param  extension                the file extension for which a loader should be find.
-     * @return                          a {@link RoutesBuilderLoader}
-     * @throws IllegalArgumentException if no {@link RoutesBuilderLoader} can be found for the given file extension
-     */
-    protected RoutesBuilderLoader getRoutesLoader(String extension) throws Exception {
+    @Override
+    public RoutesBuilderLoader getRoutesLoader(String extension) throws Exception {
         RoutesBuilderLoader answer = getCamelContext().getRegistry().lookupByNameAndType(
                 ROUTES_LOADER_KEY_PREFIX + extension,
                 RoutesBuilderLoader.class);
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
index 4ee1488b429..b216f220d3d 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
@@ -51,6 +51,8 @@ public class ClassRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport
     protected Collection<RoutesBuilder> doLoadRoutesBuilders(Collection<Resource> resources) throws Exception {
         Collection<RoutesBuilder> answer = new ArrayList<>();
 
+        LOG.debug("Loading .class resources from: {}", resources);
+
         // load all the byte code first from the resources
         Map<String, byte[]> byteCodes = new LinkedHashMap<>();
         for (Resource res : resources) {
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index 167d751ca74..b4d95cd6148 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -20,21 +20,26 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.camel.CamelContextAware;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.dsl.support.ExtendedRouteBuilderLoaderSupport;
 import org.apache.camel.spi.CompilePostProcessor;
+import org.apache.camel.spi.ExtendedRoutesBuilderLoader;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.ResourceAware;
+import org.apache.camel.spi.RoutesBuilderLoader;
 import org.apache.camel.spi.annotations.RoutesLoader;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.support.RouteWatcherReloadStrategy;
@@ -57,6 +62,17 @@ public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport {
         super(EXTENSION);
     }
 
+    @Override
+    protected RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception {
+        Collection<RoutesBuilder> answer = doLoadRoutesBuilders(List.of(resource));
+        if (answer.size() == 1) {
+            RoutesBuilder builder = answer.iterator().next();
+            return (RouteBuilder) builder;
+        }
+
+        return super.doLoadRouteBuilder(resource);
+    }
+
     @Override
     protected Collection<RoutesBuilder> doLoadRoutesBuilders(Collection<Resource> resources) throws Exception {
         Collection<RoutesBuilder> answer = new ArrayList<>();
@@ -78,6 +94,14 @@ public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport {
             }
         }
 
+        if (getCompileDirectory() != null && isCompileLoadFirst()) {
+            resources = doLoadCompiledFirst(nameToResource, answer);
+            if (resources.isEmpty()) {
+                // all resources are loaded from pre-compiled
+                return answer;
+            }
+        }
+
         LOG.debug("Compiling unit: {}", unit);
         CompilationUnit.Result result = MultiCompile.compileUnit(unit);
 
@@ -129,6 +153,31 @@ public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport {
         return answer;
     }
 
+    private Collection<Resource> doLoadCompiledFirst(Map<String, Resource> nameToResource, Collection<RoutesBuilder> answer) throws Exception {
+        // look for existing compiled and load them first, and any that are missing is to be compiled
+        Collection<Resource> toBeCompiled = new ArrayList<>();
+
+        Collection<Resource> byteCodes = new ArrayList<>();
+        for (String className : nameToResource.keySet()) {
+            File source = new File(getCompileDirectory() + "/" + className + ".class");
+            if (source.exists()) {
+                byte[] code = Files.readAllBytes(source.toPath());
+                byteCodes.add(ResourceHelper.fromBytes("class:" + className + ".class", code));
+            } else {
+                toBeCompiled.add(nameToResource.get(className));
+            }
+        }
+        if (!byteCodes.isEmpty()) {
+            // use the loader that can load from class byte codes
+            ExtendedRoutesBuilderLoader loader = (ExtendedRoutesBuilderLoader) getCamelContext().adapt(ExtendedCamelContext.class)
+                    .getRoutesLoader().getRoutesLoader("class");
+            Collection<RoutesBuilder> loaded = loader.loadRoutesBuilders(byteCodes);
+            answer.addAll(loaded);
+        }
+
+        return toBeCompiled;
+    }
+
     private static void saveByteCodeToDisk(String outputDirectory, String name, byte[] byteCode) {
         // write to disk (can be triggered multiple times so only write once)
         File target = new File(outputDirectory + "/" + name + ".class");
diff --git a/dsl/camel-java-joor-dsl/src/test/java/org/apache/camel/dsl/java/joor/JavaJoorSaveToDiskTest.java b/dsl/camel-java-joor-dsl/src/test/java/org/apache/camel/dsl/java/joor/JavaJoorSaveToDiskTest.java
new file mode 100644
index 00000000000..a941a335469
--- /dev/null
+++ b/dsl/camel-java-joor-dsl/src/test/java/org/apache/camel/dsl/java/joor/JavaJoorSaveToDiskTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.dsl.java.joor;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.util.FileUtil;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+
+public class JavaJoorSaveToDiskTest {
+
+    @Test
+    public void testSaveToDisk() throws Exception {
+        FileUtil.removeDir(new File("target/compiled"));
+
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            context.start();
+
+            JavaRoutesBuilderLoader loader = new JavaRoutesBuilderLoader();
+            loader.setCamelContext(context);
+            loader.setCompileDirectory("target/compiled");
+            loader.start();
+
+            Resource resource = context.getResourceLoader().resolveResource("/routes/MyMockRoute.java");
+            RouteBuilder builder = (RouteBuilder) loader.loadRoutesBuilder(resource);
+
+            builder.setCamelContext(context);
+            builder.configure();
+        }
+
+        // should have saved to disk
+        Assertions.assertTrue(new File("target/compiled/MyMockRoute.class").exists());
+
+        // should be able to load from disk
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            context.start();
+
+            JavaRoutesBuilderLoader loader = new JavaRoutesBuilderLoader();
+            loader.setCamelContext(context);
+            loader.setCompileDirectory("target/compiled");
+            loader.setCompileLoadFirst(true);
+            loader.start();
+
+            Resource resource = context.getResourceLoader().resolveResource("/routes/MyMockRoute.java");
+            RouteBuilder builder = (RouteBuilder) loader.loadRoutesBuilder(resource);
+
+            builder.setCamelContext(context);
+            builder.configure();
+        }
+
+    }
+
+}