KAFKA-16437 Upgrade to Jakarta and Jetty 12 (KIP-1032) (#16754)

This commit implements the changes for KIP-1032. This updates Kafka to Jakarta specs, JavaEE 10 and Jetty 12. The changes here primarily effect Kafka Connect and MM2.

Todo/Notes:

1) I bumped the connect modules to JDK 17 but I also had to bump a couple other things that had a dependency on conect. The tools project depends on connect so that had to be bumped, and streams depends on tools so that needed to be bumped. This means we may need to separate some things if we don't want to enforce JDK 17 on streams.

2) There is an issue with a test in DedicatedMirrorIntegrationTest that I had to change for now that involves escaping characters and not quite sure what to do about it yet. The cause is the Servlet 6 spec changing what is allowed in the path. See: Jetty 12: 400: Ambiguous URI path encoding for path <%=FOO%>~1 (encoded: %3C%25%3DFOO%25%3E%7E1) jetty/jetty.project#11890

3) I had to configure the idle timeout in Jetty requests to match our request timeout so tests didn't fail. This was needed to fix the ConnectWorkerIntegrationTest#testPollTimeoutExpiry() test

Testing is being done by just using the existing tests for Connect and MM2 which should be sufficient.

Reviewers: Greg Harris <greg.harris@aiven.io>, David Arthur <mumrah@gmail.com>, Chia-Ping Tsai <chia7712@gmail.com>
This commit is contained in:
Christopher L. Shannon 2024-12-11 10:24:14 -05:00 committed by GitHub
parent d2ad418cfd
commit bd6d0fbf3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
59 changed files with 380 additions and 313 deletions

View File

@ -302,7 +302,6 @@ see: licenses/CDDL+GPL-1.1
javax.activation-api-1.2.0 javax.activation-api-1.2.0
javax.annotation-api-1.3.2 javax.annotation-api-1.3.2
javax.servlet-api-3.1.0 javax.servlet-api-3.1.0
javax.ws.rs-api-2.1.1
jaxb-api-2.3.1 jaxb-api-2.3.1
activation-1.1.1 activation-1.1.1

View File

