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 2023/02/18 10:57:39 UTC

[camel] branch main updated (e618e3c93da -> 25036ff2bd3)

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

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


    from e618e3c93da Regen for commit de990047ecefeed3ad6a7e613a9b48613295cd1a
     new bf94c4494b4 CAMEL-19071: camel-main / camel-jbang - Reload properties should reload components in dev mode.
     new 25036ff2bd3 CAMEL-19073: camel-main / camel-jbang - Reload properties should only reload changed properties.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/camel/spi/PropertiesComponent.java  |  9 +++
 ...teLoaderListener.java => PropertiesReload.java} | 17 ++---
 .../java/org/apache/camel/spi/ResourceReload.java  |  7 +-
 .../component/properties/PropertiesComponent.java  | 13 ++++
 .../PropertiesComponentKeepOnlyChangedTest.java    | 62 ++++++++++++++++++
 .../org/apache/camel/main/BaseMainSupport.java     | 75 ++++++++++++++++++++++
 .../apache/camel/main/MainPropertiesReload.java}   | 39 ++++++-----
 .../camel/support/RouteWatcherReloadStrategy.java  | 38 +++++++++--
 8 files changed, 223 insertions(+), 37 deletions(-)
 copy core/camel-api/src/main/java/org/apache/camel/spi/{RouteTemplateLoaderListener.java => PropertiesReload.java} (65%)
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentKeepOnlyChangedTest.java
 copy core/{camel-cloud/src/main/java/org/apache/camel/impl/cloud/DefaultServiceDiscovery.java => camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java} (58%)


[camel] 01/02: CAMEL-19071: camel-main / camel-jbang - Reload properties should reload components in dev mode.

Posted by da...@apache.org.
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 bf94c4494b44a9498bd380878473587f95315bfe
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Feb 18 11:08:41 2023 +0100

    CAMEL-19071: camel-main / camel-jbang - Reload properties should reload components in dev mode.
---
 .../{ResourceReload.java => PropertiesReload.java} | 15 +++--
 .../java/org/apache/camel/spi/ResourceReload.java  |  7 +-
 .../org/apache/camel/main/BaseMainSupport.java     | 75 ++++++++++++++++++++++
 .../apache/camel/main/MainPropertiesReload.java    | 57 ++++++++++++++++
 .../camel/support/RouteWatcherReloadStrategy.java  | 20 +++++-
 5 files changed, 163 insertions(+), 11 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java
similarity index 65%
copy from core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java
copy to core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java
index cdbb63255e1..2c795a6cbb0 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java
@@ -16,18 +16,21 @@
  */
 package org.apache.camel.spi;
 
+import java.util.Properties;
+
 /**
- * Listener for re-loading a {@link Resource} such as a Camel route.
+ * Listener for re-loading a {@link java.util.Properties} such as a Camel route.
  */
 @FunctionalInterface
