diff --git a/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java b/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java new file mode 100644 index 0000000000000..f7f01ec74d5b3 --- /dev/null +++ b/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2006-2025 Talend Inc. - www.talend.com + * + * Licensed 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.talend.sdk.component.api.configuration.type; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.talend.sdk.component.api.configuration.type.meta.ConfigurationType; +import org.talend.sdk.component.api.meta.Documentation; + +@Target(TYPE) +@Retention(RUNTIME) +@ConfigurationType("dynamicDependenciesConfiguration") +@Documentation("Mark a model (complex object) as being the configuration expected to compute dynamic dependencies.") +public @interface DynamicDependenciesConfiguration { + + String value() default "default"; +} \ No newline at end of file diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java index 7693d52fae57f..03bac31c528db 100644 --- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java +++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java @@ -211,11 +211,14 @@ private static ComponentManager buildNewComponentManager() { { info("ComponentManager version: " + ComponentManagerVersion.VERSION); info("Creating the contextual ComponentManager instance " + getIdentifiers()); - - parallelIf(Boolean.getBoolean("talend.component.manager.plugins.parallel"), - container.getDefinedNestedPlugin().stream().filter(p -> !hasPlugin(p))) - .forEach(this::addPlugin); - info("Components: " + availablePlugins()); + try { + parallelIf(Boolean.getBoolean("talend.component.manager.plugins.parallel"), + container.getDefinedNestedPlugin().stream().filter(p -> !hasPlugin(p))) + .forEach(this::addPlugin); + info("Components: " + availablePlugins()); + } catch (Exception e) { + info("Failed to load plugins from plugins.properties: " + e.getMessage()); + } } @Override diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java index 585e197c1ce3e..362e6fb3418b9 100644 --- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java +++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java @@ -429,8 +429,9 @@ void extendFamilyInNestedRepo(@TempDir final File temporaryFolder) throws Except .map(File::getName) .sorted() .toArray(String[]::new); - assertEquals(1, dependencies.length); // ignored transitive deps, enables the new root to control it - assertEquals("main.jar", dependencies[0]); // transitive-1.0.0.jar is nested + assertEquals(2, dependencies.length); // ignored transitive deps, enables the new root to control it + assertEquals("fatjar.jar", dependencies[0]); + assertEquals("main.jar", dependencies[1]); // transitive-1.0.0.jar is nested } finally { if (!transitive.delete()) { transitive.deleteOnExit(); diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java index 3ded8250b3ccd..5e75d9ebdf5fa 100644 --- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java +++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java @@ -111,6 +111,8 @@ public class ConfigurableClassLoader extends URLClassLoader { @Getter private final List cacheableClasses; + private List nestedURLs = new ArrayList<>(); + public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, final String[] nestedDependencies, final String[] jvmPrefixes) { @@ -155,6 +157,7 @@ private void loadNestedDependencies(final ClassLoader parent, final String[] nes if (url == null) { throw new IllegalArgumentException("Didn't find " + resource + " in " + asList(nestedDependencies)); } + nestedURLs.add(url); final Map resources = new HashMap<>(); final URLConnection urlConnection; final Manifest manifest; @@ -458,6 +461,15 @@ public Enumeration findResources(final String name) throws IOException { return enumeration(aggregated); } + @Override + public URL[] getURLs() { + final List urls = new ArrayList<>(Arrays.asList(super.getURLs())); + if (!nestedURLs.isEmpty()) { + urls.addAll(nestedURLs); + } + return urls.toArray(new URL[0]); + } + private boolean isNestedDependencyResource(final String name) { return name != null && name.startsWith(NESTED_MAVEN_REPOSITORY); } diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java index 67e33c498479a..287e580ae72ad 100644 --- a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java +++ b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java @@ -307,6 +307,10 @@ public Date getCreated() { return created.get(); } + public boolean hasNestedRepository() { + return hasNestedRepository; + } + public void registerTransformer(final ClassFileTransformer transformer) { transformers.add(transformer); } diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java index eddcc25799830..e4d375c5f34ec 100644 --- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java +++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java @@ -29,6 +29,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -110,11 +113,21 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe this.logInfoLevelMapping = logInfoLevelMapping; this.containerInitializer = containerInitializer; this.resolver = dependenciesResolutionConfiguration.getResolver(); - this.rootRepositoryLocation = ofNullable(dependenciesResolutionConfiguration.getRootRepositoryLocation()) + + Path rootRepo = ofNullable(dependenciesResolutionConfiguration.getRootRepositoryLocation()) .filter(Files::exists) - .orElseGet(() -> PathFactory.get(System.getProperty("user.home", "")).resolve(".m2/repository")); + .orElseGet(() -> PathFactory.get(System.getProperty("user.home")).resolve(".m2/repository")); + // if we've defaulted to user home m2 (fallback), we want to check if we're in running in a fatjar + if (PathFactory.get(System.getProperty("user.home")).resolve(".m2/repository").equals(rootRepo)) { + final URL nested = classLoaderConfiguration.getParent().getResource("MAVEN-INF/repository"); + if (nested != null) { + rootRepo = PathFactory.get(nested.getFile().replace("file:", "")); + } + } + this.rootRepositoryLocation = rootRepo; if (log.isDebugEnabled()) { + getSystemInformations(); log.debug("Using root repository: " + this.rootRepositoryLocation.toAbsolutePath()); } @@ -129,6 +142,12 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe try (final InputStream mappingStream = classLoaderConfiguration.getParent().getResourceAsStream(nestedPluginMappingResource)) { if (mappingStream != null) { + if (log.isDebugEnabled()) { + final URL plug = classLoaderConfiguration.getParent().getResource(nestedPluginMappingResource); + if (plug != null) { + log.debug("[sysinfo] plugins mapping " + plug.toString()); + } + } final Properties properties = new Properties() { { @@ -155,10 +174,13 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe this.jvmMarkers = Stream .concat(Stream.concat(Stream.of(getJre()), getComponentModules()), getCustomJvmMarkers()) .toArray(String[]::new); - this.hasNestedRepository = - this.classLoaderConfiguration.isSupportsResourceDependencies() && this.classLoaderConfiguration - .getParent() - .getResource(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY) != null; + final URL nestedMvn = this.classLoaderConfiguration + .getParent() + .getResource(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY); + this.hasNestedRepository = this.classLoaderConfiguration.isSupportsResourceDependencies() && nestedMvn != null; + if (log.isDebugEnabled() && hasNestedRepository) { + log.debug("[sysinfo] nested maven repository: " + nestedMvn); + } } public File getRootRepositoryLocation() { @@ -394,6 +416,21 @@ private String getJre() { .orElseThrow(IllegalArgumentException::new); } + private void getSystemInformations() { + try { + final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean(); + log.debug("[sysinfo] JVM arguments: " + rt.getInputArguments()); + try { + log.debug("[sysinfo] Boot classpath: " + rt.getBootClassPath()); + } catch (Exception e) { + } + log.debug("[sysinfo] Runtime classpath: " + rt.getClassPath()); + log.debug("[sysinfo] Runtime arguments: " + System.getProperty("sun.java.command")); + } catch (Exception e) { + log.debug("Unable to get JVM information: " + e.getMessage(), e); + } + } + @Override public void close() { lifecycle.closeIfNeeded(() -> { @@ -477,8 +514,8 @@ public Container create() { ? nestedContainerMapping.getOrDefault(module, module) : module; final Path resolved = resolve(moduleLocation); - info("Creating module " + moduleLocation + " (from " + module - + (Files.exists(resolved) ? ", location=" + resolved.toAbsolutePath().toString() : "") + ")"); + info(String.format("Creating module %s (from %s, location=%s)", moduleLocation, module, + resolved.toAbsolutePath())); final Stream classpath = Stream .concat(getBuiltInClasspath(moduleLocation), additionalClasspath == null ? Stream.empty() : additionalClasspath.stream());