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

davsclaus pushed a commit to branch kamelet-local-registry
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c585264fc4669393f147e43dd702dd6dc80b5a71
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue May 4 17:55:40 2021 +0200

    CAMEL-16394: Route Template local beans. WIP
---
 .../main/java/org/apache/camel/CamelContext.java   | 13 ++++
 .../org/apache/camel/RouteTemplateContext.java     | 85 ++++++++++++++++++++++
 .../apache/camel/spi/LocalBeanRepositoryAware.java | 32 ++++++++
 .../camel/impl/engine/SimpleCamelContext.java      |  7 ++
 .../org/apache/camel/impl/DefaultCamelContext.java | 23 ++++++
 .../java/org/apache/camel/impl/DefaultModel.java   | 19 ++++-
 .../camel/impl/lw/LightweightCamelContext.java     |  7 ++
 .../impl/lw/LightweightRuntimeCamelContext.java    |  7 ++
 .../camel/builder/DefaultRouteTemplateContext.java | 70 ++++++++++++++++++
 .../camel/builder/TemplatedRouteBuilder.java       | 41 ++++++++---
 .../main/java/org/apache/camel/model/Model.java    | 14 ++++
 .../org/apache/camel/model/RouteDefinition.java    | 11 +++
 .../camel/model/RouteTemplateDefinition.java       |  1 -
 .../camel/builder/RouteTemplateLocalBeanTest.java  |  1 -
 .../org/apache/camel/support/DefaultRegistry.java  | 53 +++++++++++++-
 15 files changed, 366 insertions(+), 18 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java 
b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 5053093..3a72488 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -605,9 +605,22 @@ public interface CamelContext extends 
CamelContextLifecycle, RuntimeConfiguratio
      * @return                 the id of the route added (for example when an 
id was auto assigned)
      * @throws Exception       is thrown if error creating and adding the new 
route
      */
+    @Deprecated
     String addRouteFromTemplate(String routeId, String routeTemplateId, 
Map<String, Object> parameters) throws Exception;
 
     /**
+     * Adds a new route from a given route template.
+     *
+     * @param  routeId              the id of the new route to add (optional)
+     * @param  routeTemplateId      the id of the route template (mandatory)
+     * @param  routeTemplateContext the route template context (mandatory)
+     * @return                      the id of the route added (for example 
when an id was auto assigned)
+     * @throws Exception            is thrown if error creating and adding the 
new route
+     */
+    String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception;
+
+    /**
      * Adds the given route policy factory
      *
      * @param routePolicyFactory the factory
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java 
b/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java
new file mode 100644
index 0000000..c6e8842
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.camel.spi.BeanRepository;
+
+/**
+ * The context used during creating a {@link Route} from a route template.
+ */
+public interface RouteTemplateContext {
+
+    /**
+     * Binds the bean to the repository (if possible).
+     *
+     * If the bean is {@link CamelContextAware} then the registry will 
automatic inject the context if possible.
+     *
+     * @param id   the id of the bean
+     * @param bean the bean
+     */
+    default void bind(String id, Object bean) {
+        bind(id, bean.getClass(), bean);
+    }
+
+    /**
+     * Binds the bean to the repository (if possible).
+     * <p/>
+     * Binding by id and type allows to bind multiple entries with the same id 
but with different type.
+     *
+     * If the bean is {@link CamelContextAware} then the registry will 
automatic inject the context if possible.
+     *
+     * @param id   the id of the bean
+     * @param type the type of the bean to associate the binding
+     * @param bean the bean
+     */
+    void bind(String id, Class<?> type, Object bean);
+
+    /**
+     * Binds the bean (via a supplier) to the repository (if possible).
+     * <p/>
+     * Binding by id and type allows to bind multiple entries with the same id 
but with different type.
+     *
+     * If the bean is {@link CamelContextAware} then the registry will 
automatic inject the context if possible.
+     *
+     * @param id   the id of the bean
+     * @param type the type of the bean to associate the binding
+     * @param bean a supplier for the bean
+     */
+    void bind(String id, Class<?> type, Supplier<Object> bean);
+
+    /**
+     * Gets the property with the given name
+     *
+     * @param  name name of property
+     * @return      the property value or <tt>null</tt> if no property exists
+     */
+    Object getProperty(String name);
+
+    /**
+     * The parameters to use for the route template when creating the new route
+     */
+    Map<String, Object> getParameters();
+
+    /**
+     * Gets the local bean repository for the route template when creating the 
new route
+     */
+    BeanRepository getLocalBeanRepository();
+
+}
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/LocalBeanRepositoryAware.java
 