-public interface ResourceReload {
+public interface PropertiesReload {
 
     /**
-     * Callback when the resource is re-loaded.
+     * Callback when the properties is re-loaded.
      *
-     * @param name     name of the resource such as the file name (absolute)
-     * @param resource the resource
+     * @param  name       name of the resource such as the file name (absolute)
+     * @param  properties the properties that was re-loaded
+     * @throws Exception  error reloading properties
      */
-    void onReload(String name, Resource resource);
+    void onReload(String name, Properties properties) throws Exception;
 
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java b/core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java
index cdbb63255e1..5176ef8cbcd 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/ResourceReload.java
@@ -25,9 +25,10 @@ public interface ResourceReload {
     /**
      * Callback when the resource is re-loaded.
      *
-     * @param name     name of the resource such as the file name (absolute)
-     * @param resource the resource
+     * @param  name      name of the resource such as the file name (absolute)
+     * @param  resource  the resource
+     * @throws Exception error reloading the resources
      */
-    void onReload(String name, Resource resource);
+    void onReload(String name, Resource resource) throws Exception;
 
 }
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index eb4b3f90bbf..ce1b2aaa190 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -488,6 +488,8 @@ public abstract class BaseMainSupport extends BaseService {
         if (mainConfigurationProperties.isAutoConfigurationEnabled()) {
             autoConfigurationFromProperties(camelContext, autoConfiguredProperties);
             autowireWildcardProperties(camelContext);
+            // register properties reloader so we can auto-update if updated
+            camelContext.addService(new MainPropertiesReload(this));
         }
 
         // log summary of configurations
@@ -1622,8 +1624,78 @@ public abstract class BaseMainSupport extends BaseService {
             prop.remove(key);
         }
 
+        doAutoConfigurationFromProperties(camelContext, prop, properties, false, autoConfiguredProperties);
+    }
+
+    protected void autoConfigurationFromReloadedProperties(
+            CamelContext camelContext, OrderedLocationProperties reloadedProperties)
+            throws Exception {
+
+        Map<PropertyOptionKey, OrderedLocationProperties> properties = new LinkedHashMap<>();
+
+        // filter out wildcard properties
+        for (String key : reloadedProperties.stringPropertyNames()) {
+            if (key.contains("*")) {
+                String loc = reloadedProperties.getLocation(key);
+                wildcardProperties.put(loc, key, reloadedProperties.getProperty(key));
+            }
+        }
+        // and remove wildcards
+        for (String key : wildcardProperties.stringPropertyNames()) {
+            reloadedProperties.remove(key);
+        }
+
+        OrderedLocationProperties autoConfiguredProperties = new OrderedLocationProperties();
+        doAutoConfigurationFromProperties(camelContext, reloadedProperties, properties, true, autoConfiguredProperties);
+
+        // log summary of configurations
+        if (mainConfigurationProperties.isAutoConfigurationLogSummary() && !autoConfiguredProperties.isEmpty()) {
+            boolean header = false;
+            for (var entry : autoConfiguredProperties.entrySet()) {
+                String k = entry.getKey().toString();
+                Object v = entry.getValue();
+                String loc = locationSummary(autoConfiguredProperties, k);
+
+                // tone down logging noise for our own internal configurations
+                boolean debug = loc.contains("[camel-main]");
+                if (debug && !LOG.isDebugEnabled()) {
+                    continue;
+                }
+
+                if (!header) {
+                    LOG.info("Auto-configuration summary");
+                    header = true;
+                }
+
+                if (SensitiveUtils.containsSensitive(k)) {
+                    if (debug) {
+                        LOG.debug("    {} {}=xxxxxx", loc, k);
+                    } else {
+                        LOG.info("    {} {}=xxxxxx", loc, k);
+                    }
+                } else {
+                    if (debug) {
+                        LOG.debug("    {} {}={}", loc, k, v);
+                    } else {
+                        LOG.info("    {} {}={}", loc, k, v);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void doAutoConfigurationFromProperties(
+            CamelContext camelContext, OrderedLocationProperties prop,
+            Map<PropertyOptionKey, OrderedLocationProperties> properties, boolean reload,
+            OrderedLocationProperties autoConfiguredProperties)
+            throws Exception {
+
         for (String key : prop.stringPropertyNames()) {
             computeProperties("camel.component.", key, prop, properties, name -> {
+                if (reload) {
+                    // force re-creating component on reload
+                    camelContext.removeComponent(name);
+                }
                 // its an existing component name
                 Component target = camelContext.getComponent(name);
                 if (target == null) {
@@ -1706,6 +1778,9 @@ public abstract class BaseMainSupport extends BaseService {
                 doAutowireWildcardProperties(name, component);
             }
         });
+
+        // clear in case we reload later
+        wildcardProperties.clear();
     }
 
     protected void doAutowireWildcardProperties(String name, Component component) {
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java b/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java
new file mode 100644
index 00000000000..34ddef39139
--- /dev/null
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java
@@ -0,0 +1,57 @@
+/*
+ * 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.main;
+
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.spi.PropertiesReload;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.OrderedLocationProperties;
+
+/**
+ * Reloading of application.properties when using Camel Main in reload mode, such as when using camel-jbang.
+ */
+public class MainPropertiesReload extends ServiceSupport implements PropertiesReload, CamelContextAware {
+
+    private final BaseMainSupport main;
+    private CamelContext camelContext;
+
+    public MainPropertiesReload(BaseMainSupport main) {
+        this.main = main;
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public void onReload(String name, Properties properties) throws Exception {
+        if (properties instanceof OrderedLocationProperties) {
+            OrderedLocationProperties prop = (OrderedLocationProperties) properties;
+            main.autoConfigurationFromReloadedProperties(camelContext, prop);
+            main.autowireWildcardProperties(camelContext);
+        }
+    }
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
index faa64ed8997..caef6d0e41d 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
@@ -17,6 +17,7 @@
 package org.apache.camel.support;
 
 import java.io.File;
+import java.io.InputStream;
 import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -32,10 +33,14 @@ import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.ServiceStatus;
 import org.apache.camel.StartupSummaryLevel;
 import org.apache.camel.spi.PropertiesComponent;
+import org.apache.camel.spi.PropertiesReload;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.util.AntPathMatcher;
 import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OrderedLocationProperties;
+import org.apache.camel.util.OrderedProperties;
 import org.apache.camel.util.URISupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -157,13 +162,24 @@ public class RouteWatcherReloadStrategy extends FileWatcherResourceReloadStrateg
         return "Live route reloading enabled (directory: " + dir + ")";
     }
 
-    protected void onPropertiesReload(Resource resource) {
-        LOG.info("Reloading properties: {}. (Only Camel routes can be updated with changes)",
+    protected void onPropertiesReload(Resource resource) throws Exception {
+        LOG.info("Reloading properties: {}. (Only Camel routes and components can be updated with changes)",
                 resource.getLocation());
 
         PropertiesComponent pc = getCamelContext().getPropertiesComponent();
         boolean reloaded = pc.reloadProperties(resource.getLocation());
         if (reloaded) {
+            PropertiesReload pr = getCamelContext().hasService(PropertiesReload.class);
+            if (pr != null) {
+                // load the properties, so we can update (remember location)
+                InputStream is = resource.getInputStream();
+                OrderedProperties tmp = new OrderedProperties();
+                tmp.load(is);
+                IOHelper.close(is);
+                OrderedLocationProperties properties = new OrderedLocationProperties();
+                properties.putAll(resource.getLocation(), tmp);
+                pr.onReload(resource.getLocation(), properties);
+            }
             // trigger all routes to be reloaded
             onRouteReload(null);
         }


[camel] 02/02: CAMEL-19073: camel-main / camel-jbang - Reload properties should only reload changed properties.

Posted by da...@apache.org.
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 25036ff2bd3441118f1f377531a00163f1b6b5b1
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Feb 18 11:48:57 2023 +0100

    CAMEL-19073: camel-main / camel-jbang - Reload properties should only reload changed properties.
---
 .../org/apache/camel/spi/PropertiesComponent.java  |  9 ++++
 .../component/properties/PropertiesComponent.java  | 13 +++++
 .../PropertiesComponentKeepOnlyChangedTest.java    | 62 ++++++++++++++++++++++
 .../camel/support/RouteWatcherReloadStrategy.java  | 38 ++++++++-----
 4 files changed, 108 insertions(+), 14 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
index a49fbc81bd6..2f3d3030400 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
@@ -277,6 +277,15 @@ public interface PropertiesComponent extends StaticService {
      */
     boolean reloadProperties(String pattern);
 
+    /**
+     * Filters the given list of properties, by removing properties that are already loaded and have same key and value.
+     *
+     * If all properties are not changed then the properties will become empty.
+     *
+     * @param properties the given properties to filter.
+     */
+    void keepOnlyChangeProperties(Properties properties);
+
     /**
      * Adds the {@link PropertiesLookupListener}.
      */
diff --git a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
index ecbe3f1269f..dee58f6cccf 100644
--- a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
+++ b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.function.Function;
@@ -704,6 +705,18 @@ public class PropertiesComponent extends ServiceSupport
         return answer;
     }
 
+    @Override
+    public void keepOnlyChangeProperties(Properties properties) {
+        Properties loaded = loadProperties();
+        for (String key : loaded.stringPropertyNames()) {
+            Object v1 = loaded.getProperty(key);
+            Object v2 = properties.getProperty(key);
+            if (Objects.equals(v1, v2)) {
+                properties.remove(key);
+            }
+        }
+    }
+
     @Override
     protected void doInit() throws Exception {
         super.doInit();
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentKeepOnlyChangedTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentKeepOnlyChangedTest.java
new file mode 100644
index 00000000000..90275371232
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentKeepOnlyChangedTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.component.properties;
+
+import java.util.Properties;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.spi.PropertiesComponent;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class PropertiesComponentKeepOnlyChangedTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testChanged() throws Exception {
+        PropertiesComponent pc = context.getPropertiesComponent();
+        pc.addInitialProperty("foo", "123");
+        pc.addInitialProperty("bar", "true");
+
+        Properties p = new Properties();
+        p.setProperty("foo", "123");
+        p.setProperty("bar", "false");
+        pc.keepOnlyChangeProperties(p);
+        Assertions.assertEquals(1, p.size());
+        Assertions.assertEquals("false", p.getProperty("bar"));
+
+        p = new Properties();
+        p.setProperty("foo", "123");
+        p.setProperty("bar", "true");
+        pc.keepOnlyChangeProperties(p);
+        Assertions.assertEquals(0, p.size());
+
+        p = new Properties();
+        p.setProperty("foo", "123");
+        p.setProperty("bar", "false");
+        p.setProperty("cheese", "gauda");
+        pc.keepOnlyChangeProperties(p);
+        Assertions.assertEquals(2, p.size());
+        Assertions.assertEquals("false", p.getProperty("bar"));
+        Assertions.assertEquals("gauda", p.getProperty("cheese"));
+    }
+
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
index caef6d0e41d..a3ac3215fae 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
@@ -166,22 +166,32 @@ public class RouteWatcherReloadStrategy extends FileWatcherResourceReloadStrateg
         LOG.info("Reloading properties: {}. (Only Camel routes and components can be updated with changes)",
                 resource.getLocation());
 
+        // optimize to only update if something changed
+        OrderedLocationProperties changed = null;
+
         PropertiesComponent pc = getCamelContext().getPropertiesComponent();
-        boolean reloaded = pc.reloadProperties(resource.getLocation());
-        if (reloaded) {
-            PropertiesReload pr = getCamelContext().hasService(PropertiesReload.class);
-            if (pr != null) {
-                // load the properties, so we can update (remember location)
-                InputStream is = resource.getInputStream();
-                OrderedProperties tmp = new OrderedProperties();
-                tmp.load(is);
-                IOHelper.close(is);
-                OrderedLocationProperties properties = new OrderedLocationProperties();
-                properties.putAll(resource.getLocation(), tmp);
-                pr.onReload(resource.getLocation(), properties);
+        PropertiesReload pr = getCamelContext().hasService(PropertiesReload.class);
+        if (pr != null) {
+            // load the properties, so we can update (remember location)
+            InputStream is = resource.getInputStream();
+            OrderedProperties tmp = new OrderedProperties();
+            tmp.load(is);
+            IOHelper.close(is);
+            changed = new OrderedLocationProperties();
+            changed.putAll(resource.getLocation(), tmp);
+            // filter to only keep changed properties
+            pc.keepOnlyChangeProperties(changed);
+        }
+
+        if (changed == null || !changed.isEmpty()) {
+            boolean reloaded = pc.reloadProperties(resource.getLocation());
+            if (reloaded) {
+                if (pr != null) {
+                    pr.onReload(resource.getLocation(), changed);
+                }
+                // trigger all routes to be reloaded
+                onRouteReload(null);
             }
-            // trigger all routes to be reloaded
-            onRouteReload(null);
         }
     }