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/10/28 07:43:17 UTC

[camel] branch camel-3.18.x updated: CAMEL-18614: camel-core - Updating route configuration via routes loader

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

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


The following commit(s) were added to refs/heads/camel-3.18.x by this push:
     new 092ad24bd35 CAMEL-18614: camel-core - Updating route configuration via routes loader
092ad24bd35 is described below

commit 092ad24bd352e1f5e4a822a4ecf868fa59aadf30
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Oct 28 09:39:50 2022 +0200

    CAMEL-18614: camel-core - Updating route configuration via routes loader
---
 .../apache/camel/RouteConfigurationsBuilder.java   |   8 ++
 .../camel/impl/engine/DefaultRoutesLoader.java     |   9 ++
 .../org/apache/camel/impl/DefaultCamelContext.java |  16 +++
 .../java/org/apache/camel/impl/DefaultModel.java   |  17 +++
 .../camel/impl/lw/LightweightCamelContext.java     |  10 ++
 .../camel/builder/RouteConfigurationBuilder.java   |  18 +++
 .../main/java/org/apache/camel/model/Model.java    |  16 +++
 .../camel/model/RoutesConfigurationUpdateTest.java | 149 +++++++++++++++++++++
 8 files changed, 243 insertions(+)

diff --git a/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java b/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
index d9e95d599b0..b9761480791 100644
--- a/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
+++ b/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
@@ -29,4 +29,12 @@ public interface RouteConfigurationsBuilder {
      */
     void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception;
 
+    /**
+     * Adds or updates the route configurations from this builder to the CamelContext.
+     *
+     * @param  context   the Camel context
+     * @throws Exception is thrown if initialization of route configurations failed
+     */
+    void updateRouteConfigurationsToCamelContext(CamelContext context) throws Exception;
+
 }
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 1e3506621e0..fa0b4396a8e 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
@@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.StaticService;
 import org.apache.camel.spi.ExtendedRoutesBuilderLoader;
@@ -178,6 +179,14 @@ public class DefaultRoutesLoader extends ServiceSupport implements RoutesLoader,
         Set<String> answer = new LinkedHashSet<>();
         Collection<RoutesBuilder> builders = findRoutesBuilders(resources);
 
+        for (RoutesBuilder builder : builders) {
+            // update any existing route configurations first
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                rcb.updateRouteConfigurationsToCamelContext(getCamelContext());
+            }
+        }
+
         for (RoutesBuilder builder : builders) {
             // update any existing routes
             Set<String> ids = builder.updateRoutesToCamelContext(getCamelContext());
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 1a02fe0c44b..b35eacd6af1 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
@@ -327,6 +327,22 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
         return model.getRouteConfigurationDefinitions();
     }
 