@ -1835,7 +1835,7 @@ project(':generator') {
implementation libs.argparse4j implementation libs.argparse4j
implementation libs.jacksonDatabind implementation libs.jacksonDatabind
implementation libs.jacksonJDK8Datatypes implementation libs.jacksonJDK8Datatypes
implementation libs.jacksonJaxrsJsonProvider implementation libs.jacksonJakartarsJsonProvider
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.4.0.202211300538-r' implementation 'org.eclipse.jgit:org.eclipse.jgit:6.4.0.202211300538-r'
// SSH support for JGit based on Apache MINA sshd // SSH support for JGit based on Apache MINA sshd
@ -1882,7 +1882,7 @@ project(':clients') {
compileOnly libs.jose4j // for SASL/OAUTHBEARER JWT validation; only used by broker compileOnly libs.jose4j // for SASL/OAUTHBEARER JWT validation; only used by broker
testImplementation libs.bcpkix testImplementation libs.bcpkix
testImplementation libs.jacksonJaxrsJsonProvider testImplementation libs.jacksonJakartarsJsonProvider
testImplementation libs.jose4j testImplementation libs.jose4j
testImplementation libs.junitJupiter testImplementation libs.junitJupiter
testImplementation libs.reload4j testImplementation libs.reload4j
@ -2446,7 +2446,7 @@ project(':tools') {
implementation libs.re2j implementation libs.re2j
implementation libs.jose4j // for SASL/OAUTHBEARER JWT validation implementation libs.jose4j // for SASL/OAUTHBEARER JWT validation
implementation libs.jacksonJaxrsJsonProvider implementation libs.jacksonJakartarsJsonProvider
testImplementation project(':clients') testImplementation project(':clients')
testImplementation project(':clients').sourceSets.test.output testImplementation project(':clients').sourceSets.test.output
@ -2515,14 +2515,20 @@ project(':trogdor') {
implementation libs.slf4jApi implementation libs.slf4jApi
runtimeOnly libs.reload4j runtimeOnly libs.reload4j
implementation libs.jacksonJaxrsJsonProvider implementation libs.jacksonJakartarsJsonProvider
implementation libs.jerseyContainerServlet implementation libs.jerseyContainerServlet
implementation libs.jerseyHk2 implementation libs.jerseyHk2
implementation libs.jaxbApi // Jersey dependency that was available in the JDK before Java 9 implementation libs.jaxbApi // Jersey dependency that was available in the JDK before Java 9
implementation libs.activation // Jersey dependency that was available in the JDK before Java 9 implementation libs.activation // Jersey dependency that was available in the JDK before Java 9
implementation libs.jettyServer implementation (libs.jettyServer) {
implementation libs.jettyServlet exclude group: 'org.slf4j', module: 'slf4j-api'
implementation libs.jettyServlets }
implementation (libs.jettyServlet) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation (libs.jettyServlets) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation project(':group-coordinator') implementation project(':group-coordinator')
implementation project(':group-coordinator:group-coordinator-api') implementation project(':group-coordinator:group-coordinator-api')
@ -2572,7 +2578,7 @@ project(':shell') {
implementation project(':raft') implementation project(':raft')
implementation libs.jose4j // for SASL/OAUTHBEARER JWT validation implementation libs.jose4j // for SASL/OAUTHBEARER JWT validation
implementation libs.jacksonJaxrsJsonProvider implementation libs.jacksonJakartarsJsonProvider
testImplementation project(':clients') testImplementation project(':clients')
testImplementation project(':clients').sourceSets.test.output testImplementation project(':clients').sourceSets.test.output
@ -2895,11 +2901,7 @@ project(':streams:examples') {
dependencies { dependencies {
// this dependency should be removed after we unify data API // this dependency should be removed after we unify data API
implementation(project(':connect:json')) { implementation(project(':connect:json'))
// this transitive dependency is not used in Streams, and it breaks SBT builds
exclude module: 'javax.ws.rs-api'
}
implementation project(':streams') implementation project(':streams')
implementation libs.slf4jReload4j implementation libs.slf4jReload4j
@ -3342,7 +3344,7 @@ project(':connect:api') {
api project(':clients') api project(':clients')
implementation libs.slf4jApi implementation libs.slf4jApi
runtimeOnly libs.reload4j runtimeOnly libs.reload4j
implementation libs.jaxrsApi implementation libs.jakartaRsApi
testImplementation libs.junitJupiter testImplementation libs.junitJupiter
testImplementation project(':clients').sourceSets.test.output testImplementation project(':clients').sourceSets.test.output
@ -3466,15 +3468,23 @@ project(':connect:runtime') {
implementation libs.slf4jReload4j implementation libs.slf4jReload4j
implementation libs.jose4j // for SASL/OAUTHBEARER JWT validation implementation libs.jose4j // for SASL/OAUTHBEARER JWT validation
implementation libs.jacksonAnnotations implementation libs.jacksonAnnotations
implementation libs.jacksonJaxrsJsonProvider implementation libs.jacksonJakartarsJsonProvider
implementation libs.jerseyContainerServlet implementation libs.jerseyContainerServlet
implementation libs.jerseyHk2 implementation libs.jerseyHk2
implementation libs.jaxbApi // Jersey dependency that was available in the JDK before Java 9 implementation libs.jaxbApi // Jersey dependency that was available in the JDK before Java 9
implementation libs.activation // Jersey dependency that was available in the JDK before Java 9 implementation libs.activation // Jersey dependency that was available in the JDK before Java 9
implementation libs.jettyServer implementation (libs.jettyServer) {
implementation libs.jettyServlet exclude group: 'org.slf4j', module: 'slf4j-api'
implementation libs.jettyServlets }
implementation libs.jettyClient implementation (libs.jettyServlet) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation (libs.jettyServlets) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation (libs.jettyClient) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation libs.classgraph implementation libs.classgraph
implementation libs.mavenArtifact implementation libs.mavenArtifact
implementation libs.swaggerAnnotations implementation libs.swaggerAnnotations
@ -3637,7 +3647,7 @@ project(':connect:basic-auth-extension') {
implementation project(':connect:api') implementation project(':connect:api')
implementation libs.slf4jApi implementation libs.slf4jApi
runtimeOnly libs.reload4j runtimeOnly libs.reload4j
implementation libs.jaxrsApi implementation libs.jakartaRsApi
implementation libs.jaxAnnotationApi implementation libs.jaxAnnotationApi
testImplementation libs.bcpkix testImplementation libs.bcpkix
@ -3683,15 +3693,23 @@ project(':connect:mirror') {
implementation libs.slf4jApi implementation libs.slf4jApi
runtimeOnly libs.reload4j runtimeOnly libs.reload4j
implementation libs.jacksonAnnotations implementation libs.jacksonAnnotations
implementation libs.jacksonJaxrsJsonProvider implementation libs.jacksonJakartarsJsonProvider
implementation libs.jerseyContainerServlet implementation libs.jerseyContainerServlet
implementation libs.jerseyHk2 implementation libs.jerseyHk2
implementation libs.jaxbApi // Jersey dependency that was available in the JDK before Java 9 implementation libs.jaxbApi // Jersey dependency that was available in the JDK before Java 9
implementation libs.activation // Jersey dependency that was available in the JDK before Java 9 implementation libs.activation // Jersey dependency that was available in the JDK before Java 9
implementation libs.jettyServer implementation (libs.jettyServer) {
implementation libs.jettyServlet exclude group: 'org.slf4j', module: 'slf4j-api'
implementation libs.jettyServlets }
implementation libs.jettyClient implementation (libs.jettyServlet) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation (libs.jettyServlets) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation (libs.jettyClient) {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation libs.swaggerAnnotations implementation libs.swaggerAnnotations
testImplementation libs.junitJupiter testImplementation libs.junitJupiter

View File

@ -360,8 +360,8 @@
<subpackage name="trogdor"> <subpackage name="trogdor">
<allow pkg="com.fasterxml.jackson" /> <allow pkg="com.fasterxml.jackson" />
<allow pkg="javax.servlet" /> <allow pkg="jakarta.servlet" />
<allow pkg="javax.ws.rs" /> <allow pkg="jakarta.ws.rs" />
<allow pkg="net.sourceforge.argparse4j" /> <allow pkg="net.sourceforge.argparse4j" />
<allow pkg="org.apache.kafka.clients" /> <allow pkg="org.apache.kafka.clients" />
<allow pkg="org.apache.kafka.clients.admin" /> <allow pkg="org.apache.kafka.clients.admin" />
@ -529,7 +529,7 @@
<subpackage name="rest"> <subpackage name="rest">
<allow pkg="org.apache.kafka.connect.health" /> <allow pkg="org.apache.kafka.connect.health" />
<allow pkg="javax.ws.rs" /> <allow pkg="jakarta.ws.rs" />
<allow pkg= "javax.security.auth"/> <allow pkg= "javax.security.auth"/>
<subpackage name="basic"> <subpackage name="basic">
<allow pkg="org.apache.kafka.connect.rest"/> <allow pkg="org.apache.kafka.connect.rest"/>
@ -555,8 +555,8 @@
<allow pkg="org.apache.kafka.server.config" /> <allow pkg="org.apache.kafka.server.config" />
<allow pkg="kafka.server" /> <allow pkg="kafka.server" />
<subpackage name="rest"> <subpackage name="rest">
<allow pkg="javax.ws.rs" /> <allow pkg="jakarta.ws.rs" />
<allow pkg="javax.inject" /> <allow pkg="jakarta.inject" />
<allow pkg="org.glassfish.jersey" /> <allow pkg="org.glassfish.jersey" />
<allow pkg="org.glassfish.hk2" /> <allow pkg="org.glassfish.hk2" />
</subpackage> </subpackage>
@ -571,10 +571,10 @@
<subpackage name="rest"> <subpackage name="rest">
<allow pkg="org.eclipse.jetty" /> <allow pkg="org.eclipse.jetty" />
<allow pkg="javax.ws.rs" /> <allow pkg="jakarta.ws.rs" />
<allow pkg="javax.inject" /> <allow pkg="jakarta.inject" />
<allow pkg="org.glassfish.hk2" /> <allow pkg="org.glassfish.hk2" />
<allow pkg="javax.servlet" /> <allow pkg="jakarta.servlet" />
<allow pkg="org.glassfish.jersey" /> <allow pkg="org.glassfish.jersey" />
<allow pkg="com.fasterxml.jackson" /> <allow pkg="com.fasterxml.jackson" />
<allow pkg="org.apache.http"/> <allow pkg="org.apache.http"/>
@ -588,7 +588,7 @@
</subpackage> </subpackage>
<subpackage name="distributed"> <subpackage name="distributed">
<allow pkg="javax.ws.rs.core" /> <allow pkg="jakarta.ws.rs.core" />
</subpackage> </subpackage>
</subpackage> </subpackage>
@ -620,8 +620,8 @@
<allow pkg="org.apache.kafka.common.test" /> <allow pkg="org.apache.kafka.common.test" />
<allow pkg="kafka.zk" /> <allow pkg="kafka.zk" />
<allow pkg="kafka.utils" /> <allow pkg="kafka.utils" />
<allow class="javax.servlet.http.HttpServletResponse" /> <allow class="jakarta.servlet.http.HttpServletResponse" />
<allow class="javax.ws.rs.core.Response" /> <allow class="jakarta.ws.rs.core.Response" />
<allow pkg="com.fasterxml.jackson.core.type" /> <allow pkg="com.fasterxml.jackson.core.type" />
<allow pkg="org.apache.kafka.metadata" /> <allow pkg="org.apache.kafka.metadata" />
<allow pkg="org.eclipse.jetty.client"/> <allow pkg="org.eclipse.jetty.client"/>
@ -633,7 +633,7 @@
<subpackage name="integration"> <subpackage name="integration">
<allow pkg="org.apache.kafka.connect.util.clusters" /> <allow pkg="org.apache.kafka.connect.util.clusters" />
<allow pkg="org.apache.kafka.connect" /> <allow pkg="org.apache.kafka.connect" />
<allow pkg="javax.ws.rs" /> <allow pkg="jakarta.ws.rs" />
<allow pkg="org.apache.http"/> <allow pkg="org.apache.http"/>
<allow pkg="org.eclipse.jetty.util"/> <allow pkg="org.eclipse.jetty.util"/>
<!-- for tests --> <!-- for tests -->

View File

@ -51,7 +51,7 @@ public interface ConnectRestExtension extends Configurable, Versioned, Closeable
* will invoke this method after registering the default Connect resources. If the implementations attempt * will invoke this method after registering the default Connect resources. If the implementations attempt
* to re-register any of the Connect resources, it will be ignored and will be logged. * to re-register any of the Connect resources, it will be ignored and will be logged.
* *
* @param restPluginContext The context provides access to JAX-RS {@link javax.ws.rs.core.Configurable} and {@link * @param restPluginContext The context provides access to JAX-RS {@link jakarta.ws.rs.core.Configurable} and {@link
* ConnectClusterState}.The custom JAX-RS resources can be registered via the {@link * ConnectClusterState}.The custom JAX-RS resources can be registered via the {@link
* ConnectRestExtensionContext#configurable()} * ConnectRestExtensionContext#configurable()}
*/ */

View File

@ -19,19 +19,20 @@ package org.apache.kafka.connect.rest;
import org.apache.kafka.connect.health.ConnectClusterState; import org.apache.kafka.connect.health.ConnectClusterState;
import javax.ws.rs.core.Configurable; import jakarta.ws.rs.core.Configurable;
/** /**
* The interface provides the ability for {@link ConnectRestExtension} implementations to access the JAX-RS * The interface provides the ability for {@link ConnectRestExtension} implementations to access the JAX-RS
* {@link javax.ws.rs.core.Configurable} and cluster state {@link ConnectClusterState}. The implementation for the interface is provided * {@link jakarta.ws.rs.core.Configurable} and cluster state {@link ConnectClusterState}. The implementation for the interface is provided
* by the Connect framework. * by the Connect framework.
*/ */
public interface ConnectRestExtensionContext { public interface ConnectRestExtensionContext {
/** /**
* Provides an implementation of {@link javax.ws.rs.core.Configurable} that can be used to register JAX-RS resources. * Provides an implementation of {@link jakarta.ws.rs.core.Configurable} that can be used to register JAX-RS resources.
* *
* @return the JAX-RS {@link javax.ws.rs.core.Configurable}; never {@code null} * @return the JAX-RS {@link jakarta.ws.rs.core.Configurable}; never {@code null}
*/ */
Configurable<? extends Configurable<?>> configurable(); Configurable<? extends Configurable<?>> configurable();

View File

@ -51,7 +51,7 @@ import javax.security.auth.login.Configuration;
*</Pre> *</Pre>
* *
* <p>This is a reference implementation of the {@link ConnectRestExtension} interface. It registers an implementation of {@link * <p>This is a reference implementation of the {@link ConnectRestExtension} interface. It registers an implementation of {@link
* javax.ws.rs.container.ContainerRequestFilter} that does JAAS based authentication of incoming Basic Auth credentials. {@link * jakarta.ws.rs.container.ContainerRequestFilter} that does JAAS based authentication of incoming Basic Auth credentials. {@link
* ConnectRestExtension} implementations are loaded via the plugin class loader using {@link java.util.ServiceLoader} mechanism and hence * ConnectRestExtension} implementations are loaded via the plugin class loader using {@link java.util.ServiceLoader} mechanism and hence
* the packaged jar includes {@code META-INF/services/org.apache.kafka.connect.rest.extension.ConnectRestExtension} with the entry * the packaged jar includes {@code META-INF/services/org.apache.kafka.connect.rest.extension.ConnectRestExtension} with the entry
* {@code org.apache.kafka.connect.extension.auth.jaas.BasicAuthSecurityRestExtension} * {@code org.apache.kafka.connect.extension.auth.jaas.BasicAuthSecurityRestExtension}

View File

@ -42,12 +42,13 @@ import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.Configuration; import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Priorities; import jakarta.ws.rs.HttpMethod;
import javax.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Response; import jakarta.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.SecurityContext; import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@Priority(Priorities.AUTHENTICATION) @Priority(Priorities.AUTHENTICATION)
public class JaasBasicAuthFilter implements ContainerRequestFilter { public class JaasBasicAuthFilter implements ContainerRequestFilter {

View File

@ -31,7 +31,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier; import java.util.function.Supplier;
import javax.security.auth.login.Configuration; import javax.security.auth.login.Configuration;
import javax.ws.rs.core.Configurable;
import jakarta.ws.rs.core.Configurable;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;

View File

@ -39,11 +39,12 @@ import java.util.Map;
import javax.security.auth.callback.Callback; import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.ChoiceCallback; import javax.security.auth.callback.ChoiceCallback;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.HttpMethod;
import javax.ws.rs.core.Response; import jakarta.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.SecurityContext; import jakarta.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;

View File

@ -24,11 +24,11 @@ import org.apache.kafka.connect.runtime.rest.resources.InternalClusterResource;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import jakarta.inject.Inject;
import javax.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
import javax.ws.rs.Path; import jakarta.ws.rs.Path;
import javax.ws.rs.core.Context; import jakarta.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo; import jakarta.ws.rs.core.UriInfo;
@Path("/{source}/{target}/connectors") @Path("/{source}/{target}/connectors")
public class InternalMirrorResource extends InternalClusterResource { public class InternalMirrorResource extends InternalClusterResource {

View File

@ -280,7 +280,13 @@ public class DedicatedMirrorIntegrationTest {
// Cluster aliases // Cluster aliases
final String a = "A"; final String a = "A";
// Use a convoluted cluster name to ensure URL encoding/decoding works // Use a convoluted cluster name to ensure URL encoding/decoding works
final String b = "B- ._~:/?#[]@!$&'()*+;=\"<>%{}|\\^`618"; // The servlet 6.0 spec no longer allows some characters such as forward slashes, control characters,
// etc. even if they are encoded. Jetty 12 will enforce this and throw a 400 ambiguous error
// so the string of characters for the variable "b" has been updated to only include characters
// that are valid with the new spec.
// See https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0#uri-path-canonicalization
// and specifically the section: "10. Rejecting Suspicious Sequences." for details.
final String b = "B-_~:?#[]@!$&'()*+=\"<>{}|^`618";
final String ab = a + "->" + b; final String ab = a + "->" + b;
final String ba = b + "->" + a; final String ba = b + "->" + a;
final String testTopicPrefix = "test-topic-"; final String testTopicPrefix = "test-topic-";

View File

@ -112,8 +112,9 @@ import java.util.stream.Collectors;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import static org.apache.kafka.clients.consumer.ConsumerConfig.GROUP_ID_CONFIG; import static org.apache.kafka.clients.consumer.ConsumerConfig.GROUP_ID_CONFIG;
import static org.apache.kafka.common.utils.Utils.UncheckedCloseable; import static org.apache.kafka.common.utils.Utils.UncheckedCloseable;

View File

@ -24,8 +24,8 @@ import org.slf4j.LoggerFactory;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.ws.rs.core.Configurable; import jakarta.ws.rs.core.Configurable;
import javax.ws.rs.core.Configuration; import jakarta.ws.rs.core.Configuration;
/** /**
* The implementation delegates to {@link ResourceConfig} so that we can handle duplicate * The implementation delegates to {@link ResourceConfig} so that we can handle duplicate

View File

@ -20,7 +20,7 @@ package org.apache.kafka.connect.runtime.rest;
import org.apache.kafka.connect.health.ConnectClusterState; import org.apache.kafka.connect.health.ConnectClusterState;
import org.apache.kafka.connect.rest.ConnectRestExtensionContext; import org.apache.kafka.connect.rest.ConnectRestExtensionContext;
import javax.ws.rs.core.Configurable; import jakarta.ws.rs.core.Configurable;
public class ConnectRestExtensionContextImpl implements ConnectRestExtensionContext { public class ConnectRestExtensionContextImpl implements ConnectRestExtensionContext {

View File

@ -33,9 +33,9 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.UriBuilder;
public class HerderRequestHandler { public class HerderRequestHandler {
@ -113,6 +113,7 @@ public class HerderRequestHandler {
} }
String forwardUrl = uriBuilder.build().toString(); String forwardUrl = uriBuilder.build().toString();
log.debug("Forwarding request {} {} {}", forwardUrl, method, body); log.debug("Forwarding request {} {} {}", forwardUrl, method, body);
// TODO, we may need to set the request timeout as Idle timeout on the HttpClient
return translator.translate(restClient.httpRequest(forwardUrl, method, headers, body, resultType)); return translator.translate(restClient.httpRequest(forwardUrl, method, headers, body, resultType));
} else { } else {
log.error("Request '{} {}' failed because it couldn't find the target Connect worker within two hops (between workers).", log.error("Request '{} {}' failed because it couldn't find the target Connect worker within two hops (between workers).",

View File

@ -20,7 +20,7 @@ import org.apache.kafka.connect.errors.ConnectException;
import org.apache.kafka.connect.runtime.distributed.Crypto; import org.apache.kafka.connect.runtime.distributed.Crypto;
import org.apache.kafka.connect.runtime.rest.errors.BadRequestException; import org.apache.kafka.connect.runtime.rest.errors.BadRequestException;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Request;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -31,7 +31,8 @@ import java.util.Objects;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.HttpHeaders;
public class InternalRequestSignature { public class InternalRequestSignature {
@ -59,8 +60,10 @@ public class InternalRequestSignature {
throw new ConnectException(e); throw new ConnectException(e);
} }
byte[] requestSignature = sign(mac, key, requestBody); byte[] requestSignature = sign(mac, key, requestBody);
request.header(InternalRequestSignature.SIGNATURE_HEADER, Base64.getEncoder().encodeToString(requestSignature)) request.headers(field -> {
.header(InternalRequestSignature.SIGNATURE_ALGORITHM_HEADER, signatureAlgorithm); field.add(InternalRequestSignature.SIGNATURE_HEADER, Base64.getEncoder().encodeToString(requestSignature));
field.add(InternalRequestSignature.SIGNATURE_ALGORITHM_HEADER, signatureAlgorithm);
});
} }
/** /**

View File

@ -26,13 +26,15 @@ import org.apache.kafka.connect.runtime.rest.util.SSLUtils;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.StringRequestContent;
import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -46,8 +48,9 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response;
/** /**
* Client for outbound REST requests to other members of a Connect cluster * Client for outbound REST requests to other members of a Connect cluster
@ -65,7 +68,15 @@ public class RestClient {
// VisibleForTesting // VisibleForTesting
HttpClient httpClient(SslContextFactory.Client sslContextFactory) { HttpClient httpClient(SslContextFactory.Client sslContextFactory) {
return sslContextFactory != null ? new HttpClient(sslContextFactory) : new HttpClient(); final HttpClient client;
if (sslContextFactory != null) {
ClientConnector clientConnector = new ClientConnector();
clientConnector.setSslContextFactory(sslContextFactory);
client = new HttpClient(new HttpClientTransportDynamic(clientConnector));
} else {
client = new HttpClient();
}
return client;
} }
/** /**
@ -162,7 +173,7 @@ public class RestClient {
addHeadersToRequest(headers, req); addHeadersToRequest(headers, req);
if (serializedBody != null) { if (serializedBody != null) {
req.content(new StringContentProvider(serializedBody, StandardCharsets.UTF_8), "application/json"); req.body(new StringRequestContent("application/json", serializedBody, StandardCharsets.UTF_8));
} }
if (sessionKey != null && requestSignatureAlgorithm != null) { if (sessionKey != null && requestSignatureAlgorithm != null) {
@ -220,7 +231,7 @@ public class RestClient {
if (headers != null) { if (headers != null) {
String credentialAuthorization = headers.getHeaderString(HttpHeaders.AUTHORIZATION); String credentialAuthorization = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
if (credentialAuthorization != null) { if (credentialAuthorization != null) {
req.header(HttpHeaders.AUTHORIZATION, credentialAuthorization); req.headers(field -> field.add(HttpHeaders.AUTHORIZATION, credentialAuthorization));
} }
} }
} }

View File

@ -28,8 +28,12 @@ import org.apache.kafka.connect.runtime.health.ConnectClusterStateImpl;
import org.apache.kafka.connect.runtime.rest.errors.ConnectExceptionMapper; import org.apache.kafka.connect.runtime.rest.errors.ConnectExceptionMapper;
import org.apache.kafka.connect.runtime.rest.util.SSLUtils; import org.apache.kafka.connect.runtime.rest.util.SSLUtils;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
import org.eclipse.jetty.ee10.servlet.FilterHolder;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.servlets.HeaderFilter;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
@ -37,12 +41,8 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.Slf4jRequestLogWriter; import org.eclipse.jetty.server.Slf4jRequestLogWriter;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.CrossOriginHandler;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.eclipse.jetty.servlets.HeaderFilter;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.glassfish.hk2.utilities.Binder; import org.glassfish.hk2.utilities.Binder;
import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.hk2.utilities.binding.AbstractBinder;
@ -60,12 +60,13 @@ import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import javax.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.UriBuilder;
/** /**
* Embedded server for the REST API that provides the control plane for Kafka Connect workers. * Embedded server for the REST API that provides the control plane for Kafka Connect workers.
@ -189,6 +190,9 @@ public abstract class RestServer {
connector.setPort(port); connector.setPort(port);
// TODO: do we need this?
connector.setIdleTimeout(requestTimeout.timeoutMs());
return connector; return connector;
} }
@ -263,20 +267,21 @@ public abstract class RestServer {
ServletHolder adminServletHolder = new ServletHolder(new ServletContainer(adminResourceConfig)); ServletHolder adminServletHolder = new ServletHolder(new ServletContainer(adminResourceConfig));
adminContext.setContextPath("/"); adminContext.setContextPath("/");
adminContext.addServlet(adminServletHolder, "/*"); adminContext.addServlet(adminServletHolder, "/*");
adminContext.setVirtualHosts(new String[]{"@" + ADMIN_SERVER_CONNECTOR_NAME}); adminContext.setVirtualHosts(List.of("@" + ADMIN_SERVER_CONNECTOR_NAME));
contextHandlers.add(adminContext); contextHandlers.add(adminContext);
} }
String allowedOrigins = config.allowedOrigins(); String allowedOrigins = config.allowedOrigins();
if (!Utils.isBlank(allowedOrigins)) { if (!Utils.isBlank(allowedOrigins)) {
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); CrossOriginHandler crossOriginHandler = new CrossOriginHandler();
filterHolder.setName("cross-origin"); crossOriginHandler.setAllowedOriginPatterns(Set.of(allowedOrigins.split(",")));
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, allowedOrigins);
String allowedMethods = config.allowedMethods(); String allowedMethods = config.allowedMethods();
if (!Utils.isBlank(allowedMethods)) { if (!Utils.isBlank(allowedMethods)) {
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, allowedMethods); crossOriginHandler.setAllowedMethods(Set.of(allowedMethods.split(",")));
} }
context.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); // Setting to true matches the previously used CrossOriginFilter
crossOriginHandler.setDeliverPreflightRequests(true);
context.insertHandler(crossOriginHandler);
} }
String headerConfig = config.responseHeaders(); String headerConfig = config.responseHeaders();

View File

@ -16,7 +16,7 @@
*/ */
package org.apache.kafka.connect.runtime.rest.errors; package org.apache.kafka.connect.runtime.rest.errors;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
public class BadRequestException extends ConnectRestException { public class BadRequestException extends ConnectRestException {

View File

@ -23,14 +23,14 @@ import org.apache.kafka.connect.runtime.rest.entities.ErrorMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.ws.rs.WebApplicationException; import jakarta.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context; import jakarta.ws.rs.core.Context;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import jakarta.ws.rs.core.UriInfo;
import javax.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.ExceptionMapper;
/** /**
* Maps uncaught exceptions thrown while handling REST requests to appropriate {@link javax.ws.rs.core.Response}s * Maps uncaught exceptions thrown while handling REST requests to appropriate {@link jakarta.ws.rs.core.Response}s
*/ */
public class ConnectExceptionMapper implements ExceptionMapper<Exception> { public class ConnectExceptionMapper implements ExceptionMapper<Exception> {
private static final Logger log = LoggerFactory.getLogger(ConnectExceptionMapper.class); private static final Logger log = LoggerFactory.getLogger(ConnectExceptionMapper.class);
@ -49,7 +49,7 @@ public class ConnectExceptionMapper implements ExceptionMapper<Exception> {
.build(); .build();
} }
if (exception instanceof NotFoundException || exception instanceof javax.ws.rs.NotFoundException) { if (exception instanceof NotFoundException || exception instanceof jakarta.ws.rs.NotFoundException) {
return Response.status(Response.Status.NOT_FOUND) return Response.status(Response.Status.NOT_FOUND)
.entity(new ErrorMessage(Response.Status.NOT_FOUND.getStatusCode(), exception.getMessage())) .entity(new ErrorMessage(Response.Status.NOT_FOUND.getStatusCode(), exception.getMessage()))
.build(); .build();

View File

@ -18,7 +18,7 @@ package org.apache.kafka.connect.runtime.rest.errors;
import org.apache.kafka.connect.errors.ConnectException; import org.apache.kafka.connect.errors.ConnectException;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
public class ConnectRestException extends ConnectException { public class ConnectRestException extends ConnectException {
private final int statusCode; private final int statusCode;

View File

@ -41,21 +41,20 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/connector-plugins") @Path("/connector-plugins")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)

View File

@ -46,29 +46,28 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriInfo;
import static org.apache.kafka.connect.runtime.rest.HerderRequestHandler.IdentityTranslator; import static org.apache.kafka.connect.runtime.rest.HerderRequestHandler.IdentityTranslator;
import static org.apache.kafka.connect.runtime.rest.HerderRequestHandler.Translator; import static org.apache.kafka.connect.runtime.rest.HerderRequestHandler.Translator;
@ -81,7 +80,7 @@ public class ConnectorsResource {
private final Herder herder; private final Herder herder;
private final HerderRequestHandler requestHandler; private final HerderRequestHandler requestHandler;
@javax.ws.rs.core.Context @jakarta.ws.rs.core.Context
private ServletContext context; private ServletContext context;
private final boolean isTopicTrackingDisabled; private final boolean isTopicTrackingDisabled;
private final boolean isTopicTrackingResetDisabled; private final boolean isTopicTrackingResetDisabled;

View File

@ -30,18 +30,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.UriInfo;
/** /**
* Contains endpoints necessary for intra-cluster communication--that is, requests that * Contains endpoints necessary for intra-cluster communication--that is, requests that
@ -66,7 +65,7 @@ public abstract class InternalClusterResource {
/** /**
* @return a {@link Herder} instance that can be used to satisfy the current request; may not be null * @return a {@link Herder} instance that can be used to satisfy the current request; may not be null
* @throws javax.ws.rs.NotFoundException if no such herder can be provided * @throws jakarta.ws.rs.NotFoundException if no such herder can be provided
*/ */
protected abstract Herder herderForRequest(); protected abstract Herder herderForRequest();

View File

@ -20,8 +20,8 @@ import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.runtime.rest.RestClient; import org.apache.kafka.connect.runtime.rest.RestClient;
import org.apache.kafka.connect.runtime.rest.RestRequestTimeout; import org.apache.kafka.connect.runtime.rest.RestRequestTimeout;
import javax.inject.Inject; import jakarta.inject.Inject;
import javax.ws.rs.Path; import jakarta.ws.rs.Path;
@Path("/connectors") @Path("/connectors")
public class InternalConnectResource extends InternalClusterResource { public class InternalConnectResource extends InternalClusterResource {

View File

@ -29,20 +29,19 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/** /**
* A set of endpoints to adjust the log levels of runtime loggers. * A set of endpoints to adjust the log levels of runtime loggers.

View File

@ -28,14 +28,13 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/") @Path("/")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)

View File

@ -63,7 +63,7 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG;

View File

@ -73,9 +73,9 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static org.apache.kafka.clients.CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG; import static org.apache.kafka.clients.CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG;
import static org.apache.kafka.clients.CommonClientConfigs.METADATA_RECOVERY_STRATEGY_CONFIG; import static org.apache.kafka.clients.CommonClientConfigs.METADATA_RECOVERY_STRATEGY_CONFIG;
import static org.apache.kafka.common.config.AbstractConfig.CONFIG_PROVIDERS_CONFIG; import static org.apache.kafka.common.config.AbstractConfig.CONFIG_PROVIDERS_CONFIG;

View File

@ -40,7 +40,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.connect.integration.MonitorableSourceConnector.TOPIC_CONFIG; import static org.apache.kafka.connect.integration.MonitorableSourceConnector.TOPIC_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG;

View File

@ -36,7 +36,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;

View File

@ -55,9 +55,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static org.apache.kafka.connect.integration.MonitorableSourceConnector.TOPIC_CONFIG; import static org.apache.kafka.connect.integration.MonitorableSourceConnector.TOPIC_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG;

View File

@ -36,11 +36,11 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.ws.rs.GET; import jakarta.ws.rs.GET;
import javax.ws.rs.Path; import jakarta.ws.rs.Path;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.NAME_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.NAME_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG;

View File

@ -31,8 +31,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static jakarta.ws.rs.core.Response.Status.FORBIDDEN;
import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLASS_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.KEY_CONVERTER_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.KEY_CONVERTER_CLASS_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.TASKS_MAX_CONFIG;

View File

@ -40,7 +40,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.connect.integration.BlockingConnectorTest.Block.BLOCK_CONFIG; import static org.apache.kafka.connect.integration.BlockingConnectorTest.Block.BLOCK_CONFIG;
import static org.apache.kafka.connect.integration.BlockingConnectorTest.CONNECTOR_START; import static org.apache.kafka.connect.integration.BlockingConnectorTest.CONNECTOR_START;

View File

@ -114,9 +114,9 @@ import java.util.stream.IntStream;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import static jakarta.ws.rs.core.Response.Status.FORBIDDEN;
import static jakarta.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
import static org.apache.kafka.common.utils.Utils.UncheckedCloseable; import static org.apache.kafka.common.utils.Utils.UncheckedCloseable;
import static org.apache.kafka.connect.runtime.AbstractStatus.State.FAILED; import static org.apache.kafka.connect.runtime.AbstractStatus.State.FAILED;
import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLIENT_CONSUMER_OVERRIDES_PREFIX; import static org.apache.kafka.connect.runtime.ConnectorConfig.CONNECTOR_CLIENT_CONSUMER_OVERRIDES_PREFIX;

View File

@ -463,9 +463,7 @@ public class SynchronizationTest {
return r -> { return r -> {
// This is essentially Executors.defaultThreadFactory except with // This is essentially Executors.defaultThreadFactory except with
// custom thread names so in order to filter by thread names when debugging // custom thread names so in order to filter by thread names when debugging
SecurityManager s = System.getSecurityManager(); Thread t = new Thread(Thread.currentThread().getThreadGroup(), r,
Thread t = new Thread((s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup(), r,
threadPrefix + threadNumber.getAndIncrement(), threadPrefix + threadNumber.getAndIncrement(),
0); 0);
if (t.isDaemon()) { if (t.isDaemon()) {

View File

@ -58,7 +58,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -21,21 +21,23 @@ import org.apache.kafka.connect.errors.ConnectException;
import org.apache.kafka.connect.runtime.distributed.Crypto; import org.apache.kafka.connect.runtime.distributed.Crypto;
import org.apache.kafka.connect.runtime.rest.errors.BadRequestException; import org.apache.kafka.connect.runtime.rest.errors.BadRequestException;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.Request;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import java.net.URI;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Base64; import java.util.Base64;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import javax.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.HttpHeaders;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
@ -113,25 +115,16 @@ public class InternalRequestSignatureTest {
@Test @Test
public void addToRequestShouldAddHeadersOnValidSignatureAlgorithm() { public void addToRequestShouldAddHeadersOnValidSignatureAlgorithm() {
Request request = mock(Request.class); HttpClient httpClient = new HttpClient();
ArgumentCaptor<String> signatureCapture = ArgumentCaptor.forClass(String.class); Request request = httpClient.newRequest(URI.create("http://localhost"));
ArgumentCaptor<String> signatureAlgorithmCapture = ArgumentCaptor.forClass(String.class);
when(request.header(
eq(InternalRequestSignature.SIGNATURE_HEADER),
signatureCapture.capture()
)).thenReturn(request);
when(request.header(
eq(InternalRequestSignature.SIGNATURE_ALGORITHM_HEADER),
signatureAlgorithmCapture.capture()
)).thenReturn(request);
InternalRequestSignature.addToRequest(crypto, KEY, REQUEST_BODY, SIGNATURE_ALGORITHM, request); InternalRequestSignature.addToRequest(crypto, KEY, REQUEST_BODY, SIGNATURE_ALGORITHM, request);
assertEquals(ENCODED_SIGNATURE, assertEquals(ENCODED_SIGNATURE,
signatureCapture.getValue(), request.getHeaders().get(InternalRequestSignature.SIGNATURE_HEADER),
"Request should have valid base 64-encoded signature added as header"); "Request should have valid base 64-encoded signature added as header");
assertEquals(SIGNATURE_ALGORITHM, assertEquals(SIGNATURE_ALGORITHM,
signatureAlgorithmCapture.getValue(), request.getHeaders().get(InternalRequestSignature.SIGNATURE_ALGORITHM_HEADER),
"Request should have provided signature algorithm added as header"); "Request should have provided signature algorithm added as header");
} }

View File

@ -25,9 +25,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Request;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@ -45,7 +45,8 @@ import java.util.concurrent.TimeoutException;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.core.Response;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -118,7 +119,7 @@ public class RestClientTest {
private static Request buildThrowingMockRequest(Throwable t) throws ExecutionException, InterruptedException, TimeoutException { private static Request buildThrowingMockRequest(Throwable t) throws ExecutionException, InterruptedException, TimeoutException {
Request req = mock(Request.class); Request req = mock(Request.class);
when(req.header(anyString(), anyString())).thenReturn(req); when(req.headers(any())).thenReturn(req);
when(req.send()).thenThrow(t); when(req.send()).thenThrow(t);
return req; return req;
} }
@ -310,7 +311,7 @@ public class RestClientTest {
public void testHttpRequestInterrupted() throws ExecutionException, InterruptedException, TimeoutException { public void testHttpRequestInterrupted() throws ExecutionException, InterruptedException, TimeoutException {
Request req = mock(Request.class); Request req = mock(Request.class);
doThrow(new InterruptedException()).when(req).send(); doThrow(new InterruptedException()).when(req).send();
doReturn(req).when(req).header(anyString(), anyString()); doReturn(req).when(req).headers(any());
doReturn(req).when(httpClient).newRequest(anyString()); doReturn(req).when(httpClient).newRequest(anyString());
ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest( ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
@ -323,7 +324,7 @@ public class RestClientTest {
private void setupHttpClient(int responseCode, Request req, ContentResponse resp) throws Exception { private void setupHttpClient(int responseCode, Request req, ContentResponse resp) throws Exception {
when(resp.getStatus()).thenReturn(responseCode); when(resp.getStatus()).thenReturn(responseCode);
when(req.send()).thenReturn(resp); when(req.send()).thenReturn(resp);
when(req.header(anyString(), anyString())).thenReturn(req); when(req.headers(any())).thenReturn(req);
when(httpClient.newRequest(anyString())).thenReturn(req); when(httpClient.newRequest(anyString())).thenReturn(req);
} }

View File

@ -84,7 +84,7 @@ import java.util.TreeSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.ws.rs.BadRequestException; import jakarta.ws.rs.BadRequestException;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_HEALTH_CHECK_TIMEOUT_MS; import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_HEALTH_CHECK_TIMEOUT_MS;

View File

@ -64,12 +64,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.ws.rs.BadRequestException; import jakarta.ws.rs.BadRequestException;
import javax.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedHashMap; import jakarta.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import jakarta.ws.rs.core.UriInfo;
import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_HEALTH_CHECK_TIMEOUT_MS; import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_HEALTH_CHECK_TIMEOUT_MS;
import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS; import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS;

View File

@ -44,8 +44,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriInfo; import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.UriInfo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;

View File

@ -35,7 +35,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;

View File

@ -37,7 +37,7 @@ import org.mockito.stubbing.Stubber;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_HEALTH_CHECK_TIMEOUT_MS; import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_HEALTH_CHECK_TIMEOUT_MS;
import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS; import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS;

View File

@ -17,9 +17,12 @@
package org.apache.kafka.connect.runtime.rest.util; package org.apache.kafka.connect.runtime.rest.util;
import org.apache.kafka.common.config.SslConfigs; import org.apache.kafka.common.config.SslConfigs;
import org.apache.kafka.common.config.types.Password;
import org.apache.kafka.common.network.CertStores;
import org.apache.kafka.connect.runtime.rest.RestServerConfig; import org.apache.kafka.connect.runtime.rest.RestServerConfig;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Arrays; import java.util.Arrays;
@ -33,6 +36,22 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class SSLUtilsTest { public class SSLUtilsTest {
private Map<String, Object> sslConfig;
private String keystorePath;
private String truststorePath;
private Password keystorePassword;
private Password truststorePassword;
@BeforeEach
public void before() throws Exception {
CertStores serverCertStores = new CertStores(true, "localhost");
sslConfig = serverCertStores.getUntrustingConfig();
keystorePath = sslConfig.get("ssl.keystore.location").toString();
truststorePath = sslConfig.get("ssl.truststore.location").toString();
keystorePassword = (Password) sslConfig.get("ssl.keystore.password");
truststorePassword = (Password) sslConfig.get("ssl.keystore.password");
}
@Test @Test
public void testGetOrDefault() { public void testGetOrDefault() {
String existingKey = "exists"; String existingKey = "exists";
@ -47,13 +66,13 @@ public class SSLUtilsTest {
} }
@Test @Test
public void testCreateServerSideSslContextFactory() { public void testCreateServerSideSslContextFactory() throws Exception {
Map<String, String> configMap = new HashMap<>(); Map<String, String> configMap = new HashMap<>();
configMap.put("ssl.keystore.location", "/path/to/keystore"); configMap.put("ssl.keystore.location", keystorePath);
configMap.put("ssl.keystore.password", "123456"); configMap.put("ssl.keystore.password", keystorePassword.value());
configMap.put("ssl.key.password", "123456"); configMap.put("ssl.key.password", keystorePassword.value());
configMap.put("ssl.truststore.location", "/path/to/truststore"); configMap.put("ssl.truststore.location", truststorePath);
configMap.put("ssl.truststore.password", "123456"); configMap.put("ssl.truststore.password", truststorePassword.value());
configMap.put("ssl.provider", "SunJSSE"); configMap.put("ssl.provider", "SunJSSE");
configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5"); configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5");
configMap.put("ssl.secure.random.implementation", "SHA1PRNG"); configMap.put("ssl.secure.random.implementation", "SHA1PRNG");
@ -69,8 +88,8 @@ public class SSLUtilsTest {
RestServerConfig config = RestServerConfig.forPublic(null, configMap); RestServerConfig config = RestServerConfig.forPublic(null, configMap);
SslContextFactory.Server ssl = SSLUtils.createServerSideSslContextFactory(config); SslContextFactory.Server ssl = SSLUtils.createServerSideSslContextFactory(config);
assertEquals("file:///path/to/keystore", ssl.getKeyStorePath()); assertEquals("file://" + keystorePath, ssl.getKeyStorePath());
assertEquals("file:///path/to/truststore", ssl.getTrustStorePath()); assertEquals("file://" + truststorePath, ssl.getTrustStorePath());
assertEquals("SunJSSE", ssl.getProvider()); assertEquals("SunJSSE", ssl.getProvider());
assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites()); assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites());
assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm()); assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm());
@ -87,11 +106,11 @@ public class SSLUtilsTest {
@Test @Test
public void testCreateClientSideSslContextFactory() { public void testCreateClientSideSslContextFactory() {
Map<String, String> configMap = new HashMap<>(); Map<String, String> configMap = new HashMap<>();
configMap.put("ssl.keystore.location", "/path/to/keystore"); configMap.put("ssl.keystore.location", keystorePath);
configMap.put("ssl.keystore.password", "123456"); configMap.put("ssl.keystore.password", keystorePassword.value());
configMap.put("ssl.key.password", "123456"); configMap.put("ssl.key.password", keystorePassword.value());
configMap.put("ssl.truststore.location", "/path/to/truststore"); configMap.put("ssl.truststore.location", truststorePath);
configMap.put("ssl.truststore.password", "123456"); configMap.put("ssl.truststore.password", truststorePassword.value());
configMap.put("ssl.provider", "SunJSSE"); configMap.put("ssl.provider", "SunJSSE");
configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5"); configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5");
configMap.put("ssl.secure.random.implementation", "SHA1PRNG"); configMap.put("ssl.secure.random.implementation", "SHA1PRNG");
@ -107,8 +126,8 @@ public class SSLUtilsTest {
RestServerConfig config = RestServerConfig.forPublic(null, configMap); RestServerConfig config = RestServerConfig.forPublic(null, configMap);
SslContextFactory.Client ssl = SSLUtils.createClientSideSslContextFactory(config); SslContextFactory.Client ssl = SSLUtils.createClientSideSslContextFactory(config);
assertEquals("file:///path/to/keystore", ssl.getKeyStorePath()); assertEquals("file://" + keystorePath, ssl.getKeyStorePath());
assertEquals("file:///path/to/truststore", ssl.getTrustStorePath()); assertEquals("file://" + truststorePath, ssl.getTrustStorePath());
assertEquals("SunJSSE", ssl.getProvider()); assertEquals("SunJSSE", ssl.getProvider());
assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites()); assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites());
assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm()); assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm());
@ -123,11 +142,11 @@ public class SSLUtilsTest {
@Test @Test
public void testCreateServerSideSslContextFactoryDefaultValues() { public void testCreateServerSideSslContextFactoryDefaultValues() {
Map<String, String> configMap = new HashMap<>(); Map<String, String> configMap = new HashMap<>();
configMap.put("ssl.keystore.location", "/path/to/keystore"); configMap.put("ssl.keystore.location", keystorePath);
configMap.put("ssl.keystore.password", "123456"); configMap.put("ssl.keystore.password", keystorePassword.value());
configMap.put("ssl.key.password", "123456"); configMap.put("ssl.key.password", keystorePassword.value());
configMap.put("ssl.truststore.location", "/path/to/truststore"); configMap.put("ssl.truststore.location", truststorePath);
configMap.put("ssl.truststore.password", "123456"); configMap.put("ssl.truststore.password", truststorePassword.value());
configMap.put("ssl.provider", "SunJSSE"); configMap.put("ssl.provider", "SunJSSE");
configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5"); configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5");
configMap.put("ssl.secure.random.implementation", "SHA1PRNG"); configMap.put("ssl.secure.random.implementation", "SHA1PRNG");
@ -148,11 +167,11 @@ public class SSLUtilsTest {
@Test @Test
public void testCreateClientSideSslContextFactoryDefaultValues() { public void testCreateClientSideSslContextFactoryDefaultValues() {
Map<String, String> configMap = new HashMap<>(); Map<String, String> configMap = new HashMap<>();
configMap.put("ssl.keystore.location", "/path/to/keystore"); configMap.put("ssl.keystore.location", keystorePath);
configMap.put("ssl.keystore.password", "123456"); configMap.put("ssl.keystore.password", keystorePassword.value());
configMap.put("ssl.key.password", "123456"); configMap.put("ssl.key.password", keystorePassword.value());
configMap.put("ssl.truststore.location", "/path/to/truststore"); configMap.put("ssl.truststore.location", truststorePath);
configMap.put("ssl.truststore.password", "123456"); configMap.put("ssl.truststore.password", truststorePassword.value());
configMap.put("ssl.provider", "SunJSSE"); configMap.put("ssl.provider", "SunJSSE");
configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5"); configMap.put("ssl.cipher.suites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5");
configMap.put("ssl.secure.random.implementation", "SHA1PRNG"); configMap.put("ssl.secure.random.implementation", "SHA1PRNG");

View File

@ -37,7 +37,7 @@ import java.util.function.BiFunction;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.test.TestUtils.waitForCondition; import static org.apache.kafka.test.TestUtils.waitForCondition;

View File

@ -37,14 +37,15 @@ import org.apache.kafka.connect.util.SinkUtils;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.StringRequestContent;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@ -55,7 +56,9 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.connect.runtime.rest.RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS;
abstract class EmbeddedConnect { abstract class EmbeddedConnect {
@ -81,6 +84,10 @@ abstract class EmbeddedConnect {
this.kafkaCluster = new EmbeddedKafkaCluster(numBrokers, brokerProps, clientProps); this.kafkaCluster = new EmbeddedKafkaCluster(numBrokers, brokerProps, clientProps);
this.maskExitProcedures = maskExitProcedures; this.maskExitProcedures = maskExitProcedures;
this.httpClient = new HttpClient(); this.httpClient = new HttpClient();
// Necessary to prevent the rest request from timing out too early
// Before this change,ConnectWorkerIntegrationTest#testPollTimeoutExpiry() was failing
// because the request was being stopped by jetty before the framework responded
this.httpClient.setIdleTimeout(DEFAULT_REST_REQUEST_TIMEOUT_MS);
this.assertions = new ConnectAssertions(this); this.assertions = new ConnectAssertions(this);
// we should keep the original class loader and set it back after connector stopped since the connector will change the class loader, // we should keep the original class loader and set it back after connector stopped since the connector will change the class loader,
// and then, the Mockito will use the unexpected class loader to generate the wrong proxy instance, which makes mock failed // and then, the Mockito will use the unexpected class loader to generate the wrong proxy instance, which makes mock failed
@ -992,8 +999,8 @@ abstract class EmbeddedConnect {
Request req = httpClient.newRequest(url); Request req = httpClient.newRequest(url);
req.method(httpMethod); req.method(httpMethod);
if (body != null) { if (body != null) {
headers.forEach(req::header); req.headers(mutable -> headers.forEach(mutable::add));
req.content(new StringContentProvider(body), "application/json"); req.body(new StringRequestContent("application/json", body, StandardCharsets.UTF_8));
} }
ContentResponse res = req.send(); ContentResponse res = req.send();

View File

@ -37,7 +37,7 @@ import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.apache.kafka.connect.runtime.ConnectorConfig.KEY_CONVERTER_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.KEY_CONVERTER_CLASS_CONFIG;
import static org.apache.kafka.connect.runtime.ConnectorConfig.VALUE_CONVERTER_CLASS_CONFIG; import static org.apache.kafka.connect.runtime.ConnectorConfig.VALUE_CONVERTER_CLASS_CONFIG;

View File

@ -70,15 +70,15 @@ versions += [
jackson: "2.16.2", jackson: "2.16.2",
jacoco: "0.8.10", jacoco: "0.8.10",
javassist: "3.29.2-GA", javassist: "3.29.2-GA",
jetty: "9.4.56.v20240826", jetty: "12.0.15",
jersey: "2.39.1", jersey: "3.1.9",
jline: "3.25.1", jline: "3.25.1",
jmh: "1.37", jmh: "1.37",
hamcrest: "2.2", hamcrest: "2.2",
scalaLogging: "3.9.5", scalaLogging: "3.9.5",
jaxAnnotation: "1.3.2", jaxAnnotation: "1.3.2",
jaxb: "2.3.1", jaxb: "2.3.1",
jaxrs: "2.1.1", jakartaRs: "3.1.0",
jfreechart: "1.0.0", jfreechart: "1.0.0",
jopt: "5.0.4", jopt: "5.0.4",
jose4j: "0.9.4", jose4j: "0.9.4",
@ -159,15 +159,15 @@ libs += [
jacksonModuleScala: "com.fasterxml.jackson.module:jackson-module-scala_$versions.baseScala:$versions.jackson", jacksonModuleScala: "com.fasterxml.jackson.module:jackson-module-scala_$versions.baseScala:$versions.jackson",
jacksonJDK8Datatypes: "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$versions.jackson", jacksonJDK8Datatypes: "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$versions.jackson",
jacksonBlackbird: "com.fasterxml.jackson.module:jackson-module-blackbird:$versions.jackson", jacksonBlackbird: "com.fasterxml.jackson.module:jackson-module-blackbird:$versions.jackson",
jacksonJaxrsJsonProvider: "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$versions.jackson", jacksonJakartarsJsonProvider: "com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:$versions.jackson",
jaxAnnotationApi: "javax.annotation:javax.annotation-api:$versions.jaxAnnotation", jaxAnnotationApi: "javax.annotation:javax.annotation-api:$versions.jaxAnnotation",
jaxbApi: "javax.xml.bind:jaxb-api:$versions.jaxb", jaxbApi: "javax.xml.bind:jaxb-api:$versions.jaxb",
jaxrsApi: "javax.ws.rs:javax.ws.rs-api:$versions.jaxrs", jakartaRsApi: "jakarta.ws.rs:jakarta.ws.rs-api:$versions.jakartaRs",
javassist: "org.javassist:javassist:$versions.javassist", javassist: "org.javassist:javassist:$versions.javassist",
jettyServer: "org.eclipse.jetty:jetty-server:$versions.jetty", jettyServer: "org.eclipse.jetty:jetty-server:$versions.jetty",
jettyClient: "org.eclipse.jetty:jetty-client:$versions.jetty", jettyClient: "org.eclipse.jetty:jetty-client:$versions.jetty",
jettyServlet: "org.eclipse.jetty:jetty-servlet:$versions.jetty", jettyServlet: "org.eclipse.jetty.ee10:jetty-ee10-servlet:$versions.jetty",
jettyServlets: "org.eclipse.jetty:jetty-servlets:$versions.jetty", jettyServlets: "org.eclipse.jetty.ee10:jetty-ee10-servlets:$versions.jetty",
jerseyContainerServlet: "org.glassfish.jersey.containers:jersey-container-servlet:$versions.jersey", jerseyContainerServlet: "org.glassfish.jersey.containers:jersey-container-servlet:$versions.jersey",
jerseyHk2: "org.glassfish.jersey.inject:jersey-hk2:$versions.jersey", jerseyHk2: "org.glassfish.jersey.inject:jersey-hk2:$versions.jersey",
jline: "org.jline:jline:$versions.jline", jline: "org.jline:jline:$versions.jline",

View File

@ -40,6 +40,13 @@ For a detailed description of spotbugs bug categories, see https://spotbugs.read
<Bug pattern="DM_EXIT"/> <Bug pattern="DM_EXIT"/>
</Match> </Match>
<Match>
<!-- Disable warnings about creating Classloaders inside doPrivilege.
DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED: Classloaders should only be created inside doPrivileged block
The security manager has been deprecated for removal as of JDK 17, see https://openjdk.org/jeps/411 -->
<Bug pattern="DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED"/>
</Match>
<Match> <Match>
<!-- Disable warnings about the lack of equals() when compareTo() is implemented. <!-- Disable warnings about the lack of equals() when compareTo() is implemented.
EQ_COMPARETO_USE_OBJECT_EQUALS: This class defines a compareTo method but no equals() method --> EQ_COMPARETO_USE_OBJECT_EQUALS: This class defines a compareTo method but no equals() method -->

View File

@ -49,7 +49,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.UriBuilder;
import static net.sourceforge.argparse4j.impl.Arguments.store; import static net.sourceforge.argparse4j.impl.Arguments.store;
import static net.sourceforge.argparse4j.impl.Arguments.storeTrue; import static net.sourceforge.argparse4j.impl.Arguments.storeTrue;

View File

@ -25,17 +25,17 @@ import org.apache.kafka.trogdor.rest.UptimeResponse;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.ServletContext; import jakarta.servlet.ServletContext;
import javax.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import javax.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import javax.ws.rs.DefaultValue; import jakarta.ws.rs.DefaultValue;
import javax.ws.rs.GET; import jakarta.ws.rs.GET;
import javax.ws.rs.POST; import jakarta.ws.rs.POST;
import javax.ws.rs.PUT; import jakarta.ws.rs.PUT;
import javax.ws.rs.Path; import jakarta.ws.rs.Path;
import javax.ws.rs.Produces; import jakarta.ws.rs.Produces;
import javax.ws.rs.QueryParam; import jakarta.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
/** /**
* The REST resource for the Agent. This describes the RPCs which the agent can accept. * The REST resource for the Agent. This describes the RPCs which the agent can accept.
@ -54,7 +54,7 @@ import javax.ws.rs.core.MediaType;
public class AgentRestResource { public class AgentRestResource {
private final AtomicReference<Agent> agent = new AtomicReference<>(null); private final AtomicReference<Agent> agent = new AtomicReference<>(null);
@javax.ws.rs.core.Context @jakarta.ws.rs.core.Context
private ServletContext context; private ServletContext context;
public void setAgent(Agent myAgent) { public void setAgent(Agent myAgent) {

View File

@ -63,8 +63,8 @@ import java.util.TreeMap;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import javax.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
import javax.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.UriBuilder;
import static net.sourceforge.argparse4j.impl.Arguments.append; import static net.sourceforge.argparse4j.impl.Arguments.append;
import static net.sourceforge.argparse4j.impl.Arguments.store; import static net.sourceforge.argparse4j.impl.Arguments.store;

View File

@ -33,20 +33,20 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.ServletContext; import jakarta.servlet.ServletContext;
import javax.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import javax.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import javax.ws.rs.DefaultValue; import jakarta.ws.rs.DefaultValue;
import javax.ws.rs.GET; import jakarta.ws.rs.GET;
import javax.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
import javax.ws.rs.POST; import jakarta.ws.rs.POST;
import javax.ws.rs.PUT; import jakarta.ws.rs.PUT;
import javax.ws.rs.Path; import jakarta.ws.rs.Path;
import javax.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import javax.ws.rs.Produces; import jakarta.ws.rs.Produces;
import javax.ws.rs.QueryParam; import jakarta.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
/** /**
* The REST resource for the Coordinator. This describes the RPCs which the coordinator * The REST resource for the Coordinator. This describes the RPCs which the coordinator
@ -66,7 +66,7 @@ import javax.ws.rs.core.Response;
public class CoordinatorRestResource { public class CoordinatorRestResource {
private final AtomicReference<Coordinator> coordinator = new AtomicReference<>(); private final AtomicReference<Coordinator> coordinator = new AtomicReference<>();
@javax.ws.rs.core.Context @jakarta.ws.rs.core.Context
private ServletContext context; private ServletContext context;
public void setCoordinator(Coordinator myCoordinator) { public void setCoordinator(Coordinator myCoordinator) {

View File

@ -21,20 +21,19 @@ import org.apache.kafka.common.utils.ThreadUtils;
import org.apache.kafka.trogdor.common.JsonUtil; import org.apache.kafka.trogdor.common.JsonUtil;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.Slf4jRequestLogWriter; import org.eclipse.jetty.server.Slf4jRequestLogWriter;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -102,14 +101,13 @@ public class JsonRestServer {
context.setContextPath("/"); context.setContextPath("/");
context.addServlet(servletHolder, "/*"); context.addServlet(servletHolder, "/*");
RequestLogHandler requestLogHandler = new RequestLogHandler();
Slf4jRequestLogWriter slf4jRequestLogWriter = new Slf4jRequestLogWriter(); Slf4jRequestLogWriter slf4jRequestLogWriter = new Slf4jRequestLogWriter();
slf4jRequestLogWriter.setLoggerName(JsonRestServer.class.getCanonicalName()); slf4jRequestLogWriter.setLoggerName(JsonRestServer.class.getCanonicalName());
CustomRequestLog requestLog = new CustomRequestLog(slf4jRequestLogWriter, CustomRequestLog.EXTENDED_NCSA_FORMAT + " %{ms}T"); CustomRequestLog requestLog = new CustomRequestLog(slf4jRequestLogWriter, CustomRequestLog.EXTENDED_NCSA_FORMAT + " %{ms}T");
requestLogHandler.setRequestLog(requestLog); jettyServer.setRequestLog(requestLog);
HandlerCollection handlers = new HandlerCollection(); ContextHandlerCollection handlers = new ContextHandlerCollection();
handlers.setHandlers(new Handler[]{context, new DefaultHandler(), requestLogHandler}); handlers.setHandlers(new Handler[]{context, new DefaultHandler()});
StatisticsHandler statsHandler = new StatisticsHandler(); StatisticsHandler statsHandler = new StatisticsHandler();
statsHandler.setHandler(handlers); statsHandler.setHandler(handlers);
jettyServer.setHandler(statsHandler); jettyServer.setHandler(statsHandler);

View File

@ -25,9 +25,9 @@ import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.ExceptionMapper;
public class RestExceptionMapper implements ExceptionMapper<Throwable> { public class RestExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class); private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);

View File

@ -62,7 +62,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;

View File

@ -26,8 +26,8 @@ import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import javax.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
import javax.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;