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 8f142df68a6859f2c78b79369da58874ab09e31e
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Mar 28 11:57:10 2022 +0200

    CAMEL-17784: ExtendedRoutesBuilderLoader SPI which allows routes loader to 
load multiple routes in the same unit. In preparation for camel-java-joor-dsl 
to compile all java sources together.
---
 .../camel/spi/ExtendedRoutesBuilderLoader.java     | 21 ++++++++
 .../java/org/apache/camel/spi/ResourceAware.java   | 44 +++++++++++++++++
 .../camel/impl/engine/DefaultRoutesLoader.java     | 50 ++++++++++++-------
 .../org/apache/camel/builder/RouteBuilder.java     |  3 +-
 .../org/apache/camel/model/RouteDefinition.java    |  4 +-
 .../org/apache/camel/model/RoutesDefinition.java   |  3 +-
 .../support/ExtendedRouteBuilderLoaderSupport.java | 51 ++++++++++++++++++++
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     | 56 ++++++++++++++--------
 8 files changed, 193 insertions(+), 39 deletions(-)

diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/ExtendedRoutesBuilderLoader.java
 
b/core/camel-api/src/main/java/org/apache/camel/spi/ExtendedRoutesBuilderLoader.java
new file mode 100644
index 0000000..3c3a016
--- /dev/null
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/ExtendedRoutesBuilderLoader.java
@@ -0,0 +1,21 @@
+package org.apache.camel.spi;
+
+import java.util.Collection;
+
+import org.apache.camel.RoutesBuilder;
+
+/**
+ * An extended {@link RoutesBuilderLoader} that is capable of loading from 
multiple resources in one unit (such as
+ * compiling them together).
+ */
+public interface ExtendedRoutesBuilderLoader extends RoutesBuilderLoader {
+
+    /**
+     * Loads {@link RoutesBuilder} from multiple {@link Resource}s.
+     *
+     * @param  resources the resources to be loaded.
+     * @return           a set of loaded {@link RoutesBuilder}s
+     */
+    Collection<RoutesBuilder> loadRoutesBuilders(Collection<Resource> 
resources) throws Exception;
+
+}
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/ResourceAware.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/ResourceAware.java
new file mode 100644
index 0000000..f02b8dc
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/ResourceAware.java
@@ -0,0 +1,44 @@
+/*
+ * 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.spi;
+
+/**
+ * An interface to represent an object which wishes to be injected with the 
{@link Resource}
+ */
+public interface ResourceAware {
+
+    /**
+     * Set the {@link Resource} resource if the object is an instance of 
{@link ResourceAware}.
+     */
+    static <T> T trySetResource(T object, Resource resource) {
+        if (resource != null && object instanceof ResourceAware) {
+            ((ResourceAware) object).setResource(resource);
+        }
+
+        return object;
+    }
+
+    /**
+     * Gets the {@link Resource}.
+     */
+    Resource getResource();
+
+    /**
+     * Sets the {@link Resource}.
+     */
+    void setResource(Resource resource);
+}
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 0f4737f..4ff9f39 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
@@ -18,6 +18,7 @@ package org.apache.camel.impl.engine;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -29,6 +30,7 @@ import org.apache.camel.CamelContextAware;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.StaticService;
+import org.apache.camel.spi.ExtendedRoutesBuilderLoader;
 import org.apache.camel.spi.FactoryFinder;
 import org.apache.camel.spi.ModelineFactory;
 import org.apache.camel.spi.Resource;