b/core/camel-api/src/main/java/org/apache/camel/spi/LocalBeanRepositoryAware.java
new file mode 100644
index 0000000..d0c62d5
--- /dev/null
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/LocalBeanRepositoryAware.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Allows a {@link BeanRepository} to temporary have a local repository take 
precedence, such as when creating route
+ * templates to give more flexibility.
+ */
+public interface LocalBeanRepositoryAware {
+
+    /**
+     * Sets a special local bean repository (ie thread local) that take 
precedence and will use first, if a bean exists.
+     *
+     * @param repository the local repository, or <tt>null</tt> to unset when 
no longer needed.
+     */
+    void setLocalBeanRepository(BeanRepository repository);
+
+}
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
index 254fc2d..a5aa0f5 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
@@ -23,6 +23,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Processor;
 import org.apache.camel.Route;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.catalog.RuntimeCamelCatalog;
 import org.apache.camel.health.HealthCheckRegistry;
@@ -623,6 +624,12 @@ public class SimpleCamelContext extends 
AbstractCamelContext {
     }
 
     @Override
+    public String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public String getTestExcludeRoutes() {
         throw new UnsupportedOperationException();
     }
diff --git 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 9801bce..1236c6e 100644
--- 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -31,6 +31,7 @@ import org.apache.camel.FailedToStartRouteException;
 import org.apache.camel.Predicate;
 import org.apache.camel.Processor;
 import org.apache.camel.Route;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.StartupStep;
 import org.apache.camel.ValueHolder;
 import org.apache.camel.api.management.JmxSystemPropertyKeys;
@@ -67,6 +68,7 @@ import org.apache.camel.spi.BeanRepository;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.ExecutorServiceManager;
+import org.apache.camel.spi.LocalBeanRepositoryAware;
 import org.apache.camel.spi.ModelReifierFactory;
 import org.apache.camel.spi.ModelToXMLDumper;
 import org.apache.camel.spi.PackageScanClassResolver;
@@ -393,6 +395,15 @@ public class DefaultCamelContext extends 
SimpleCamelContext implements ModelCame
     }
 
     @Override