+    @Override
+    public RouteConfigurationDefinition getRouteConfigurationDefinition(String id) {
+        if (model == null && isLightweight()) {
+            throw new IllegalStateException("Access to model not supported in lightweight mode");
+        }
+        return model.getRouteConfigurationDefinition(id);
+    }
+
+    @Override
+    public void removeRouteConfiguration(RouteConfigurationDefinition routeConfigurationDefinition) throws Exception {
+        if (model == null && isLightweight()) {
+            throw new IllegalStateException("Access to model not supported in lightweight mode");
+        }
+        model.removeRouteConfiguration(routeConfigurationDefinition);
+    }
+
     @Override
     public List<RouteDefinition> getRouteDefinitions() {
         if (model == null && isLightweight()) {
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 477b67a62fa..e1dba69e1aa 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
@@ -158,6 +158,23 @@ public class DefaultModel implements Model {
         return routesConfigurations;
     }
 
+    @Override
+    public synchronized RouteConfigurationDefinition getRouteConfigurationDefinition(String id) {
+        for (RouteConfigurationDefinition def : routesConfigurations) {
+            if (def.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory()).equals(id)) {
+                return def;
+            }
+        }
+        // you can have a global route configuration that has no ID assigned
+        return routesConfigurations.stream().filter(c -> c.getId() == null).findFirst().orElse(null);
+    }
+
+    @Override
+    public void removeRouteConfiguration(RouteConfigurationDefinition routeConfigurationDefinition) throws Exception {
+        RouteConfigurationDefinition toBeRemoved = getRouteConfigurationDefinition(routeConfigurationDefinition.getId());
+        this.routesConfigurations.remove(toBeRemoved);
+    }
+
     @Override
     public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
         if (routeDefinitions == null || routeDefinitions.isEmpty()) {
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 5afb8d37a2e..ca4f645574f 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
@@ -1847,6 +1847,16 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
         return getModelCamelContext().getRouteConfigurationDefinitions();
     }
 
+    @Override
+    public void removeRouteConfiguration(RouteConfigurationDefinition routeConfigurationDefinition) throws Exception {
+        getModelCamelContext().removeRouteConfiguration(routeConfigurationDefinition);
+    }
+
+    @Override
+    public RouteConfigurationDefinition getRouteConfigurationDefinition(String id) {
+        return getModelCamelContext().getRouteConfigurationDefinition(id);
+    }
+
     @Override
     public List<RouteDefinition> getRouteDefinitions() {
         return getModelCamelContext().getRouteDefinitions();
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
index 9b7b43e70c6..0b22d14404f 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.builder;
 
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.camel.CamelContext;
@@ -79,6 +80,23 @@ public abstract class RouteConfigurationBuilder extends RouteBuilder implements
         populateRoutesConfiguration();
     }
 
+    @Override
+    public void updateRouteConfigurationsToCamelContext(CamelContext context) throws Exception {
+        setCamelContext(context);
+        routeConfigurationCollection.setCamelContext(context);
+        if (initializedConfiguration.compareAndSet(false, true)) {
+            configuration();
+        }
+        List<RouteConfigurationDefinition> list = getRouteConfigurationCollection().getRouteConfigurations();
+        if (!list.isEmpty()) {
+            // remove existing before updating
+            for (RouteConfigurationDefinition def : list) {
+                context.getExtension(Model.class).removeRouteConfiguration(def);
+            }
+            populateRoutesConfiguration();
+        }
+    }
+
     protected void populateRoutesConfiguration() throws Exception {
         CamelContext camelContext = getContext();
         if (camelContext == null) {
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 84d0792d95e..ae3528bd3de 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
@@ -71,6 +71,22 @@ public interface Model {
      */
     List<RouteConfigurationDefinition> getRouteConfigurationDefinitions();
 
+    /**
+     * Removes a route configuration from the context
+     *
+     * @param  routeConfigurationDefinition route configuration to remove
+     * @throws Exception                    if the route configuration could not be removed for whatever reason
+     */
+    void removeRouteConfiguration(RouteConfigurationDefinition routeConfigurationDefinition) throws Exception;
+
+    /**
+     * Gets the route configuration definition with the given id
+     *
+     * @param  id id of the route configuration
+     * @return    the route configuration definition or <tt>null</tt> if not found
+     */
+    RouteConfigurationDefinition getRouteConfigurationDefinition(String id);
+
     /**
      * Returns a list of the current route definitions
      *
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationUpdateTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationUpdateTest.java
new file mode 100644
index 00000000000..d1ecbed63dc
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationUpdateTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.model;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationUpdateTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testRoutesConfigurationUpdate() throws Exception {
+        context.start();
+
+        RouteConfigurationBuilder rcb = new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration("myConfig").onException(Exception.class).handled(true).to("mock:error");
+            }
+        };
+        rcb.addRouteConfigurationsToCamelContext(context);
+        RouteBuilder rb = new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("start").routeConfigurationId("myConfig")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2").routeId("start2").routeConfigurationId("myConfig")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        };
+        rb.addRoutesToCamelContext(context);
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+        getMockEndpoint("mock:error2").expectedMessageCount(0);
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+        assertMockEndpointsSatisfied();
+
+        // update route configuration and routes (remove routes first)
+        context.getRouteController().removeAllRoutes();
+        RouteConfigurationBuilder rcb2 = new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration("myConfig").onException(Exception.class).handled(true).to("mock:error2");
+            }
+        };
+        rcb2.updateRouteConfigurationsToCamelContext(context);
+        RouteBuilder rb2 = new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("start").routeConfigurationId("myConfig")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2").routeId("start2").routeConfigurationId("myConfig")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        };
+        rb2.updateRoutesToCamelContext(context);
+
+        resetMocks();
+
+        getMockEndpoint("mock:error").expectedMessageCount(0);
+        getMockEndpoint("mock:error2").expectedBodiesReceived("Hello World2", "Bye World2");
+        template.sendBody("direct:start", "Hello World2");
+        template.sendBody("direct:start2", "Bye World2");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationGlobalUpdate() throws Exception {
+        context.start();
+
+        RouteConfigurationBuilder rcb = new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+            }
+        };
+        rcb.addRouteConfigurationsToCamelContext(context);
+        RouteBuilder rb = new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("start")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2").routeId("start2")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        };
+        rb.addRoutesToCamelContext(context);
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+        getMockEndpoint("mock:error2").expectedMessageCount(0);
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+        assertMockEndpointsSatisfied();
+
+        // update route configuration and routes (remove routes first)
+        context.getRouteController().removeAllRoutes();
+        RouteConfigurationBuilder rcb2 = new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration().onException(Exception.class).handled(true).to("mock:error2");
+            }
+        };
+        rcb2.updateRouteConfigurationsToCamelContext(context);
+        RouteBuilder rb2 = new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("start")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2").routeId("start2")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        };
+        rb2.updateRoutesToCamelContext(context);
+
+        resetMocks();
+
+        getMockEndpoint("mock:error").expectedMessageCount(0);
+        getMockEndpoint("mock:error2").expectedBodiesReceived("Hello World2", "Bye World2");
+        template.sendBody("direct:start", "Hello World2");
+        template.sendBody("direct:start2", "Bye World2");
+        assertMockEndpointsSatisfied();
+    }
+
+}