Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions component-starter-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -462,16 +462,6 @@
</exclusions>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<configuration>
<allowSystemExits>true</allowSystemExits>
<scripts>
<script>${project.basedir}/src/build/GrabMavenWrapper.groovy</script>
</scripts>
</configuration>
<executions>
Comment thread
undx marked this conversation as resolved.
<execution>
<id>grab-maven-wrapper</id>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,14 +381,15 @@ private byte[] swallow(final Supplier<StreamingOutput> dependency) {
}
}

private static Route route(final String id, final String path, final SortedMap<String, String> queries,
// visible for testing
static Route route(final String id, final String path, final SortedMap<String, String> queries,
final Map<String, String> requestHeaders, final Map<String, String> responseHeaders, final String content) {
return new Route(id, 200, path, queries,
responseHeaders.isEmpty()
? singletonMap("Accept", responseHeaders.getOrDefault("Content-Type", "application/json"))
: requestHeaders,
responseHeaders.isEmpty() ? singletonMap("Content-Type", "application/json") : responseHeaders,
content.getBytes(StandardCharsets.UTF_8));
content == null ? new byte[0] : content.getBytes(StandardCharsets.UTF_8));
}

private static Route route(final String id, final String path, final SortedMap<String, String> queries,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (C) 2006-2026 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.tools.webapp.standalone.generator;

import static java.util.Collections.emptyMap;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.nio.charset.StandardCharsets;
import java.util.TreeMap;

import org.junit.jupiter.api.Test;
import org.talend.sdk.component.tools.webapp.standalone.Route;

class StaticResourceGeneratorTest {

@Test
void routeWithNullContentHasEmptyBody() {
final Route route = StaticResourceGenerator
.route("component_server_environment", "/api/v1/cache/clear", new TreeMap<>(), emptyMap(), emptyMap(),
null);

assertEquals(200, route.getStatus());
assertEquals("/api/v1/cache/clear", route.getPath());
assertArrayEquals(new byte[0], route.getContent());
}

@Test
void routeWithContentKeepsUtf8Body() {
final Route route = StaticResourceGenerator
.route("component_server_environment", "/api/v1/environment", new TreeMap<>(), emptyMap(), emptyMap(),
"{\"a\":\"é\"}");

assertArrayEquals("{\"a\":\"é\"}".getBytes(StandardCharsets.UTF_8), route.getContent());
}
}
23 changes: 23 additions & 0 deletions repository-knowledge.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,29 @@ The repo has **two** JUnit testing modules under `component-runtime-testing/`:

Always depend on `component-runtime-junit` for new test code.

### `uispec` goal — isolated classloader and how to verify it

[2026-10-05 | QTDI-3531] `talend-component:uispec` (`StaticUiSpecGenerator`) starts an embedded server, so it must not run in
the mojo's own realm: that realm contains the plugin dependencies plus the transitive dependencies of
every connector CAR declared as plugin dependency, and a CXF 4 (jakarta servlet) there shadows CXF 3.6
(javax) → `VerifyError`. The design therefore relies on an isolated classloader
(`UiSpecGeneratorMojo` + `uispec-generator.properties`, versions kept in lock-step with the plugin
version), guarded by the invoker IT `src/it/uispec`. The invoker configuration lives in the `ci-build`
profile (also auto-activated when `JENKINS_URL` is set), and the IT must run against the freshly
packaged plugin (a bare `invoker:run` resolves a stale remote SNAPSHOT instead):

```bash
mvn verify -pl talend-component-maven-plugin -Pci-build -DskipTests -Dinvoker.test=uispec
```

The mojo resolves the generator classpath from `${project.remoteProjectRepositories}` (the artifacts are
regular dependencies, not plugins); `UiSpecGeneratorMojoTest` covers the isolation logic in the default build.

[2026-10-05 | QTDI-3531] Manual validation against real connectors: in
`connectors/cloud/cloud-components-docker`, run
`mvn -o talend-component:uispec -PPUSH_DOCKER -Dcomponent-runtime.version=<local SNAPSHOT>`
(~2 min, produces `target/talend-component-kit/uispec.zip`).

---

## CI / Jenkinsfile patterns
Expand Down
16 changes: 16 additions & 0 deletions talend-component-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,22 @@
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>org/talend/sdk/component/maven/uispec-generator.properties</exclude>
</excludes>
</resource>
<resource>
<!-- versions of the libraries the uispec generator classpath is resolved with -->
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>org/talend/sdk/component/maven/uispec-generator.properties</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/sun.nio.cs=ALL-UNNAMED --add-opens=java.base/sun.security.action=ALL-UNNAMED --add-opens=java.base/sun.security.x509=ALL-UNNAMED --add-opens=java.base/sun.util.calendar=ALL-UNNAMED
78 changes: 78 additions & 0 deletions talend-component-maven-plugin/src/it/uispec/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2006-2026 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-runtime</artifactId>
<version>@project.version@</version>
</parent>

<artifactId>sample-it-uispec</artifactId>
<name>Component Runtime :: Maven Plugin :: IT :: UiSpec</name>

<properties>
<rootlocation>${project.basedir}</rootlocation>
<talend.build.name>${talend.build.name.base}.sample.it.uispec</talend.build.name>
<spotless.skip>true</spotless.skip>
</properties>

<dependencies>
<dependency>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-api</artifactId>
<version>@project.version@</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.talend.sdk.component</groupId>
<artifactId>talend-component-maven-plugin</artifactId>
<version>@project.version@</version>
<dependencies>
<dependency>
<groupId>org.talend.components</groupId>
<artifactId>@it-component-artifact-id@</artifactId>
<version>@it-component-version@</version>
<classifier>component</classifier>
<type>car</type>
</dependency>
<!-- shadows the CXF/servlet version used by the embedded server if the generator runs in the plugin classloader -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>4.1.8</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>uispec</id>
<goals>
<goal>uispec</goal>
</goals>
<phase>package</phase>
<configuration>
<uiSpecZip>${project.build.directory}/talend-component-kit/uispec.zip</uiSpecZip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
38 changes: 38 additions & 0 deletions talend-component-maven-plugin/src/it/uispec/postbuild.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (C) 2006-2026 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.
*/
import java.nio.file.Paths
import java.util.zip.ZipFile

/**
* Checks that the uispec mojo generated its archive even if the plugin classpath is polluted by conflicting libraries
*/
static def checkUiSpecMojo(final File basedir) {
final File zip = Paths.get(basedir.toString()).resolve('target/talend-component-kit/uispec.zip').toFile()
if (!zip.exists()) {
throw new FileNotFoundException("Could not find uispec archive ${zip}")
}
final ZipFile archive = new ZipFile(zip)
try {
final List<String> names = archive.entries().collect { it.name }
assert names.contains('component/')
assert names.contains('configuration/')
assert names.any { it.startsWith('component/') && it != 'component/' }
} finally {
archive.close()
}
}

checkUiSpecMojo(basedir)
Loading
Loading