From 4a6cc2ce4e950842c813c087362c3fd896e73960 Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Tue, 16 Dec 2025 12:24:04 +0100 Subject: [PATCH 1/7] feat(QTDI-2134): initial commit --- ... => DynamicDependenciesConfiguration.java} | 6 +-- .../runtime/manager/ComponentManager.java | 13 +++--- .../runtime/manager/ComponentManagerTest.java | 5 ++- .../classloader/ConfigurableClassLoader.java | 12 +++++ .../sdk/component/container/Container.java | 4 ++ .../component/container/ContainerManager.java | 44 ++++++++++++++++--- .../config/DynamicDependenciesConf.java | 4 +- 7 files changed, 69 insertions(+), 19 deletions(-) rename component-api/src/main/java/org/talend/sdk/component/api/configuration/type/{DynamicDependenciesServiceConfiguration.java => DynamicDependenciesConfiguration.java} (85%) diff --git a/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesServiceConfiguration.java b/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java similarity index 85% rename from component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesServiceConfiguration.java rename to component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java index d367dce515f68..f7f01ec74d5b3 100644 --- a/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesServiceConfiguration.java +++ b/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java @@ -26,9 +26,9 @@ @Target(TYPE) @Retention(RUNTIME) -@ConfigurationType("dynamicDependenciesServiceConfiguration") -@Documentation("Mark a model (complex object) as being the configuration used in services annotated with @DynamicDependencies.") -public @interface DynamicDependenciesServiceConfiguration { +@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 56957e149196f..446b262fd3ebd 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 1441c9e7088e9..e9934f20b71f0 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 @@ -441,8 +441,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 ac3ed4fbdfa37..b5579f3ecfa67 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; @@ -111,8 +114,11 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe this.containerInitializer = containerInitializer; this.resolver = dependenciesResolutionConfiguration.getResolver(); this.rootRepositoryLocation = dependenciesResolutionConfiguration.getRootRepositoryLocation(); - info("Using root repository: " + this.rootRepositoryLocation.toAbsolutePath()); + if (log.isDebugEnabled()) { + getSystemInformations(); + } + final String nestedPluginMappingResource = ofNullable(classLoaderConfiguration.getNestedPluginMappingResource()) .orElse("TALEND-INF/plugins.properties"); this.classLoaderConfiguration = new ClassLoaderConfiguration( @@ -124,6 +130,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() { { @@ -150,10 +162,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() { @@ -389,6 +404,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(() -> { @@ -472,8 +502,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()); diff --git a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java index 22258c28bebca..4d182f743ac96 100644 --- a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java +++ b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java @@ -18,14 +18,14 @@ import java.io.Serializable; import org.talend.sdk.component.api.configuration.Option; -import org.talend.sdk.component.api.configuration.type.DynamicDependenciesServiceConfiguration; +import org.talend.sdk.component.api.configuration.type.DynamicDependenciesConfiguration; import org.talend.sdk.component.api.configuration.ui.layout.GridLayout; import org.talend.sdk.component.api.meta.Documentation; import lombok.Data; @Data -@DynamicDependenciesServiceConfiguration +@DynamicDependenciesConfiguration @GridLayout({ @GridLayout.Row({ "group" }), @GridLayout.Row({ "artifact" }) From 83505e1d25c7a3e92ceb693431cf9434bac07c42 Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Mon, 22 Dec 2025 19:00:57 +0100 Subject: [PATCH 2/7] feat(QTDI-2134): parent resources filtering --- .../runtime/manager/ComponentManager.java | 33 +++++++++++++++++++ .../classloader/ConfigurableClassLoader.java | 26 +++++++++++++-- .../sdk/component/container/Container.java | 3 +- .../component/container/ContainerManager.java | 3 ++ ...DependencyListLocalRepositoryResolver.java | 26 +++++++++++++-- 5 files changed, 84 insertions(+), 7 deletions(-) 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 446b262fd3ebd..14f14b4a4febb 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 @@ -113,6 +113,7 @@ import org.apache.xbean.finder.archive.FileArchive; import org.apache.xbean.finder.archive.FilteredArchive; import org.apache.xbean.finder.archive.JarArchive; +import org.apache.xbean.finder.filter.ContainsFilter; import org.apache.xbean.finder.filter.ExcludeIncludeFilter; import org.apache.xbean.finder.filter.Filter; import org.apache.xbean.finder.filter.FilterList; @@ -315,6 +316,8 @@ public String[] categories() { // + tcomp "runtime" indeed (invisible from the components but required for the runtime private final Filter classesFilter; + private final Filter resourcesFilter; + private final ParameterModelService parameterModelService; private final InternationalizationServiceFactory internationalizationServiceFactory; @@ -430,6 +433,13 @@ public ComponentManager(final Path m2, final String dependenciesResource, final .map(PrefixFilter::new) .toArray(Filter[]::new)); + resourcesFilter = new FilterList(Stream.concat( + Stream.of("META-INF/services/"), + additionalParentResources()) + .distinct() + .map(ContainsFilter::new) + .toArray(Filter[]::new)); + jsonpProvider = loadJsonProvider(); jsonbProvider = loadJsonbProvider(); // these factories have memory caches so ensure we reuse them properly @@ -463,6 +473,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final migrationHandlerFactory = new MigrationHandlerFactory(reflections); final Predicate isContainerClass = name -> isContainerClass(classesFilter, name); + final Predicate isParentResource = name -> isContainerResource(resourcesFilter, name); final ContainerManager.ClassLoaderConfiguration defaultClassLoaderConfiguration = ContainerManager.ClassLoaderConfiguration .builder() @@ -470,6 +481,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final .parentClassesFilter(isContainerClass) .classesFilter(isContainerClass.negate()) .supportsResourceDependencies(true) + .parentResourcesFilter(isParentResource) .create(); this.container = new ContainerManager(ContainerManager.DependenciesResolutionConfiguration .builder() @@ -614,6 +626,16 @@ private Stream additionalContainerClasses() { .orElseGet(Stream::empty)); } + private Stream additionalParentResources() { + return Stream + .concat(customizers.stream().flatMap(Customizer::parentResources), + ofNullable( + System.getProperty("talend.component.manager.classloader.container.parentResources")) + .map(s -> s.split(",")) + .map(Stream::of) + .orElseGet(Stream::empty)); + } + public static Path findM2() { return new MavenRepositoryDefaultResolver().discover(); } @@ -1048,6 +1070,10 @@ protected boolean isContainerClass(final Filter filter, final String name) { return name != null && filter.accept(name); } + protected boolean isContainerResource(final Filter filter, final String name) { + return name != null && filter.accept(name); + } + @Override public void close() { container.close(); @@ -2210,6 +2236,13 @@ public interface Customizer { */ Stream containerClassesAndPackages(); + /** + * @return + */ + default Stream parentResources() { + return Stream.empty(); + } + /** * @return advanced toggle to ignore built-in beam exclusions and let this customizer override them. */ 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 5e75d9ebdf5fa..e62328e557796 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 @@ -92,6 +92,9 @@ public class ConfigurableClassLoader extends URLClassLoader { @Getter private final Predicate childFirstFilter; + @Getter + private final Predicate resourcesFilter; + private final Map> resources = new HashMap<>(); private final Collection transformers = new ArrayList<>(); @@ -116,7 +119,16 @@ public class ConfigurableClassLoader extends URLClassLoader { public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, final String[] nestedDependencies, final String[] jvmPrefixes) { - this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes); + this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, (name) -> false); + if (nestedDependencies != null) { + loadNestedDependencies(parent, nestedDependencies); + } + } + + public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, + final Predicate parentFilter, final Predicate childFirstFilter, + final String[] nestedDependencies, final String[] jvmPrefixes, final Predicate resourcesFilter) { + this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, resourcesFilter); if (nestedDependencies != null) { loadNestedDependencies(parent, nestedDependencies); } @@ -124,12 +136,14 @@ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoa private ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, - final Map> resources, final String[] jvmPrefixes) { + final Map> resources, final String[] jvmPrefixes, + final Predicate resourcesFilter) { super(urls, parent); this.id = id; this.creationUrls = urls; this.parentFilter = parentFilter; this.childFirstFilter = childFirstFilter; + this.resourcesFilter = resourcesFilter; this.resources.putAll(resources); this.fullPathJvmPrefixes = @@ -232,7 +246,7 @@ public void registerTransformer(final ClassFileTransformer transformer) { public synchronized URLClassLoader createTemporaryCopy() { final ConfigurableClassLoader self = this; return temporaryCopy == null ? temporaryCopy = new ConfigurableClassLoader(id, creationUrls, getParent(), - parentFilter, childFirstFilter, resources, fullPathJvmPrefixes) { + parentFilter, childFirstFilter, resources, fullPathJvmPrefixes, resourcesFilter) { @Override public synchronized void close() throws IOException { @@ -475,6 +489,12 @@ private boolean isNestedDependencyResource(final String name) { } private boolean isInJvm(final URL resource) { + // Services and parent allowed resources that should always be found by top level classloader. + // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments. + // Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties. + if (resourcesFilter.test(resource.getFile())) { + return true; + } final Path path = toPath(resource); if (path == null) { return false; 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 287e580ae72ad..8990bfbe45030 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 @@ -145,7 +145,8 @@ public Container(final String id, final String rootModule, final Artifact[] depe : null; final ConfigurableClassLoader loader = new ConfigurableClassLoader(id, urls, overrideClassLoaderConfig.getParent(), overrideClassLoaderConfig.getParentClassesFilter(), - overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers); + overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers, + overrideClassLoaderConfig.getParentResourcesFilter()); transformers.forEach(loader::registerTransformer); activeSpecificTransformers(loader); return loader; 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 b5579f3ecfa67..9995b12da2932 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 @@ -125,6 +125,7 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe ofNullable(classLoaderConfiguration.getParent()).orElseGet(ContainerManager.class::getClassLoader), ofNullable(classLoaderConfiguration.getClassesFilter()).orElseGet(() -> name -> true), ofNullable(classLoaderConfiguration.getParentClassesFilter()).orElseGet(() -> name -> true), + ofNullable(classLoaderConfiguration.getParentResourcesFilter()).orElseGet(() -> name -> true), classLoaderConfiguration.isSupportsResourceDependencies(), nestedPluginMappingResource); if (classLoaderConfiguration.isSupportsResourceDependencies()) { try (final InputStream mappingStream = @@ -451,6 +452,8 @@ public static class ClassLoaderConfiguration { private final Predicate parentClassesFilter; + private final Predicate parentResourcesFilter; + // is nested jar in jar supported (1 level only) private final boolean supportsResourceDependencies; diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java index c061f2d95caec..70d0fe75f0416 100644 --- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java +++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.Properties; import java.util.function.Function; import java.util.function.Predicate; import java.util.jar.JarFile; @@ -61,8 +62,8 @@ public class MvnDependencyListLocalRepositoryResolver implements Resolver { @Override public Stream resolve(final ClassLoader rootLoader, final String artifact) { - return Stream - .of(readDependencies(ofNullable(getJar(artifact)) + return Stream.of( + readDependencies(ofNullable(getJar(artifact)) .filter(Files::exists) .map(this::findDependenciesFile) .orElseGet(() -> { @@ -98,7 +99,26 @@ public Stream resolve(final ClassLoader rootLoader, final String artif } return ""; - }))); + })), readDynamicDependencies(rootLoader, artifact)); + } + + private String readDynamicDependencies(ClassLoader rootLoader, String artifact) { + try (final InputStream stream = rootLoader.getResourceAsStream("TALEND-INF/dynamic-dependencies.properties")) { + if (stream == null) { + return ""; + } + final Properties properties = new Properties() { + + { + load(stream); + } + }; + final String dyndeps = properties.getProperty(artifact, ""); + return dyndeps.replaceAll(",", System.lineSeparator()); + } catch (final IOException e) { + log.debug(e.getMessage(), e); + return ""; + } } private Path getJar(final String artifact) { From 921e7fec4fe592ff0918f50f61cba8a9af4ac56f Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Mon, 22 Dec 2025 19:04:00 +0100 Subject: [PATCH 3/7] Revert "feat(QTDI-2134): parent resources filtering" This reverts commit 83505e1d25c7a3e92ceb693431cf9434bac07c42. --- .../runtime/manager/ComponentManager.java | 33 ------------------- .../classloader/ConfigurableClassLoader.java | 26 ++------------- .../sdk/component/container/Container.java | 3 +- .../component/container/ContainerManager.java | 3 -- ...DependencyListLocalRepositoryResolver.java | 26 ++------------- 5 files changed, 7 insertions(+), 84 deletions(-) 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 14f14b4a4febb..446b262fd3ebd 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 @@ -113,7 +113,6 @@ import org.apache.xbean.finder.archive.FileArchive; import org.apache.xbean.finder.archive.FilteredArchive; import org.apache.xbean.finder.archive.JarArchive; -import org.apache.xbean.finder.filter.ContainsFilter; import org.apache.xbean.finder.filter.ExcludeIncludeFilter; import org.apache.xbean.finder.filter.Filter; import org.apache.xbean.finder.filter.FilterList; @@ -316,8 +315,6 @@ public String[] categories() { // + tcomp "runtime" indeed (invisible from the components but required for the runtime private final Filter classesFilter; - private final Filter resourcesFilter; - private final ParameterModelService parameterModelService; private final InternationalizationServiceFactory internationalizationServiceFactory; @@ -433,13 +430,6 @@ public ComponentManager(final Path m2, final String dependenciesResource, final .map(PrefixFilter::new) .toArray(Filter[]::new)); - resourcesFilter = new FilterList(Stream.concat( - Stream.of("META-INF/services/"), - additionalParentResources()) - .distinct() - .map(ContainsFilter::new) - .toArray(Filter[]::new)); - jsonpProvider = loadJsonProvider(); jsonbProvider = loadJsonbProvider(); // these factories have memory caches so ensure we reuse them properly @@ -473,7 +463,6 @@ public ComponentManager(final Path m2, final String dependenciesResource, final migrationHandlerFactory = new MigrationHandlerFactory(reflections); final Predicate isContainerClass = name -> isContainerClass(classesFilter, name); - final Predicate isParentResource = name -> isContainerResource(resourcesFilter, name); final ContainerManager.ClassLoaderConfiguration defaultClassLoaderConfiguration = ContainerManager.ClassLoaderConfiguration .builder() @@ -481,7 +470,6 @@ public ComponentManager(final Path m2, final String dependenciesResource, final .parentClassesFilter(isContainerClass) .classesFilter(isContainerClass.negate()) .supportsResourceDependencies(true) - .parentResourcesFilter(isParentResource) .create(); this.container = new ContainerManager(ContainerManager.DependenciesResolutionConfiguration .builder() @@ -626,16 +614,6 @@ private Stream additionalContainerClasses() { .orElseGet(Stream::empty)); } - private Stream additionalParentResources() { - return Stream - .concat(customizers.stream().flatMap(Customizer::parentResources), - ofNullable( - System.getProperty("talend.component.manager.classloader.container.parentResources")) - .map(s -> s.split(",")) - .map(Stream::of) - .orElseGet(Stream::empty)); - } - public static Path findM2() { return new MavenRepositoryDefaultResolver().discover(); } @@ -1070,10 +1048,6 @@ protected boolean isContainerClass(final Filter filter, final String name) { return name != null && filter.accept(name); } - protected boolean isContainerResource(final Filter filter, final String name) { - return name != null && filter.accept(name); - } - @Override public void close() { container.close(); @@ -2236,13 +2210,6 @@ public interface Customizer { */ Stream containerClassesAndPackages(); - /** - * @return - */ - default Stream parentResources() { - return Stream.empty(); - } - /** * @return advanced toggle to ignore built-in beam exclusions and let this customizer override them. */ 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 e62328e557796..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 @@ -92,9 +92,6 @@ public class ConfigurableClassLoader extends URLClassLoader { @Getter private final Predicate childFirstFilter; - @Getter - private final Predicate resourcesFilter; - private final Map> resources = new HashMap<>(); private final Collection transformers = new ArrayList<>(); @@ -119,16 +116,7 @@ public class ConfigurableClassLoader extends URLClassLoader { public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, final String[] nestedDependencies, final String[] jvmPrefixes) { - this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, (name) -> false); - if (nestedDependencies != null) { - loadNestedDependencies(parent, nestedDependencies); - } - } - - public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, - final Predicate parentFilter, final Predicate childFirstFilter, - final String[] nestedDependencies, final String[] jvmPrefixes, final Predicate resourcesFilter) { - this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, resourcesFilter); + this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes); if (nestedDependencies != null) { loadNestedDependencies(parent, nestedDependencies); } @@ -136,14 +124,12 @@ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoa private ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, - final Map> resources, final String[] jvmPrefixes, - final Predicate resourcesFilter) { + final Map> resources, final String[] jvmPrefixes) { super(urls, parent); this.id = id; this.creationUrls = urls; this.parentFilter = parentFilter; this.childFirstFilter = childFirstFilter; - this.resourcesFilter = resourcesFilter; this.resources.putAll(resources); this.fullPathJvmPrefixes = @@ -246,7 +232,7 @@ public void registerTransformer(final ClassFileTransformer transformer) { public synchronized URLClassLoader createTemporaryCopy() { final ConfigurableClassLoader self = this; return temporaryCopy == null ? temporaryCopy = new ConfigurableClassLoader(id, creationUrls, getParent(), - parentFilter, childFirstFilter, resources, fullPathJvmPrefixes, resourcesFilter) { + parentFilter, childFirstFilter, resources, fullPathJvmPrefixes) { @Override public synchronized void close() throws IOException { @@ -489,12 +475,6 @@ private boolean isNestedDependencyResource(final String name) { } private boolean isInJvm(final URL resource) { - // Services and parent allowed resources that should always be found by top level classloader. - // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments. - // Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties. - if (resourcesFilter.test(resource.getFile())) { - return true; - } final Path path = toPath(resource); if (path == null) { return false; 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 8990bfbe45030..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 @@ -145,8 +145,7 @@ public Container(final String id, final String rootModule, final Artifact[] depe : null; final ConfigurableClassLoader loader = new ConfigurableClassLoader(id, urls, overrideClassLoaderConfig.getParent(), overrideClassLoaderConfig.getParentClassesFilter(), - overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers, - overrideClassLoaderConfig.getParentResourcesFilter()); + overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers); transformers.forEach(loader::registerTransformer); activeSpecificTransformers(loader); return loader; 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 9995b12da2932..b5579f3ecfa67 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 @@ -125,7 +125,6 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe ofNullable(classLoaderConfiguration.getParent()).orElseGet(ContainerManager.class::getClassLoader), ofNullable(classLoaderConfiguration.getClassesFilter()).orElseGet(() -> name -> true), ofNullable(classLoaderConfiguration.getParentClassesFilter()).orElseGet(() -> name -> true), - ofNullable(classLoaderConfiguration.getParentResourcesFilter()).orElseGet(() -> name -> true), classLoaderConfiguration.isSupportsResourceDependencies(), nestedPluginMappingResource); if (classLoaderConfiguration.isSupportsResourceDependencies()) { try (final InputStream mappingStream = @@ -452,8 +451,6 @@ public static class ClassLoaderConfiguration { private final Predicate parentClassesFilter; - private final Predicate parentResourcesFilter; - // is nested jar in jar supported (1 level only) private final boolean supportsResourceDependencies; diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java index 70d0fe75f0416..c061f2d95caec 100644 --- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java +++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; -import java.util.Properties; import java.util.function.Function; import java.util.function.Predicate; import java.util.jar.JarFile; @@ -62,8 +61,8 @@ public class MvnDependencyListLocalRepositoryResolver implements Resolver { @Override public Stream resolve(final ClassLoader rootLoader, final String artifact) { - return Stream.of( - readDependencies(ofNullable(getJar(artifact)) + return Stream + .of(readDependencies(ofNullable(getJar(artifact)) .filter(Files::exists) .map(this::findDependenciesFile) .orElseGet(() -> { @@ -99,26 +98,7 @@ public Stream resolve(final ClassLoader rootLoader, final String artif } return ""; - })), readDynamicDependencies(rootLoader, artifact)); - } - - private String readDynamicDependencies(ClassLoader rootLoader, String artifact) { - try (final InputStream stream = rootLoader.getResourceAsStream("TALEND-INF/dynamic-dependencies.properties")) { - if (stream == null) { - return ""; - } - final Properties properties = new Properties() { - - { - load(stream); - } - }; - final String dyndeps = properties.getProperty(artifact, ""); - return dyndeps.replaceAll(",", System.lineSeparator()); - } catch (final IOException e) { - log.debug(e.getMessage(), e); - return ""; - } + }))); } private Path getJar(final String artifact) { From f92f29dde20031c34abcefab87e349e622d969ca Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Mon, 22 Dec 2025 19:04:57 +0100 Subject: [PATCH 4/7] feat(QTDI-2134): parent resources filtering --- .../classloader/ConfigurableClassLoader.java | 26 ++++++++++++++++--- .../sdk/component/container/Container.java | 3 ++- .../component/container/ContainerManager.java | 3 +++ 3 files changed, 28 insertions(+), 4 deletions(-) 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 5e75d9ebdf5fa..e62328e557796 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 @@ -92,6 +92,9 @@ public class ConfigurableClassLoader extends URLClassLoader { @Getter private final Predicate childFirstFilter; + @Getter + private final Predicate resourcesFilter; + private final Map> resources = new HashMap<>(); private final Collection transformers = new ArrayList<>(); @@ -116,7 +119,16 @@ public class ConfigurableClassLoader extends URLClassLoader { public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, final String[] nestedDependencies, final String[] jvmPrefixes) { - this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes); + this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, (name) -> false); + if (nestedDependencies != null) { + loadNestedDependencies(parent, nestedDependencies); + } + } + + public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, + final Predicate parentFilter, final Predicate childFirstFilter, + final String[] nestedDependencies, final String[] jvmPrefixes, final Predicate resourcesFilter) { + this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, resourcesFilter); if (nestedDependencies != null) { loadNestedDependencies(parent, nestedDependencies); } @@ -124,12 +136,14 @@ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoa private ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent, final Predicate parentFilter, final Predicate childFirstFilter, - final Map> resources, final String[] jvmPrefixes) { + final Map> resources, final String[] jvmPrefixes, + final Predicate resourcesFilter) { super(urls, parent); this.id = id; this.creationUrls = urls; this.parentFilter = parentFilter; this.childFirstFilter = childFirstFilter; + this.resourcesFilter = resourcesFilter; this.resources.putAll(resources); this.fullPathJvmPrefixes = @@ -232,7 +246,7 @@ public void registerTransformer(final ClassFileTransformer transformer) { public synchronized URLClassLoader createTemporaryCopy() { final ConfigurableClassLoader self = this; return temporaryCopy == null ? temporaryCopy = new ConfigurableClassLoader(id, creationUrls, getParent(), - parentFilter, childFirstFilter, resources, fullPathJvmPrefixes) { + parentFilter, childFirstFilter, resources, fullPathJvmPrefixes, resourcesFilter) { @Override public synchronized void close() throws IOException { @@ -475,6 +489,12 @@ private boolean isNestedDependencyResource(final String name) { } private boolean isInJvm(final URL resource) { + // Services and parent allowed resources that should always be found by top level classloader. + // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments. + // Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties. + if (resourcesFilter.test(resource.getFile())) { + return true; + } final Path path = toPath(resource); if (path == null) { return false; 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 287e580ae72ad..8990bfbe45030 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 @@ -145,7 +145,8 @@ public Container(final String id, final String rootModule, final Artifact[] depe : null; final ConfigurableClassLoader loader = new ConfigurableClassLoader(id, urls, overrideClassLoaderConfig.getParent(), overrideClassLoaderConfig.getParentClassesFilter(), - overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers); + overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers, + overrideClassLoaderConfig.getParentResourcesFilter()); transformers.forEach(loader::registerTransformer); activeSpecificTransformers(loader); return loader; 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 b5579f3ecfa67..9995b12da2932 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 @@ -125,6 +125,7 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe ofNullable(classLoaderConfiguration.getParent()).orElseGet(ContainerManager.class::getClassLoader), ofNullable(classLoaderConfiguration.getClassesFilter()).orElseGet(() -> name -> true), ofNullable(classLoaderConfiguration.getParentClassesFilter()).orElseGet(() -> name -> true), + ofNullable(classLoaderConfiguration.getParentResourcesFilter()).orElseGet(() -> name -> true), classLoaderConfiguration.isSupportsResourceDependencies(), nestedPluginMappingResource); if (classLoaderConfiguration.isSupportsResourceDependencies()) { try (final InputStream mappingStream = @@ -451,6 +452,8 @@ public static class ClassLoaderConfiguration { private final Predicate parentClassesFilter; + private final Predicate parentResourcesFilter; + // is nested jar in jar supported (1 level only) private final boolean supportsResourceDependencies; From 26a5079a456672d581339ea430f3b69cc762f3d0 Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Mon, 5 Jan 2026 16:32:31 +0100 Subject: [PATCH 5/7] feat(QTDI-2134): reintroduce MAVEN-INF resolve --- ...DependencyListLocalRepositoryResolver.java | 93 ++++++++++++------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java index c061f2d95caec..34687b5e82505 100644 --- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java +++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.Properties; import java.util.function.Function; import java.util.function.Predicate; import java.util.jar.JarFile; @@ -61,44 +62,68 @@ public class MvnDependencyListLocalRepositoryResolver implements Resolver { @Override public Stream resolve(final ClassLoader rootLoader, final String artifact) { - return Stream - .of(readDependencies(ofNullable(getJar(artifact)) - .filter(Files::exists) - .map(this::findDependenciesFile) - .orElseGet(() -> { - final boolean isNested; - try (final InputStream stream = rootLoader - .getResourceAsStream(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY + artifact)) { - isNested = stream != null; - } catch (final IOException e) { - log.debug(e.getMessage(), e); - return ""; - } + final String standardDeps = ofNullable(getJar(artifact)) + .filter(Files::exists) + .map(this::findDependenciesFile) + .orElseGet(() -> { + final boolean isNested; + try (final InputStream stream = rootLoader + .getResourceAsStream(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY + artifact)) { + isNested = stream != null; + } catch (final IOException e) { + log.debug(e.getMessage(), e); + return ""; + } - if (isNested) { // we reuse ConfigurableClassLoader just to not - // rewrite the logic but it is NOT a plugin! - try (final ConfigurableClassLoader configurableClassLoader = - new ConfigurableClassLoader("", new URL[0], rootLoader, name -> true, - name -> true, new String[] { artifact }, new String[0])) { - try (final InputStream deps = - configurableClassLoader.getResourceAsStream(dependenciesListFile)) { - return ofNullable(deps).map(s -> { - try { - return slurp(s); - } catch (final IOException e) { - log.debug(e.getMessage(), e); - return ""; - } - }).orElse(""); + if (isNested) { // we reuse ConfigurableClassLoader just to not + // rewrite the logic but it is NOT a plugin! + try (final ConfigurableClassLoader configurableClassLoader = + new ConfigurableClassLoader("", new URL[0], rootLoader, name -> true, + name -> true, new String[] { artifact }, new String[0])) { + try (final InputStream deps = + configurableClassLoader.getResourceAsStream(dependenciesListFile)) { + return ofNullable(deps).map(s -> { + try { + return slurp(s); + } catch (final IOException e) { + log.debug(e.getMessage(), e); + return ""; } - } catch (final IOException e) { - log.debug(e.getMessage(), e); - return ""; - } + }).orElse(""); } - + } catch (final IOException e) { + log.debug(e.getMessage(), e); return ""; - }))); + } + } + + return ""; + }); + final String dynamicDeps = findDynamicDependencies(rootLoader, artifact); + final String allDeps = Stream.of(standardDeps, dynamicDeps) + .filter(s -> !s.isEmpty()) + .collect(joining(System.lineSeparator())); + + return Stream.of(readDependencies(allDeps)); + } + + private String findDynamicDependencies(final ClassLoader rootLoader, final String artifact) { + try (final InputStream stream = rootLoader.getResourceAsStream("TALEND-INF/dynamic-dependencies.properties")) { + if (stream == null) { + return ""; + } + final Properties properties = new Properties() { + + { + load(stream); + } + }; + final String dyndeps = properties.getProperty(artifact, ""); + return dyndeps.replaceAll(",", System.lineSeparator()); + } catch (final IOException e) { + log.debug(e.getMessage(), e); + return ""; + } } private Path getJar(final String artifact) { From 9589b3c29911252466220b0030054f17f6353d36 Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Tue, 6 Jan 2026 18:52:06 +0100 Subject: [PATCH 6/7] feat(QTDI-2134): parentFilterResource configuration --- .../runtime/manager/ComponentManager.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) 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 446b262fd3ebd..7f6843def8670 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 @@ -113,6 +113,7 @@ import org.apache.xbean.finder.archive.FileArchive; import org.apache.xbean.finder.archive.FilteredArchive; import org.apache.xbean.finder.archive.JarArchive; +import org.apache.xbean.finder.filter.ContainsFilter; import org.apache.xbean.finder.filter.ExcludeIncludeFilter; import org.apache.xbean.finder.filter.Filter; import org.apache.xbean.finder.filter.FilterList; @@ -315,6 +316,8 @@ public String[] categories() { // + tcomp "runtime" indeed (invisible from the components but required for the runtime private final Filter classesFilter; + private final Filter resourcesFilter; + private final ParameterModelService parameterModelService; private final InternationalizationServiceFactory internationalizationServiceFactory; @@ -429,7 +432,12 @@ public ComponentManager(final Path m2, final String dependenciesResource, final .distinct() .map(PrefixFilter::new) .toArray(Filter[]::new)); - + resourcesFilter = new FilterList(Stream.concat( + Stream.of("META-INF/services/"), + additionalParentResources()) + .distinct() + .map(ContainsFilter::new) + .toArray(Filter[]::new)); jsonpProvider = loadJsonProvider(); jsonbProvider = loadJsonbProvider(); // these factories have memory caches so ensure we reuse them properly @@ -463,6 +471,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final migrationHandlerFactory = new MigrationHandlerFactory(reflections); final Predicate isContainerClass = name -> isContainerClass(classesFilter, name); + final Predicate isParentResource = name -> isParentResource(resourcesFilter, name); final ContainerManager.ClassLoaderConfiguration defaultClassLoaderConfiguration = ContainerManager.ClassLoaderConfiguration .builder() @@ -470,6 +479,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final .parentClassesFilter(isContainerClass) .classesFilter(isContainerClass.negate()) .supportsResourceDependencies(true) + .parentResourcesFilter(isParentResource) .create(); this.container = new ContainerManager(ContainerManager.DependenciesResolutionConfiguration .builder() @@ -614,6 +624,16 @@ private Stream additionalContainerClasses() { .orElseGet(Stream::empty)); } + private Stream additionalParentResources() { + return Stream + .concat(customizers.stream().flatMap(Customizer::parentResources), + ofNullable( + System.getProperty("talend.component.manager.classloader.container.parentResources")) + .map(s -> s.split(",")) + .map(Stream::of) + .orElseGet(Stream::empty)); + } + public static Path findM2() { return new MavenRepositoryDefaultResolver().discover(); } @@ -1048,6 +1068,10 @@ protected boolean isContainerClass(final Filter filter, final String name) { return name != null && filter.accept(name); } + protected boolean isParentResource(final Filter filter, final String name) { + return name != null && filter.accept(name); + } + @Override public void close() { container.close(); @@ -2210,6 +2234,13 @@ public interface Customizer { */ Stream containerClassesAndPackages(); + /** + * @return + */ + default Stream parentResources() { + return Stream.empty(); + } + /** * @return advanced toggle to ignore built-in beam exclusions and let this customizer override them. */ From 82d0275a72abe6070b3804d4e28974a667a0a599 Mon Sep 17 00:00:00 2001 From: Emmanuel GALLOIS Date: Thu, 8 Jan 2026 11:01:16 +0100 Subject: [PATCH 7/7] feat(QTDI-2134): doc for configuration type --- .../pages/_partials/generated_configuration-types.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc b/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc index 3fa442503bb76..00241ce1bc0c3 100644 --- a/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc +++ b/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc @@ -47,18 +47,18 @@ Mark a model (complex object) as being a dataset discovery configuration. ---- -= DynamicDependenciesServiceConfiguration += DynamicDependenciesConfiguration -Mark a model (complex object) as being the configuration used in services annotated with @DynamicDependencies. +Mark a model (complex object) as being the configuration expected to compute dynamic dependencies. -- API: @org.talend.sdk.component.api.configuration.type.DynamicDependenciesServiceConfiguration +- API: @org.talend.sdk.component.api.configuration.type.DynamicDependenciesConfiguration - Sample: [source,js] ---- { "tcomp::configurationtype::name":"test", - "tcomp::configurationtype::type":"dynamicDependenciesServiceConfiguration" + "tcomp::configurationtype::type":"dynamicDependenciesConfiguration" } ----