gnodet-bot commented on code in PR #28126:
URL: https://github.com/apache/camel/pull/28126#discussion_r4317516065


##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java:
##########
@@ -883,6 +885,17 @@ protected void autoconfigure(CamelContext camelContext) 
throws Exception {
         super.autoconfigure(camelContext);
     }
 
+    @Override
+    protected void autoConfigurationFromReloadedProperties(
+            CamelContext camelContext, OrderedLocationProperties 
reloadedProperties, boolean changed)
+            throws Exception {
+        // a dependency added to a properties file while the application runs 
is downloaded before the beans and
+        // components of the reload are created (CAMEL-25833)
+        new 
ReloadDependencyDownloader(camelContext).download(reloadedProperties,
+                getInstanceType() + ".dependencies", getInstanceType() + 
".dependencies.main");
+        super.autoConfigurationFromReloadedProperties(camelContext, 
reloadedProperties, changed);

Review Comment:
   ⚠️ **Behavioral concern:** The `changed` parameter is received but not 
consulted before calling `download()`. In the parent class, `changed=false` 
signals secret rotation (property values changed but same set of dependencies). 
Should the download be skipped when `changed=false`?
   
   ```suggestion
           if (changed) {
               new 
ReloadDependencyDownloader(camelContext).download(reloadedProperties,
                       getInstanceType() + ".dependencies", getInstanceType() + 
".dependencies.main");
           }
           super.autoConfigurationFromReloadedProperties(camelContext, 
reloadedProperties, changed);
   ```
   
   If downloading on every reload (including pure secret rotation) is 
intentional, a brief comment explaining why would help future maintainers.



##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ReloadDependencyDownloader.java:
##########
@@ -0,0 +1,117 @@
+/*
+ * 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.download;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.tooling.maven.MavenGav;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Downloads the dependencies of a properties file that changed while the 
application runs, such as a
+ * camel.jbang.dependencies line added to application.properties in dev mode, 
so the beans and components of the reload
+ * can use them. The dependencies of the properties files are otherwise only 
downloaded when the application starts
+ * ({@link CommandLineDependencyDownloader}), while a //DEPS line in a source 
file is downloaded in a reload as well.
+ * <p/>
+ * A library that is on the classpath in another version is not downloaded, as 
both versions would then be on the
+ * classpath: changing the version needs a restart.
+ */
+public final class ReloadDependencyDownloader {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ReloadDependencyDownloader.class);
+
+    private final CamelContext camelContext;
+    private final DependencyDownloader downloader;
+
+    public ReloadDependencyDownloader(CamelContext camelContext) {
+        this.camelContext = camelContext;
+        this.downloader = camelContext.hasService(DependencyDownloader.class);
+    }
+
+    /**
+     * Downloads the dependencies in the given keys of the properties (comma 
separated, as when the application starts)
+     * that are not on the classpath.
+     *
+     * @return the dependencies that are not downloaded as another version of 
them is on the classpath, which need a
+     *         restart
+     */
+    public List<String> download(Properties properties, String... keys) {
+        List<String> restart = new ArrayList<>();
+        if (downloader == null) {
+            return restart;
+        }
+        for (String key : keys) {
+            String value = properties.getProperty(key);
+            if (value == null) {
+                continue;
+            }
+            for (String dep : value.split(",")) {
+                dep = dep.trim();
+                if (dep.isEmpty()) {
+                    continue;
+                }
+                MavenGav gav = CatalogDependencyResolver.resolve(dep, 
camelContext.getVersion());
+                String groupId = gav.getGroupId();
+                String artifactId = gav.getArtifactId();
+                String version = gav.getVersion();
+                if (artifactId == null || 
downloader.alreadyOnClasspath(groupId, artifactId, version)) {
+                    continue;
+                }
+                String loaded = loadedVersion(groupId, artifactId);
+                if (loaded != null) {
+                    LOG.warn("The dependency {}:{}:{} in {} is not downloaded, 
as version {} is on the classpath:"
+                             + " restart to change the version",
+                            groupId, artifactId, version, key, loaded);
+                    restart.add(groupId + ":" + artifactId + ":" + version);
+                    continue;
+                }
+                LOG.info("Downloading the dependency {}:{}:{} added to {}", 
groupId, artifactId, version, key);
+                downloader.downloadDependency(groupId, artifactId, version);
+            }
+        }
+        return restart;
+    }
+
+    /**
+     * The version of the library that the downloader has put on the 
classpath, from the path of its JAR in the Maven
+     * repository (such as 
.../com/github/javafaker/javafaker/1.0.1/javafaker-1.0.1.jar), or null.
+     */
+    private String loadedVersion(String groupId, String artifactId) {

Review Comment:
   💡 **Minor note:** `loadedVersion()` relies on the Maven repository URL 
layout to determine the currently-loaded version. This is acceptable since 
`camel-jbang --dev` always uses `URLClassLoader` with standard repository 
paths, but a brief Javadoc comment documenting the assumption (Maven repo 
layout required) would make the constraint explicit and prevent future 
confusion if this method is reused in different contexts.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to