+    public String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception {
+        if (model == null && isLightweight()) {
+            throw new IllegalStateException("Access to model not supported in 
lightweight mode");
+        }
+        return model.addRouteFromTemplate(routeId, routeTemplateId, 
routeTemplateContext);
+    }
+
+    @Override
     public List<RestDefinition> getRestDefinitions() {
         if (model == null && isLightweight()) {
             throw new IllegalStateException("Access to model not supported in 
lightweight mode");
@@ -714,6 +725,10 @@ public class DefaultCamelContext extends 
SimpleCamelContext implements ModelCame
         }
 
         PropertiesComponent pc = 
getCamelContextReference().getPropertiesComponent();
+        LocalBeanRepositoryAware localBeans = null;
+        if (getCamelContextReference().getRegistry() instanceof 
LocalBeanRepositoryAware) {
+            localBeans = (LocalBeanRepositoryAware) 
getCamelContextReference().getRegistry();
+        }
         try {
             RouteDefinitionHelper.forceAssignIds(getCamelContextReference(), 
routeDefinitions);
             for (RouteDefinition routeDefinition : routeDefinitions) {
@@ -732,6 +747,11 @@ public class DefaultCamelContext extends 
SimpleCamelContext implements ModelCame
                     prop.putAll(routeDefinition.getTemplateParameters());
                     pc.setLocalProperties(prop);
 
+                    // we need to shadow the bean registry on the CamelContext 
with the local beans from the route template context
+                    if (localBeans != null) {
+                        
localBeans.setLocalBeanRepository(routeDefinition.getRouteTemplateContext().getLocalBeanRepository());
+                    }
+
                     // need to reset auto assigned ids, so there is no clash 
when creating routes
                     
ProcessorDefinitionHelper.resetAllAutoAssignedNodeIds(routeDefinition);
                 }
@@ -753,6 +773,9 @@ public class DefaultCamelContext extends SimpleCamelContext 
implements ModelCame
 
                 // clear local after the route is created via the reifier
                 pc.setLocalProperties(null);
+                if (localBeans != null) {
+                    localBeans.setLocalBeanRepository(null);
+                }
             }
         } finally {
             if (!alreadyStartingRoutes) {
diff --git 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index c1d456c..620e678 100644
--- 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -29,6 +29,8 @@ import java.util.function.Function;
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.FailedToCreateRouteFromTemplateException;
+import org.apache.camel.RouteTemplateContext;
+import org.apache.camel.builder.DefaultRouteTemplateContext;
 import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.FaultToleranceConfigurationDefinition;
 import org.apache.camel.model.HystrixConfigurationDefinition;
@@ -48,6 +50,7 @@ import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.model.validator.ValidatorDefinition;
 import org.apache.camel.spi.ModelReifierFactory;
+import org.apache.camel.support.SimpleRegistry;
 import org.apache.camel.util.AntPathMatcher;
 
 public class DefaultModel implements Model {
@@ -220,8 +223,16 @@ public class DefaultModel implements Model {
     }
 
     @Override
+    @Deprecated
     public String addRouteFromTemplate(final String routeId, final String 
routeTemplateId, final Map<String, Object> parameters)
             throws Exception {
+        RouteTemplateContext rtc = new 
DefaultRouteTemplateContext(camelContext, new SimpleRegistry(), parameters);
+        return addRouteFromTemplate(routeId, routeTemplateId, rtc);
+    }
+
+    @Override
+    public String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception {
         RouteTemplateDefinition target = null;
         for (RouteTemplateDefinition def : routeTemplateDefinitions) {
             if (routeTemplateId.equals(def.getId())) {
@@ -243,7 +254,7 @@ public class DefaultModel implements Model {
                     prop.put(temp.getName(), temp.getDefaultValue());
                 } else {
                     // this is a required parameter do we have that as input
-                    if (!parameters.containsKey(temp.getName())) {
+                    if 
(!routeTemplateContext.getParameters().containsKey(temp.getName())) {
                         templatesBuilder.add(temp.getName());
                     }
                 }
@@ -256,8 +267,8 @@ public class DefaultModel implements Model {
         }
 
         // then override with user parameters
-        if (parameters != null) {
-            prop.putAll(parameters);
+        if (routeTemplateContext.getParameters() != null) {
+            prop.putAll(routeTemplateContext.getParameters());
         }
 
         RouteTemplateDefinition.Converter converter = 
RouteTemplateDefinition.Converter.DEFAULT_CONVERTER;
@@ -283,6 +294,8 @@ public class DefaultModel implements Model {
             def.setId(routeId);
         }
         def.setTemplateParameters(prop);
+        def.setRouteTemplateContext(routeTemplateContext);
+
         // assign ids to the routes and validate that the id's are all unique
         String duplicate = RouteDefinitionHelper.validateUniqueIds(def, 
routeDefinitions);
         if (duplicate != null) {
diff --git 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
index 9ffb1f5..14cd80c 100644
--- 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
+++ 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
@@ -41,6 +41,7 @@ import org.apache.camel.Predicate;
 import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.Route;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.Service;
 import org.apache.camel.ServiceStatus;
@@ -1757,6 +1758,12 @@ public class LightweightCamelContext implements 
ExtendedCamelContext, CatalogCam
     }
 
     @Override
+    public String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception {
+        return getModelCamelContext().addRouteFromTemplate(routeId, 
routeTemplateId, routeTemplateContext);
+    }
+
+    @Override
     public List<RestDefinition> getRestDefinitions() {
         return getModelCamelContext().getRestDefinitions();
     }
diff --git 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
index 66ec1d4..409c494 100644
--- 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
+++ 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
@@ -49,6 +49,7 @@ import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.Route;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
@@ -1922,6 +1923,12 @@ public class LightweightRuntimeCamelContext implements 
ExtendedCamelContext, Cat
     }
 
     @Override
+    public String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void setLightweight(boolean lightweight) {
         throw new UnsupportedOperationException();
     }
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/DefaultRouteTemplateContext.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/DefaultRouteTemplateContext.java
new file mode 100644
index 0000000..d7a2574
--- /dev/null
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/DefaultRouteTemplateContext.java
@@ -0,0 +1,70 @@
+/*
+ * 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.builder;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RouteTemplateContext;
+import org.apache.camel.spi.BeanRepository;
+import org.apache.camel.spi.Registry;
+
+// TODO: Should this be moved to some other module/package?
+
+public final class DefaultRouteTemplateContext implements RouteTemplateContext 
{
+
+    private final CamelContext camelContext;
+    private final Registry registry;
+    private final Map<String, Object> parameters;
+
+    public DefaultRouteTemplateContext(CamelContext camelContext, Registry 
registry, Map<String, Object> parameters) {
+        this.camelContext = camelContext;
+        this.registry = registry;
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void bind(String id, Object bean) {
+        registry.bind(id, bean);
+    }
+
+    @Override
+    public void bind(String id, Class<?> type, Object bean) {
+        registry.bind(id, type, bean);
+    }
+
+    @Override
+    public void bind(String id, Class<?> type, Supplier<Object> bean) {
+        registry.bind(id, type, bean);
+    }
+
+    @Override
+    public Object getProperty(String name) {
+        return camelContext.resolvePropertyPlaceholders(name);
+    }
+
+    @Override
+    public Map<String, Object> getParameters() {
+        return parameters;
+    }
+
+    @Override
+    public BeanRepository getLocalBeanRepository() {
+        return registry;
+    }
+}
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/TemplatedRouteBuilder.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/TemplatedRouteBuilder.java
index 8939b9f..6f2322b 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/TemplatedRouteBuilder.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/TemplatedRouteBuilder.java
@@ -22,6 +22,7 @@ import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.RouteTemplateDefinition;
@@ -35,14 +36,18 @@ public final class TemplatedRouteBuilder {
 
     private final CamelContext camelContext;
     private final String routeTemplateId;
-    private String routeId;
     private final Map<String, Object> parameters = new HashMap<>();
+    // TODO: Need to shadow regular camel registry during route creation
     private final Registry localRegistry = new DefaultRegistry();
+    private final RouteTemplateContext routeTemplateContext;
+    private String routeId;
     private Consumer<RouteTemplateDefinition> handler;
+    private Consumer<RouteTemplateContext> configurer;
 
     private TemplatedRouteBuilder(CamelContext camelContext, String 
routeTemplateId) {
         this.camelContext = camelContext;
         this.routeTemplateId = routeTemplateId;
+        this.routeTemplateContext = new 
DefaultRouteTemplateContext(camelContext, localRegistry, parameters);
     }
 
     /**
@@ -91,8 +96,8 @@ public final class TemplatedRouteBuilder {
     /**
      * Binds the bean to the template local repository (takes precedence over 
global beans)
      *
-     * @param  id                    the id of the bean
-     * @param  bean                  the bean
+     * @param id   the id of the bean
+     * @param bean the bean
      */
     public TemplatedRouteBuilder bind(String id, Object bean) {
         localRegistry.bind(id, bean);
@@ -102,9 +107,9 @@ public final class TemplatedRouteBuilder {
     /**
      * Binds the bean to the template local repository (takes precedence over 
global beans)
      *
-     * @param  id                    the id of the bean
-     * @param  type                  the type of the bean to associate the 
binding
-     * @param  bean                  the bean
+     * @param id   the id of the bean
+     * @param type the type of the bean to associate the binding
+     * @param bean the bean
      */
     public TemplatedRouteBuilder bind(String id, Class<?> type, Object bean) {
         localRegistry.bind(id, type, bean);
@@ -114,9 +119,9 @@ public final class TemplatedRouteBuilder {
     /**
      * Binds the bean (via a supplier) to the template local repository (takes 
precedence over global beans)
      *
-     * @param  id                    the id of the bean
-     * @param  type                  the type of the bean to associate the 
binding
-     * @param  bean                  the bean
+     * @param id   the id of the bean
+     * @param type the type of the bean to associate the binding
+     * @param bean the bean
      */
     public TemplatedRouteBuilder bind(String id, Class<?> type, 
Supplier<Object> bean) {
         localRegistry.bind(id, type, bean);
@@ -136,6 +141,17 @@ public final class TemplatedRouteBuilder {
     }
 
     /**
+     * Sets a configurer which allows to do configuration while the route 
template is being used to create a route. This
+     * gives control over the creating process, such as binding local beans 
and doing other kind of customization.
+     *
+     * @param configurer the configurer with callback to invoke with the given 
route template context
+     */
+    public TemplatedRouteBuilder configure(Consumer<RouteTemplateContext> 
configurer) {
+        this.configurer = configurer;
+        return this;
+    }
+
+    /**
      * Adds the route to the {@link CamelContext} which is built from the 
configured route template.
      *
      * @return the route id of the route that was added.
@@ -150,9 +166,10 @@ public final class TemplatedRouteBuilder {
                 }
                 handler.accept(def);
             }
-            // TODO: provide local beans from builder (either via new 
parameter here)
-            // or some way via a new RouteTemplateContext that stores such 
information
-            return camelContext.addRouteFromTemplate(routeId, routeTemplateId, 
parameters);
+            if (configurer != null) {
+                configurer.accept(routeTemplateContext);
+            }
+            return camelContext.addRouteFromTemplate(routeId, routeTemplateId, 
routeTemplateContext);
         } catch (Exception e) {
             throw RuntimeCamelException.wrapRuntimeException(e);
         }
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java 
b/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
index b619650..5d41864 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
@@ -174,9 +175,22 @@ public interface Model {
      * @return                 the id of the route added (for example when an 
id was auto assigned)
      * @throws Exception       is thrown if error creating and adding the new 
route
      */
+    @Deprecated
     String addRouteFromTemplate(String routeId, String routeTemplateId, 
Map<String, Object> parameters) throws Exception;
 
     /**
+     * Adds a new route from a given route template
+     *
+     * @param  routeId              the id of the new route to add (optional)
+     * @param  routeTemplateId      the id of the route template (mandatory)
+     * @param  routeTemplateContext the route template context (mandatory)
+     * @return                      the id of the route added (for example 
when an id was auto assigned)
+     * @throws Exception            is thrown if error creating and adding the 
new route
+     */
+    String addRouteFromTemplate(String routeId, String routeTemplateId, 
RouteTemplateContext routeTemplateContext)
+            throws Exception;
+
+    /**
      * Returns a list of the current REST definitions
      *
      * @return list of the current REST definitions
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 f41df10..e6a3d0d 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
@@ -35,6 +35,7 @@ import javax.xml.bind.annotation.XmlType;
 import org.apache.camel.Endpoint;
 import org.apache.camel.ErrorHandlerFactory;
 import org.apache.camel.NamedRoute;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.ShutdownRoute;
 import org.apache.camel.ShutdownRunningTask;
 import org.apache.camel.builder.EndpointConsumerBuilder;
@@ -82,6 +83,7 @@ public class RouteDefinition extends 
OutputDefinition<RouteDefinition> implement
     private OutputTypeDefinition outputType;
     private List<PropertyDefinition> routeProperties;
     private Map<String, Object> templateParameters;
+    private RouteTemplateContext routeTemplateContext;
 
     public RouteDefinition() {
     }
@@ -672,6 +674,15 @@ public class RouteDefinition extends 
OutputDefinition<RouteDefinition> implement
         this.templateParameters = templateParameters;
     }
 
+    public RouteTemplateContext getRouteTemplateContext() {
+        return routeTemplateContext;
+    }
+
+    @XmlTransient
+    public void setRouteTemplateContext(RouteTemplateContext 
routeTemplateContext) {
+        this.routeTemplateContext = routeTemplateContext;
+    }
+
     // Properties
     // -----------------------------------------------------------------------
 
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
index 724a657..cadb574 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
@@ -17,7 +17,6 @@
 package org.apache.camel.model;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
index c91938a..c106091 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
@@ -17,7 +17,6 @@
 package org.apache.camel.builder;
 
 import org.apache.camel.ContextTestSupport;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.junit.jupiter.api.Test;
 
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
index 86fd9ed..dba5f1c 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
@@ -32,6 +32,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.BeanRepository;
+import org.apache.camel.spi.LocalBeanRepositoryAware;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
@@ -45,9 +46,11 @@ import org.apache.camel.util.IOHelper;
  * Notice that beans in the fallback registry are not managed by the 
first-choice registry, so these beans may not
  * support dependency injection and other features that the first-choice 
registry may offer.
  */
-public class DefaultRegistry extends ServiceSupport implements Registry, 
CamelContextAware {
+public class DefaultRegistry extends ServiceSupport implements Registry, 
LocalBeanRepositoryAware, CamelContextAware {
 
     protected CamelContext camelContext;
+    protected final ThreadLocal<BeanRepository> localRepository = new 
ThreadLocal<>();
+    protected volatile boolean localRepositoryEnabled; // flag to keep track 
if local is in use or not
     protected List<BeanRepository> repositories;
     protected Registry fallbackRegistry = new SimpleRegistry();
     protected Registry supplierRegistry = new SupplierRegistry();
@@ -87,6 +90,19 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, CamelCo
     }
 
     /**
+     * Sets a special local bean repository (ie thread local) that take 
precedence and will use first, if a bean exists.
+     */
+    public void setLocalBeanRepository(BeanRepository repository) {
+        if (repository != null) {
+            this.localRepository.set(repository);
+            this.localRepositoryEnabled = true;
+        } else {
+            this.localRepository.remove();
+            this.localRepositoryEnabled = false;
+        }
+    }
+
+    /**
      * Gets the fallback {@link Registry}
      */
     public Registry getFallbackRegistry() {
@@ -164,6 +180,15 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, CamelCo
             throw RuntimeCamelException.wrapRuntimeCamelException(e);
         }
 
+        // local repository takes precedence
+        BeanRepository local = localRepositoryEnabled ? localRepository.get() 
: null;
+        if (local != null) {
+            answer = local.lookupByName(name);
+            if (answer != null) {
+                return unwrap(answer);
+            }
+        }
+
         if (repositories != null) {
             for (BeanRepository r : repositories) {
                 answer = r.lookupByName(name);
@@ -196,6 +221,14 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, CamelCo
             throw RuntimeCamelException.wrapRuntimeCamelException(e);
         }
 
+        // local repository takes precedence
+        BeanRepository local = localRepositoryEnabled ? localRepository.get() 
: null;
+        if (local != null) {
+            answer = local.lookupByNameAndType(name, type);
+            if (answer != null) {
+                return (T) unwrap(answer);
+            }
+        }
         if (repositories != null) {
             for (BeanRepository r : repositories) {
                 answer = r.lookupByNameAndType(name, type);
@@ -219,6 +252,15 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, CamelCo
     public <T> Map<String, T> findByTypeWithName(Class<T> type) {
         Map<String, T> answer = new LinkedHashMap<>();
 
+        // local repository takes precedence
+        BeanRepository local = localRepositoryEnabled ? localRepository.get() 
: null;
+        if (local != null) {
+            Map<String, T> found = local.findByTypeWithName(type);
+            if (found != null && !found.isEmpty()) {
+                answer.putAll(found);
+            }
+        }
+
         if (repositories != null) {
             for (BeanRepository r : repositories) {
                 Map<String, T> found = r.findByTypeWithName(type);
@@ -244,6 +286,15 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, CamelCo
     public <T> Set<T> findByType(Class<T> type) {
         Set<T> answer = new LinkedHashSet<>();
 
+        // local repository takes precedence
+        BeanRepository local = localRepositoryEnabled ? localRepository.get() 
: null;
+        if (local != null) {
+            Set<T> found = local.findByType(type);
+            if (found != null && !found.isEmpty()) {
+                answer.addAll(found);
+            }
+        }
+
         if (repositories != null) {
             for (BeanRepository r : repositories) {
                 Set<T> found = r.findByType(type);

Reply via email to