@@ -86,20 +88,44 @@ public class DefaultRoutesLoader extends ServiceSupport 
implements RoutesLoader,
     public Collection<RoutesBuilder> findRoutesBuilders(Collection<Resource> 
resources) throws Exception {
         List<RoutesBuilder> answer = new ArrayList<>(resources.size());
 
-        for (Resource resource : resources) {
-            RoutesBuilderLoader loader = resolveRoutesBuilderLoader(resource);
-
-            if (camelContext.isModeline()) {
-                ModelineFactory factory = 
camelContext.adapt(ExtendedCamelContext.class).getModelineFactory();
+        // first we need to parse for modeline to gather all the configurations
+        if (camelContext.isModeline()) {
+            ModelineFactory factory = 
camelContext.adapt(ExtendedCamelContext.class).getModelineFactory();
+            for (Resource resource : resources) {
+                RoutesBuilderLoader loader = 
resolveRoutesBuilderLoader(resource);
                 // gather resources for modeline
                 factory.parseModeline(resource);
                 // pre-parse before loading
                 loader.preParseRoute(resource);
             }
+        }
+
+        // now group resources by loader
+        Map<RoutesBuilderLoader, List<Resource>> groups = new 
LinkedHashMap<>();
+        for (Resource resource : resources) {
+            RoutesBuilderLoader loader = resolveRoutesBuilderLoader(resource);
+            List<Resource> list = groups.getOrDefault(loader, new 
ArrayList<Resource>());
+            list.add(resource);
+            groups.put(loader, list);
+        }
 
-            RoutesBuilder builder = loader.loadRoutesBuilder(resource);
-            if (builder != null) {
-                answer.add(builder);
+        // now load all the same resources for each loader
+        for (Map.Entry<RoutesBuilderLoader, List<Resource>> entry : 
groups.entrySet()) {
+            RoutesBuilderLoader loader = entry.getKey();
+            if (loader instanceof ExtendedRoutesBuilderLoader) {
+                // extended loader can load all resources ine one unit
+                ExtendedRoutesBuilderLoader extLoader = 
(ExtendedRoutesBuilderLoader) loader;
+                Collection<RoutesBuilder> builders = 
extLoader.loadRoutesBuilders(entry.getValue());
+                if (builders != null) {
+                    answer.addAll(builders);
+                }
+            } else {
+                for (Resource resource : entry.getValue()) {
+                    RoutesBuilder builder = loader.loadRoutesBuilder(resource);
+                    if (builder != null) {
+                        answer.add(builder);
+                    }
+                }
             }
         }
 
@@ -156,14 +182,6 @@ public class DefaultRoutesLoader extends ServiceSupport 
implements RoutesLoader,
         Set<String> answer = new LinkedHashSet<>();
         Collection<RoutesBuilder> builders = findRoutesBuilders(resources);
 
-        if (camelContext.isModeline()) {
-            ModelineFactory factory = 
camelContext.adapt(ExtendedCamelContext.class).getModelineFactory();
-            // gather resources for modeline
-            for (Resource resource : resources) {
-                factory.parseModeline(resource);
-            }
-        }
-
         for (RoutesBuilder builder : builders) {
             // update any existing routes
             Set<String> ids = 
builder.updateRoutesToCamelContext(getCamelContext());
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
index 26411e97..d661d53 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -51,6 +51,7 @@ import org.apache.camel.model.rest.RestsDefinition;
 import org.apache.camel.spi.OnCamelContextEvent;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.support.LifecycleStrategySupport;
 import org.apache.camel.util.ObjectHelper;
@@ -64,7 +65,7 @@ import org.slf4j.LoggerFactory;
  * A <a href="http://camel.apache.org/dsl.html";>Java DSL</a> which is used to 
build {@link Route} instances in a
  * {@link CamelContext} for smart routing.
  */
-public abstract class RouteBuilder extends BuilderSupport implements 
RoutesBuilder, Ordered {
+public abstract class RouteBuilder extends BuilderSupport implements 
RoutesBuilder, Ordered, ResourceAware {
     protected Logger log = LoggerFactory.getLogger(getClass());
 
     private Resource resource;
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
index c7e2d3e..a0bd0c2 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -48,6 +48,7 @@ import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.spi.AsEndpointUri;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 import org.apache.camel.spi.RoutePolicy;
 
 /**
@@ -58,7 +59,8 @@ import org.apache.camel.spi.RoutePolicy;
 @XmlType(propOrder = { "input", "inputType", "outputType", "outputs", 
"routeProperties" })
 @XmlAccessorType(XmlAccessType.PROPERTY)
 // must use XmlAccessType.PROPERTY as there is some custom logic needed to be 
executed in the setter methods
-public class RouteDefinition extends OutputDefinition<RouteDefinition> 
implements NamedRoute, PreconditionContainer {
+public class RouteDefinition extends OutputDefinition<RouteDefinition>
+        implements NamedRoute, PreconditionContainer, ResourceAware {
     private final AtomicBoolean prepared = new AtomicBoolean();
     private FromDefinition input;
     private String routeConfigurationId;
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
index 2ce18c6..f53235d 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
@@ -33,6 +33,7 @@ import org.apache.camel.builder.EndpointConsumerBuilder;
 import org.apache.camel.spi.AsEndpointUri;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 import org.apache.camel.support.OrderedComparator;
 import org.apache.camel.support.PatternHelper;
 import org.slf4j.Logger;
@@ -45,7 +46,7 @@ import org.slf4j.LoggerFactory;
 @XmlRootElement(name = "routes")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class RoutesDefinition extends 
OptionalIdentifiedDefinition<RoutesDefinition>
-        implements RouteContainer, CamelContextAware {
+        implements RouteContainer, CamelContextAware, ResourceAware {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(RoutesDefinition.class);
 
diff --git 
a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/ExtendedRouteBuilderLoaderSupport.java
 
b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/ExtendedRouteBuilderLoaderSupport.java
new file mode 100644
index 0000000..870df61
--- /dev/null
+++ 
b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/ExtendedRouteBuilderLoaderSupport.java
@@ -0,0 +1,51 @@
+/*
+ * 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.support;
+
+import java.util.Collection;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.ExtendedRoutesBuilderLoader;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.RoutesBuilderLoader;
+
+/**
+ * Base class for {@link RoutesBuilderLoader} implementations.
+ */
+public abstract class ExtendedRouteBuilderLoaderSupport extends 
RouteBuilderLoaderSupport
+        implements ExtendedRoutesBuilderLoader {
+
+    protected ExtendedRouteBuilderLoaderSupport(String extension) {
+        super(extension);
+    }
+
+    @Override
+    protected RouteBuilder doLoadRouteBuilder(Resource resource) throws 
Exception {
+        // noop
+        return null;
+    }
+
+    @Override
+    public Collection<RoutesBuilder> loadRoutesBuilders(Collection<Resource> 
resources) throws Exception {
+        Collection<RoutesBuilder> answer = doLoadRoutesBuilders(resources);
+        return answer;
+    }
+
+    protected abstract Collection<RoutesBuilder> 
doLoadRoutesBuilders(Collection<Resource> resources) throws Exception;
+
+}
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 c29e54d..a5d1d26 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
@@ -18,14 +18,19 @@ package org.apache.camel.dsl.java.joor;
 
 import java.io.FileNotFoundException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.RoutesBuilder;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.dsl.support.CompilePostProcessor;
-import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
+import org.apache.camel.dsl.support.ExtendedRouteBuilderLoaderSupport;
 import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 import org.apache.camel.spi.annotations.RoutesLoader;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.FileUtil;
@@ -34,7 +39,7 @@ import org.joor.Reflect;
 
 @ManagedResource(description = "Managed JavaRoutesBuilderLoader")
 @RoutesLoader(JavaRoutesBuilderLoader.EXTENSION)
-public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
+public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport 
{
     public static final String EXTENSION = "java";
     public static final Pattern PACKAGE_PATTERN = Pattern.compile(
             "^\\s*package\\s+([a-zA-Z][\\.\\w]*)\\s*;.*$", Pattern.MULTILINE);
@@ -44,29 +49,40 @@ public class JavaRoutesBuilderLoader extends 
RouteBuilderLoaderSupport {
     }
 
     @Override
-    public RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception 
{
-        try (InputStream is = resource.getInputStream()) {
-            if (is == null) {
-                throw new FileNotFoundException(resource.getLocation());
-            }
-            String content = IOHelper.loadText(is);
-            String name = determineName(resource, content);
+    protected Collection<RoutesBuilder> 
doLoadRoutesBuilders(Collection<Resource> resources) throws Exception {
+        Collection<RoutesBuilder> answer = new ArrayList<>();
 
-            Reflect ref = Reflect.compile(name, content).create();
-            Class<?> clazz = ref.type();
-            Object obj = ref.get();
+        // TODO: when joor supports compiling in one unit
+        for (Resource resource : resources) {
+            try (InputStream is = resource.getInputStream()) {
+                if (is == null) {
+                    throw new FileNotFoundException(resource.getLocation());
+                }
+                String content = IOHelper.loadText(is);
+                String name = determineName(resource, content);
 
-            // support custom annotation scanning post compilation
-            // such as to register custom beans, type converters, etc.
-            for (CompilePostProcessor pre : getCompilePostProcessors()) {
-                pre.postCompile(getCamelContext(), name, clazz, obj);
-            }
+                Reflect ref = Reflect.compile(name, content).create();
+                Class<?> clazz = ref.type();
+                Object obj = ref.get();
+
+                // inject context and resource
+                CamelContextAware.trySetCamelContext(obj, getCamelContext());
+                ResourceAware.trySetResource(obj, resource);
 
-            if (obj instanceof RouteBuilder) {
-                return (RouteBuilder) obj;
+                // support custom annotation scanning post compilation
+                // such as to register custom beans, type converters, etc.
+                for (CompilePostProcessor pre : getCompilePostProcessors()) {
+                    pre.postCompile(getCamelContext(), name, clazz, obj);
+                }
+
+                if (obj instanceof RouteBuilder) {
+                    RouteBuilder builder = (RouteBuilder) obj;
+                    answer.add(builder);
+                }
             }
-            return null;
         }
+
+        return answer;
     }
 
     private static String determineName(Resource resource, String content) {

Reply via email to