Merge remote-tracking branch '3.1' into `4.0`
Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f42b9db..9dcb3de 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-[//]: # " Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. "
+[//]: # " Copyright (c) 2018, 2024 Oracle and/or its affiliates. All rights reserved. "
[//]: # " "
[//]: # " This program and the accompanying materials are made available under the "
[//]: # " terms of the Eclipse Public License v. 2.0, which is available at "
@@ -18,13 +18,14 @@
## Project description
-Eclipse Jersey is a REST framework that provides a JAX-RS (JSR-370) implementation and more.
+Eclipse Jersey is a REST framework that provides a <a href="https://jcp.org/en/jsr/detail?id=370">JAX-RS (JSR-370)</a>,
+now mainly <a href="https://projects.eclipse.org/projects/ee4j.rest">Jakarta REST</a>, implementation and more.
Jersey provides its own APIs that extend the JAX-RS toolkit with additional features and utilities
to further simplify RESTful service and client development. Jersey also exposes numerous extension
SPIs so that developers may extend Jersey to best suit their needs.
Goals of Jersey project can be summarized in the following points:
-* Track the JAX-RS API and provide regular releases of production quality implementations that ships with GlassFish;
+* Track the JAX-RS/Jakarta REST API and provide regular releases of production quality implementations that ships with GlassFish;
* Provide APIs to extend Jersey & Build a community of users and developers; and finally
@@ -41,6 +42,21 @@
* https://github.com/eclipse-ee4j/jersey
+## Eclipse Development Process
+
+This Eclipse Foundation open project is governed by the Eclipse Foundation
+Development Process and operates under the terms of the Eclipse IP Policy.
+
+## Specifications
+
+This specification project operates under the terms of the Eclipse Foundation
+Specification process.
+
+* https://eclipse.org/projects/dev_process
+* https://www.eclipse.org/org/documents/Eclipse_IP_Policy.pdf
+* https://www.eclipse.org/projects/efsp/
+* https://www.eclipse.org/legal/efsp_non_assert.php
+
## Eclipse Contributor Agreement
Before your contribution can be accepted by the project team contributors must
diff --git a/bom/pom.xml b/bom/pom.xml
index 62d66ad..c5297ce 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.eclipse.ee4j</groupId>
<artifactId>project</artifactId>
- <version>1.0.8</version>
+ <version>1.0.9</version>
<relativePath/>
</parent>
@@ -385,6 +385,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-netty</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-util</artifactId>
<version>${project.version}</version>
@@ -400,11 +405,6 @@
<version>2.4</version>
<inherited>true</inherited>
</plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-site-plugin</artifactId>
- <version>3.9.1</version>
- </plugin>
</plugins>
</build>
diff --git a/bundles/apidocs/pom.xml b/bundles/apidocs/pom.xml
index 39738e9..13f8a1b 100644
--- a/bundles/apidocs/pom.xml
+++ b/bundles/apidocs/pom.xml
@@ -122,10 +122,6 @@
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
- <groupId>jakarta.persistence</groupId>
- <artifactId>jakarta.persistence-api</artifactId>
- </dependency>
- <dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jdk-http</artifactId>
<version>${project.version}</version>
@@ -298,7 +294,7 @@
<dependencySourceIncludes>
<dependencySourceInclude>org.glassfish.jersey.*:*</dependencySourceInclude>
</dependencySourceIncludes>
- <excludePackageNames>*.internal:*.internal.*:*.innate:*.innate.*</excludePackageNames>
+ <excludePackageNames>*.innate:*.innate.*</excludePackageNames>
</configuration>
</execution>
</executions>
diff --git a/bundles/jaxrs-ri/pom.xml b/bundles/jaxrs-ri/pom.xml
index 8fad2a8..282151f 100644
--- a/bundles/jaxrs-ri/pom.xml
+++ b/bundles/jaxrs-ri/pom.xml
@@ -217,7 +217,9 @@
<showWarnings>false</showWarnings>
<fork>false</fork>
<excludes>
- <exclude>module-info.java</exclude><exclude>META-INF/versions/11/**</exclude>
+ <exclude>module-info.java</exclude>
+ <exclude>META-INF/versions/11/**</exclude>
+ <exclude>META-INF/versions/21/**</exclude>
</excludes>
</configuration>
</plugin>
@@ -314,6 +316,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
+ <version>${shade.mvn.plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
diff --git a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
index 8d93b91..3b6bed5 100644
--- a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
+++ b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
@@ -754,7 +754,8 @@
if (i.markSupported()) {
inputStream = i;
} else {
- inputStream = new BufferedInputStream(i, ReaderWriter.BUFFER_SIZE);
+ inputStream = ReaderWriter.AUTOSIZE_BUFFER ? new BufferedInputStream(i)
+ : new BufferedInputStream(i, ReaderWriter.BUFFER_SIZE);
}
}
@@ -881,7 +882,8 @@
Object objectRequest = context.getAttribute(JERSEY_REQUEST_ATTR_NAME);
if (objectRequest != null) {
ClientRequest clientRequest = (ClientRequest) objectRequest;
- SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(clientRequest).build();
+ SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(clientRequest)
+ .setSNIHostName(clientRequest).build();
sniConfig.setSNIServerName(socket);
final int socketTimeout = ((ClientRequest) objectRequest).resolveProperty(ClientProperties.READ_TIMEOUT, -1);
@@ -940,12 +942,12 @@
}
@Override
- public synchronized void mark(int readlimit) {
+ public void mark(int readlimit) {
in.mark(readlimit);
}
@Override
- public synchronized void reset() throws IOException {
+ public void reset() throws IOException {
checkAborted();
in.reset();
}
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
index 422d919..9b92517 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -60,8 +60,10 @@
private final int connectTimeout;
private final ProxyConfiguration proxyConfiguration;
private final AtomicReference<SSLParamConfigurator> sniConfigs = new AtomicReference<>(null);
+ private final Configuration configuration;
ConnectorConfiguration(Client client, Configuration config) {
+ configuration = config;
final Map<String, Object> properties = config.getProperties();
int proposedChunkSize = JdkConnectorProperties.getValue(properties, ClientProperties.CHUNKED_ENCODING_SIZE,
@@ -181,6 +183,10 @@
return sniConfigs.get();
}
+ Configuration getConfiguration() {
+ return configuration;
+ }
+
@Override
public String toString() {
return "ConnectorConfiguration{"
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
index b20f00c..7413caf 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -51,7 +51,8 @@
void send(HttpRequest httpRequest, CompletionHandler<HttpResponse> completionHandler) {
final Map<String, List<Object>> headers = new HashMap<>();
httpRequest.getHeaders().forEach((k, v) -> headers.put(k, (List) v));
- final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().uri(httpRequest.getUri()).headers(headers).build();
+ final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().uri(httpRequest.getUri())
+ .headers(headers).setSNIHostName(connectorConfiguration.getConfiguration()).build();
connectorConfiguration.setSniConfig(sniConfig);
final DestinationConnectionPool.DestinationKey destinationKey = new DestinationConnectionPool.DestinationKey(
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
index 15725e7..4070300 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -496,7 +496,7 @@
if (contentLengths != null) {
try {
- int bodyLength = Integer.parseInt(contentLengths.get(0));
+ long bodyLength = Long.parseLong(contentLengths.get(0));
if (bodyLength == 0) {
expectContent = false;
return;
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
index 0a3ede0..7dccd87 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -31,7 +31,7 @@
abstract boolean parse(ByteBuffer input) throws ParseException;
- static TransferEncodingParser createFixedLengthParser(AsynchronousBodyInputStream responseBody, int expectedLength) {
+ static TransferEncodingParser createFixedLengthParser(AsynchronousBodyInputStream responseBody, long expectedLength) {
return new FixedLengthEncodingParser(responseBody, expectedLength);
}
@@ -42,11 +42,11 @@
private static class FixedLengthEncodingParser extends TransferEncodingParser {
- private final int expectedLength;
+ private final long expectedLength;
private final AsynchronousBodyInputStream responseBody;
- private volatile int consumedLength = 0;
+ private volatile long consumedLength = 0;
- FixedLengthEncodingParser(AsynchronousBodyInputStream responseBody, int expectedLength) {
+ FixedLengthEncodingParser(AsynchronousBodyInputStream responseBody, long expectedLength) {
this.expectedLength = expectedLength;
this.responseBody = responseBody;
}
diff --git a/connectors/netty-connector/pom.xml b/connectors/netty-connector/pom.xml
index b455a8a..bd695c5 100644
--- a/connectors/netty-connector/pom.xml
+++ b/connectors/netty-connector/pom.xml
@@ -49,6 +49,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-jetty</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -75,4 +81,26 @@
</plugins>
</build>
+ <profiles>
+ <profile>
+ <id>JettyExclude</id>
+ <activation>
+ <jdk>(1.8,17)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <testExcludes>
+ <testExclude>org/glassfish/jersey/netty/connector/HugeHeaderTest.java</testExclude>
+ </testExcludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
</project>
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java
index 9c79d12..562edad 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -129,4 +129,56 @@
public static final Integer
DEFAULT_EXPECT_100_CONTINUE_TIMEOUT_VALUE = 500;
+
+ /**
+ * Parameter which allows extending of the header size for the Netty connector
+ *
+ * @since 2.44
+ */
+ public static final String
+ MAX_HEADER_SIZE = "jersey.config.client.netty.maxHeaderSize";
+
+ /**
+ * Default header size for Netty Connector.
+ * Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
+ *
+ * @since 2.44
+ */
+ public static final Integer
+ DEFAULT_HEADER_SIZE = 8192;
+
+ /**
+ * Parameter which allows extending of the initial line length for the Netty connector
+ *
+ * @since 2.44
+ */
+ public static final String
+ MAX_INITIAL_LINE_LENGTH = "jersey.config.client.netty.maxInitialLineLength";
+
+ /**
+ * Default initial line length for Netty Connector.
+ * Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
+ *
+ * @since 2.44
+ */
+ public static final Integer
+ DEFAULT_INITIAL_LINE_LENGTH = 4096;
+
+ /**
+ * Parameter which allows extending of the chunk size for the Netty connector
+ *
+ * @since 2.44
+ */
+ public static final String
+ MAX_CHUNK_SIZE = "jersey.config.client.netty.maxChunkSize";
+
+ /**
+ * Default chunk size for Netty Connector.
+ * Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
+ *
+ * @since 2.44
+ */
+ public static final Integer
+ DEFAULT_CHUNK_SIZE = 8192;
+
}
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
index ab71e1f..4fbec4c 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -34,7 +34,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -89,6 +88,7 @@
import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
import org.glassfish.jersey.client.spi.Connector;
+import org.glassfish.jersey.innate.VirtualThreadUtil;
import org.glassfish.jersey.message.internal.OutboundMessageContext;
import org.glassfish.jersey.netty.connector.internal.NettyEntityWriter;
@@ -130,14 +130,15 @@
NettyConnector(Client client) {
- final Map<String, Object> properties = client.getConfiguration().getProperties();
+ final Configuration configuration = client.getConfiguration();
+ final Map<String, Object> properties = configuration.getProperties();
final Object threadPoolSize = properties.get(ClientProperties.ASYNC_THREADPOOL_SIZE);
if (threadPoolSize != null && threadPoolSize instanceof Integer && (Integer) threadPoolSize > 0) {
- executorService = Executors.newFixedThreadPool((Integer) threadPoolSize);
+ executorService = VirtualThreadUtil.withConfig(configuration).newFixedThreadPool((Integer) threadPoolSize);
this.group = new NioEventLoopGroup((Integer) threadPoolSize);
} else {
- executorService = Executors.newCachedThreadPool();
+ executorService = VirtualThreadUtil.withConfig(configuration).newCachedThreadPool();
this.group = new NioEventLoopGroup();
}
@@ -208,7 +209,7 @@
try {
final SSLParamConfigurator sslConfig = SSLParamConfigurator.builder()
- .request(jerseyRequest).setSNIAlways(true).build();
+ .request(jerseyRequest).setSNIAlways(true).setSNIHostName(jerseyRequest).build();
String key = requestUri.getScheme() + "://" + sslConfig.getSNIHostName() + ":" + port;
ArrayList<Channel> conns;
@@ -303,7 +304,17 @@
p.addLast(sslHandler);
}
- p.addLast(new HttpClientCodec());
+ final Integer maxHeaderSize = ClientProperties.getValue(config.getProperties(),
+ NettyClientProperties.MAX_HEADER_SIZE,
+ NettyClientProperties.DEFAULT_HEADER_SIZE);
+ final Integer maxChunkSize = ClientProperties.getValue(config.getProperties(),
+ NettyClientProperties.MAX_CHUNK_SIZE,
+ NettyClientProperties.DEFAULT_CHUNK_SIZE);
+ final Integer maxInitialLineLength = ClientProperties.getValue(config.getProperties(),
+ NettyClientProperties.MAX_INITIAL_LINE_LENGTH,
+ NettyClientProperties.DEFAULT_INITIAL_LINE_LENGTH);
+
+ p.addLast(new HttpClientCodec(maxInitialLineLength, maxHeaderSize, maxChunkSize));
p.addLast(new ChunkedWriteHandler());
p.addLast(new HttpContentDecompressor());
}
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HugeHeaderTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HugeHeaderTest.java
new file mode 100644
index 0000000..dddf8d9
--- /dev/null
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HugeHeaderTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.netty.connector;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.jetty.JettyTestContainerFactory;
+import org.glassfish.jersey.test.jetty.JettyTestContainerProperties;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class HugeHeaderTest extends JerseyTest {
+
+ private static final int SERVER_HEADER_SIZE = 1234567;
+
+ private static final String hugeHeader =
+ "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyz";
+
+ @Path("/test")
+ public static class HttpMethodResource {
+ @POST
+ public Response post(
+ @HeaderParam("X-HUGE-HEADER") String hugeHeader,
+ String entity) {
+
+ return Response.noContent()
+ .header("X-HUGE-HEADER", hugeHeader)
+ .header("X-HUGE-HEADER-SIZE", hugeHeader.length())
+ .build();
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(HugeHeaderTest.HttpMethodResource.class);
+ }
+
+ @Override
+ protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+ final Map<String, Object> configurationProperties = new HashMap<>();
+ configurationProperties.put(JettyTestContainerProperties.HEADER_SIZE, SERVER_HEADER_SIZE);
+ return new JettyTestContainerFactory(configurationProperties);
+ }
+
+ @Override
+ protected void configureClient(ClientConfig config) {
+ config.connectorProvider(new NettyConnectorProvider());
+ }
+
+ @Test
+ public void testContentHeaderTrunked() {
+ final StringBuffer veryHugeHeader = new StringBuffer();
+ for (int i = 1; i < 33; i++) {
+ veryHugeHeader.append(hugeHeader);
+ }
+ final Response response = target("test").request()
+ .header("X-HUGE-HEADER", veryHugeHeader.toString())
+ .post(null);
+
+ assertNull(response.getHeaderString("X-HUGE-HEADER-SIZE"));
+ assertNull(response.getHeaderString("X-HUGE-HEADER"));
+ response.close();
+ }
+
+ @Test
+ public void testConnectorHeaderSize() {
+ final StringBuffer veryHugeHeader = new StringBuffer();
+ for (int i = 1; i < 35; i++) {
+ veryHugeHeader.append(hugeHeader);
+ }
+ int headerSize = veryHugeHeader.length();
+ Response response = target("test")
+ .property(NettyClientProperties.MAX_HEADER_SIZE, 77750)
+ .request()
+
+
+ .header("X-HUGE-HEADER", veryHugeHeader.toString())
+ .post(null);
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
+
+ assertEquals(String.valueOf(headerSize), response.getHeaderString("X-HUGE-HEADER-SIZE"));
+ assertEquals(veryHugeHeader.toString(), response.getHeaderString("X-HUGE-HEADER"));
+ response.close();
+ }
+}
diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java
index 28d03d4..11d74a6 100644
--- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java
+++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -18,10 +18,15 @@
import java.io.IOException;
import java.net.URI;
+import java.util.concurrent.ThreadFactory;
import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.Configuration;
import org.glassfish.jersey.grizzly2.httpserver.internal.LocalizationMessages;
+import org.glassfish.jersey.innate.VirtualThreadSupport;
+import org.glassfish.jersey.innate.VirtualThreadUtil;
+import org.glassfish.jersey.innate.virtual.LoomishExecutors;
import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder;
import org.glassfish.jersey.process.JerseyProcessingUncaughtExceptionHandler;
import org.glassfish.jersey.server.ApplicationHandler;
@@ -281,11 +286,20 @@
: uri.getPort();
final NetworkListener listener = new NetworkListener("grizzly", host, port);
+ final Configuration configuration = handler != null ? handler.getConfiguration().getConfiguration() : null;
- listener.getTransport().getWorkerThreadPoolConfig().setThreadFactory(new ThreadFactoryBuilder()
+ final LoomishExecutors executors = VirtualThreadUtil.withConfig(configuration, false);
+ final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("grizzly-http-server-%d")
.setUncaughtExceptionHandler(new JerseyProcessingUncaughtExceptionHandler())
- .build());
+ .setThreadFactory(executors.getThreadFactory())
+ .build();
+
+ if (executors.isVirtual()) {
+ listener.getTransport().setWorkerThreadPool(executors.newCachedThreadPool());
+ } else {
+ listener.getTransport().getWorkerThreadPoolConfig().setThreadFactory(threadFactory);
+ }
listener.setSecure(secure);
if (sslEngineConfigurator != null) {
diff --git a/containers/grizzly2-servlet/src/main/java/org/glassfish/jersey/grizzly2/servlet/GrizzlyWebContainerFactory.java b/containers/grizzly2-servlet/src/main/java/org/glassfish/jersey/grizzly2/servlet/GrizzlyWebContainerFactory.java
index a70ee7f..d513d0a 100644
--- a/containers/grizzly2-servlet/src/main/java/org/glassfish/jersey/grizzly2/servlet/GrizzlyWebContainerFactory.java
+++ b/containers/grizzly2-servlet/src/main/java/org/glassfish/jersey/grizzly2/servlet/GrizzlyWebContainerFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
import jakarta.servlet.Servlet;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.uri.UriComponent;
@@ -251,11 +252,13 @@
}
}
+ ResourceConfig configuration = new ResourceConfig();
if (initParams != null) {
registration.setInitParameters(initParams);
+ configuration.addProperties((Map) initParams);
}
- HttpServer server = GrizzlyHttpServerFactory.createHttpServer(u);
+ HttpServer server = GrizzlyHttpServerFactory.createHttpServer(u, configuration);
context.deploy(server);
return server;
}
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
index 1695711..fbaeb41 100644
--- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
+++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -46,6 +46,7 @@
import org.eclipse.jetty.security.AuthenticationState;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.thread.Scheduler;
import org.glassfish.jersey.innate.inject.InternalBinder;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.internal.inject.ReferencingFactory;
@@ -91,8 +92,6 @@
*/
private boolean configSetStatusOverSendError;
- private final ScheduledThreadPoolExecutor timeoutScheduler;
-
/**
* Referencing factory for Jetty request.
*/
@@ -141,8 +140,7 @@
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception {
- final ResponseWriter responseWriter = new ResponseWriter(timeoutScheduler, request, response,
- callback, configSetStatusOverSendError);
+ final ResponseWriter responseWriter = new ResponseWriter(request, response, callback, configSetStatusOverSendError);
try {
LOGGER.debugLog(LocalizationMessages.CONTAINER_STARTED());
final URI baseUri = getBaseUri(request);
@@ -254,37 +252,38 @@
}
}
- private static final class ResponseWriter implements ContainerResponseWriter {
+ private static class ResponseWriter implements ContainerResponseWriter {
private final Request request;
private final Response response;
private final Callback callback;
private final boolean configSetStatusOverSendError;
private final long asyncStartTimeNanos;
- private final ScheduledExecutorService timeoutScheduler;
+ private final Scheduler scheduler;
private final ConcurrentLinkedQueue<TimeoutHandler> timeoutHandlerQueue = new ConcurrentLinkedQueue<>();
- private ScheduledFuture<?> currentTimerTask;
+ private Scheduler.Task currentTimerTask;
- ResponseWriter(final ScheduledExecutorService timeoutScheduler, final Request request, final Response response,
+ ResponseWriter(final Request request, final Response response,
final Callback callback, final boolean configSetStatusOverSendError) {
- this.timeoutScheduler = timeoutScheduler;
this.request = request;
this.response = response;
this.callback = callback;
this.asyncStartTimeNanos = System.nanoTime();
this.configSetStatusOverSendError = configSetStatusOverSendError;
+
+ this.scheduler = request.getComponents().getScheduler();
}
private synchronized void setNewTimeout(long timeOut, TimeUnit timeUnit) {
long timeOutNanos = timeUnit.toNanos(timeOut);
if (currentTimerTask != null) {
// Do not interrupt, see callTimeoutHandlers()
- currentTimerTask.cancel(false);
+ currentTimerTask.cancel();
}
// Use System.nanoTime() as the clock source here, because the returned value is not prone to wall-clock
// drift - unlike System.currentTimeMillis().
long delayNanos = Math.max(asyncStartTimeNanos - System.nanoTime() + timeOutNanos, 0L);
- currentTimerTask = timeoutScheduler.schedule(this::callTimeoutHandlers, delayNanos, TimeUnit.NANOSECONDS);
+ currentTimerTask = scheduler.schedule(this::callTimeoutHandlers, delayNanos, TimeUnit.NANOSECONDS);
}
private void callTimeoutHandlers() {
@@ -438,20 +437,7 @@
appHandler.onShutdown(this);
appHandler = null;
- timeoutScheduler.shutdown();
boolean needInterrupt = false;
- while (true) {
- try {
- if (timeoutScheduler.awaitTermination(1L, TimeUnit.MINUTES)) {
- break;
- }
- } catch (InterruptedException e) {
- if (!needInterrupt) {
- needInterrupt = true;
- timeoutScheduler.shutdownNow();
- }
- }
- }
if (needInterrupt) {
Thread.currentThread().interrupt();
}
@@ -459,21 +445,6 @@
private static final AtomicInteger TIMEOUT_HANDLER_ID_GEN = new AtomicInteger();
- private static ScheduledThreadPoolExecutor createTimeoutScheduler() {
- // Note: creating the thread-pool does not start the core-pool threads.
- ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, r -> {
- Thread t = new Thread(r, "JettyHttpContainer-Timeout-Handler #" + TIMEOUT_HANDLER_ID_GEN.incrementAndGet());
- t.setDaemon(true);
- return t;
- });
- // Limit the number of timeout handling threads to a quarter of the number of CPUs, at least 2.
- executor.setMaximumPoolSize(Math.max(2, Runtime.getRuntime().availableProcessors() / 4));
- executor.allowCoreThreadTimeOut(true);
- // Don't Keep timeout handling threads around "forever".
- executor.setKeepAliveTime(100, TimeUnit.MILLISECONDS);
- return executor;
- }
-
/**
* Create a new Jetty HTTP container.
*
@@ -481,7 +452,6 @@
* @param parentContext DI provider specific context with application's registered bindings.
*/
JettyHttpContainer(final Application application, final Object parentContext) {
- this.timeoutScheduler = createTimeoutScheduler();
this.appHandler = new ApplicationHandler(application, new JettyBinder(), parentContext);
}
@@ -491,7 +461,6 @@
* @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container.
*/
JettyHttpContainer(final Application application) {
- this.timeoutScheduler = createTimeoutScheduler();
this.appHandler = new ApplicationHandler(application, new JettyBinder());
cacheConfigSetStatusOverSendError();
@@ -503,7 +472,6 @@
* @param applicationClass JAX-RS / Jersey class of application to be deployed on Jetty HTTP container.
*/
JettyHttpContainer(final Class<? extends Application> applicationClass) {
- this.timeoutScheduler = createTimeoutScheduler();
this.appHandler = new ApplicationHandler(applicationClass, new JettyBinder());
cacheConfigSetStatusOverSendError();
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java
index 8ce9599..cb66f21 100644
--- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java
+++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java
@@ -20,7 +20,10 @@
import java.util.concurrent.ThreadFactory;
import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.Configuration;
+import org.glassfish.jersey.innate.VirtualThreadUtil;
+import org.glassfish.jersey.innate.virtual.LoomishExecutors;
import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder;
import org.glassfish.jersey.jetty.internal.LocalizationMessages;
import org.glassfish.jersey.process.JerseyProcessingUncaughtExceptionHandler;
@@ -254,7 +257,8 @@
}
final int port = (uri.getPort() == -1) ? defaultPort : uri.getPort();
- final Server server = new Server(new JettyConnectorThreadPool());
+ final Configuration configuration = handler != null ? handler.getConfiguration() : null;
+ final Server server = new Server(new JettyConnectorThreadPool(configuration));
final HttpConfiguration config = new HttpConfiguration();
if (sslContextFactory != null) {
config.setSecureScheme("https");
@@ -292,10 +296,20 @@
//
// Keeping this for backwards compatibility for the time being
private static final class JettyConnectorThreadPool extends QueuedThreadPool {
- private final ThreadFactory threadFactory = new ThreadFactoryBuilder()
- .setNameFormat("jetty-http-server-%d")
- .setUncaughtExceptionHandler(new JerseyProcessingUncaughtExceptionHandler())
- .build();
+ private final ThreadFactory threadFactory;
+
+ private JettyConnectorThreadPool(Configuration configuration) {
+ final LoomishExecutors executors = VirtualThreadUtil.withConfig(configuration, false);
+ if (executors.isVirtual()) {
+ super.setMaxThreads(Integer.MAX_VALUE - 1);
+ }
+
+ this.threadFactory = new ThreadFactoryBuilder()
+ .setNameFormat("jetty-http-server-%d")
+ .setUncaughtExceptionHandler(new JerseyProcessingUncaughtExceptionHandler())
+ .setThreadFactory(executors.getThreadFactory())
+ .build();
+ }
@Override
public Thread newThread(Runnable runnable) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientExecutorProvidersConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientExecutorProvidersConfigurator.java
index 3faee56..9b128d0 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientExecutorProvidersConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientExecutorProvidersConfigurator.java
@@ -38,6 +38,7 @@
import org.glassfish.jersey.spi.ScheduledExecutorServiceProvider;
import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.core.Configuration;
/**
* Configurator which initializes and register {@link ExecutorServiceProvider} and
@@ -66,7 +67,8 @@
@Override
public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) {
- Map<String, Object> runtimeProperties = bootstrapBag.getConfiguration().getProperties();
+ final Configuration configuration = bootstrapBag.getConfiguration();
+ Map<String, Object> runtimeProperties = configuration.getProperties();
ExecutorServiceProvider defaultAsyncExecutorProvider;
ScheduledExecutorServiceProvider defaultScheduledExecutorProvider;
@@ -96,12 +98,12 @@
.named("ClientAsyncThreadPoolSize");
injectionManager.register(asyncThreadPoolSizeBinding);
- defaultAsyncExecutorProvider = new DefaultClientAsyncExecutorProvider(asyncThreadPoolSize);
+ defaultAsyncExecutorProvider = new DefaultClientAsyncExecutorProvider(asyncThreadPoolSize, configuration);
} else {
if (MANAGED_EXECUTOR_SERVICE != null) {
defaultAsyncExecutorProvider = new ClientExecutorServiceProvider(MANAGED_EXECUTOR_SERVICE);
} else {
- defaultAsyncExecutorProvider = new DefaultClientAsyncExecutorProvider(0);
+ defaultAsyncExecutorProvider = new DefaultClientAsyncExecutorProvider(0, configuration);
}
}
}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
index aa0676b..88a3d01 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -467,24 +467,6 @@
public static final String QUERY_PARAM_STYLE = "jersey.config.client.uri.query.param.style";
/**
- * <p>
- * Most connectors support HOST header value to be used as an SNIHostName. However, the HOST header is restricted in JDK.
- * {@code HttpUrlConnector} and {@code JavaNetHttpConnector} need
- * to have an extra System Property set to allow HOST header.
- * As an option to HOST header, this property allows the HOST name to be pre-set on a Client and does not need to
- * be set on each request.
- * </p>
- * <p>
- * The value MUST be an instance of {@link java.lang.String}.
- * </p>
- * <p>
- * The name of the configuration property is <tt>{@value}</tt>.
- * </p>
- * @since 3.1.2
- */
- public static final String SNI_HOST_NAME = "jersey.config.client.sniHostName";
-
- /**
* Sets the {@link org.glassfish.jersey.client.spi.ConnectorProvider} class. Overrides the value from META-INF/services.
*
* <p>
@@ -501,6 +483,31 @@
public static final String CONNECTOR_PROVIDER = "jersey.config.client.connector.provider";
/**
+ * <p>
+ * Sets the {@code hostName} to be used for calculating the {@link javax.net.ssl.SNIHostName} during the HTTPS request.
+ * Takes precedence over the HTTP HOST header, if set.
+ * </p>
+ * <p>
+ * By default, the {@code SNIHostName} is set when the HOST HTTP header differs from the HTTP request host.
+ * When the {@code hostName} matches the HTTPS request host, the {@code SNIHostName} is not set,
+ * and the HTTP HOST header is not used for setting the {@code SNIHostName}. This allows for Domain Fronting.
+ * </p>
+ * <p>
+ * Most connectors support HOST header value to be used as an SNIHostName. However, the HOST header is restricted in JDK.
+ * {@code HttpUrlConnector} and {@code JavaNetHttpConnector} need
+ * to have an extra System Property set to allow HOST header.
+ * </p>
+ * <p>
+ * The value MUST be an instance of {@link java.lang.String}.
+ * </p>
+ * <p>
+ * The name of the configuration property is <tt>{@value}</tt>.
+ * </p>
+ * @since 3.1.2
+ */
+ public static final String SNI_HOST_NAME = "jersey.config.client.snihostname";
+
+ /**
* <p>The {@link javax.net.ssl.SSLContext} {@link java.util.function.Supplier} to be used to set ssl context in the current
* HTTP request. Has precedence over the {@link Client#getSslContext()}.
* </p>
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/DefaultClientAsyncExecutorProvider.java b/core-client/src/main/java/org/glassfish/jersey/client/DefaultClientAsyncExecutorProvider.java
index 2f9fa71..2a19b0d 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/DefaultClientAsyncExecutorProvider.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/DefaultClientAsyncExecutorProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,9 @@
import jakarta.inject.Inject;
import jakarta.inject.Named;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.Context;
+
import org.glassfish.jersey.client.internal.LocalizationMessages;
import org.glassfish.jersey.internal.util.collection.LazyValue;
@@ -46,8 +49,9 @@
* See also {@link org.glassfish.jersey.client.ClientProperties#ASYNC_THREADPOOL_SIZE}.
*/
@Inject
- public DefaultClientAsyncExecutorProvider(@Named("ClientAsyncThreadPoolSize") final int poolSize) {
- super("jersey-client-async-executor");
+ public DefaultClientAsyncExecutorProvider(@Named("ClientAsyncThreadPoolSize") final int poolSize,
+ @Context Configuration configuration) {
+ super("jersey-client-async-executor", configuration);
this.asyncThreadPoolSize = Values.lazy(new Value<Integer>() {
@Override
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
index e0446d2..90d138d 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -94,7 +94,7 @@
/**
* A value of {@code true} declares that the client will try to set
* unsupported HTTP method to {@link java.net.HttpURLConnection} via
- * reflection.
+ * reflection as a workaround for a missing HTTP method.
* <p>
* NOTE: Enabling this property may cause security related warnings/errors
* and it may break when other JDK implementation is used. <b>Use only
@@ -103,6 +103,10 @@
* <p>The value MUST be an instance of {@link java.lang.Boolean}.</p>
* <p>The default value is {@code false}.</p>
* <p>The name of the configuration property is <tt>{@value}</tt>.</p>
+ * <p>Since JDK 16 the JDK internal classes are not opened for reflection and the workaround method does not work,
+ * unless {@code --add-opens java.base/java.net=ALL-UNNAMED} for HTTP requests and additional
+ * {@code --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED} for HTTPS (HttpsUrlConnection) options are set.
+ * </p>
*/
public static final String SET_METHOD_WORKAROUND =
"jersey.config.client.httpUrlConnection.setMethodWorkaround";
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
index cb32a5c..79dc60e 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,25 +16,23 @@
package org.glassfish.jersey.client.innate.http;
-import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.HttpHeaders;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.ClientRequest;
+import org.glassfish.jersey.http.HttpHeaders;
+import org.glassfish.jersey.internal.PropertiesResolver;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
+import jakarta.ws.rs.core.Configuration;
import jakarta.ws.rs.core.UriBuilder;
-import org.glassfish.jersey.internal.PropertiesResolver;
-import org.glassfish.jersey.internal.util.PropertiesHelper;
-
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Optional;
-import java.util.Properties;
/**
* A unified routines to configure {@link SSLParameters}.
@@ -48,11 +46,12 @@
* Builder of the {@link SSLParamConfigurator} instance.
*/
public static final class Builder {
- private URI uri = null;
+ private URI uri;
private String sniHostNameHeader = null;
- private String sniHostNameProperty = null;
+ private String sniHostPrecedence = null;
private boolean setAlways = false;
+
/**
* Sets the SNIHostName and {@link URI} from the {@link ClientRequest} instance.
* @param clientRequest the {@link ClientRequest}
@@ -60,7 +59,7 @@
*/
public Builder request(ClientRequest clientRequest) {
this.sniHostNameHeader = getSniHostNameHeader(clientRequest.getHeaders());
- this.sniHostNameProperty = clientRequest.resolveProperty(ClientProperties.SNI_HOST_NAME, String.class);
+ this.sniHostPrecedence = resolveSniHostNameProperty(clientRequest);
this.uri = clientRequest.getUri();
return this;
}
@@ -71,7 +70,7 @@
* @return the builder instance
*/
public Builder configuration(Configuration configuration) {
- this.sniHostNameProperty = (String) configuration.getProperty(ClientProperties.SNI_HOST_NAME);
+ this.sniHostPrecedence = getSniHostNameProperty(configuration);
return this;
}
@@ -107,6 +106,62 @@
}
/**
+ * <p>
+ * Sets the {@code hostName} to be used for calculating the {@link javax.net.ssl.SNIHostName}.
+ * Takes precedence over the HTTP HOST header, if set.
+ * </p>
+ * <p>
+ * By default, the {@code SNIHostName} is set when the HOST HTTP header differs from the HTTP request host.
+ * When the {@code hostName} matches the HTTP request host, the {@code SNIHostName} is not set,
+ * and the HTTP HOST header is not used for setting the {@code SNIHostName}. This allows Domain Fronting.
+ * </p>
+ * @param hostName the host the {@code SNIHostName} should be set for.
+ * @return the builder instance.
+ */
+ public Builder setSNIHostName(String hostName) {
+ sniHostPrecedence = hostName;
+ return this;
+ }
+
+ /**
+ * <p>
+ * Sets the {@code hostName} to be used for calculating the {@link javax.net.ssl.SNIHostName}.
+ * The {@code hostName} value is taken from the {@link Configuration} if the property
+ * {@link ClientProperties#SNI_HOST_NAME} is set.
+ * Takes precedence over the HTTP HOST header, if set.
+ * </p>
+ * <p>
+ * By default, the {@code SNIHostName} is set when the HOST HTTP header differs from the HTTP request host.
+ * When the {@code hostName} matches the HTTP request host, the {@code SNIHostName} is not set,
+ * and the HTTP HOST header is not used for setting the {@code SNIHostName}. This allows for Domain Fronting.
+ * </p>
+ * @param configuration the host the {@code SNIHostName} should be set for.
+ * @return the builder instance.
+ */
+ public Builder setSNIHostName(Configuration configuration) {
+ return setSNIHostName(getSniHostNameProperty(configuration));
+ }
+
+ /**
+ * <p>
+ * Sets the {@code hostName} to be used for calculating the {@link javax.net.ssl.SNIHostName}.
+ * The {@code hostName} value is taken from the {@link PropertiesResolver} if the property
+ * {@link ClientProperties#SNI_HOST_NAME} is set.
+ * Takes precedence over the HTTP HOST header, if set.
+ * </p>
+ * <p>
+ * By default, the {@code SNIHostName} is set when the HOST HTTP header differs from the HTTP request host.
+ * When the {@code hostName} matches the HTTPS request host, the {@code SNIHostName} is not set,
+ * and the HTTP HOST header is not used for setting the {@code SNIHostName}. This allows for Domain Fronting.
+ * </p>
+ * @param resolver the host the {@code SNIHostName} should be set for.
+ * @return the builder instance.
+ */
+ public Builder setSNIHostName(PropertiesResolver resolver) {
+ return setSNIHostName(resolveSniHostNameProperty(resolver));
+ }
+
+ /**
* Builds the {@link SSLParamConfigurator} instance.
* @return the configured {@link SSLParamConfigurator} instance.
*/
@@ -121,23 +176,34 @@
}
final String hostHeader = hostHeaders.get(0).toString();
- final String trimmedHeader;
- if (hostHeader != null) {
- int index = hostHeader.indexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ;
- final String trimmedHeader0 = index != -1 ? hostHeader.substring(0, index).trim() : hostHeader.trim();
- trimmedHeader = trimmedHeader0.isEmpty() ? hostHeader : trimmedHeader0;
- } else {
- trimmedHeader = null;
- }
+ return hostHeader;
+ }
- return trimmedHeader;
+ private static String resolveSniHostNameProperty(PropertiesResolver resolver) {
+ String property = resolver.resolveProperty(ClientProperties.SNI_HOST_NAME, String.class);
+ if (property == null) {
+ property = resolver.resolveProperty(ClientProperties.SNI_HOST_NAME.toLowerCase(Locale.ROOT), String.class);
+ }
+ return property;
+ }
+
+ private static String getSniHostNameProperty(Configuration configuration) {
+ Object property = configuration.getProperty(ClientProperties.SNI_HOST_NAME);
+ if (property == null) {
+ property = configuration.getProperty(ClientProperties.SNI_HOST_NAME.toLowerCase(Locale.ROOT));
+ }
+ return (String) property;
}
}
private SSLParamConfigurator(SSLParamConfigurator.Builder builder) {
- String sniHostName = builder.sniHostNameHeader == null ? builder.sniHostNameProperty : builder.sniHostNameHeader;
uri = builder.uri;
- sniConfigurator = SniConfigurator.createWhenHostHeader(uri, sniHostName, builder.setAlways);
+ if (builder.sniHostPrecedence == null) {
+ sniConfigurator = SniConfigurator.createWhenHostHeader(uri, builder.sniHostNameHeader, builder.setAlways);
+ } else {
+ // Do not set SNI always, the property can be used to turn the SNI off
+ sniConfigurator = SniConfigurator.createWhenHostHeader(uri, builder.sniHostPrecedence, false);
+ }
}
/**
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
index 9e766f5..baf1c28 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -50,26 +50,31 @@
}
/**
- * Create ClientSNI when {@link HttpHeaders#HOST} is set different from the request URI host (or {@code whenDiffer}.is false).
+ * Create {@link SniConfigurator} when {@code sniHost} is set different from the request URI host
+ * (or {@code whenDiffer}.is false).
* @param hostUri the Uri of the HTTP request
- * @param sniHostName the SniHostName either from HttpHeaders or the
- * {@link org.glassfish.jersey.client.ClientProperties#SNI_HOST_NAME} property from Configuration object.
+ * @param sniHost the preferred host name to create the {@link SNIHostName}
* @param whenDiffer create {@SniConfigurator only when different from the request URI host}
- * @return ClientSNI or empty when {@link HttpHeaders#HOST}
+ * @return Optional {@link SniConfigurator} or empty when {@code sniHost} is equal to the requestHost
*/
- static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, String sniHostName, boolean whenDiffer) {
- if (sniHostName == null) {
+ static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, String sniHost, boolean whenDiffer) {
+ final String trimmedHeader;
+ if (sniHost != null) {
+ int index = sniHost.indexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ;
+ final String trimmedHeader0 = index != -1 ? sniHost.substring(0, index).trim() : sniHost.trim();
+ trimmedHeader = trimmedHeader0.isEmpty() ? sniHost : trimmedHeader0;
+ } else {
return Optional.empty();
}
if (hostUri != null) {
final String hostUriString = hostUri.getHost();
- if (!whenDiffer && hostUriString.equals(sniHostName)) {
+ if (!whenDiffer && hostUriString.equals(trimmedHeader)) {
return Optional.empty();
}
}
- return Optional.of(new SniConfigurator(sniHostName));
+ return Optional.of(new SniConfigurator(trimmedHeader));
}
/**
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
index c89cf19..b5b28f3 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
@@ -357,7 +357,8 @@
private ClientResponse _apply(final ClientRequest request) throws IOException {
final HttpURLConnection uc;
final Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(request);
- final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(request).build();
+ final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(request)
+ .setSNIHostName(request).build();
final URI sniUri;
if (sniConfig.isSNIRequired()) {
sniUri = sniConfig.toIPRequestUri();
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/ClientRequestTest.java b/core-client/src/test/java/org/glassfish/jersey/client/ClientRequestTest.java
index 1f7de34..c075af9 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/ClientRequestTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/ClientRequestTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -46,8 +46,8 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.same;
/**
* {@code ClientRequest} unit tests.
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java
new file mode 100644
index 0000000..06dcdec
--- /dev/null
+++ b/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.client.innate.http;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.ClientRequest;
+import org.glassfish.jersey.client.JerseyClient;
+import org.glassfish.jersey.http.HttpHeaders;
+import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.internal.PropertiesDelegate;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class SSLParamConfiguratorTest {
+ @Test
+ public void testNoHost() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(false));
+ }
+
+ @Test
+ public void testHostHeaderHasPrecedence() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ request.getHeaders().add(HttpHeaders.HOST, "yyy.com");
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("yyy.com"));
+ }
+
+ @Test
+ public void testPropertyOnClientHasPrecedence() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ client.property(ClientProperties.SNI_HOST_NAME, "yyy.com");
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("yyy.com"));
+ }
+
+ @Test
+ public void testPropertyOnDelegateHasPrecedence() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ client.property(ClientProperties.SNI_HOST_NAME, "yyy.com");
+ delegate.setProperty(ClientProperties.SNI_HOST_NAME, "zzz.com");
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("zzz.com"));
+ }
+
+ @Test
+ public void testPropertyOnDelegateHasPrecedenceOverHost() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ client.property(ClientProperties.SNI_HOST_NAME, "yyy.com");
+ delegate.setProperty(ClientProperties.SNI_HOST_NAME, "zzz.com");
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ request.getHeaders().add(HttpHeaders.HOST, "www.com");
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("zzz.com"));
+ }
+
+ @Test
+ public void testDisableSni() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ client.property(ClientProperties.SNI_HOST_NAME, "yyy.com");
+ delegate.setProperty(ClientProperties.SNI_HOST_NAME, "xxx.com");
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ request.getHeaders().add(HttpHeaders.HOST, "www.com");
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(false));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("xxx.com"));
+ }
+
+ @Test
+ public void testLowerCasePropertyOnClientHasPrecedence() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ final ClientConfig config = client.getConfiguration();
+ final PropertiesDelegate delegate = new MapPropertiesDelegate();
+ client.property(ClientProperties.SNI_HOST_NAME.toLowerCase(Locale.ROOT), "yyy.com");
+ ClientRequest request = new ClientRequest(uri, config, delegate) {};
+ request.getHeaders().add(HttpHeaders.HOST, "www.com");
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder().request(request).build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("yyy.com"));
+ }
+
+ @Test
+ public void testUriAndHeadersAndConfig() {
+ final URI uri = URI.create("http://xxx.com:8080");
+ final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+ Map<String, List<Object>> httpHeaders = new MultivaluedHashMap<>();
+ httpHeaders.put(HttpHeaders.HOST, Collections.singletonList("www.com"));
+ SSLParamConfigurator configurator = SSLParamConfigurator.builder()
+ .uri(uri)
+ .headers(httpHeaders)
+ .configuration(client.getConfiguration())
+ .build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("www.com"));
+
+ client.property(ClientProperties.SNI_HOST_NAME, "yyy.com");
+ configurator = SSLParamConfigurator.builder()
+ .uri(uri)
+ .headers(httpHeaders)
+ .configuration(client.getConfiguration())
+ .build();
+ MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+ MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("yyy.com"));
+ }
+}
diff --git a/core-common/pom.xml b/core-common/pom.xml
index c4ac5ff..71494de 100644
--- a/core-common/pom.xml
+++ b/core-common/pom.xml
@@ -255,9 +255,172 @@
<profiles>
<profile>
+ <id>build.jdk20-</id>
+ <activation>
+ <jdk>[11,21)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add.java20-</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/java20-</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>build.jdk21</id>
+ <activation>
+ <jdk>[21,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add.java20-</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/java21</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <configuration>
+ <!-- compile everything to ensure module-info contains right entries -->
+ <release>21</release>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <target>
+ <echo>Building for JDK 21+</echo>
+ </target>
+ </configuration>
+ </execution>
+ <execution>
+ <id>compile-java21</id>
+ <phase>process-resources</phase>
+ <configuration>
+ <target>
+ <mkdir dir="${java21.build.outputDirectory}" />
+ <javac srcdir="${java21.sourceDirectory}${path.separator}${project.basedir}/src/main/java/org/glassfish/jersey/innate/virtual" destdir="${java21.build.outputDirectory}"
+ classpath="${project.build.outputDirectory}" includeantruntime="false" release="21"/>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>copyJDK21FilesToMultiReleaseJar</id>
+ <activation>
+ <file>
+ <!-- ${java21.build.outputDirectory} does not work here -->
+ <exists>target/classes-java21/org/glassfish/jersey/innate/VirtualThreadSupport.class</exists>
+ </file>
+ <jdk>[11,21)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Multi-Release>true</Multi-Release>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <inherited>true</inherited>
+ <executions>
+ <execution>
+ <id>copy-jdk21-sources</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/generated-sources/rsrc-gen/META-INF/versions/21/org/glassfish/jersey/innate</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${java21.sourceDirectory}/org/glassfish/jersey/innate</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-jdk21-classes-to-meta-inf</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.outputDirectory}/META-INF/versions/21</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${java21.build.outputDirectory}</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
<id>securityOff</id>
<properties>
- <surefire.security.argline />
+ <surefire.security.argline />
</properties>
<build>
<plugins>
@@ -294,6 +457,8 @@
<properties>
<surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/surefire.policy</surefire.security.argline>
+ <java21.build.outputDirectory>${project.build.directory}/classes-java21</java21.build.outputDirectory>
+ <java21.sourceDirectory>${project.basedir}/src/main/java21</java21.sourceDirectory>
</properties>
</project>
diff --git a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
index e71e5e1..ced63b3 100644
--- a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
+++ b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -321,6 +321,30 @@
public static final String PARAM_CONVERTERS_THROW_IAE = "jersey.config.paramconverters.throw.iae";
/**
+ * <p>
+ * Defines the {@link java.util.concurrent.ThreadFactory} to be used by internal default Executor Services.
+ * </p>
+ * <p>
+ * The default is {@link java.util.concurrent.Executors#defaultThreadFactory()} on platform threads and
+ * {@code Thread.ofVirtual().factory()} on virtual threads.
+ * </p>
+ * @since 3.1.7
+ */
+ public static String THREAD_FACTORY = "jersey.config.threads.factory";
+
+ /**
+ * <p>
+ * Defines whether the virtual threads should be used by Jersey on JDK 21+ when not using an exact number
+ * of threads by {@code FixedThreadPool}.
+ * </p>
+ * <p>
+ * The default is {@code false} for this version of Jersey.
+ * </p>
+ * @since 3.1.7
+ */
+ public static String USE_VIRTUAL_THREADS = "jersey.config.threads.use.virtual";
+
+ /**
* Prevent instantiation.
*/
private CommonProperties() {
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/VirtualThreadUtil.java b/core-common/src/main/java/org/glassfish/jersey/innate/VirtualThreadUtil.java
new file mode 100644
index 0000000..3511d8e
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/VirtualThreadUtil.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.innate;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.innate.virtual.LoomishExecutors;
+
+import jakarta.ws.rs.core.Configuration;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Factory class to provide JDK specific implementation of bits related to the virtual thread support.
+ */
+public final class VirtualThreadUtil {
+
+ private static final boolean USE_VIRTUAL_THREADS_BY_DEFAULT = false;
+
+ /**
+ * Do not instantiate.
+ */
+ private VirtualThreadUtil() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Return an instance of {@link LoomishExecutors} based on a configuration property.
+ * @param config the {@link Configuration}
+ * @return the {@link LoomishExecutors} instance.
+ */
+ public static LoomishExecutors withConfig(Configuration config) {
+ return withConfig(config, USE_VIRTUAL_THREADS_BY_DEFAULT);
+ }
+
+ /**
+ * Return an instance of {@link LoomishExecutors} based on a configuration property.
+ * @param config the {@link Configuration}
+ * @param useVirtualByDefault the default use if not said otherwise by property
+ * @return the {@link LoomishExecutors} instance.
+ */
+ public static LoomishExecutors withConfig(Configuration config, boolean useVirtualByDefault) {
+ ThreadFactory tfThreadFactory = null;
+ boolean useVirtualThreads = useVirtualThreads(config, useVirtualByDefault);
+
+ if (config != null) {
+ Object threadFactory = config.getProperty(CommonProperties.THREAD_FACTORY);
+ if (threadFactory != null && ThreadFactory.class.isInstance(threadFactory)) {
+ tfThreadFactory = (ThreadFactory) threadFactory;
+ }
+ }
+
+ return tfThreadFactory == null
+ ? VirtualThreadSupport.allowVirtual(useVirtualThreads)
+ : VirtualThreadSupport.allowVirtual(useVirtualThreads, tfThreadFactory);
+ }
+
+ /**
+ * Check configuration if the use of the virtual threads is expected or return the default value if not.
+ * @param config the {@link Configuration}
+ * @param useByDefault the default expectation
+ * @return the expected
+ */
+ private static boolean useVirtualThreads(Configuration config, boolean useByDefault) {
+ boolean bUseVirtualThreads = useByDefault;
+ if (config != null) {
+ Object useVirtualThread = config.getProperty(CommonProperties.USE_VIRTUAL_THREADS);
+ if (useVirtualThread != null && Boolean.class.isInstance(useVirtualThread)) {
+ bUseVirtualThreads = (boolean) useVirtualThread;
+ }
+ if (useVirtualThread != null && String.class.isInstance(useVirtualThread)) {
+ bUseVirtualThreads = Boolean.parseBoolean(useVirtualThread.toString());
+ }
+ }
+ return bUseVirtualThreads;
+ }
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/inject/package-info.java b/core-common/src/main/java/org/glassfish/jersey/innate/inject/package-info.java
index 4baccd6..b276f3c 100644
--- a/core-common/src/main/java/org/glassfish/jersey/innate/inject/package-info.java
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/inject/package-info.java
@@ -16,5 +16,6 @@
/**
* Jersey innate injection related packages. The innate packages will not be opened by JPMS outside of Jersey.
+ * Not for public use.
*/
package org.glassfish.jersey.innate.inject;
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/inject/spi/ExternalRegistrables.java b/core-common/src/main/java/org/glassfish/jersey/innate/inject/spi/ExternalRegistrables.java
new file mode 100644
index 0000000..f5c5f8f
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/inject/spi/ExternalRegistrables.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.innate.inject.spi;
+
+import jakarta.ws.rs.RuntimeType;
+import java.util.List;
+
+/**
+ * Provide a list of classes or interfaces the InjectionManager can support.
+ */
+public interface ExternalRegistrables {
+
+ /**
+ * Contract - RuntimeType pair. For a contract applicable on both client and server, use {@code null} as RuntimeType.
+ */
+ public static final class ClassRuntimeTypePair {
+ private final Class<?> contract;
+ private final RuntimeType runtimeType;
+
+ public ClassRuntimeTypePair(Class<?> contract, RuntimeType runtimeType) {
+ this.contract = contract;
+ this.runtimeType = runtimeType;
+ }
+
+ public Class<?> getContract() {
+ return contract;
+ }
+
+ public RuntimeType getRuntimeType() {
+ return runtimeType;
+ }
+ }
+
+ /**
+ * List of contracts that can be registered into Jersey to be passed by the external injection framework.
+ * @return list of contracts allowed to be registered in Jersey.
+ */
+ List<ClassRuntimeTypePair> registrableContracts();
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/inject/spi/package-info.java b/core-common/src/main/java/org/glassfish/jersey/innate/inject/spi/package-info.java
new file mode 100644
index 0000000..5ad36dd
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/inject/spi/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/**
+ * Jersey innate injection related packages. The innate packages will not be opened by JPMS outside of Jersey.
+ * Not for public use.
+ */
+package org.glassfish.jersey.innate.inject.spi;
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/package-info.java b/core-common/src/main/java/org/glassfish/jersey/innate/package-info.java
index 7d5ae69..a1835bb 100644
--- a/core-common/src/main/java/org/glassfish/jersey/innate/package-info.java
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,5 +16,6 @@
/**
* Jersey innate packages. The innate packages will not be opened by JPMS outside of Jersey.
+ * Not for public use.
*/
package org.glassfish.jersey.innate;
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/virtual/LoomishExecutors.java b/core-common/src/main/java/org/glassfish/jersey/innate/virtual/LoomishExecutors.java
new file mode 100644
index 0000000..9065746
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/virtual/LoomishExecutors.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.innate.virtual;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * {@link Executors} facade to support virtual threads.
+ */
+public interface LoomishExecutors {
+ /**
+ * Creates a thread pool that creates new threads as needed and uses virtual threads if available.
+ * @return the newly created thread pool
+ */
+ ExecutorService newCachedThreadPool();
+
+ /**
+ * Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue
+ * and uses virtual threads if available
+ * @param nThreads – the number of threads in the pool
+ * @return the newly created thread pool
+ */
+ ExecutorService newFixedThreadPool(int nThreads);
+
+ /**
+ * Returns thread factory used to create new threads
+ * @return thread factory used to create new threads
+ * @see Executors#defaultThreadFactory()
+ */
+ ThreadFactory getThreadFactory();
+
+ /**
+ * Return true if the virtual thread use is requested.
+ * @return whether the virtual thread use is requested.
+ */
+ boolean isVirtual();
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/virtual/package-info.java b/core-common/src/main/java/org/glassfish/jersey/innate/virtual/package-info.java
new file mode 100644
index 0000000..c56f91b
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/virtual/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/**
+ * Jersey innate packages. The innate packages will not be opened by JPMS outside of Jersey.
+ * Not for public use.
+ * This virtual package should contain only classes that do not have dependencies on Jersey, or the REST API to be buildable with
+ * ant for multi-release.
+ */
+package org.glassfish.jersey.innate.virtual;
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java
index 4bbab3e..f5c467a 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -43,7 +43,9 @@
import jakarta.annotation.Priority;
import org.glassfish.jersey.JerseyPriorities;
+import org.glassfish.jersey.innate.inject.spi.ExternalRegistrables;
import org.glassfish.jersey.internal.LocalizationMessages;
+import org.glassfish.jersey.internal.ServiceFinder;
import org.glassfish.jersey.model.ContractProvider;
import org.glassfish.jersey.model.internal.RankedComparator;
import org.glassfish.jersey.model.internal.RankedProvider;
@@ -103,6 +105,14 @@
interfaces.putAll(JAX_RS_PROVIDER_INTERFACE_WHITELIST);
interfaces.put(jakarta.ws.rs.core.Feature.class, ProviderRuntime.BOTH);
interfaces.put(Binder.class, ProviderRuntime.BOTH);
+
+ try {
+ ServiceFinder<ExternalRegistrables> registerables = ServiceFinder.find(ExternalRegistrables.class, true);
+ registerables.forEach(regs -> regs.registrableContracts()
+ .forEach(pair -> interfaces.put(pair.getContract(), ProviderRuntime.fromRuntimeType(pair.getRuntimeType()))));
+ } catch (Throwable t) {
+ LOGGER.warning(LocalizationMessages.ERROR_EXTERNAL_REGISTERABLES_IGNORED(t.getMessage()));
+ }
return interfaces;
}
@@ -119,6 +129,10 @@
public RuntimeType getRuntime() {
return runtime;
}
+
+ private static ProviderRuntime fromRuntimeType(RuntimeType type) {
+ return type == null ? BOTH : (type == RuntimeType.SERVER ? SERVER : CLIENT);
+ }
}
/**
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/AbstractMessageReaderWriterProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/AbstractMessageReaderWriterProvider.java
index f7e2673..466eaaa 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/AbstractMessageReaderWriterProvider.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/AbstractMessageReaderWriterProvider.java
@@ -46,7 +46,7 @@
*
* @deprecated use {@code StandardCharsets.UTF_8} instead.
*/
- @Deprecated
+ @Deprecated(forRemoval = true)
public static final Charset UTF8 = StandardCharsets.UTF_8;
/**
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java
index 39f74fb..e9f1bc2 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.glassfish.jersey.innate.VirtualThreadSupport;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.guava.Preconditions;
@@ -58,11 +59,13 @@
public final class CommittingOutputStream extends OutputStream {
private static final Logger LOGGER = Logger.getLogger(CommittingOutputStream.class.getName());
+ private final boolean isVirtualThread = VirtualThreadSupport.isVirtualThread();
+
/**
* Null stream provider.
*/
private static final OutboundMessageContext.StreamProvider NULL_STREAM_PROVIDER =
- contentLength -> new NullOutputStream();
+ contentLength -> OutputStream.nullOutputStream();
/**
* Default size of the buffer which will be used if no user defined size is specified.
*/
@@ -170,7 +173,7 @@
Preconditions.checkState(streamProvider != null, STREAM_PROVIDER_NULL);
adaptedOutput = streamProvider.getOutputStream(currentSize);
if (adaptedOutput == null) {
- adaptedOutput = new NullOutputStream();
+ adaptedOutput = OutputStream.nullOutputStream();
}
directWrite = true;
@@ -275,7 +278,13 @@
commitStream(currentSize);
if (buffer != null) {
- buffer.writeTo(adaptedOutput);
+ if (isVirtualThread && adaptedOutput != null) {
+ adaptedOutput.write(buffer.toByteArray());
+ } else {
+ // Virtual thread in JDK 21 are blocked by synchronized writeTo
+ // but about 10% faster than ^ without virtual threads.
+ buffer.writeTo(adaptedOutput);
+ }
}
}
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/InputStreamProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/InputStreamProvider.java
index c07dcbf..6bf66cb 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/InputStreamProvider.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/InputStreamProvider.java
@@ -78,10 +78,8 @@
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException {
- try {
+ try (t) {
ReaderWriter.writeTo(t, entityStream);
- } finally {
- t.close();
}
}
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/NullOutputStream.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/NullOutputStream.java
deleted file mode 100644
index 26d3f14..0000000
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/NullOutputStream.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0, which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the
- * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- * version 2 with the GNU Classpath Exception, which is available at
- * https://www.gnu.org/software/classpath/license.html.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- */
-
-package org.glassfish.jersey.message.internal;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.glassfish.jersey.internal.LocalizationMessages;
-
-/**
- * A {@code "dev/null"} output stream - an output stream implementation that discards all the
- * data written to it. This implementation is not thread-safe.
- *
- * Note that once a null output stream instance is {@link #close() closed}, any subsequent attempts
- * to write the data to the closed stream result in an {@link java.io.IOException} being thrown.
- *
- * @author Miroslav Fuksa
- * @author Marek Potociar
- */
-public class NullOutputStream extends OutputStream {
-
- private boolean isClosed;
-
- @Override
- public void write(int b) throws IOException {
- checkClosed();
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- checkClosed();
- if (b == null) {
- throw new NullPointerException();
- } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- }
- }
-
- @Override
- public void flush() throws IOException {
- checkClosed();
- }
-
- private void checkClosed() throws IOException {
- if (isClosed) {
- throw new IOException(LocalizationMessages.OUTPUT_STREAM_CLOSED());
- }
- }
-
- @Override
- public void close() throws IOException {
- isClosed = true;
- }
-}
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
index 018c9f0..ae8e7d8 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
@@ -43,7 +43,7 @@
* A utility class for reading and writing using byte and character streams.
* <p>
* If a byte or character array is utilized then the size of the array
- * is by default the value of {@value org.glassfish.jersey.message.MessageProperties#IO_DEFAULT_BUFFER_SIZE}.
+ * is by default decided by the JRE.
* This value can be set using the system property
* {@value org.glassfish.jersey.message.MessageProperties#IO_BUFFER_SIZE}.
*
@@ -57,14 +57,19 @@
*
* @deprecated use {@code StandardCharsets.UTF_8} instead
*/
- @Deprecated
+ @Deprecated(forRemoval = true)
public static final Charset UTF8 = StandardCharsets.UTF_8;
/**
* The buffer size for arrays of byte and character.
*/
public static final int BUFFER_SIZE = getBufferSize();
- private static int getBufferSize() {
+ /**
+ * Whether {@linkplain BUFFER_SIZE} is to be ignored in favor of JRE's own decision.
+ */
+ public static final boolean AUTOSIZE_BUFFER = getAutosizeBuffer();
+
+ private static int getIOBufferSize() {
// TODO should we unify this buffer size and CommittingOutputStream buffer size (controlled by CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER)?
final String value = AccessController.doPrivileged(PropertiesHelper.getSystemProperty(MessageProperties.IO_BUFFER_SIZE));
if (value != null) {
@@ -78,11 +83,20 @@
LOGGER.log(Level.CONFIG,
"Value of " + MessageProperties.IO_BUFFER_SIZE
+ " property is not a valid positive integer [" + value + "]."
- + " Reverting to default [" + MessageProperties.IO_DEFAULT_BUFFER_SIZE + "].",
+ + " Reverting to default [at JRE's discretion].",
e);
}
}
- return MessageProperties.IO_DEFAULT_BUFFER_SIZE;
+ return -1;
+ }
+
+ private static int getBufferSize() {
+ final int ioBufferSize = getIOBufferSize();
+ return ioBufferSize == -1 ? MessageProperties.IO_DEFAULT_BUFFER_SIZE : ioBufferSize;
+ }
+
+ private static boolean getAutosizeBuffer() {
+ return getIOBufferSize() == -1;
}
/**
@@ -93,6 +107,11 @@
* @throws IOException if there is an error reading or writing bytes.
*/
public static void writeTo(InputStream in, OutputStream out) throws IOException {
+ if (AUTOSIZE_BUFFER) {
+ in.transferTo(out);
+ return;
+ }
+
int read;
final byte[] data = new byte[BUFFER_SIZE];
while ((read = in.read(data)) != -1) {
@@ -108,6 +127,11 @@
* @throws IOException if there is an error reading or writing characters.
*/
public static void writeTo(Reader in, Writer out) throws IOException {
+ if (AUTOSIZE_BUFFER) {
+ in.transferTo(out);
+ return;
+ }
+
int read;
final char[] data = new char[BUFFER_SIZE];
while ((read = in.read(data)) != -1) {
diff --git a/core-common/src/main/java/org/glassfish/jersey/spi/AbstractThreadPoolProvider.java b/core-common/src/main/java/org/glassfish/jersey/spi/AbstractThreadPoolProvider.java
index 27cf449..79ac262 100644
--- a/core-common/src/main/java/org/glassfish/jersey/spi/AbstractThreadPoolProvider.java
+++ b/core-common/src/main/java/org/glassfish/jersey/spi/AbstractThreadPoolProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -29,6 +29,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.glassfish.jersey.innate.VirtualThreadUtil;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder;
import org.glassfish.jersey.internal.util.ExtendedLogger;
@@ -37,6 +38,8 @@
import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.process.JerseyProcessingUncaughtExceptionHandler;
+import jakarta.ws.rs.core.Configuration;
+
/**
* Abstract thread pool executor provider.
* <p>
@@ -69,9 +72,7 @@
private final String name;
private final AtomicBoolean closed = new AtomicBoolean(false);
- private final LazyValue<E> lazyExecutorServiceProvider =
- Values.lazy((Value<E>) () -> createExecutor(getCorePoolSize(), createThreadFactory(), getRejectedExecutionHandler()));
-
+ private final LazyValue<E> lazyExecutorServiceProvider;
/**
* Inheritance constructor.
*
@@ -79,7 +80,20 @@
* provided thread pool executor.
*/
protected AbstractThreadPoolProvider(final String name) {
+ this(name, null);
+ }
+
+ /**
+ * Inheritance constructor.
+ *
+ * @param name name of the provided thread pool executor. Will be used in the names of threads created & used by the
+ * provided thread pool executor.
+ * @param configuration {@link Configuration} properties.
+ */
+ protected AbstractThreadPoolProvider(final String name, Configuration configuration) {
this.name = name;
+ lazyExecutorServiceProvider = Values.lazy((Value<E>) () ->
+ createExecutor(getCorePoolSize(), createThreadFactory(configuration), getRejectedExecutionHandler()));
}
/**
@@ -208,9 +222,10 @@
return null;
}
- private ThreadFactory createThreadFactory() {
+ private ThreadFactory createThreadFactory(Configuration configuration) {
final ThreadFactoryBuilder factoryBuilder = new ThreadFactoryBuilder()
.setNameFormat(name + "-%d")
+ .setThreadFactory(VirtualThreadUtil.withConfig(configuration).getThreadFactory())
.setUncaughtExceptionHandler(new JerseyProcessingUncaughtExceptionHandler());
final ThreadFactory backingThreadFactory = getBackingThreadFactory();
diff --git a/core-common/src/main/java/org/glassfish/jersey/spi/ScheduledThreadPoolExecutorProvider.java b/core-common/src/main/java/org/glassfish/jersey/spi/ScheduledThreadPoolExecutorProvider.java
index e805b23..348db2b 100644
--- a/core-common/src/main/java/org/glassfish/jersey/spi/ScheduledThreadPoolExecutorProvider.java
+++ b/core-common/src/main/java/org/glassfish/jersey/spi/ScheduledThreadPoolExecutorProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
import java.util.concurrent.ThreadFactory;
import jakarta.annotation.PreDestroy;
+import jakarta.ws.rs.core.Configuration;
/**
* Default implementation of the Jersey {@link org.glassfish.jersey.spi.ScheduledExecutorServiceProvider
@@ -66,6 +67,17 @@
super(name);
}
+ /**
+ * Create a new instance of the scheduled thread pool executor provider.
+ *
+ * @param name provider name. The name will be used to name the threads created & used by the
+ * provisioned scheduled thread pool executor.
+ * @@param configuration {@link Configuration} properties.
+ */
+ public ScheduledThreadPoolExecutorProvider(final String name, Configuration configuration) {
+ super(name, configuration);
+ }
+
@Override
public ScheduledExecutorService getExecutorService() {
return super.getExecutor();
diff --git a/core-common/src/main/java/org/glassfish/jersey/spi/ThreadPoolExecutorProvider.java b/core-common/src/main/java/org/glassfish/jersey/spi/ThreadPoolExecutorProvider.java
index 09e0770..df3dd09 100644
--- a/core-common/src/main/java/org/glassfish/jersey/spi/ThreadPoolExecutorProvider.java
+++ b/core-common/src/main/java/org/glassfish/jersey/spi/ThreadPoolExecutorProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -26,6 +26,7 @@
import java.util.concurrent.TimeUnit;
import jakarta.annotation.PreDestroy;
+import jakarta.ws.rs.core.Configuration;
/**
* Default implementation of the Jersey {@link org.glassfish.jersey.spi.ExecutorServiceProvider executor service provider SPI}.
@@ -61,6 +62,17 @@
super(name);
}
+ /**
+ * Create a new instance of the thread pool executor provider.
+ *
+ * @param name provider name. The name will be used to name the threads created & used by the
+ * provisioned thread pool executor.
+ * @param configuration {@link Configuration} properties.
+ */
+ public ThreadPoolExecutorProvider(final String name, Configuration configuration) {
+ super(name, configuration);
+ }
+
@Override
public ExecutorService getExecutorService() {
return super.getExecutor();
diff --git a/core-common/src/main/java20-/org/glassfish/jersey/innate/VirtualThreadSupport.java b/core-common/src/main/java20-/org/glassfish/jersey/innate/VirtualThreadSupport.java
new file mode 100644
index 0000000..867a65b
--- /dev/null
+++ b/core-common/src/main/java20-/org/glassfish/jersey/innate/VirtualThreadSupport.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.innate;
+
+import org.glassfish.jersey.innate.virtual.LoomishExecutors;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Utility class for the virtual thread support.
+ */
+public final class VirtualThreadSupport {
+
+ private static final LoomishExecutors NON_VIRTUAL = new NonLoomishExecutors(Executors.defaultThreadFactory());
+
+ /**
+ * Do not instantiate.
+ */
+ private VirtualThreadSupport() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Informs whether the given {@link Thread} is virtual.
+ * @return true when the current thread is virtual.
+ */
+ public static boolean isVirtualThread() {
+ return false;
+ }
+
+ /**
+ * Return an instance of {@link LoomishExecutors} based on a permission to use virtual threads.
+ * @param allow whether to allow virtual threads.
+ * @return the {@link LoomishExecutors} instance.
+ */
+ public static LoomishExecutors allowVirtual(boolean allow) {
+ return NON_VIRTUAL;
+ }
+
+ /**
+ * Return an instance of {@link LoomishExecutors} based on a permission to use virtual threads.
+ * @param allow whether to allow virtual threads.
+ * @param threadFactory the thread factory to be used by a the {@link ExecutorService}.
+ * @return the {@link LoomishExecutors} instance.
+ */
+ public static LoomishExecutors allowVirtual(boolean allow, ThreadFactory threadFactory) {
+ return new NonLoomishExecutors(threadFactory);
+ }
+
+ private static final class NonLoomishExecutors implements LoomishExecutors {
+ private final ThreadFactory threadFactory;
+
+ private NonLoomishExecutors(ThreadFactory threadFactory) {
+ this.threadFactory = threadFactory;
+ }
+
+ @Override
+ public ExecutorService newCachedThreadPool() {
+ return Executors.newCachedThreadPool();
+ }
+
+ @Override
+ public ExecutorService newFixedThreadPool(int nThreads) {
+ return Executors.newFixedThreadPool(nThreads);
+ }
+
+ @Override
+ public ThreadFactory getThreadFactory() {
+ return threadFactory;
+ }
+
+ @Override
+ public boolean isVirtual() {
+ return false;
+ }
+ }
+}
diff --git a/core-common/src/main/java21/org/glassfish/jersey/innate/VirtualThreadSupport.java b/core-common/src/main/java21/org/glassfish/jersey/innate/VirtualThreadSupport.java
new file mode 100644
index 0000000..0e7d695
--- /dev/null
+++ b/core-common/src/main/java21/org/glassfish/jersey/innate/VirtualThreadSupport.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.innate;
+
+import org.glassfish.jersey.innate.virtual.LoomishExecutors;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Utility class for the virtual thread support.
+ */
+public final class VirtualThreadSupport {
+
+ private static final LoomishExecutors VIRTUAL_THREADS = new Java21LoomishExecutors(Thread.ofVirtual().factory());
+ private static final LoomishExecutors NON_VIRTUAL_THREADS = new NonLoomishExecutors(Executors.defaultThreadFactory());
+
+ /**
+ * Do not instantiate.
+ */
+ private VirtualThreadSupport() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Informs whether the given {@link Thread} is virtual.
+ * @return true when the current thread is virtual.
+ */
+ public static boolean isVirtualThread() {
+ return Thread.currentThread().isVirtual();
+ }
+
+ /**
+ * Return an instance of {@link LoomishExecutors} based on a permission to use virtual threads.
+ * @param allow whether to allow virtual threads.
+ * @return the {@link LoomishExecutors} instance.
+ */
+ public static LoomishExecutors allowVirtual(boolean allow) {
+ return allow ? VIRTUAL_THREADS : NON_VIRTUAL_THREADS;
+ }
+
+ /**
+ * Return an instance of {@link LoomishExecutors} based on a permission to use virtual threads.
+ * @param allow whether to allow virtual threads.
+ * @param threadFactory the thread factory to be used by a the {@link ExecutorService}.
+ * @return the {@link LoomishExecutors} instance.
+ */
+ public static LoomishExecutors allowVirtual(boolean allow, ThreadFactory threadFactory) {
+ return allow ? new Java21LoomishExecutors(threadFactory) : new NonLoomishExecutors(threadFactory);
+ }
+
+ private static class NonLoomishExecutors implements LoomishExecutors {
+ private final ThreadFactory threadFactory;
+
+ private NonLoomishExecutors(ThreadFactory threadFactory) {
+ this.threadFactory = threadFactory;
+ }
+
+ @Override
+ public ExecutorService newCachedThreadPool() {
+ return Executors.newCachedThreadPool(getThreadFactory());
+ }
+
+ @Override
+ public ExecutorService newFixedThreadPool(int nThreads) {
+ return Executors.newFixedThreadPool(nThreads, getThreadFactory());
+ }
+
+ @Override
+ public ThreadFactory getThreadFactory() {
+ return threadFactory;
+ }
+
+ @Override
+ public boolean isVirtual() {
+ return false;
+ }
+ }
+
+ private static class Java21LoomishExecutors implements LoomishExecutors {
+ private final ThreadFactory threadFactory;
+
+ private Java21LoomishExecutors(ThreadFactory threadFactory) {
+ this.threadFactory = threadFactory;
+ }
+
+ @Override
+ public ExecutorService newCachedThreadPool() {
+ return Executors.newThreadPerTaskExecutor(getThreadFactory());
+ }
+
+ @Override
+ public ExecutorService newFixedThreadPool(int nThreads) {
+ ThreadFactory threadFactory = this == VIRTUAL_THREADS ? Executors.defaultThreadFactory() : getThreadFactory();
+ return Executors.newFixedThreadPool(nThreads, threadFactory);
+ }
+
+ @Override
+ public ThreadFactory getThreadFactory() {
+ return threadFactory;
+ }
+
+ @Override
+ public boolean isVirtual() {
+ return true;
+ }
+ }
+}
diff --git a/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties b/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties
index b60bf25..e9cd448 100644
--- a/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties
+++ b/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018 Payara Foundation and/or its affiliates.
#
# This program and the accompanying materials are made available under the
@@ -39,6 +39,7 @@
error.entity.provider.basictypes.character.morechars=A single character expected in the entity input stream.
error.entity.provider.basictypes.constructor=Error converting entity to {0} type by single String constructor.
error.entity.provider.basictypes.unkwnown=Unsupported basic type {0}.
+error.external.registerables.ignored=Error reading external registrable contracts: {0}.
error.finding.exception.mapper.type=Could not find exception type for given ExceptionMapper class: {0}.
error.interceptor.reader.proceed=Last reader interceptor in the chain called the method proceed.
error.interceptor.writer.proceed=Last writer interceptor in the chain called the method proceed.
diff --git a/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java b/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java
index ed4d5dc..a138afb 100644
--- a/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java
+++ b/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -32,8 +32,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
index 1e6d678..d976cca 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
@@ -68,7 +68,6 @@
import org.glassfish.jersey.message.MessageBodyWorkers;
import org.glassfish.jersey.message.internal.MessageBodyFactory;
import org.glassfish.jersey.message.internal.MessagingBinders;
-import org.glassfish.jersey.message.internal.NullOutputStream;
import org.glassfish.jersey.model.internal.ComponentBag;
import org.glassfish.jersey.model.internal.ManagedObjectsFinalizer;
import org.glassfish.jersey.model.internal.RankedComparator;
@@ -593,7 +592,7 @@
* @return response future.
*/
public Future<ContainerResponse> apply(final ContainerRequest requestContext) {
- return apply(requestContext, new NullOutputStream());
+ return apply(requestContext, OutputStream.nullOutputStream());
}
/**
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java b/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java
index b671e68..a0fedf4 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java
@@ -53,7 +53,7 @@
public class ChunkedOutput<T> extends GenericType<T> implements Closeable {
private static final byte[] ZERO_LENGTH_DELIMITER = new byte[0];
- private final BlockingDeque<T> queue = new LinkedBlockingDeque<>();
+ private final BlockingDeque<T> queue;
private final byte[] chunkDelimiter;
private final AtomicBoolean resumed = new AtomicBoolean(false);
private final Lock lock = new ReentrantLock();
@@ -72,12 +72,59 @@
private volatile ContainerResponse responseContext;
private volatile ConnectionCallback connectionCallback;
-
/**
* Create new {@code ChunkedOutput}.
*/
protected ChunkedOutput() {
this.chunkDelimiter = ZERO_LENGTH_DELIMITER;
+ queue = new LinkedBlockingDeque<>();
+ }
+
+ /**
+ * Create new {@code ChunkedOutput} based on builder.
+ *
+ * @param builder the builder to use
+ */
+ protected ChunkedOutput(Builder<T> builder) {
+ super();
+ if (builder.queueCapacity > 0) {
+ queue = new LinkedBlockingDeque<>(builder.queueCapacity);
+ } else {
+ queue = new LinkedBlockingDeque<>();
+ }
+ if (builder.chunkDelimiter != null) {
+ this.chunkDelimiter = new byte[builder.chunkDelimiter.length];
+ System.arraycopy(builder.chunkDelimiter, 0, this.chunkDelimiter, 0, builder.chunkDelimiter.length);
+ } else {
+ this.chunkDelimiter = ZERO_LENGTH_DELIMITER;
+ }
+ if (builder.asyncContextProvider != null) {
+ this.asyncContext = builder.asyncContextProvider.get();
+ }
+ }
+
+ /**
+ * Create new {@code ChunkedOutput} based on builder.
+ *
+ * @param builder the builder to use
+ */
+ private ChunkedOutput(TypedBuilder<T> builder) {
+ super(builder.chunkType);
+
+ if (builder.queueCapacity > 0) {
+ queue = new LinkedBlockingDeque<>(builder.queueCapacity);
+ } else {
+ queue = new LinkedBlockingDeque<>();
+ }
+ if (builder.chunkDelimiter != null) {
+ this.chunkDelimiter = new byte[builder.chunkDelimiter.length];
+ System.arraycopy(builder.chunkDelimiter, 0, this.chunkDelimiter, 0, builder.chunkDelimiter.length);
+ } else {
+ this.chunkDelimiter = ZERO_LENGTH_DELIMITER;
+ }
+ if (builder.asyncContextProvider != null) {
+ this.asyncContext = builder.asyncContextProvider.get();
+ }
}
/**
@@ -88,6 +135,7 @@
public ChunkedOutput(final Type chunkType) {
super(chunkType);
this.chunkDelimiter = ZERO_LENGTH_DELIMITER;
+ queue = new LinkedBlockingDeque<>();
}
/**
@@ -103,6 +151,7 @@
} else {
this.chunkDelimiter = ZERO_LENGTH_DELIMITER;
}
+ queue = new LinkedBlockingDeque<>();
}
/**
@@ -120,6 +169,7 @@
}
this.asyncContext = asyncContextProvider == null ? null : asyncContextProvider.get();
+ queue = new LinkedBlockingDeque<>();
}
/**
@@ -137,6 +187,7 @@
} else {
this.chunkDelimiter = ZERO_LENGTH_DELIMITER;
}
+ queue = new LinkedBlockingDeque<>();
}
/**
@@ -151,6 +202,7 @@
} else {
this.chunkDelimiter = chunkDelimiter.getBytes();
}
+ queue = new LinkedBlockingDeque<>();
}
/**
@@ -167,6 +219,26 @@
} else {
this.chunkDelimiter = chunkDelimiter.getBytes();
}
+ queue = new LinkedBlockingDeque<>();
+ }
+
+ /**
+ * Returns a builder to create a ChunkedOutput with custom configuration.
+ *
+ * @return builder
+ */
+ public static <T> Builder<T> builder() {
+ return new Builder<>();
+ }
+
+ /**
+ * Returns a builder to create a ChunkedOutput with custom configuration.
+ *
+ * @param chunkType chunk type. Must not be {code null}.
+ * @return builder
+ */
+ public static <T> TypedBuilder<T> builder(Type chunkType) {
+ return new TypedBuilder<>(chunkType);
}
/**
@@ -181,7 +253,12 @@
}
if (chunk != null) {
- queue.add(chunk);
+ try {
+ queue.put(chunk);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IOException(e);
+ }
}
flushQueue();
@@ -351,7 +428,6 @@
/**
* Get state information.
- *
* Please note that {@code ChunkedOutput} can be closed by the client side - client can close connection
* from its side.
*
@@ -363,10 +439,12 @@
/**
* Executed only in case of close being triggered by client.
+ *
* @param e Exception causing the close
*/
- protected void onClose(Exception e){
-
+ protected void onClose(Exception e) {
+ // drain queue when an exception occurs to prevent deadlocks
+ queue.clear();
}
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@@ -409,4 +487,78 @@
this.connectionCallback = connectionCallbackRunner;
flushQueue();
}
+
+ /**
+ * Builder that allows to create a new ChunkedOutput based on the given configuration options.
+ *
+ * @param <Y>
+ */
+ public static class Builder<Y> {
+ byte[] chunkDelimiter;
+ int queueCapacity = -1;
+ Provider<AsyncContext> asyncContextProvider;
+
+ private Builder() {
+ // hide constructor
+ }
+
+ /**
+ * Set the chunk delimiter, in bytes.
+ * @param chunkDelimiter the chunk delimiter in bytes
+ * @return builder
+ */
+ public Builder<Y> chunkDelimiter(byte[] chunkDelimiter) {
+ this.chunkDelimiter = chunkDelimiter;
+ return this;
+ }
+
+ /**
+ * Set the queue capacity. If greater than 0, the queue is bounded and will block when full.
+ * @param queueCapacity the queue capacity
+ * @return builder
+ */
+ public Builder<Y> queueCapacity(int queueCapacity) {
+ this.queueCapacity = queueCapacity;
+ return this;
+ }
+
+ /**
+ * Set the async context provider.
+ * @param asyncContextProvider the async context provider
+ * @return builder
+ */
+ public Builder<Y> asyncContextProvider(Provider<AsyncContext> asyncContextProvider) {
+ this.asyncContextProvider = asyncContextProvider;
+ return this;
+ }
+
+ /**
+ * Build the ChunkedOutput based on the given configuration.
+ * @return the ChunkedOutput
+ */
+ public ChunkedOutput<Y> build() {
+ return new ChunkedOutput<>(this);
+ }
+ }
+
+ /**
+ * Builder that allows to create a new ChunkedOutput based on the given configuration options.
+ *
+ * @param <Y>
+ */
+ public static class TypedBuilder<Y> extends Builder<Y> {
+ private Type chunkType;
+
+ private TypedBuilder(Type chunkType) {
+ this.chunkType = chunkType;
+ }
+
+ /**
+ * Build the ChunkedOutput based on the given configuration.
+ * @return the ChunkedOutput
+ */
+ public ChunkedOutput<Y> build() {
+ return new ChunkedOutput<>(this);
+ }
+ }
}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerExecutorProvidersConfigurator.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerExecutorProvidersConfigurator.java
index 9466038..79d269b 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ServerExecutorProvidersConfigurator.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerExecutorProvidersConfigurator.java
@@ -27,6 +27,7 @@
import org.glassfish.jersey.spi.ScheduledThreadPoolExecutorProvider;
import org.glassfish.jersey.spi.ThreadPoolExecutorProvider;
+import jakarta.ws.rs.core.Configuration;
import jakarta.ws.rs.RuntimeType;
/**
@@ -44,7 +45,7 @@
ComponentBag componentBag = runtimeConfig.getComponentBag();
// TODO: Do we need to register DEFAULT Executor and ScheduledExecutor to InjectionManager?
- ScheduledExecutorServiceProvider defaultScheduledExecutorProvider = new DefaultBackgroundSchedulerProvider();
+ ScheduledExecutorServiceProvider defaultScheduledExecutorProvider = new DefaultBackgroundSchedulerProvider(runtimeConfig);
Binding<ScheduledExecutorServiceProvider, ?> schedulerBinding = Bindings
.service(defaultScheduledExecutorProvider)
.to(ScheduledExecutorServiceProvider.class)
@@ -68,8 +69,8 @@
@BackgroundScheduler
private static class DefaultBackgroundSchedulerProvider extends ScheduledThreadPoolExecutorProvider {
- public DefaultBackgroundSchedulerProvider() {
- super("jersey-background-task-scheduler");
+ public DefaultBackgroundSchedulerProvider(Configuration configuration) {
+ super("jersey-background-task-scheduler", configuration);
}
@Override
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java
index d6eb5a6..531e927 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java
@@ -131,6 +131,14 @@
private final boolean rfc7231LocationHeaderRelativeUriResolution;
/**
+ * Cached value of configuration property
+ * {@link org.glassfish.jersey.server.ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR}.
+ * If {@code true} method {@link ServerRuntime.CompletionCallbackRunner#onComplete(Throwable)}
+ * is used over {@link DefaultExceptionMapper#toResponse(Throwable)}.
+ */
+ private final boolean configSetStatusOverSendError;
+
+ /**
* Default exception mapper (@since 3.1.0 according to JAX-RS 3.1 spec)
*/
private static final ExceptionMapper<Throwable> DEFAULT_EXCEPTION_MAPPER = new DefaultExceptionMapper();
@@ -197,6 +205,9 @@
this.rfc7231LocationHeaderRelativeUriResolution = ServerProperties.getValue(configuration.getProperties(),
ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231,
Boolean.FALSE, Boolean.class);
+
+ this.configSetStatusOverSendError = ServerProperties.getValue(configuration.getProperties(),
+ ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, false, Boolean.class);
}
/**
@@ -452,15 +463,17 @@
if (!processResponseError(responseError)) {
// Pass the exception to the container.
- LOGGER.log(Level.WARNING, LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER(), responseError);
-
try {
request.getResponseWriter().failure(responseError);
} finally {
- defaultMapperResponse = processResponseWithDefaultExceptionMapper(responseError, request);
-
- // completionCallbackRunner.onComplete(responseError); is called from
- // processResponseWithDefaultExceptionMapper
+ if (runtime.configSetStatusOverSendError) {
+ completionCallbackRunner.onComplete(responseError);
+ } else {
+ LOGGER.log(Level.WARNING,
+ LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER(),
+ responseError);
+ defaultMapperResponse = processResponseWithDefaultExceptionMapper(responseError, request);
+ }
}
}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/UriRoutingContext.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/UriRoutingContext.java
index f7a9875..94bbaa1 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/UriRoutingContext.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/UriRoutingContext.java
@@ -36,6 +36,9 @@
import jakarta.ws.rs.core.UriBuilder;
import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
+import org.glassfish.jersey.internal.util.collection.LazyValue;
+import org.glassfish.jersey.internal.util.collection.Value;
+import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.message.internal.TracingLogger;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
@@ -69,7 +72,7 @@
private final LinkedList<ResourceMethod> matchedLocators = new LinkedList<>();
private final LinkedList<Resource> locatorSubResources = new LinkedList<>();
- private final TracingLogger tracingLogger;
+ private final LazyValue<TracingLogger> tracingLogger;
private volatile ResourceMethod matchedResourceMethod = null;
private volatile Throwable mappedThrowable = null;
@@ -89,7 +92,8 @@
*/
public UriRoutingContext(final ContainerRequest requestContext) {
this.requestContext = requestContext;
- this.tracingLogger = TracingLogger.getInstance(requestContext);
+ // Tracing Logger is initialized after UriContext before pushMatchedResource
+ this.tracingLogger = Values.lazy((Value<TracingLogger>) () -> TracingLogger.getInstance(requestContext));
}
// RoutingContext
@@ -100,7 +104,7 @@
@Override
public void pushMatchedResource(final Object resource) {
- tracingLogger.log(ServerTraceEvent.MATCH_RESOURCE, resource);
+ tracingLogger.get().log(ServerTraceEvent.MATCH_RESOURCE, resource);
matchedResources.push(resource);
}
@@ -111,7 +115,7 @@
@Override
public void pushMatchedLocator(final ResourceMethod resourceLocator) {
- tracingLogger.log(ServerTraceEvent.MATCH_LOCATOR, resourceLocator.getInvocable().getHandlingMethod());
+ tracingLogger.get().log(ServerTraceEvent.MATCH_LOCATOR, resourceLocator.getInvocable().getHandlingMethod());
matchedLocators.push(resourceLocator);
}
@@ -192,14 +196,14 @@
@Override
public void setMatchedResourceMethod(final ResourceMethod resourceMethod) {
- tracingLogger.log(ServerTraceEvent.MATCH_RESOURCE_METHOD, resourceMethod.getInvocable().getHandlingMethod());
+ tracingLogger.get().log(ServerTraceEvent.MATCH_RESOURCE_METHOD, resourceMethod.getInvocable().getHandlingMethod());
this.matchedResourceMethod = resourceMethod;
}
@Override
public void pushMatchedRuntimeResource(final RuntimeResource runtimeResource) {
- if (tracingLogger.isLogEnabled(ServerTraceEvent.MATCH_RUNTIME_RESOURCE)) {
- tracingLogger.log(ServerTraceEvent.MATCH_RUNTIME_RESOURCE,
+ if (tracingLogger.get().isLogEnabled(ServerTraceEvent.MATCH_RUNTIME_RESOURCE)) {
+ tracingLogger.get().log(ServerTraceEvent.MATCH_RUNTIME_RESOURCE,
runtimeResource.getResources().get(0).getPath(),
runtimeResource.getResources().get(0).getPathPattern().getRegex(),
matchResults.peek().group()
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java
index f08cfb1..501372a 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,7 +22,7 @@
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@@ -155,7 +155,7 @@
return new URL(jarUrlString).openStream();
} catch (final MalformedURLException e) {
return Files.newInputStream(
- Paths.get(UriComponent.decode(jarUrlString, UriComponent.Type.PATH)));
+ Path.of(UriComponent.decode(jarUrlString, UriComponent.Type.PATH)));
}
}
}
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/JarUtils.java b/core-server/src/test/java/org/glassfish/jersey/server/JarUtils.java
index 50a5402..003a735 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/JarUtils.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/JarUtils.java
@@ -90,11 +90,7 @@
final InputStream f = new BufferedInputStream(
Files.newInputStream(new File(base, entry.getKey()).toPath()));
- final byte[] buf = new byte[1024];
- int read = 1024;
- while ((read = f.read(buf, 0, read)) != -1) {
- jos.write(buf, 0, read);
- }
+ f.transferTo(jos);
jos.closeEntry();
}
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/scanning/JarFileScannerTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/scanning/JarFileScannerTest.java
index 6c07e9f..d76efcd 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/internal/scanning/JarFileScannerTest.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/scanning/JarFileScannerTest.java
@@ -19,7 +19,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -114,7 +114,7 @@
private int countJarEntriesUsingScanner(final String parent, final boolean recursive) throws IOException {
int scannedEntryCount = 0;
- try (final InputStream jaxRsApi = Files.newInputStream(Paths.get(this.jaxRsApiPath))) {
+ try (final InputStream jaxRsApi = Files.newInputStream(Path.of(this.jaxRsApiPath))) {
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, parent, recursive);
while (jarFileScanner.hasNext()) {
// Fetch next entry.
@@ -136,7 +136,7 @@
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testClassEnumerationWithNonexistentPackage(final boolean recursive) throws IOException {
- try (final InputStream jaxRsApi = Files.newInputStream(Paths.get(this.jaxRsApiPath))) {
+ try (final InputStream jaxRsApi = Files.newInputStream(Path.of(this.jaxRsApiPath))) {
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, "jakarta/ws/r", recursive);
assertFalse(jarFileScanner.hasNext(), "Unexpectedly found package 'jakarta.ws.r' in jakarta.ws.rs-api");
}
@@ -145,7 +145,7 @@
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testClassEnumerationWithClassPrefix(final boolean recursive) throws IOException {
- try (final InputStream jaxRsApi = Files.newInputStream(Paths.get(this.jaxRsApiPath))) {
+ try (final InputStream jaxRsApi = Files.newInputStream(Path.of(this.jaxRsApiPath))) {
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, "jakarta/ws/rs/GE", recursive);
assertFalse(jarFileScanner.hasNext(), "Unexpectedly found package 'jakarta.ws.rs.GE' in jakarta.ws.rs-api");
}
diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index ee2effc..7b1bbaa 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -203,6 +203,39 @@
</entry>
</row>
<row>
+ <entry>&jersey.common.CommonProperties.THREAD_FACTORY;(Jersey 3.1.7 or later)
+ </entry>
+ <entry>
+ <literal>jersey.config.threads.factory</literal>
+ </entry>
+ <entry>
+ <para>
+ Defines the <literal>java.util.concurrent.ThreadFactory</literal> to be used by internal default
+ <literal>ExecutorServices</literal>.
+ </para>
+ <para>
+ The default is <literal>java.util.concurrent.Executors#defaultThreadFactory()</literal> on
+ platform threads and<literal>Thread.ofVirtual().factory()</literal> on virtual threads.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.common.CommonProperties.USE_VIRTUAL_THREADS;(Jersey 3.1.7 or later)
+ </entry>
+ <entry>
+ <literal>jersey.config.threads.use.virtual</literal>
+ </entry>
+ <entry>
+ <para>
+ Defines whether the virtual threads should be used by Jersey on JDK 21+ when not using an exact number
+ of threads by <literal>FixedThreadPool</literal>.
+ </para>
+ <para>
+ The default is &lit.false; for this version of Jersey.
+ </para>
+ </entry>
+ </row>
+ <row>
<entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME;
</entry>
<entry>
@@ -1169,7 +1202,22 @@
</para>
</entry>
</row>
-
+ <row>
+ <entry>&jersey.client.ClientProperties.SNI_HOST_NAME; (Jersey 2.43 or later)</entry>
+ <entry><literal>jersey.config.client.sniHostName</literal></entry>
+ <entry>
+ <para>
+ Sets the host name to be used for calculating the <literal>javax.net.ssl.SNIHostName</literal>
+ during the HTTPS request. Takes precedence over the HTTP HOST header, if set.
+ </para>
+ <para>
+ By default, the <literal>SNIHostName</literal> is set when the HOST HTTP header differs from
+ the HTTP request host. When the property value host name matches the HTTPS request host,
+ the <literal>SNIHostName</literal> is not set, and the HTTP HOST header is not used for
+ setting the <literal>SNIHostName</literal>. This allows for Domain Fronting.
+ </para>
+ </entry>
+ </row>
<row>
<entry>&jersey.client.ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION;
(Jersey 2.2 or later)</entry>
@@ -1351,7 +1399,7 @@
<entry>
<para>
If set to &lit.true; then XML root element tag name for collections will
- be derived from <literal>javax.xml.bind.annotation.XmlRootElement</literal>
+ be derived from <literal>jakarta.xml.bind.annotation.XmlRootElement</literal>
annotation value and won't be de-capitalized.
</para>
<para>
@@ -1983,6 +2031,39 @@
</para>
</entry>
</row>
+ <row>
+ <entry>&jersey.netty.NettyClientProperties.MAX_HEADER_SIZE;</entry>
+ <entry><literal>jersey.config.client.netty.maxHeaderSize</literal></entry>
+ <entry>
+ <para>
+ Parameter which allows extending of the header size for the Netty connector
+
+ Default header size is 8192b.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.netty.NettyClientProperties.MAX_CHUNK_SIZE;</entry>
+ <entry><literal>jersey.config.client.netty.maxChunkSize</literal></entry>
+ <entry>
+ <para>
+ Parameter which allows extending of the chunk size for the Netty connector
+
+ Default chunk size is 8192b.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.netty.NettyClientProperties.MAX_INITIAL_LINE_LENGTH;</entry>
+ <entry><literal>jersey.config.client.netty.maxInitialLineLength</literal></entry>
+ <entry>
+ <para>
+ Parameter which allows extending of the initial line length for the Netty connector
+
+ Default initial line length is 4096b.
+ </para>
+ </entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -2091,4 +2172,80 @@
</tgroup>
</table>
</section>
+ <section xml:id="appendix-properties-multipart">
+ <title>Multipart configuration properties</title>
+
+ <para>
+ List of multipart configuration properties that can be found in &jersey.media.multipart.MultiPartProperties; class.
+ </para>
+
+ <table>
+ <title>
+ List of multipart configuration properties settable in the
+ &jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE; configuration file.
+ </title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Constant</entry>
+ <entry>Value</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.BUFFER_THRESHOLD;</entry>
+ <entry><literal>jersey.config.multipart.bufferThreshold</literal></entry>
+ <entry>
+ <para>
+ Name of the resource property for the threshold size (in bytes) above which a
+ body part entity will be buffered to disk instead of being held in memory.
+ </para>
+ <para>
+ The default value is &jersey.message.MessageProperties.IO_DEFAULT_BUFFER_SIZE;
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.MAX_PARTS;</entry>
+ <entry><literal>jersey.config.multipart.maxParts</literal></entry>
+ <entry>
+ <para>
+ Limit the maximum number of parts the multipart entity can have. If the limit is over,
+ the error response status <literal>413 - REQUEST_ENTITY_TOO_LARGE</literal>
+ is returned.
+ </para>
+ <para>
+ By default, the number is unlimited.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE;</entry>
+ <entry><literal>jersey-multipart-config.properties</literal></entry>
+ <entry>
+ <para>
+ Name of a properties resource that (if found in the classpath
+ for this application) will be used to configure the settings returned
+ by our getter methods.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.TEMP_DIRECTORY;</entry>
+ <entry><literal>jersey.config.multipart.tempDir</literal></entry>
+ <entry>
+ <para>
+ Name of the resource property for the directory to store temporary files containing body parts
+ of multipart message that extends allowed memory threshold.
+ </para>
+ <para>
+ The default value is not set (will be taken from <literal>java.io.tmpdir</literal> system property).
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
</appendix>
\ No newline at end of file
diff --git a/docs/src/main/docbook/async.xml b/docs/src/main/docbook/async.xml
index f496bab..f39b76b 100644
--- a/docs/src/main/docbook/async.xml
+++ b/docs/src/main/docbook/async.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -270,6 +270,9 @@
public ChunkedOutput<String> getChunkedResponse() {
final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class);
+ // Or use the builder pattern instead, which also allows to configure the queue capacity
+ // final ChunkedOutput<String> output = ChunkedOutput.<String>builder(String.class).queueCapacity(10).build();
+
new Thread() {
public void run() {
try {
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml
index 32bd1ce..390b9a3 100644
--- a/docs/src/main/docbook/client.xml
+++ b/docs/src/main/docbook/client.xml
@@ -673,71 +673,6 @@
</tbody>
</tgroup>
</table>
-
- <warning xml:id="connectors.warning" xreflabel="Header modification issue">
- <para>
- Be aware of using other than default &lit.jersey.client.Connector; implementation.
- There is an issue handling HTTP headers in
- &lit.jaxrs.WriterInterceptor; or &lit.jaxrs.ext.MessageBodyWriter;.
- If you need to change header fields do not use nor
- &lit.jersey.apache.ApacheConnectorProvider; nor &lit.jersey.grizzly.GrizzlyConnectorProvider;
- nor &lit.jersey.jetty.JettyConnectorProvider; neither &lit.jersey.netty.NettyConnectorProvider;.
- The issue for example applies to Jersey <xref linkend="multipart" endterm="multipart.short"/>
- feature that also modifies HTTP headers.
- </para>
- <para>
- On the other hand, in the default transport connector, there are some restrictions on the headers, that
- can be sent in the default configuration.
- <literal>HttpUrlConnectorProvider</literal> uses &lit.jdk6.HttpUrlConnection; as an underlying connection
- implementation. This JDK class by default restricts the use of following headers:
- <itemizedlist>
- <listitem>&lit.http.header.AccessControlRequestHeaders;</listitem>
- <listitem>&lit.http.header.AccessControlRequestMethod;</listitem>
- <listitem>&lit.http.header.Connection; (with one exception - &lit.http.header.Connection; header with
- value <literal>Closed</literal> is allowed by default)</listitem>
- <listitem>&lit.http.header.ContentLength;</listitem>
- <listitem>&lit.http.header.ContentTransferEncoding;</listitem>
- <listitem>&lit.http.header.Host;</listitem>
- <listitem>&lit.http.header.Keep-Alive;</listitem>
- <listitem>&lit.http.header.Origin;</listitem>
- <listitem>&lit.http.header.Trailer;</listitem>
- <listitem>&lit.http.header.Transfer-Encoding;</listitem>
- <listitem>&lit.http.header.Upgrade;</listitem>
- <listitem>&lit.http.header.Via;</listitem>
- <listitem>all the headers starting with &lit.http.header.Sec.prefix;</listitem>
- </itemizedlist>
- The underlying connection can be configured to permit all headers to be sent,
- however this behaviour can be changed only by setting the system property
- <literal>sun.net.http.allowRestrictedHeaders</literal>.
- <example>
- <title>Sending restricted headers with <literal>HttpUrlConnector</literal></title>
- <programlisting language="java" linenumbering="numbered">
- Client client = ClientBuilder.newClient();
- System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
-
- Response response = client.target(yourUri).path(yourPath).request().
- header("Origin", "http://example.com").
- header("Access-Control-Request-Method", "POST").
- get();
- </programlisting>
- </example>
- </para>
- <para>
- Note, that internally the &lit.jdk6.HttpUrlConnection; instances are pooled, so (un)setting the
- property after already creating a target typically does not have any effect.
- The property influences all the connections <emphasis>created</emphasis> after the property has been
- (un)set, but there is no guarantee, that your request will use a connection
- created after the property change.
- </para>
- <para>
- In a simple environment, setting the property before creating the first target is sufficient, but in complex
- environments (such as application servers), where some poolable connections might exist before your
- application even bootstraps, this approach is not 100% reliable and we recommend using a different client
- transport connector, such as Apache Connector.
- These limitations have to be considered especially when invoking <emphasis>CORS</emphasis> (Cross Origin
- Resource Sharing) requests.
- </para>
- </warning>
</para>
<para>
As indicated earlier, &jersey.client.Connector; and &jersey.client.ConnectorProvider; contracts are Jersey-specific
@@ -746,8 +681,8 @@
instance:
<programlisting language="java" linenumbering="numbered">ClientConfig clientConfig = new ClientConfig();
-clientConfig.connectorProvider(new GrizzlyConnectorProvider());
-Client client = ClientBuilder.newClient(clientConfig);</programlisting>
+ clientConfig.connectorProvider(new GrizzlyConnectorProvider());
+ Client client = ClientBuilder.newClient(clientConfig);</programlisting>
&lit.jaxrs.client.Client; accepts as a constructor argument a &lit.jaxrs.core.Configurable; instance. Jersey
implementation of the &lit.jaxrs.core.Configurable; provider for the client is &lit.jersey.client.ClientConfig;.
@@ -766,11 +701,96 @@
Jersey 2.40. The following example shows how to setup the custom Grizzly Asynchronous HTTP Client based
&lit.jersey.client.ConnectorProvider; in a Jersey client instance:
<programlisting language="java" linenumbering="numbered">Client client = ClientBuilder.newBuilder()
- .property(ClientProperties.CONNECTOR_PROVIDER, "org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider")
- .build();</programlisting>
+ .property(ClientProperties.CONNECTOR_PROVIDER, "org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider")
+ .build();</programlisting>
For more information about the property see <xref linkend="appendix-properties"/>.
</para>
+ <para>
+ <warning xml:id="connectors.warning" xreflabel="Header modification issue">
+ <para>
+ Be aware of using other than default &lit.jersey.client.Connector; implementation.
+ There is an issue handling HTTP headers in
+ &lit.jaxrs.WriterInterceptor; or &lit.jaxrs.ext.MessageBodyWriter;.
+ If you need to change header fields do not use neither
+ &lit.jersey.apache.ApacheConnectorProvider; nor &lit.jersey.grizzly.GrizzlyConnectorProvider;
+ nor &lit.jersey.jetty.JettyConnectorProvider; (for asynchronous requests).
+ Other older version connectors can be affected by this issue as well.
+ The issue for example applies to Jersey <xref linkend="multipart" endterm="multipart.short"/>
+ feature that also modifies HTTP headers.
+ </para>
+ </warning>
+ </para>
+ <section>
+ <title>The default &lit.jersey.client.HttpUrlConnector;</title>
+
+ <para>The default connector is the most advanced connector, and it supports the most features Jersey has to offer.
+ However, there are a few limitations coming from the &lit.jdk6.HttpUrlConnection;</para>.
+ <para>
+ One limitation is in the variety of HTTP methods supported by the &lit.jdk6.HttpUrlConnection;, since only the
+ original HTTP/1.1 methods are supported. For instance, HTTP Patch method is not supported. See
+ property &jersey.client.HttpUrlConnectorProvider.SET_METHOD_WORKAROUND; in the Appendix
+ <xref linkend="appendix-properties-client-default"/> for a possible workaround.
+ </para>
+ <para>
+ Also, in the default transport connector, there are some restrictions on the headers, that
+ can be sent in the default configuration.
+ <literal>HttpUrlConnectorProvider</literal> uses &lit.jdk6.HttpUrlConnection; as an underlying connection
+ implementation. This JDK class by default restricts the use of following headers:
+ <itemizedlist>
+ <listitem>&lit.http.header.AccessControlRequestHeaders;</listitem>
+ <listitem>&lit.http.header.AccessControlRequestMethod;</listitem>
+ <listitem>&lit.http.header.Connection; (with one exception - &lit.http.header.Connection; header with
+ value <literal>Closed</literal> is allowed by default)</listitem>
+ <listitem>&lit.http.header.ContentLength;</listitem>
+ <listitem>&lit.http.header.ContentTransferEncoding;</listitem>
+ <listitem>&lit.http.header.Host;</listitem>
+ <listitem>&lit.http.header.Keep-Alive;</listitem>
+ <listitem>&lit.http.header.Origin;</listitem>
+ <listitem>&lit.http.header.Trailer;</listitem>
+ <listitem>&lit.http.header.Transfer-Encoding;</listitem>
+ <listitem>&lit.http.header.Upgrade;</listitem>
+ <listitem>&lit.http.header.Via;</listitem>
+ <listitem>all the headers starting with &lit.http.header.Sec.prefix;</listitem>
+ </itemizedlist>
+ The underlying connection can be configured to permit all headers to be sent,
+ however this behaviour can be changed only by setting the system property
+ <literal>sun.net.http.allowRestrictedHeaders</literal>.
+ <example>
+ <title>Sending restricted headers with <literal>HttpUrlConnector</literal></title>
+ <programlisting language="java" linenumbering="numbered">
+ Client client = ClientBuilder.newClient();
+ System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
+
+ Response response = client.target(yourUri).path(yourPath).request().
+ header("Origin", "http://example.com").
+ header("Access-Control-Request-Method", "POST").
+ get();
+ </programlisting>
+ </example>
+ <warning>
+ <para>
+ Internally, the &lit.jdk6.HttpUrlConnection; instances are pooled, so (un)setting the
+ property after already creating a target typically does not have any effect.
+ The property influences all the connections <emphasis>created</emphasis> after the property has been
+ (un)set, but there is no guarantee, that your request will use a connection
+ created after the property change.
+ </para>
+ <para>
+ In a simple environment, setting the property before creating the first target is sufficient, but in complex
+ environments (such as application servers), where some poolable connections might exist before your
+ application even bootstraps, this approach is not 100% reliable and we recommend using a different client
+ transport connector, such as Apache Connector.
+ These limitations have to be considered especially when invoking <emphasis>CORS</emphasis> (Cross Origin
+ Resource Sharing) requests.
+ </para>
+ </warning>
+ </para>
+ <para>
+ The limited configurability of the &lit.jdk6.HttpUrlConnection; is another aspect to consider. For details, see
+ <literal>Java Networking Properties</literal>, for instance property <literal>http.maxConnections</literal>.
+ </para>
+ </section>
<section>
<title>Client Connectors Properties</title>
<para>
@@ -903,7 +923,7 @@
<para>
To solve injection of a custom type into a client provider instance
use &jersey.client.InjectionManagerClientProvider; to
- extract &hk2.ServiceLocator; which can return the required injection. The following example shows how to utilize
+ extract &lit.jersey.common.internal.inject.InjectionManager; which can return the required injection. The following example shows how to utilize
&lit.jersey.client.InjectionManagerClientProvider;:
</para>
<example>
@@ -928,7 +948,7 @@
</example>
<para>
For more information see javadoc of &jersey.client.InjectionManagerClientProvider;
- (and javadoc of &lit.jersey.common.InjectionManagerProvider; which supports common JAX-RS components).
+ (and javadoc of &lit.jersey.common.InjectionManagerProvider; which supports common Jakarta REST components).
</para>
</section>
@@ -1089,6 +1109,19 @@
Note that only <literal>Apache Connector, JDK Connector, Netty connector</literal>, and the default
<literal>HttpUrlConnector</literal> do support this feature.
</para>
+ <para>
+ Sometimes, it may be required the <literal>SNIHostName</literal> is not set, or it differs from the
+ HTTP <literal>Host</literal> header. In that case, the &jersey.client.ClientProperties.SNI_HOST_NAME;
+ property can be utilized. The property sets the host name to be used for calculating the
+ <literal>javax.net.ssl.SNIHostName</literal>. The property takes precedence over the HTTP
+ <literal>Host</literal> header.
+ </para>
+ <para>
+ When the host name in the the &jersey.client.ClientProperties.SNI_HOST_NAME; property matches the HTTP request
+ host, the <literal>SNIHostName</literal> is not set, and the HTTP <literal>Host</literal> header is not used
+ for setting the <literal>SNIHostName</literal>.
+ Turning the SNI off allows for Domain Fronting.
+ </para>
</section>
</section>
diff --git a/docs/src/main/docbook/custom-di.xml b/docs/src/main/docbook/custom-di.xml
index 6e83b52..407cc2e 100644
--- a/docs/src/main/docbook/custom-di.xml
+++ b/docs/src/main/docbook/custom-di.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -60,6 +60,35 @@
</para>
<para>
+ Since Jersey 2.26, the injection has been abstracted, so that &hk2.link; can be eventually replaced by the CDI or
+ any other injection framework. In the next chapters, we document possibilities provided directly by &hk2.link; and
+ by Jersey abstraction components.
+ </para>
+
+ <section xml:id="injection.manager">
+ <title>InjectionManager</title>
+
+ <para>
+ Since Jersey 2.26, Jersey comes with the main abstraction interface to communicate with the DI container, the
+ &jersey.common.internal.inject.InjectionManager;. What is <literal>ServiceLocator</literal> for &hk2.link;, or
+ <literal>BeanManager</literal> for CDI, that's &jersey.common.internal.inject.InjectionManager; for Jersey.
+ </para>
+ <para>
+ &jersey.common.internal.inject.InjectionManager; can be injected into the user provided classes instantiated
+ by Jersey. It can also be obtained programmatically by &jersey.client.InjectionManagerClientProvider;
+ and &lit.jersey.common.InjectionManagerProvider; from Jakarta REST components, such as
+ &jaxrs.core.FeatureContext;, or &jaxrs.ext.MessageBodyReader; and &jaxrs.ext.MessageBodyReader;.
+ </para>
+ <para>
+ Customers used to the &hk2.ServiceLocator; can still use it directly; the &hk2.ServiceLocator; can be obtained
+ either directly by injection, or programmatically as <literal>InjectionManager.getInstance(ServiceLocator.class)</literal>.
+ </para>
+ </section>
+
+ <section>
+ <title>Implementing Custom Injection Provider</title>
+
+ <para>
Relying on Servlet HTTP session concept is not very RESTful. It turns the originally state-less HTTP
communication schema into a state-full manner. However, it could serve
as a good example that will help me demonstrate implementation of the use cases described above.
@@ -68,10 +97,7 @@
Below we will show how to make actual Servlet &jee9.servlet.HttpSession; injectable into JAX-RS components
and how to make this injection work with a custom inject annotation type. Finally, we will demonstrate
how you can write &lit.jee9.servlet.HttpSession;-scoped JAX-RS resources.
- </para>
-
- <section>
- <title>Implementing Custom Injection Provider</title>
+ </para>
<para>
Jersey implementation allows you to directly inject &jee9.servlet.HttpServletRequest; instance into
@@ -89,7 +115,11 @@
...
}</programlisting>
+ </para>
+ <section>
+ <title>Using HK2 classes</title>
+ <para>
To make the above injection work, you will need to define an additional HK2 binding in your
application &jersey.server.ResourceConfig;.
Let's start with a custom HK2 &hk2.Factory; implementation that knows how to extract
@@ -145,48 +175,122 @@
@Override
protected void configure() {
bindFactory(HttpSessionFactory.class).to(HttpSession.class)
- .proxy(true).proxyForSameScope(false).in(RequestScoped.class);
+ .proxy(true).proxyForSameScope(false).in(RequestScoped.class);
}
});
}
}</programlisting>
- Note that we did not define any explicit injection scope for the new injection binding.
- By default, HK2 factories are bound in a HK2 &hk2.PerLookup; scope, which is in most
- cases a good choice and it is suitable also in our example.
- </para>
+ Note that if we did not define any explicit injection scope for the new injection binding,
+ By default, HK2 factories are bound in a HK2 &hk2.PerLookup; scope, which is in most
+ cases a good choice, and it is suitable also in our example.
+ </para>
- <para>
- To summarize the approach described above, here is a list of steps to follow
- when implementing custom injection provider in your Jersey application :
+ <para>
+ To summarize the approach described above, here is a list of steps to follow
+ when implementing custom injection provider in your Jersey application :
- <itemizedlist>
- <listitem><simpara>Implement your own HK2 &lit.hk2.Factory; to provide the
- injectable instances.</simpara></listitem>
- <listitem><simpara>Use the HK2 &lit.hk2.Factory; to define an injection
- binding for the injected instance via custom HK2 &lit.hk2.Binder;.</simpara></listitem>
- <listitem><simpara>Register the custom HK2 &lit.hk2.Binder; in your application
- &lit.jersey.server.ResourceConfig;.</simpara></listitem>
- </itemizedlist>
- </para>
+ <itemizedlist>
+ <listitem><simpara>Implement your own HK2 &lit.hk2.Factory; to provide the
+ injectable instances.</simpara></listitem>
+ <listitem><simpara>Use the HK2 &lit.hk2.Factory; to define an injection
+ binding for the injected instance via custom HK2 &lit.hk2.Binder;.</simpara></listitem>
+ <listitem><simpara>Register the custom HK2 &lit.hk2.Binder; in your application
+ &lit.jersey.server.ResourceConfig;.</simpara></listitem>
+ </itemizedlist>
+ </para>
- <para>
- While the &lit.hk2.Factory;-based approach is quite straight-forward and should help you to
- quickly prototype or even implement final solutions, you should bear in mind, that your
- implementation does not need to be based on factories. You can for instance bind your own
- types directly, while still taking advantage of HK2 provided dependency injection.
- Also, in your implementation you may want to pay more attention to defining or managing
- injection binding scopes for the sake of performance or correctness of your custom injection
- extension.
+ <para>
+ While the &lit.hk2.Factory;-based approach is quite straight-forward and should help you to
+ quickly prototype or even implement final solutions, you should bear in mind, that your
+ implementation does not need to be based on factories. You can for instance bind your own
+ types directly, while still taking advantage of HK2 provided dependency injection.
+ Also, in your implementation you may want to pay more attention to defining or managing
+ injection binding scopes for the sake of performance or correctness of your custom injection
+ extension.
- <important>
- <para>
- While the individual injection binding implementations vary and depend on your use case,
- to enable your custom injection extension in Jersey, you must register your custom HK2 &hk2.Binder;
- implementation in your application &jersey.server.ResourceConfig;!
- </para>
- </important>
- </para>
+ <important>
+ <para>
+ While the individual injection binding implementations vary and depend on your use case,
+ to enable your custom injection extension in Jersey, you must register your custom HK2 &hk2.Binder;
+ implementation in your application &jersey.server.ResourceConfig;!
+ </para>
+ </important>
+ </para>
+ </section>
+ <section>
+ <title>Injection Provider Using Jersey API</title>
+ <para>
+ To make the <literal>HttpSession</literal> injection work without using HK2 API,
+ we will need to create a custom supplier that knows how to extract
+ &lit.jee9.servlet.HttpSession; out of given &lit.jee9.servlet.HttpServletRequest;.
+
+ <programlisting language="java">import java.util.function.Supplier
+ ...
+
+public class HttpSessionSupplier implements Supplier<HttpSession> {
+
+ private final HttpServletRequest request;
+
+ @Inject
+ public HttpSessionSupplier(HttpServletRequest request) {
+ this.request = request;
+ }
+
+ @Override
+ public HttpSession get() {
+ return request.getSession();
+ }
+
+}</programlisting>
+
+ Once implemented, the supplier can be used in a custom Jersey &jersey.common.internal.inject.AbstractBinder;
+ to define the new injection binding for &lit.jee9.servlet.HttpSession;. Finally, the implemented binder
+ can be registered in your &jersey.server.ResourceConfig;:
+
+ <programlisting language="java">import org.glassfish.jersey.internal.inject.AbstractBinder;
+ ...
+public class MyApplication extends ResourceConfig {
+
+ public MyApplication() {
+
+ ...
+
+ register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bindFactory(HttpSessionSupplier.class).to(HttpSession.class)
+ .proxy(true).proxyForSameScope(false).in(RequestScoped.class);
+ }
+ });
+ }
+}</programlisting>
+ The default scope for Jersey binder is similarly as for the HK2, the
+ &jersey.common.internal.inject.PerLookup;.
+ </para>
+ <para>
+ To summarize the approach described above, here is a list of steps to follow
+ when implementing custom injection provider in your Jersey application :
+
+ <itemizedlist>
+ <listitem><simpara>Implement your own Supplier to provide the
+ injectable instances.</simpara></listitem>
+ <listitem><simpara>Use the Supplier to define an injection
+ binding for the injected instance via custom &jersey.common.internal.inject.AbstractBinder;.
+ </simpara></listitem>
+ <listitem><simpara>Register the custom &jersey.common.internal.inject.AbstractBinder; in your application
+ &lit.jersey.server.ResourceConfig;.</simpara></listitem>
+ </itemizedlist>
+
+ <important>
+ <para>
+ Similarly to the HK2, to enable your custom injection extension in Jersey,
+ you must register your custom &jersey.common.internal.inject.AbstractBinder;
+ implementation in your application &jersey.server.ResourceConfig;!
+ </para>
+ </important>
+ </para>
+ </section>
</section>
<section>
@@ -231,6 +335,8 @@
use case will help us to avoid use case specific distractions and allow us better focus on
the important aspects of the job of defining a custom injection annotation.
</para>
+ <section>
+ <title>Custom Injection Annotation using HK2</title>
<para>
If you remember from the previous section, to make the injection in the code snippet above work,
@@ -317,6 +423,104 @@
}
}</programlisting>
</para>
+ </section>
+ <section>
+ <title>Custom Injection Annotation using Jersey InjectionResolver</title>
+
+ <para>
+ Jersey also comes with its &jersey.common.internal.inject.InjectionResolver; used to translate into
+ the HK2 &hk2.InjectionResolver; during runtime. The abstraction is important for allowing to support
+ the custom injection annotation in various DI containers. For instance, the abstraction is used when
+ supporting injection using &jaxrs.core.Context; in the CDI container (<literal>jersey-cdi2-se</literal> module).
+ </para>
+ <para>
+ The SessionInjectResolver then looks as follows:
+<programlisting language="java">import jakarta.inject.Inject;
+
+import jakarta.servlet.http.HttpSession;
+
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+
+...
+
+public class SessionInjectResolver implements InjectionResolver<SessionInject> {
+
+ private final InjectionManger injectionManager;
+
+ public SessionInjectResolver(InjectionManager) {
+ this.injectionManager = injectionManager;
+ }
+
+ @Override
+ public Object resolve(Injectee injectee) {
+ if (HttpSession.class == injectee.getRequiredType()) {
+ return injectionManager.getInstance(HttpServletRequest.class).getSession();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isConstructorParameterIndicator() {
+ return false;
+ }
+
+ @Override
+ public boolean isMethodParameterIndicator() {
+ return false;
+ }
+
+ @Override
+ public Class<SessionInject> getAnnotation() {
+ return SessionInject.class;
+ }
+}</programlisting>
+
+ The SessionInjectResolver uses &jersey.common.internal.inject.InjectionManager; described in
+ <xref linkend="injection.manager"/>.
+ </para>
+ <para>
+ Unlike with &hk2.link;, Jersey &jersey.common.internal.inject.InjectionResolver; can only be bound
+ as instance in the &jersey.common.internal.inject.AbstractBinder;. That is why the
+ &jersey.common.internal.inject.InjectionManager; is used in the <literal>InjectionResolver</literal>
+ to resolve the <literal>HttpSession</literal> instance.
+ </para>
+ <para>
+ The &jersey.common.internal.inject.InjectionResolver; can be registered in the with Jersey application
+ &lit.jersey.server.ResourceConfig; as follows:
+
+<programlisting language="java">import jakarta.ws.rs.core.Feature;
+
+import org.glassfish.jersey.InjectionManagerProvider;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+
+
+import jakarta.inject.Singleton;
+
+...
+
+public class MyApplication extends ResourceConfig {
+
+public MyApplication() {
+
+ ...
+
+ register(new Feature() {
+ @Override
+ public boolean configure(FeatureContext context) {
+ final InjectionManager injectionManager = InjectionManagerProvider.getInjectionManager(context);
+ context.register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(new SessionInjectResolver(injectionManager)).to(HttpSession.class).in(Singleton.class);
+ }
+ });
+ return true;
+ }
+ });
+}</programlisting>
+ </para>
+ </section>
</section>
<section>
diff --git a/docs/src/main/docbook/dependencies.xml b/docs/src/main/docbook/dependencies.xml
index 3dab231..5b81a58 100644
--- a/docs/src/main/docbook/dependencies.xml
+++ b/docs/src/main/docbook/dependencies.xml
@@ -33,25 +33,15 @@
<title>Java SE Compatibility</title>
<para>
- <emphasis>3.x branch: </emphasis>
+ <emphasis>4.0 branch: </emphasis>
<itemizedlist>
<listitem>
- <para>This user guide refers only to version 3 and above of Jersey, its compatibility is described below</para>
+ <para>This user guide refers only to version 4.0.x of Jersey, its compatibility is described below.</para>
</listitem>
<listitem>
- <para>Since version 3.0.0 all Jersey components are compiled with Java SE 1.8 target.
- It means, that you will need at least Java SE 1.8 to be able to compile and run your application
- which uses the latest Jersey 3.0.x.
- Some modules, however, are fully compatible with JDK 11 and above (Jetty modules based on Jetty 11).
- Some modules (Helidon Connector, Spring 6) require JDK 17.
- </para>
- </listitem>
- <listitem>
- <para>Since version 3.1.0 all Jersey components are compiled with Java SE 11 target.
+ <para>Since version 4.0.0 all Jersey components are compiled with Java SE 17 target.
It means, that you will need at least Java SE 11 to be able to compile and run your application
- which uses the latest Jersey 3.1.x.
- Some modules, however, are fully compatible with JDK 17 and above (Jetty modules based on Jetty 12
- [since 3.1.4], Helidon Connector, Spring 6).
+ which uses the latest Jersey 4.0.x.
</para>
</listitem>
<listitem>
@@ -60,7 +50,40 @@
</para>
</listitem>
</itemizedlist>
+ <table pgwide="1" frame='all' xml:id="jersey-jdk-compatibility">
+ <title>Jersey 4.0.x JDK compatibility</title>
+ <tgroup cols='3' align='center' colsep='1' rowsep='1'>
+ <colspec colname='c1'/>
+ <colspec colname='c2'/>
+ <colspec colname='c3'/>
+ <thead>
+ <row>
+ <entry>Jersey version</entry>
+ <entry>JDK min version</entry>
+ <entry>JDK max version</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row><entry>4.0.0</entry><entry>17</entry><entry>23</entry></row>
+ </tbody>
+ </tgroup>
+ </table>
</para>
+ <section>
+ <title>Virtual Threads and Thread Factories</title>
+ <para>
+ With JDK 21 and above, Jersey has the ability to use virtual threads instead of
+ the <literal>CachedThreadPool</literal> in the internal <literal>ExecutorServices</literal>.
+ Jersey also has the ability to specify the backing <literal>ThreadFactory</literal> for the
+ default <literal>ExecutorServices</literal> (the default <literal>ExecutorServices</literal>
+ can be overridden by the &jersey.common.spi.ExecutorServiceProvider; SPI).
+ </para>
+ <para>
+ To enable virtual threads and/or specify the <literal>ThreadFactory</literal>, use
+ &jersey.common.CommonProperties.USE_VIRTUAL_THREADS; and/or &jersey.common.CommonProperties.THREAD_FACTORY;
+ properties, respectively. See also the <xref linkend="appendix-properties-common"/> in appendix for property details.
+ </para>
+ </section>
</section>
<section>
<title>Introduction to Jersey dependencies</title>
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent
index be67534..1893612 100644
--- a/docs/src/main/docbook/jersey.ent
+++ b/docs/src/main/docbook/jersey.ent
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
<!--
- Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -54,7 +54,7 @@
<!ENTITY heroku.uri "https://www.heroku.com">
<!ENTITY heroku.link "<link xlink:href='&heroku.uri;'>Heroku</link>">
<!ENTITY hk2.javadoc.uri "https://javaee.github.io/hk2/apidocs/">
-<!ENTITY hk2.link "<link xlink:href='https://github.com/eclipse-ee4j/glassfish-hk2'>Glassfish-HK2</link>">
+<!ENTITY hk2.link "<link xlink:href='https://eclipse-ee4j.github.io/glassfish-hk2/'>Glassfish-HK2</link>">
<!ENTITY hk2.spring-bridge.link "<link xlink:href='https://javaee.github.io/hk2/spring-bridge/'>The Spring/HK2 Bridge</link>">
<!ENTITY jaxb.release.uri "https://eclipse-ee4j.github.io/jaxb-ri">
<!ENTITY jaxb.javadoc.uri "&jaxb.release.uri;/docs/api/jakarta.xml.bind">
@@ -62,7 +62,7 @@
<!ENTITY jaxrs.javadoc.uri "https://jakartaee.github.io/rest/apidocs/&jax-rs.version;/jakarta/ws/rs">
<!ENTITY jaxrs21.javadoc.uri "https://jakartaee.github.io/rest/apidocs/&jax-rs21.version;/javax/ws/rs">
<!ENTITY jaxrs31.spec.uri "https://jakarta.ee/specifications/restful-ws/&jax-rs31.spec.version;/jakarta-restful-ws-spec-&jax-rs31.spec.version;.html">
-<!ENTITY jsonb.javadoc.uri "https://javaee.github.io/javaee-spec/javadocs/javax/json/bind">
+<!ENTITY jsonb.javadoc.uri "https://jakarta.ee/specifications/jsonb/2.0/apidocs/jakarta/json/bind">
<!ENTITY jersey.documentation.uri "https://eclipse-ee4j.github.io/jersey.github.io">
<!ENTITY jersey.ext.bean-validation.deps.link "<link xlink:href='&jersey.project-info.uri.prefix;/jersey-bean-validation/dependencies.html'>jersey-bean-validation</link>" >
@@ -220,6 +220,7 @@
<!ENTITY jaxrs.core.EntityPart "<link xlink:href='&jaxrs.javadoc.uri;/core/EntityPart.html'>EntityPart</link>">
<!ENTITY jaxrs.core.EntityTag "<link xlink:href='&jaxrs.javadoc.uri;/core/EntityTag.html'>EntityTag</link>">
<!ENTITY jaxrs.core.Feature "<link xlink:href='&jaxrs.javadoc.uri;/core/Feature.html'>Feature</link>">
+<!ENTITY jaxrs.core.FeatureContext "<link xlink:href='&jaxrs.javadoc.uri;/core/FeatureContext.html'>FeatureContext</link>">
<!ENTITY jaxrs.core.Form "<link xlink:href='&jaxrs.javadoc.uri;/core/Form.html'>Form</link>">
<!ENTITY jaxrs.core.GenericEntity "<link xlink:href='&jaxrs.javadoc.uri;/core/GenericEntity.html'>GenericEntity<T></link>">
<!ENTITY jaxrs.core.GenericType "<link xlink:href='&jaxrs.javadoc.uri;/core/GenericType.html'>GenericType<T></link>">
@@ -359,6 +360,7 @@
<!ENTITY jersey.client.ClientProperties.PROXY_USERNAME "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#PROXY_USERNAME'>ClientProperties.PROXY_USERNAME</link>" >
<!ENTITY jersey.client.ClientProperties.READ_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#READ_TIMEOUT'>ClientProperties.READ_TIMEOUT</link>" >
<!ENTITY jersey.client.ClientProperties.REQUEST_ENTITY_PROCESSING "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#REQUEST_ENTITY_PROCESSING'>ClientProperties.REQUEST_ENTITY_PROCESSING</link>" >
+<!ENTITY jersey.client.ClientProperties.SNI_HOST_NAME "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#SNI_HOST_NAME'>ClientProperties.SNI_HOST_NAME</link>" >
<!ENTITY jersey.client.ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#SUPPRESS_HTTP_COMPLIANCE_VALIDATION'>ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION</link>" >
<!ENTITY jersey.client.ClientProperties.SSL_CONTEXT_SUPPLIER "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#SSL_CONTEXT_SUPPLIER'>ClientProperties.SSL_CONTEXT_SUPPLIER</link>" >
<!ENTITY jersey.client.ClientProperties.USE_ENCODING "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#USE_ENCODING'>ClientProperties.USE_ENCODING</link>" >
@@ -414,9 +416,13 @@
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER</link>" >
<!ENTITY jersey.common.CommonProperties.PARAM_CONVERTERS_THROW_IAE "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#PARAM_CONVERTERS_THROW_IAE'>CommonProperties.PARAM_CONVERTERS_THROW_IAE</link>" >
+<!ENTITY jersey.common.CommonProperties.THREAD_FACTORY "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#THREAD_FACTORY'>CommonProperties.THREAD_FACTORY</link>" >
+<!ENTITY jersey.common.CommonProperties.USE_VIRTUAL_THREADS "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#USE_VIRTUAL_THREADS'>CommonProperties.USE_VIRTUAL_THREADS</link>" >
<!ENTITY jersey.common.internal.inject.DisposableSupplier "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/DisposableSupplier.html'>DisposableSupplier</link>">
<!ENTITY jersey.common.internal.inject.InjectionManager "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/InjectionManager.html'>InjectionManager</link>">
+<!ENTITY jersey.common.internal.inject.InjectionResolver "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/InjectionResolver.html'>InjectionResolver</link>">
<!ENTITY jersey.common.internal.inject.AbstractBinder "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/AbstractBinder.html'>AbstractBinder</link>">
+<!ENTITY jersey.common.internal.inject.PerLookup "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/PerLookup.html'>PerLookup</link>">
<!ENTITY jersey.common.internal.inject.Binder "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/Binder.html'>Binder</link>">
<!ENTITY jersey.common.InjectionManagerProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/InjectionManagerProvider.html'>InjectionManagerProvider</link>">
<!ENTITY jersey.common.SslConfigurator "<link xlink:href='&jersey.javadoc.uri.prefix;/SslConfigurator.html'>SslConfigurator</link>">
@@ -553,7 +559,12 @@
<!ENTITY jersey.media.multipart.FormDataParam "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/FormDataParam.html'>@FormDataParam</link>" >
<!ENTITY jersey.media.multipart.MultiPart "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPart.html'>MultiPart</link>" >
<!ENTITY jersey.media.multipart.MultiPartFeature "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartFeature.html'>MultiPartFeature</link>" >
-<!ENTITY jersey.media.multipart.StreamDataBodyPart "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/file/StreamDataBodyPart.html'>StreamDataBodyPart</link>" >
+<!ENTITY jersey.media.multipart.MultiPartProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html'>MultiPartProperties</link>" >
+<!ENTITY jersey.media.multipart.MultiPartProperties.BUFFER_THRESHOLD "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#BUFFER_THRESHOLD'>MultiPartProperties.BUFFER_THRESHOLD</link>">
+<!ENTITY jersey.media.multipart.MultiPartProperties.MAX_PARTS "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#MAX_PARTS'>MultiPartProperties.MAX_PARTS</link>">
+<!ENTITY jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#MULTI_PART_CONFIG_RESOURCE'>MultiPartProperties.MULTI_PART_CONFIG_RESOURCE</link>">
+<!ENTITY jersey.media.multipart.MultiPartProperties.TEMP_DIRECTORY "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#TEMP_DIRECTORY'>MultiPartProperties.TEMP_DIRECTORY</link>">
+<!ENTITY jersey.media.multipart.StreamDataBodyPart "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/file/StreamDataBodyPart.html'>StreamDataBodyPart</link>">
<!ENTITY jersey.message.MessageBodyWorkers "<link xlink:href='&jersey.javadoc.uri.prefix;/message/MessageBodyWorkers.html'>MessageBodyWorkers</link>">
<!ENTITY jersey.message.MessageProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/message/MessageProperties.html'>MessageProperties</link>">
<!ENTITY jersey.message.MessageProperties.DEFLATE_WITHOUT_ZLIB "<link xlink:href='&jersey.javadoc.uri.prefix;/message/MessageProperties.html#DEFLATE_WITHOUT_ZLIB'>MessageProperties.DEFLATE_WITHOUT_ZLIB</link>">
@@ -583,6 +594,9 @@
<!ENTITY jersey.netty.NettyClientProperties.MAX_REDIRECTS "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_REDIRECTS'>NettyClientProperties.MAX_REDIRECTS</link>" >
<!ENTITY jersey.netty.NettyClientProperties.PRESERVE_METHOD_ON_REDIRECT "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#PRESERVE_METHOD_ON_REDIRECT'>NettyClientProperties.PRESERVE_METHOD_ON_REDIRECT</link>" >
<!ENTITY jersey.netty.NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#EXPECT_100_CONTINUE_TIMEOUT'>NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT</link>" >
+<!ENTITY jersey.netty.NettyClientProperties.MAX_HEADER_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_HEADER_SIZE'>NettyClientProperties.MAX_HEADER_SIZE</link>" >
+<!ENTITY jersey.netty.NettyClientProperties.MAX_INITIAL_LINE_LENGTH "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_INITIAL_LINE_LENGTH'>NettyClientProperties.MAX_INITIAL_LINE_LENGTH</link>" >
+<!ENTITY jersey.netty.NettyClientProperties.MAX_CHUNK_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_CHUNK_SIZE'>NettyClientProperties.MAX_CHUNK_SIZE</link>" >
<!ENTITY jersey.netty.NettyConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyConnectorProvider.html'>NettyConnectorProvider</link>">
<!ENTITY jersey.server.ApplicationHandler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ApplicationHandler.html'>ApplicationHandler</link>">
<!ENTITY jersey.server.BackgroundScheduler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/BackgroundScheduler.html'>@BackgroundScheduler</link>">
@@ -971,6 +985,7 @@
<!ENTITY lit.jersey.client.EncodingFeature "<literal>EncodingFeature</literal>">
<!ENTITY lit.jersey.client.HttpAuthenticationFeature "<literal>HttpAuthenticationFeature</literal>">
<!ENTITY lit.jersey.client.HttpUrlConnectorProvider "<literal>HttpUrlConnectorProvider</literal>">
+<!ENTITY lit.jersey.client.HttpUrlConnector "<literal>HttpUrlConnector</literal>">
<!ENTITY lit.jersey.client.InjectionManagerClientProvider "<literal>InjectionManagerClientProvider</literal>">
<!ENTITY lit.jersey.client.oauth1.AccessToken "<literal>AccessToken</literal>">
<!ENTITY lit.jersey.client.oauth1.ConsumerCredentials "<literal>ConsumerCredentials</literal>">
diff --git a/docs/src/main/docbook/media.xml b/docs/src/main/docbook/media.xml
index 288b923..34d2a7d 100644
--- a/docs/src/main/docbook/media.xml
+++ b/docs/src/main/docbook/media.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" standalone="no"?>
<!--
- Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -1753,8 +1753,8 @@
<programlisting language="java">// MediaType of the body part will be derived from the file.
final List<EntityPart> multiPartEntity = new List<>();
-list.add(EntityPart.withFileName("file001.txt").content(new FileInputStream("file001.txt")).build());
-list.add(EntityPart.withFileName("mypom.xml").content(new FileInputStream("pom.xml")).build());
+list.add(EntityPart.withFileName("file001.txt").content(Files.newInputStream(Path.of("file001.txt"))).build());
+list.add(EntityPart.withFileName("mypom.xml").content(Files.newInputStream(Path.of("pom.xml"))).build());
final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {};
final Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE);
@@ -1935,6 +1935,25 @@
</tip>
</section>
</section>
+ <section xml:id="multipart.configuration">
+ <title>Properties for configuring the Multipart</title>
+ <para>
+ There are multiple options that can be used when configuring
+ the multipart. See &jersey.media.multipart.MultiPartProperties; or <xref linkend="appendix-properties-multipart"/>
+ for the possibilities.
+ </para>
+ <para>
+ The options can set in a configuration file specified by the
+ &jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE; property.
+ That is the standard Java properties file.
+ </para>
+ <para>
+ Or the options can be set programmatically,
+ by registering <literal>ContextResolver<MultiPartProperties></literal>. For instance:
+ </para>
+ <programlisting language="java">ResourceConfig resourceConfig = new ResourceConfig();
+resourceConfig.register(new MultiPartProperties().bufferThreshold(65535).maxParts(2).resolver());</programlisting>
+ </section>
<section xml:id="multipart.server.rest">
<title>Server using Jakarta REST API</title>
<para>
diff --git a/docs/src/main/docbook/modules.xml b/docs/src/main/docbook/modules.xml
index 70adc4d..93dcc25 100644
--- a/docs/src/main/docbook/modules.xml
+++ b/docs/src/main/docbook/modules.xml
@@ -455,6 +455,14 @@
<entry>Jersey extension module providing support for Mustache templates.</entry>
</row>
<row>
+ <entry>
+ <link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-mvc-thymeleaf/dependencies.html">
+ jersey-mvc-thymeleaf
+ </link>
+ </entry>
+ <entry>Jersey extension module providing support for Thymeleaf templates.</entry>
+</row>
+<row>
<entry>
<link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-proxy-client/dependencies.html">
jersey-proxy-client
diff --git a/etc/jenkins/jenkins_build.sh b/etc/jenkins/jenkins_build.sh
index 9983a05..3543e90 100644
--- a/etc/jenkins/jenkins_build.sh
+++ b/etc/jenkins/jenkins_build.sh
@@ -2,4 +2,4 @@
export DEBUG=true
-mvn -V -U -B -e -Pstaging clean install glassfish-copyright:check -Dcopyright.quiet=false
\ No newline at end of file
+mvn -V -U -B -e -Pstaging clean install glassfish-copyright:check -Dcopyright.quiet=false -DskipSBOM
diff --git a/etc/scripts/TCK/EE10/jakarta-ee10-tck.sh b/etc/scripts/TCK/EE10/jakarta-ee10-tck.sh
deleted file mode 100644
index 75dd07c..0000000
--- a/etc/scripts/TCK/EE10/jakarta-ee10-tck.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for listing staging from the staging repo.
-#
-# Input Parameters:
-# JERSEY_VERSION - type: String
-# - example: 3.1.5
-# - description: version of Jersey (EE10) to be tested
-# GLASSFISH_VERSION - type: String
-# - example: 7.0.6
-# - description: version of GF (EE10) to be used within tests
-# TCK_VERSION - type: String
-# - example: 3.1.3
-# - description: version of a TCK bundle which will be downloaded from the staging/central
-# Configuration:
-#
-# JDK:
-# openjdk-jdk11-latest
-# Git:
-# https://github.com/eclipse-ee4j/jersey
-# Branch:
-# */3.1
-#
-#
-
-#
-# The first sh invocation
-#
-#!/bin/bash -xe
-
-MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
-mvn -f tests/jersey-tck/pom.xml clean install \
- -Dtck.version=${TCK_VERSION} \
- -Dglassfish.container.version=${GLASSFISH_VERSION} \
- -Djersey.version=${JERSEY_VERSION} | tee tck.log
-
-
-#
-# The second sh invocation
-#
-#!/bin/bash -xe
-
-MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
-mvn -f tests/jersey-tck/pom.xml dependency:copy -Dartifact=jakarta.ws.rs:jakarta-restful-ws-tck:${TCK_VERSION} -Dtck.version=${TCK_VERSION} -Dtransitive=false
-export DOWNLOAD_PATH='tests/jersey-tck/target/dependency/'
-export NAME=`ls ${DOWNLOAD_PATH}`
-
-echo '***********************************************************************************' >> SUMMARY.TXT
-echo '*** TCK bundle information ***' >> SUMMARY.TXT
-echo "*** Name: ${NAME} ***" >> SUMMARY.TXT
-echo '*** Artifact ID: jakarta.ws.rs:jakarta-restful-ws-tck:'${TCK_VERSION}' ***' >> SUMMARY.TXT
-echo '*** Date and size: '`stat -c "date: %y, size(b): %s" ${DOWNLOAD_PATH}/${NAME}`' ***' >> SUMMARY.TXT
-echo '*** SHA256SUM: '`sha256sum ${DOWNLOAD_PATH}/${NAME} | awk '{print $1}'`' ***' >> SUMMARY.TXT
-echo '*** ***' >> SUMMARY.TXT
-echo '***********************************************************************************' >> SUMMARY.TXT
-echo '*** TCK results summary ***' >> SUMMARY.TXT
-export TESTS_RUN=`grep 'Skipped: [0-9]*$' tck.log | grep -o 'Tests run: [0-9]*' | awk '{ SUM += $3 } END { print SUM }'`
-export FAILURES=`grep 'Skipped: [0-9]*$' tck.log | grep -o 'Failures: [0-9]*' | awk '{ SUM += $2 } END { print SUM }'`
-export ERRORS=`grep 'Skipped: [0-9]*$' tck.log | grep -o 'Errors: [0-9]*' | awk '{ SUM += $2 } END { print SUM }'`
-export SKIPPED=`grep 'Skipped: [0-9]*$' tck.log | grep -o 'Skipped: [0-9]*' | awk '{ SUM += $2 } END { print SUM }'`
-echo '[INFO] Number of Tests Passed = '${TESTS_RUN} >> SUMMARY.TXT
-echo '[INFO] Number of Tests Failed = '${FAILURES} >> SUMMARY.TXT
-echo '[INFO] Number of Tests with Errors = '${ERRORS} >> SUMMARY.TXT
-echo '[INFO] Number of Skipped Tests = '${SKIPPED} >> SUMMARY.TXT
-echo '[INFO] ****************************************************************************' >> SUMMARY.TXT
-grep 'Tests run:' tck.log | grep --invert-match 'Skipped: [0-9]*$' >> SUMMARY.TXT
-
-
-#
-# Archive the artifacts:
-# tck.log,tests/jersey-tck/target/glassfish7/glassfish/domains/domain1/logs/server.log,tests/jersey-tck/pom.xml,SUMMARY.TXT
-#
\ No newline at end of file
diff --git a/etc/scripts/TCK/EE8/jersey-staging-GF-integration.sh b/etc/scripts/TCK/EE8/jersey-staging-GF-integration.sh
deleted file mode 100644
index 92c43c0..0000000
--- a/etc/scripts/TCK/EE8/jersey-staging-GF-integration.sh
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/bin/bash -ex
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for Jersey EE8 integration into Glassfish 5.
-#
-# Input Parameters:
-# GF_URL - type: String
-# - value: http://central.maven.org/maven2/org/glassfish/main/distributions/glassfish/5.1.0/glassfish-5.1.0.zip
-# - description: actual URL of the Glassfish 5
-# MAVEN_REPO_URL - type: String
-# - value: https://jakarta.oss.sonatype.org/content/groups/staging/org/glassfish/jersey
-# - description: Jersey binaries location
-# JERSEY_VERSION - type: String
-# - value: 2.42
-# - description: the version of Jersey to be integrated into the GF
-# JERSEY_JARS - type: Multi-line String
-# - value: containers/glassfish/jersey-gf-ejb/${JERSEY_VERSION}/jersey-gf-ejb
-# containers/jersey-container-grizzly2-http/${JERSEY_VERSION}/jersey-container-grizzly2-http
-# containers/jersey-container-servlet/${JERSEY_VERSION}/jersey-container-servlet
-# containers/jersey-container-servlet-core/${JERSEY_VERSION}/jersey-container-servlet-core
-# core/jersey-client/${JERSEY_VERSION}/jersey-client
-# core/jersey-common/${JERSEY_VERSION}/jersey-common
-# core/jersey-server/${JERSEY_VERSION}/jersey-server
-# ext/jersey-bean-validation/${JERSEY_VERSION}/jersey-bean-validation
-# ext/cdi/jersey-cdi1x/${JERSEY_VERSION}/jersey-cdi1x
-# ext/cdi/jersey-cdi1x-servlet/${JERSEY_VERSION}/jersey-cdi1x-servlet
-# ext/cdi/jersey-cdi1x-transaction/${JERSEY_VERSION}/jersey-cdi1x-transaction
-# ext/jersey-entity-filtering/${JERSEY_VERSION}/jersey-entity-filtering
-# ext/jersey-mvc/${JERSEY_VERSION}/jersey-mvc
-# ext/jersey-mvc-jsp/${JERSEY_VERSION}/jersey-mvc-jsp
-# inject/jersey-hk2/${JERSEY_VERSION}/jersey-hk2
-# media/jersey-media-jaxb/${JERSEY_VERSION}/jersey-media-jaxb
-# media/jersey-media-json-binding/${JERSEY_VERSION}/jersey-media-json-binding
-# media/jersey-media-json-jackson/${JERSEY_VERSION}/jersey-media-json-jackson
-# media/jersey-media-json-jettison/${JERSEY_VERSION}/jersey-media-json-jettison
-# media/jersey-media-json-processing/${JERSEY_VERSION}/jersey-media-json-processing
-# media/jersey-media-moxy/${JERSEY_VERSION}/jersey-media-moxy
-# media/jersey-media-multipart/${JERSEY_VERSION}/jersey-media-multipart
-# media/jersey-media-sse/${JERSEY_VERSION}/jersey-media-sse
-# - description: List of binaries to be integrated into the GF 5
-#
-#
-# Configuration:
-#
-# JDK:
-# (System)
-# Git:
-# ------none------
-#
-# Copy artifacts from another project:
-# JAXRS_build
-# Latest successful build
-# Artifacts to copy:
-# **/*.jar
-# Target directory:
-# download
-# [X] Flatten directories [X] Fingerprint Artifacts
-#
-#
-#
-ls
-cd download
-wget -q ${GF_URL} -O glassfish.zip
-#wget -q ${JAX_RS_JAR} -O jakarta.ws.rs-api.jar
-
-while IFS= read -r line ; do wget -q ${MAVEN_REPO_URL}/$line-${JERSEY_VERSION}.jar; done <<< "${JERSEY_JARS}"
-
-echo Listing grabbed jars
-ls *.jar
-
-#unzip
-unzip -q glassfish.zip -d ${WORKSPACE}
-cd ${WORKSPACE}/glassfish5/glassfish/modules
-
-#replace API jar
-#cp -v ${WORKSPACE}/download/jakarta.ws.rs-api.jar .
-
-#replace Jersey Jar
-for jarfile in ${WORKSPACE}/download/*.jar; do
- echo $(basename $jarfile) | sed -e 's/-RC[0-9][0-9]*//' | sed -e 's/-SNAPSHOT//' | sed -e 's/\.[0-9][0-9]*//' | sed -e 's/\.[0-9][0-9]*//' | sed -e 's/-[0-9][0-9]*//' | while IFS= read -r gfnamejar ; do if [ -f $gfnamejar ]; then rm -v $gfnamejar; cp -v $jarfile $gfnamejar; fi; done;
-done
-
-cd ${WORKSPACE}
-zip -r glassfish.zip glassfish5
-
-
-#
-# Archive the artifacts:
-# glassfish.zip
-#
-#
diff --git a/etc/scripts/TCK/EE8/tck-build.sh b/etc/scripts/TCK/EE8/tck-build.sh
deleted file mode 100644
index 40a9cb1..0000000
--- a/etc/scripts/TCK/EE8/tck-build.sh
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/bin/bash -ex
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for building EE8 TCK bundle for Jersey.
-#
-# Input Parameters:
-# GF_URL - type: String
-# - value: https://search.maven.org/remotecontent?filepath=org/glassfish/main/distributions/glassfish/5.1.0/glassfish-5.1.0.zip
-# - description: actual URL of the Glassfish 5
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk8-latest
-# Git:
-# https://github.com/eclipse-ee4j/jakartaee-tck.git
-# Branch:
-# */master
-# Check out to a sub-directory:
-# CTS
-#
-# [X] With Ant:
-# apache-ant-latest
-# JDK:
-# oracle-jdk8-latest
-#
-# Copy artifacts from another project:
-# ts_jte_alter
-# Latest successful build
-# Artifacts to copy:
-# ts.jte
-# Target directory:
-# download
-# [X] Flatten directories [X] Fingerprint Artifacts
-#
-#
-#
-
-mkdir ${WORKSPACE}/CTS/tools
-mkdir ${WORKSPACE}/CTS/tools/ant
-
-#create zip command
-#mkdir batch
-#touch ${WORKSPACE}/batch/zip.sh
-#chmod +x ${WORKSPACE}/batch/zip.sh
-#touch ${WORKSPACE}/batch/zip
-#chmod +x ${WORKSPACE}/batch/zip
-#alias zip='${WORKSPACE}/batch/zip.sh'
-
-#echo "echo ARG1=\$1">batch/zip.sh
-#echo "echo ARG2=\$2">>batch/zip.sh
-#echo "echo ARG3=\$3">>batch/zip.sh
-#echo "if [ \$1='-T' ]; then">>batch/zip.sh
-#echo " exit">>batch/zip.sh
-#echo "fi">>batch/zip.sh
-#echo "filename=\`echo \$2 | cut -d'.' -f 1,2\`">>batch/zip.sh
-#echo "echo filename=\$filename">>batch/zip.sh
-#echo "tar -zcvf '\${filename}'.tar.gz \$3">>batch/zip.sh
-#echo "mv \${filename}.tar.gz \${filename}.zip">>batch/zip.sh
-#echo "echo created \${filename}.zip">>batch/zip.sh
-
-#echo "${WORKSPACE}/batch/zip.sh \$*">batch/zip
-
-#cat batch/zip.sh
-#cat batch/zip
-
-
-#Set variables
-export ANT_OPTS=-Djavax.xml.accessExternalSchema=all
-
-cd download
-#wget -4 https://jenkins.eclipse.org/jersey/view/TCK/job/ts_jte_alter/lastSuccessfulBuild/artifact/ts.jte
-
-#wget -q https://ci.adoptopenjdk.net/view/Build%20Monitor/job/jtharness/lastSuccessfulBuild/artifact/jtharness.tar.gz -O jtharness.tar.gz
-#wget -q https://ci.adoptopenjdk.net/view/Build%20Monitor/job/sigtest/lastSuccessfulBuild/artifact/sigtest.tar.gz -O sigtest.tar.gz
-#wget -q http://central.maven.org/maven2/com/sun/xml/bind/jaxb-xjc/2.2.7/jaxb-xjc-2.2.7.jar -O jaxb-xjc.jar
-#wget -q http://central.maven.org/maven2/ant-contrib/ant-contrib/1.0b3/ant-contrib-1.0b3.jar -O ant-contrib.jar
-#wget -q http://central.maven.org/maven2/commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.jar
-#wget -q http://central.maven.org/maven2/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar
-#wget -q http://central.maven.org/maven2/commons-codec/commons-codec/1.3/commons-codec-1.3.jar
-#tar xfz jtharness.tar.gz
-#tar xvfz sigtest.tar.gz
-#unzip -q sigtest-4.0
-#cp -av ${WORKSPACE}/download/sigtest-4.0/lib/. ${WORKSPACE}/CTS/lib/
-#cp -v ${WORKSPACE}/download/jtharness/lib/javatest.jar ${WORKSPACE}/CTS/lib/javatest.jar
-#cp -v ${WORKSPACE}/download/jaxb-xjc.jar ${WORKSPACE}/CTS/lib/
-#cp -v ${WORKSPACE}/download/ant-contrib.jar ${WORKSPACE}/CTS/lib/
-#cp -v ${WORKSPACE}/download/ant-contrib.jar ${WORKSPACE}/CTS/lib/ant-contrib-1.0b3.jar
-#cp -v ${WORKSPACE}/download/commons-httpclient-3.1.jar ${WORKSPACE}/CTS/lib/
-#cp -v ${WORKSPACE}/download/commons-logging-1.1.1.jar ${WORKSPACE}/CTS/lib/
-#cp -v ${WORKSPACE}/download/commons-codec-1.3.jar ${WORKSPACE}/CTS/lib/
-
-
-ls
-
-yes | cp -vr ${WORKSPACE}/download/ts.jte ${WORKSPACE}/CTS/install/jaxrs/bin/
-#cp -v ${WORKSPACE}/download/ts.jte ${WORKSPACE}/CTS/bin/ts.jte
-
-wget -q ${GF_URL} -O glassfish.zip
-unzip -q glassfish.zip -d ${WORKSPACE}
-
-#COMPILE TCK
-
-export TS_HOME=${WORKSPACE}/CTS
-export deliverabledir=jaxrs
-export javaee_home=${WORKSPACE}/glassfish5
-
-#touch ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/api = servlet >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/api/rs/ext/interceptor = standalone >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/ee = standalone >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/jaxrs21 = standalone >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/jaxrs21/api = servlet >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/spec = standalone >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/servlet3 = standalone >> ${WORKSPACE}/CTS/vehicle.properties
-#echo com/sun/ts/tests/jaxrs/platform = standalone >> ${WORKSPACE}/CTS/vehicle.properties
-
-#cat ${WORKSPACE}/CTS/vehicle.properties
-
-#fix the test
-cd ${WORKSPACE}/CTS/src/com/sun/ts/tests/jaxrs/jaxrs21/ee/sse/sseeventsink
-sed -i '314s/open()/register(holder::add)/' JAXRSClient.java
-sed -i '315s/register(holder::add)/open()/' JAXRSClient.java
-#end of fix
-
-cd ${WORKSPACE}/CTS/install/${deliverabledir}/bin
-ant build.all
-ant update.jaxrs.wars
-
-# BUNDLE TCK
-
-cd ${WORKSPACE}/CTS/release/tools/
-ant jakartaee-jaxrs
-#ls ${WORKSPACE}/CTS/release/JAXRS_BUILD/
-cd ${WORKSPACE}/CTS/release/JAXRS_BUILD/latest
-for fn in `ls *.zip`; do cp -v "${fn}" `echo ${fn} | cut -d'_' -f 1`_latest.zip; done
-
-#zip -s 10m jaxrstck_split_latest.zip jaxrstck-2.1_latest.zip
-#ls
-
-
-
-#
-# Archive the artifacts:
-# CTS/release/JAXRS_BUILD/latest/*.z*
-#
-#
-
diff --git a/etc/scripts/TCK/EE8/tck-run-pipeline.groovy b/etc/scripts/TCK/EE8/tck-run-pipeline.groovy
deleted file mode 100644
index 95936f1..0000000
--- a/etc/scripts/TCK/EE8/tck-run-pipeline.groovy
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env groovy
-
-/*
- * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0, which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the
- * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- * version 2 with the GNU Classpath Exception, which is available at
- * https://www.gnu.org/software/classpath/license.html.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- */
-
-/**
- * Runs TCK for Jersey EE8 on GlassFish 5
- *
- * Input Parameters:
- *
- * GF_INTEGRATION_JOB_NAME - type: String
- * - value: Jersey_Staging_GF_Integration
- * - description: name of a job from which the prepared archive of the Glassfish 5 is taken
- * - possible values: Jersey_binaries_GF_integration
- * Jersey_Staging_GF_Integration
- * GF5_Jersey2_Archive_Integration
- * TS_JTE_JOB_NAME - type: String
- * - value: ts_jte_alter
- * - description: name of a job from which prepared ts.jte is taken
- * TCK_BUNDLE_JOB_OR_URL - type: String
- * - value: tck_build
- * - description: name of a job from which prepared TCK bundle is taken
- */
-
-node {
-
- // Job that created the API artifact
- def GF_BUILD_JOB = "${env.GF_INTEGRATION_JOB_NAME}"
- def TS_JTE_BUILD_JOB = "${env.TS_JTE_JOB_NAME}"
- def TCK_BUNDLE_URL = "${env.TCK_BUNDLE_JOB_OR_URL}"
- def API_JAR_NAME="jakarta.ws.rs-api.jar"
-
- echo "GF_BUILD_JOB=${GF_BUILD_JOB}"
- echo "TS_JTE_BUILD_JOB=${TS_JTE_BUILD_JOB}"
- echo "TCK_BUNDLE_URL=${TCK_BUNDLE_URL}"
-
- //TCK properties
- env.deliverabledir="jaxrs"
- env.tck_root="restful-ws-tck"
- env.TS_HOME="${env.WORKSPACE}/${env.tck_root}"
- env.javaee_home="${env.WORKSPACE}/glassfish5"
-
- env.JAVA_HOME= tool name: 'oracle-jdk8-latest', type: 'jdk'
- env.ANT_HOME= tool name: 'apache-ant-latest', type: 'ant'
- env.PATH="${ANT_HOME}/bin:${JAVA_HOME}/bin:${PATH}"
- env.ANT_OPTS="-Djavax.xml.accessExternalSchema=all"
-
- stage("Grab GF and ts.jte artifacts") {
- //https://go.cloudbees.com/docs/cloudbees-documentation/cjoc-user-guide/index.html#cluster-copy-artifacts
- dir ("download") {
- copyArtifacts(projectName: "${GF_BUILD_JOB}")
- copyArtifacts(projectName: "${TS_JTE_BUILD_JOB}")
- }
- }
-
- stage("Grab TCK bundle") {
- env.TCK_BUNDLE_URL = "${TCK_BUNDLE_URL}"
- if (!(env.TCK_BUNDLE_URL).startsWith("http")) {
- dir ("download") {
- copyArtifacts(projectName: "${TCK_BUNDLE_URL}", filter: "**/*_latest.zip")
- //flatten - could be done by copyRemoteArtifacts but mapper arg expects java class
- sh "find . -mindepth 2 -type f -print -exec mv {} . \\;"
-
- //sh "rm *doc*.zip"
- sh "mv ${deliverabledir}-tck*.zip ${deliverabledir}-tck.zip"
- }
- } else {
- sh '''#!/bin/bash -ex
- cd ${WORKSPACE}/download
- wget -q ${TCK_BUNDLE_URL} -O ${deliverabledir}-tck.zip
- '''
- }
- }
-
- stage("Unzip TCK and GF") {
- sh '''#!/bin/bash -ex
- cd ${WORKSPACE}
- unzip ${WORKSPACE}/download/glassfish.zip
- unzip -q ${WORKSPACE}/download/${deliverabledir}-tck.zip
- ls
- ls ${tck_root}
-
- cd ${WORKSPACE}/glassfish5/glassfish/modules
- jar xf jersey-common.jar META-INF/MANIFEST.MF
- cat META-INF/MANIFEST.MF | grep Bundle-Version
- '''
- }
-
- stage ("Replace ts.jte") {
- sh '''#!/bin/bash -ex
- ls ${TS_HOME}
- ls ${TS_HOME}/bin
- yes | cp -rfv ${WORKSPACE}/download/ts.jte ${TS_HOME}/bin/ts.jte
- '''
- }
-
- stage("Configure TCK") {
- sh '''#!/bin/bash -ex
- cd ${TS_HOME}/bin
- ant config.vi
- '''
- }
-
- stage ("Deploy TCK tests") {
- sh '''#!/bin/bash -ex
- cd ${TS_HOME}/bin
- ant deploy.all
- '''
- }
-
- stage ("Run TCK tests") {
- sh '''#!/bin/bash -ex
- cd ${TS_HOME}/bin
- ant run.all | tee run.log
- '''
- }
-
- stage ("Create summary.txt, API, and run.log artifacts") {
- sh '''#!/bin/bash -ex
- cd ${TS_HOME}/bin
- cat run.log | sed -e '1,/Completed running/d' > summary.txt
- PASSED_COUNT=`head -1 summary.txt | tail -1 | sed 's/.*=\\s\\(.*\\)/\\1/'`
- FAILED_COUNT=`head -2 summary.txt | tail -1 | sed 's/.*=\\s\\(.*\\)/\\1/'`
- ERROR_COUNT=`head -3 summary.txt | tail -1 | sed 's/.*=\\s\\(.*\\)/\\1/'`
-
- echo ERROR_COUNT=${ERROR_COUNT}
- echo FAILED_COUNT=${FAILED_COUNT}
- echo PASSED_COUNT=${PASSED_COUNT}
- '''
-
- archiveArtifacts artifacts: "${env.tck_root}/bin/summary.txt", fingerprint: true
- archiveArtifacts artifacts: "${env.tck_root}/bin/run.log", fingerprint: true
- archiveArtifacts artifacts: "glassfish5/glassfish/modules/${API_JAR_NAME}", fingerprint: true
- archiveArtifacts artifacts: "glassfish5/glassfish/modules/META-INF/MANIFEST.MF", fingerprint: true
- archiveArtifacts artifacts: "glassfish5/glassfish/domains/domain1/logs/server.log", fingerprint: true
- }
-}
\ No newline at end of file
diff --git a/etc/scripts/TCK/EE8/ts-jte-alter.sh b/etc/scripts/TCK/EE8/ts-jte-alter.sh
deleted file mode 100644
index 27d908a..0000000
--- a/etc/scripts/TCK/EE8/ts-jte-alter.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for generating ts.jte for EE8 Jersey TCK.
-#
-# Input Parameters:
-#
-# SERVER_HOME - type: String
-# - value: ${ts.home}/../glassfish5/glassfish
-# JAXRS_API_JAR_NAME - type: String
-# - value: jakarta.ws.rs-api.jar
-# HARNESS_REPORT_DIR - type: String
-# - value: ${ts.home}/../JTreport
-# HARNESS_WORK_DIR - type: String
-# - value: ${ts.home}/../JTwork
-#
-# Configuration:
-#
-# JDK:
-# (System)
-# Git:
-# ----none----
-#
-#
-
-wget https://raw.githubusercontent.com/eclipse-ee4j/jakartaee-tck/master/install/jaxrs/bin/ts.jte
-
-JARS_ON_CP="\
-\${web.home}/modules/jersey-client.jar:\
-\${web.home}/modules/jersey-common.jar:\
-\${web.home}/modules/jersey-container-servlet.jar:\
-\${web.home}/modules/jersey-container-servlet-core.jar:\
-\${web.home}/modules/jersey-hk2.jar:\
-\${web.home}/modules/jersey-media-jaxb.jar:\
-\${web.home}/modules/jersey-media-json-binding.jar:\
-\${web.home}/modules/jersey-media-json-processing.jar:\
-\${web.home}/modules/jersey-media-sse.jar:\
-\${web.home}/modules/jersey-server.jar:\
-\${web.home}/modules/jsonp-jaxrs.jar:\
-\${web.home}/modules/asm-all-repackaged.jar:\
-\${web.home}/modules/bean-validator.jar:\
-\${web.home}/modules/endorsed/jakarta.annotation-api.jar:\
-\${web.home}/modules/cdi-api.jar:\
-\${web.home}/modules/cglib.jar:\
-\${web.home}/modules/hk2-api.jar:\
-\${web.home}/modules/hk2-locator.jar:\
-\${web.home}/modules/hk2-utils.jar:\
-\${web.home}/modules/javassist.jar:\
-\${web.home}/modules/jakarta.ejb-api.jar:\
-\${web.home}/modules/jakarta.inject.jar:\
-\${web.home}/modules/jakarta.json.jar:\
-\${web.home}/modules/jakarta.json-api.jar:\
-\${web.home}/modules/jakarta.json.bind-api.jar:\
-\${web.home}/modules/jakarta.interceptor-api.jar:\
-\${web.home}/modules/jakarta.servlet-api.jar:\
-\${web.home}/modules/osgi-resource-locator.jar:\
-\${web.home}/modules/weld-osgi-bundle.jar:\
-\${web.home}/modules/yasson.jar"
-
-sed -i 's/^impl\.vi=/impl\.vi=glassfish/g' ts.jte
-sed -i "s/^web\.home=/$(echo web\.home=${SERVER_HOME} | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i "s/^impl\.vi\.deploy\.dir=/$(echo impl\.vi\.deploy\.dir=\${web.home}/domains/domain1/autodeploy | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i 's/^jaxrs_impl_name=/jaxrs_impl_name=jersey/g' ts.jte
-sed -i 's/^harness\.log\.traceflag=/harness\.log\.traceflag=true/g' ts.jte
-sed -i 's/^webServerHost=/webServerHost=localhost/g' ts.jte
-sed -i 's/^webServerPort=/webServerPort=8080/g' ts.jte
-sed -i "s/^work\.dir=\/tmp\/JTwork/$(echo work\.dir=${HARNESS_WORK_DIR} | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i "s/^report\.dir=\/tmp\/JTreport/$(echo report\.dir=${HARNESS_REPORT_DIR} | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i "s/^jaxrs_impl\.classes=/$(echo jaxrs_impl\.classes=${JARS_ON_CP} | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i "s/^jaxrs\.classes=/$(echo jaxrs\.classes=\${web.home}/modules/${JAXRS_API_JAR_NAME} | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i "s/^jaxrs_impl_lib=/$(echo jaxrs_impl_lib=\${web.home}/modules/jersey-container-servlet-core.jar | sed -e 's/\\/\\\\/g; s/\//\\\//g;')/g" ts.jte
-sed -i "s/^servlet_adaptor=/servlet_adaptor=org\/glassfish\/jersey\/servlet\/ServletContainer.class/g" ts.jte
-
-sed -i "s/-Dcts.tmp=\.*/-Djavax.xml.accessExternalSchema=all -Dcts.tmp=/g" ts.jte
-
-
-#
-# Archive the artifacts:
-# ts.jte
\ No newline at end of file
diff --git a/etc/scripts/release/EE10/bundle-apidocs.sh b/etc/scripts/release/EE10/bundle-apidocs.sh
deleted file mode 100644
index 089a1a9..0000000
--- a/etc/scripts/release/EE10/bundle-apidocs.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for releasing api docs bundle by release tag.
-#
-# Input Parameters:
-#
-# VERSION - type: String
-# - example: 3.1.6
-# - description: Name of the existing version tag in the Git repo.
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk17-latest
-# Git:
-# git@github.com:eclipse-ee4j/jersey.git
-# Branches to build:
-# tags/${VERSION}
-#
-# Bindings:
-# Secret file:
-# Variable:
-# KEYRING
-# Credentials:
-# secret-subkeys.asc
-#
-#
-
-
- gpg --batch --import ${KEYRING}
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
-
-#!/bin/bash -xe
-
-# Execution environment
-MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
-echo '-[ Run maven release plugin ]---------------------------------------------------'
-
-mvn -q -V -C -DstagingDescription="org.glassfish.jersey.bundles.apidocs:${VERSION}" \
- -Pstaging,oss-release,pre-release -DskipTests -pl :apidocs \
- -Djersey.version=${VERSION} -Dsource.mvn.plugin.version=3.2.0 install javadoc:jar gpg:sign deploy
\ No newline at end of file
diff --git a/etc/scripts/release/EE10/bundle-examples.sh b/etc/scripts/release/EE10/bundle-examples.sh
deleted file mode 100644
index c49fa1c..0000000
--- a/etc/scripts/release/EE10/bundle-examples.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for releasing examples bundle by release tag.
-#
-# Input Parameters:
-#
-# VERSION - type: String
-# - example: 3.1.6
-# - description: Name of the existing version tag in the Git repo.
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk11-latest
-# Git:
-# git@github.com:eclipse-ee4j/jersey.git
-# Branches to build:
-# tags/${VERSION}
-#
-# Bindings:
-# Secret file:
-# Variable:
-# KEYRING
-# Credentials:
-# secret-subkeys.asc
-#
-#
-
-
- gpg --batch --import ${KEYRING}
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
-
-
- # Execution environment
- MVN_HOME="/opt/tools/apache-maven/latest/"
- PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
- mvn clean install -C -B -Djersey.version=${VERSION} -DskipTests -Ppre-release,staging -pl org.glassfish.jersey.examples:project -amd
-
- mvn -C -B -DstagingDescription="org.glassfish.jersey.examples:${VERSION}" \
- -Pstaging,oss-release,pre-release \
- -Djersey.version=${VERSION} -DskipTests -pl :jersey-examples \
- deploy
\ No newline at end of file
diff --git a/etc/scripts/release/EE10/bundle-user-guide.sh b/etc/scripts/release/EE10/bundle-user-guide.sh
deleted file mode 100644
index 8890a79..0000000
--- a/etc/scripts/release/EE10/bundle-user-guide.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for releasing User Guide bundle by release tag.
-#
-# Input Parameters:
-#
-# VERSION - type: String
-# - example: 3.1.6
-# - description: Name of the existing version tag in the Git repo.
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk11-latest
-# Git:
-# git@github.com:eclipse-ee4j/jersey.git
-# Credentials:
-# GitHub bot SSH
-# Branches to build:
-# refs/tags/${VERSION}
-#
-# Bindings:
-# Secret file:
-# Variable:
-# KEYRING
-# Credentials:
-# secret-subkeys.asc
-#
-#
-
-
- gpg --batch --import ${KEYRING}
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
-
-#!/bin/bash -xe
-
-# Execution environment
-MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
-cd docs
-
-echo '-[ Run maven release plugin ]---------------------------------------------------'
-
-mvn -q -C -DstagingDescription="org.glassfish.jersey.jersey-documentation:${VERSION}" \
- -Pstaging,oss-release,pre-release \
- -DskipTests \
- install javadoc:jar gpg:sign deploy
\ No newline at end of file
diff --git a/etc/scripts/release/EE10/release.groovy b/etc/scripts/release/EE10/release.groovy
deleted file mode 100644
index ad2f167..0000000
--- a/etc/scripts/release/EE10/release.groovy
+++ /dev/null
@@ -1,333 +0,0 @@
-#!/usr/bin/env groovy
-
-/*
- * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0, which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the
- * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- * version 2 with the GNU Classpath Exception, which is available at
- * https://www.gnu.org/software/classpath/license.html.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- */
-
-/**
- * Release script for Jakarta EE10 Jersey versions
- * Release branch is 3.1
- *
- * Input Parameters:
- * RELEASE_VERSION - type: String
- * - example: 3.1.6
- * - Description: mandatory release version. Later is being published to staging/central.
- * NEXT_VERSION - type: String
- * - example: 3.1.99-SNAPSHOT
- * - Description: mandatory next developing version will be committed in to the release branch and later
- * merged into the original release branch for further developing.
- * BRANCH - type: Choice Parameter
- * - values: 3.1
- * - Description: Original release branch from which the codebase is being checked out
- * DRY_RUN - type: Boolean
- * - Description: if checked nothing is really committed to Git nor published to the staging
- * OVERWRITE - type: Boolean
- * - Description: if checked allows replacing of the previously published RELEASE_VERSION of Jersey
- *
- */
-
-#!/usr/bin/env groovy
-
-node {
-
- def MVN_HOME = tool name: 'apache-maven-latest', type: 'maven'
- def HELP_PLUGIN = 'org.apache.maven.plugins:maven-help-plugin:2.1.1'
- def TARGET = 'package javadoc:jar gpg:sign install:install'
- def DEPLOY_TARGET = ''
- def RELEASE_VERSION = RELEASE_VERSION
- def NEXT_VERSION = NEXT_VERSION
- def RELEASE_TAG = ''
- def NEW_RELEASE_BRANCH = ''
- def OVERWRITE = OVERWRITE
- def PROJECT_NAME = 'Jersey'
- def LOGIN = 'jersey-bot'
- def EMAIL = 'jersey-bot@eclipse.org'
- def REPO = 'git@github.com:eclipse-ee4j/jersey.git'
- def SECRET_FILE_ID = 'secret-subkeys.asc'
- def CREDENTIALS_ID = 'github-bot-ssh'
- def GIT_ORIGIN = 'origin'
- def RELEASE_FOLDER = env.WORKSPACE
- def RELEASE_BRANCH = BRANCH
-
- def STAGING_NAME_PATTERN = 'orgglassfishjersey-[0-9]+'
- def STAGING_NAME = ''
- def STAGING_PREV_NAME = ''
- def STAGING_OPEN_NAME = ''
- def STAGING_DESC = 'org.glassfish.jersey:' + RELEASE_VERSION
- def STAGING_BOM_DESC = 'org.glassfish.jersey.bom:' + RELEASE_VERSION
- def STAGING_PROFILE_ID = '70fa3a107a8918'
-
- def MULTIRELEASE_MODULES = ':jersey-wadl-doclet,:jersey-spring6,:jersey-helidon-connector,:jersey-jetty-connector,:jersey-jetty-http2-connector,:jersey-container-jetty-http,:jersey-container-jetty-http2,:jersey-test-framework-provider-jetty,:jersey-test-framework-provider-jetty-http2'
-
- def JDK_11_HOME = tool name: 'openjdk-jdk11-latest', type: 'jdk'
- //def JDK_12_HOME = tool name: 'openjdk-jdk12-latest', type: 'jdk'
- def JDK_21_HOME = tool name: 'openjdk-jdk21-latest', type: 'jdk'
- //def JDK_8_HOME = tool name: 'oracle-jdk8-latest', type: 'jdk'
-
- env.JAVA_HOME = JDK_11_HOME
- env.PATH = "${env.JAVA_HOME}/bin:${env.PATH}:${MVN_HOME}/bin"
-
- sh 'java -version'
-
- stage('Fetch from git') {
- git(branch: RELEASE_BRANCH, credentialsId: CREDENTIALS_ID, url: REPO)
- }
- stage('Prepare environment') {
-
- dir(RELEASE_FOLDER) {
- //# Check whether top level pom.xml contains SNAPSHOT version
- if (!sh(returnStdout: true, script: "grep '<version>' pom.xml | grep 'SNAPSHOT'")?.trim()) {
- error('-[ Missing SNAPSHOT version in POM! ]-------------------------------------------')
- }
-
- //# Compute release versions
- def SNAPSHOT_VERSION = sh(returnStdout: true, script: 'mvn -q -Dexec.executable="echo" -Dexec.args=\'${project.version}\' --non-recursive exec:exec -Pstaging').trim()
-
- if (!RELEASE_VERSION?.trim()) {
- if (!SNAPSHOT_VERSION?.trim()) {
- error('-[ Missing required snapshot version number! ]----------------------------------')
- } else {
- def versionTokens = SNAPSHOT_VERSION.split('-')
- RELEASE_VERSION = versionTokens[0]
- }
- }
-
- if (!NEXT_VERSION?.trim()) {
- def (MAJOR_VERSION, MINOR_VERSION) = RELEASE_VERSION.tokenize('.')
- def NEXT_MINOR_VERSION = (MINOR_VERSION as Integer) + 1
- NEXT_VERSION = MAJOR_VERSION + '.' + NEXT_MINOR_VERSION + '-SNAPSHOT'
- }
-
- RELEASE_TAG = RELEASE_VERSION
- NEW_RELEASE_BRANCH = RELEASE_VERSION+'-BRANCH'
-
- echo "Current version: ${SNAPSHOT_VERSION}"
- echo "Release version: ${RELEASE_VERSION}"
- echo "Next version: ${NEXT_VERSION}"
- echo "Release tag: ${RELEASE_TAG}"
- echo "Release branch: ${NEW_RELEASE_BRANCH}"
-
- if (!SNAPSHOT_VERSION?.trim() || !RELEASE_VERSION?.trim() || !NEXT_VERSION?.trim()) {
- error '-[ Missing required version numbers! ]------------------------------------------'
- }
-
- if (DRY_RUN == 'true') {
- echo '-[ Dry run turned on ]----------------------------------------------------------'
- //TARGET = 'install'
- } else {
- DEPLOY_TARGET = ' deploy:deploy'
- }
- echo '-[ Configure git user ]--------------------------------------------------------'
- sh "git config --local user.email \"${EMAIL}\""
- sh "git config --local user.name \"$LOGIN\""
-
- }
-
- }
- stage('Prepare GPG') {
- withCredentials([file(credentialsId: SECRET_FILE_ID, variable: 'KEYRING')]) {
- //# Workaround: GPG initialization
- sh("gpg --batch --import ${KEYRING}")
- sh '''
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
- '''
- }
- }
- stage('Prepare branch') {
- echo '-[ Prepare branch ]-------------------------------------------------------------'
-
- echo '-[ Switching to release branch ]-------------------------------------------------'
- sh """
- git checkout ${GIT_ORIGIN}/${RELEASE_BRANCH} && true
- git reset --hard ${GIT_ORIGIN}/${RELEASE_BRANCH} && true
- git checkout -B ${NEW_RELEASE_BRANCH}
- """
- echo '-[ Release tag cleanup ]--------------------------------------------------------'
- def TAG_NAME = sh(returnStdout: true, script: "git tag | grep ${RELEASE_TAG}\$ || true").trim()
- if (RELEASE_TAG == TAG_NAME) {
- if (OVERWRITE == 'true') {
- echo "${RELEASE_TAG} tag already exists, deleting"
- sshagent([CREDENTIALS_ID]) {
- sh "git push --delete origin ${RELEASE_TAG} && true"
- }
- } else {
- error "${RELEASE_TAG} tag already exists"
- }
- //# Always delete local tag if exists
- sh """
- git tag --delete ${RELEASE_TAG} && true
- """
- }
- sh '''
- sed -i 's|<suppress files="generated" checks=".*"/>|<suppress files="generated" checks=".*"/><suppress files="unpacked-src" checks=".*"/>|g' etc/config/checkstyle-suppressions.xml
- '''
- }
- stage('Check previous stagings') {
- if (DRY_RUN == 'true') {
- echo DRY_RUN + ' ------'
- } else {
- if (OVERWRITE == 'true') {
- STAGING_PREV_NAME = sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging nexus-staging:rc-list | awk '/\\[INFO] $STAGING_NAME_PATTERN[ ]+CLOSED[ ]+$STAGING_DESC[ ]*\$/ {if(a){a = \$2\",\"a} else{a = \$2}}END{print a}'").trim()
- echo 'Previously closed staging name: ' + STAGING_PREV_NAME
- }
-
- STAGING_OPEN_NAME = sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging nexus-staging:rc-list | awk '/$STAGING_NAME_PATTERN OPEN / {if(a){a = \$2\",\"a} else{a = \$2}}END{print a}'").trim()
-
- if (!STAGING_OPEN_NAME?.trim()) {
- echo 'No currently open stagings'
- } else {
- echo 'Currently open redundand staging: ' + STAGING_OPEN_NAME + ', immediately closing'
- sh """
- OPEN_STAGINGS=${STAGING_OPEN_NAME}
- mvn -B -q -Pstaging nexus-staging:rc-drop -DstagingRepositoryId=\${OPEN_STAGINGS}
- """
- }
- }
- }
- /*
- stage('Open new staging') {
- if (DRY_RUN == 'true') {
- echo DRY_RUN + ' ------'
- } else {
- STAGING_NAME = sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging -DstagingProfileId=${STAGING_PROFILE_ID} -DstagingDescription=${STAGING_DESC} nexus-staging:rc-open | awk '/\\[INFO] Opened / {print \$3}'").trim()
- echo 'New staging name: '+STAGING_NAME
- }
- }*/
- stage("Build ${PROJECT_NAME}") {
- echo env.JAVA_HOME
- echo '-[ Run maven release ]---------------------------------------------------------'
- echo '-[ Set Release version ]-------------------------------------------------------'
- sh """
- cd ${RELEASE_FOLDER}
- mvn -q -B -V -Pstaging versions:set -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false
- mvn -q -B -V -Pstaging versions:set -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false -f bom/pom.xml
- """
- echo '-[ Update Copyright years ]----------------------------------------------------'
- sh '''#!/bin/bash -e
-
- export CURRENT_YEAR=`date '+%Y'`
- export SED_CMD_LINE='sed -i "s#, 20.. Oracle and/or its affiliates#, ${CURRENT_YEAR} Oracle and/or its affiliates#g"'
-
- git status --porcelain --untracked-files=no > modified_pom.log
- cp modified_pom.log list_of_poms.txt
- sed -i "s| M |$SED_CMD_LINE |g" modified_pom.log
- sed -i "s| M ||g" list_of_poms.txt
-
- bash modified_pom.log
-
- echo ${CURRENT_YEAR} current year
-
- while IFS= read -r path_to_pom
- do
- export CP_YEAR=`grep -o 'Copyright (c) 20.. Oracle and/or its affiliates' ${path_to_pom} | awk '{print $3}'`
- [[ -z ${CP_YEAR} ]] && CP_YEAR=${CURRENT_YEAR} || echo ${CP_YEAR}
- [[ ${CP_YEAR} == ${CURRENT_YEAR} ]] || ( sed -i "s#Copyright (c) ${CP_YEAR} Oracle and/or its affiliates#Copyright (c) ${CP_YEAR}, ${CURRENT_YEAR} Oracle and/or its affiliates#g" ${path_to_pom} ; echo ${path_to_pom} )
- unset CP_YEAR
- done < "list_of_poms.txt"
- '''
- echo '-[ Run release build ]---------------------------------------------------------'
- dir(RELEASE_FOLDER) {
- //env.JAVA_HOME = JDK_12_HOME
- //sh 'mvn clean install -am -Pstaging -pl :jersey-wadl-doclet -DskipTests -B -q -V -Djersey.version=${RELEASE_VERSION}'
- env.JAVA_HOME = JDK_21_HOME
- sh "mvn clean install -B -q -V -DskipTests -am -Pstaging -Djersey.version=${RELEASE_VERSION} --projects ${MULTIRELEASE_MODULES}"
- env.JAVA_HOME = JDK_11_HOME
- //
- sh "mvn -q -B -V -Djersey.version=${RELEASE_VERSION} -DskipTests -Ddoclint=none -Dadditionalparam='-Xdoclint:none' " +
- " -Poss-release,staging -U -C ${TARGET} ${DEPLOY_TARGET}"
- //sh "mvn -Poss-release,staging -pl :jersey-wadl-doclet -am install gpg:sign ${DEPLOY_TARGET} -B -q -V -DskipTests -Djersey.version=${RELEASE_VERSION}"
-
- }
- }
- stage('Prepare release') {
- sh '''
- git checkout -- etc/config/checkstyle-suppressions.xml
- '''
- echo '-[ Perform release commit to git ]---------------------------------------------'
- sh "git commit -a -m ${RELEASE_VERSION}"
- sh "git tag -m ${RELEASE_TAG} -a ${RELEASE_TAG}"
- echo '-[ Set next snapshot version ]-------------------------------------------------'
- dir(RELEASE_FOLDER) {
- sh """
- mvn -q -B -Pstaging -Djersey.version=${RELEASE_VERSION} versions:set -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false
- mvn -q -B -Pstaging -Djersey.version=${RELEASE_VERSION} versions:set -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false -f bom/pom.xml
- """
- }
- echo '-[ Perform commit to git ]-----------------------------------------------------'
- sh "git commit -a -m ${NEXT_VERSION}"
- }
- stage('Publish release') {
- if (DRY_RUN == 'true') {
- echo '-[ Prepared branch ]----------------------------------------------------------'
- sh "git branch --list ${NEW_RELEASE_BRANCH}"
- echo '-[ Prepared tag ]-------------------------------------------------------------'
- sh "git tag --list ${NEW_RELEASE_BRANCH}"
- echo '-[ Prepared commits ]---------------------------------------------------------'
- sh 'git log -n 5'
- sshagent([CREDENTIALS_ID]) {
- sh "git push ${GIT_ORIGIN} ${NEW_RELEASE_BRANCH} --dry-run"
- }
- return
- } else {
- sshagent([CREDENTIALS_ID]) {
- sh "git push -f ${GIT_ORIGIN} ${NEW_RELEASE_BRANCH} --follow-tags"
- }
- }
- }
- stage('Find related staging') {
- if (DRY_RUN != 'true') {
- if (!STAGING_NAME?.trim()) {
- try {
- STAGING_NAME =
- sh(returnStdout: true,
- script: "mvn -Djersey.version=${RELEASE_VERSION} -B --non-recursive -Pstaging nexus-staging:rc-list | awk '/$STAGING_NAME_PATTERN OPEN / {if(a){a = \$2\",\"a} else{a = \$2}}END{print a}'"
- ).trim()
- } catch (Error err) {
- currentBuild.result = 'UNSTABLE'
- }
- }
- echo 'Staging name: ' + STAGING_NAME
- } else {
- echo 'DRY_RUN'
- }
- }
- stage('Close released staging') {
- if (!STAGING_NAME?.trim()) {
- echo 'Nothing to be closed'
- } else {
- sh("mvn -B -q -Pstaging -Djersey.version=${RELEASE_VERSION} nexus-staging:rc-close -DstagingRepositoryId=${STAGING_NAME} -DstagingDescription='${STAGING_DESC}'")
- }
- }
- stage('Drop redundant staging') {
- if (!STAGING_PREV_NAME?.trim()) {
- echo 'Nothing to be dropped'
- } else {
- try {
- sh("""
- OPEN_STAGINGS=${STAGING_PREV_NAME}
- mvn -Djersey.version=${RELEASE_VERSION} -B -q -Pstaging nexus-staging:rc-drop -DstagingRepositoryId=\${OPEN_STAGINGS}
- """)
- } catch (Error err) {
- currentBuild.result = 'UNSTABLE'
- }
- }
- }
-}
\ No newline at end of file
diff --git a/etc/scripts/release/EE8/bundle-apidocs.sh b/etc/scripts/release/EE8/bundle-apidocs.sh
deleted file mode 100644
index dc360cc..0000000
--- a/etc/scripts/release/EE8/bundle-apidocs.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for releasing api docs bundle by release tag.
-#
-# Input Parameters:
-#
-# VERSION - type: String
-# - example: 2.42
-# - description: Name of the existing version tag in the Git repo.
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk8-latest
-# Git:
-# git@github.com:eclipse-ee4j/jersey.git
-# Branches to build:
-# tags/${VERSION}
-#
-# Bindings:
-# Secret file:
-# Variable:
-# KEYRING
-# Credentials:
-# secret-subkeys.asc
-#
-#
-
-
- gpg --batch --import ${KEYRING}
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
-
- # Execution environment
- MVN_HOME="/opt/tools/apache-maven/latest/"
- PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
- if [[ $VERSION == 2* ]] ;
- then
- export PROFILE_BUNDLE=',jetty2x'
- fi
-
- sed -i "s|org.glassfish.jersey.ext.micrometer|org.glassfish.jersey.ext|g" bundles/apidocs/pom.xml
-
- echo '-[ Run maven release plugin ]---------------------------------------------------'
-
- mvn -q -C -DstagingDescription="org.glassfish.jersey.bundles.apidocs:${VERSION}" \
- -Pstaging,oss-release,pre-release${PROFILE_BUNDLE} -DskipTests -Denforcer.skip -pl bundles/apidocs \
- install javadoc:jar gpg:sign deploy -Dsource.mvn.plugin.version=3.2.0
\ No newline at end of file
diff --git a/etc/scripts/release/EE8/bundle-examples.sh b/etc/scripts/release/EE8/bundle-examples.sh
deleted file mode 100644
index 61afc00..0000000
--- a/etc/scripts/release/EE8/bundle-examples.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for releasing examples bundle by release tag.
-#
-# Input Parameters:
-#
-# VERSION - type: String
-# - example: 2.42
-# - description: Name of the existing version tag in the Git repo.
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk8-latest
-# Git:
-# git@github.com:eclipse-ee4j/jersey.git
-# Branches to build:
-# tags/${VERSION}
-#
-# Bindings:
-# Secret file:
-# Variable:
-# KEYRING
-# Credentials:
-# secret-subkeys.asc
-#
-#
-
-
- gpg --batch --import ${KEYRING}
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
-
- # Execution environment
- MVN_HOME="/opt/tools/apache-maven/latest/"
- PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
- mvn clean install -C -B -DskipTests -Denforcer.skip -Ppre-release,staging -pl org.glassfish.jersey.examples:project -amd
-
- mvn -C -B -DstagingDescription="org.glassfish.jersey.examples:${VERSION}" \
- -Pstaging,oss-release,pre-release -Denforcer.skip=true \
- -DskipTests -pl :jersey-examples \
- deploy
\ No newline at end of file
diff --git a/etc/scripts/release/EE8/bundle-user-guide.sh b/etc/scripts/release/EE8/bundle-user-guide.sh
deleted file mode 100644
index f6a121d..0000000
--- a/etc/scripts/release/EE8/bundle-user-guide.sh
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for releasing User Guide bundle by release tag.
-#
-# Input Parameters:
-#
-# VERSION - type: String
-# - example: 2.42
-# - description: Name of the existing version tag in the Git repo.
-#
-# Configuration:
-#
-# JDK:
-# oracle-jdk11-latest
-# Git:
-# git@github.com:eclipse-ee4j/jersey.git
-# Credentials:
-# GitHub bot SSH
-# Branches to build:
-# refs/tags/${VERSION}
-#
-# Bindings:
-# Secret file:
-# Variable:
-# KEYRING
-# Credentials:
-# secret-subkeys.asc
-#
-#
-
-
- gpg --batch --import ${KEYRING}
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
-
- # Execution environment
- MVN_HOME="/opt/tools/apache-maven/latest/"
- PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
- echo '-[ Set version to ]-'${VERSION}
-
- mvn -q -Pstaging versions:set -DnewVersion=${VERSION} -DgenerateBackupPoms=false -Djersey.version=${VERSION}
-
- cd docs
-
- echo '-[ Run maven release plugin ]---------------------------------------------------'
-
- mvn -q -C -DstagingDescription="org.glassfish.jersey.jersey-documentation:${VERSION}" \
- -Pstaging,oss-release,pre-release \
- -DskipTests \
- -Djersey.version=${VERSION} \
- install javadoc:jar gpg:sign deploy
\ No newline at end of file
diff --git a/etc/scripts/release/EE8/release.groovy b/etc/scripts/release/EE8/release.groovy
deleted file mode 100644
index 3a88d31..0000000
--- a/etc/scripts/release/EE8/release.groovy
+++ /dev/null
@@ -1,347 +0,0 @@
-#!/usr/bin/env groovy
-
-/*
- * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0, which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the
- * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- * version 2 with the GNU Classpath Exception, which is available at
- * https://www.gnu.org/software/classpath/license.html.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- */
-
-/**
- * Release script for Jakarta EE8/9 Jersey versions
- * Release branches are 2.x or 3.0
- *
- * Input Parameters:
- * RELEASE_VERSION - type: String
- * - example: 2.42
- * - Description: mandatory release version. Later is being published to staging/central.
- * NEXT_VERSION - type: String
- * - example: 2.43-SNAPSHOT
- * - Description: mandatory next developing version will be committed in to the release branch and later
- * merged into the original release branch for further developing.
- * BRANCH - type: Choice Parameter
- * - values: 2.x
- * 3.0
- * - Description: Original release branch from which the codebase is being checked out
- * DRY_RUN - type: Boolean
- * - Description: if checked nothing is really committed to Git nor published to the staging
- * OVERWRITE - type: Boolean
- * - Description: if checked allows replacing of the previously published RELEASE_VERSION of Jersey
- *
- */
-
-node {
-
- def MVN_HOME = tool name: 'apache-maven-latest', type: 'maven'
- def HELP_PLUGIN = 'org.apache.maven.plugins:maven-help-plugin:2.1.1'
- def TARGET = 'package javadoc:jar gpg:sign install:install'
- def DEPLOY_TARGET = ''
- def RELEASE_VERSION = RELEASE_VERSION
- def NEXT_VERSION = NEXT_VERSION
- def RELEASE_TAG = ''
- def NEW_RELEASE_BRANCH = ''
- def OVERWRITE = OVERWRITE
- def PROJECT_NAME = 'Jersey'
- def LOGIN = 'jersey-bot'
- def EMAIL = 'jersey-bot@eclipse.org'
- def REPO = 'git@github.com:eclipse-ee4j/jersey.git'
- def SECRET_FILE_ID = 'secret-subkeys.asc'
- def CREDENTIALS_ID = 'github-bot-ssh'
- def GIT_ORIGIN = 'origin'
- def RELEASE_FOLDER = env.WORKSPACE
- def RELEASE_BRANCH = BRANCH
-
- def STAGING_NAME_PATTERN = 'orgglassfishjersey-[0-9]+'
- def STAGING_NAME = ''
- def STAGING_PREV_NAME = ''
- def STAGING_OPEN_NAME = ''
- def STAGING_DESC = 'org.glassfish.jersey:' + RELEASE_VERSION
- def STAGING_BOM_DESC = 'org.glassfish.jersey.bom:' + RELEASE_VERSION
- def STAGING_PROFILE_ID = '70fa3a107a8918'
-
- def JDK_11_HOME = tool name: 'openjdk-jdk11-latest', type: 'jdk'
- def JDK_12_HOME = tool name: 'openjdk-jdk12-latest', type: 'jdk'
- def JDK_17_HOME = tool name: 'openjdk-jdk17-latest', type: 'jdk'
- def JDK_8_HOME = tool name: 'oracle-jdk8-latest', type: 'jdk'
-
- def ZX_BRANCH_MODULES = ',:jersey-jetty-connector,:jersey-container-jetty-http,:jersey-container-jetty-servlet,:jersey-test-framework-provider-jetty,:jersey-test-framework-core,:jersey-container-servlet-core'
-
- env.JAVA_HOME = JDK_8_HOME
- env.PATH = "${env.JAVA_HOME}/bin:${env.PATH}:${MVN_HOME}/bin"
-
- if (RELEASE_BRANCH == '2.x') {
- ZX_BRANCH_MODULES = ''
- }
-
- sh 'java -version'
-
- stage('Fetch from git') {
- git(branch: RELEASE_BRANCH, credentialsId: CREDENTIALS_ID, url: REPO)
- }
- stage('Prepare environment') {
-
- dir(RELEASE_FOLDER) {
- //# Check whether top level pom.xml contains SNAPSHOT version
- if (!sh(returnStdout: true, script: "grep '<version>' pom.xml | grep 'SNAPSHOT'")?.trim()) {
- error('-[ Missing SNAPSHOT version in POM! ]-------------------------------------------')
- }
-
- //# Compute release versions
- def SNAPSHOT_VERSION = sh(returnStdout: true, script: 'mvn -q -Dexec.executable="echo" -Dexec.args=\'${project.version}\' --non-recursive exec:exec -Pstaging').trim()
-
- if (!RELEASE_VERSION?.trim()) {
- if (!SNAPSHOT_VERSION?.trim()) {
- error('-[ Missing required snapshot version number! ]----------------------------------')
- } else {
- def versionTokens = SNAPSHOT_VERSION.split('-')
- RELEASE_VERSION = versionTokens[0]
- }
- }
-
- if (!NEXT_VERSION?.trim()) {
- def (MAJOR_VERSION, MINOR_VERSION) = RELEASE_VERSION.tokenize('.')
- def NEXT_MINOR_VERSION = (MINOR_VERSION as Integer) + 1
- NEXT_VERSION = MAJOR_VERSION + '.' + NEXT_MINOR_VERSION + '-SNAPSHOT'
- }
-
- RELEASE_TAG = RELEASE_VERSION
- NEW_RELEASE_BRANCH = RELEASE_VERSION+'-BRANCH'
-
- echo "Current version: ${SNAPSHOT_VERSION}"
- echo "Release version: ${RELEASE_VERSION}"
- echo "Next version: ${NEXT_VERSION}"
- echo "Release tag: ${RELEASE_TAG}"
- echo "Release branch: ${NEW_RELEASE_BRANCH}"
-
- if (!SNAPSHOT_VERSION?.trim() || !RELEASE_VERSION?.trim() || !NEXT_VERSION?.trim()) {
- error '-[ Missing required version numbers! ]------------------------------------------'
- }
-
- if (DRY_RUN == 'true') {
- echo '-[ Dry run turned on ]----------------------------------------------------------'
- //TARGET = 'install'
- } else {
- DEPLOY_TARGET = ' deploy:deploy'
- }
- echo '-[ Configure git user ]--------------------------------------------------------'
- sh "git config --local user.email \"${EMAIL}\""
- sh "git config --local user.name \"$LOGIN\""
-
- }
-
- }
- stage('Prepare GPG') {
- withCredentials([file(credentialsId: SECRET_FILE_ID, variable: 'KEYRING')]) {
- //# Workaround: GPG initialization
- sh("gpg --batch --import ${KEYRING}")
- sh '''
- for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
- do
- echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
- done
- '''
- }
- }
- stage('Prepare branch') {
- echo '-[ Prepare branch ]-------------------------------------------------------------'
-
- echo '-[ Switching to release branch ]-------------------------------------------------'
- sh """
- git checkout ${GIT_ORIGIN}/${RELEASE_BRANCH} && true
- git reset --hard ${GIT_ORIGIN}/${RELEASE_BRANCH} && true
- git checkout -B ${NEW_RELEASE_BRANCH}
- """
- echo '-[ Release tag cleanup ]--------------------------------------------------------'
- def TAG_NAME = sh(returnStdout: true, script: "git tag | grep ${RELEASE_TAG} || true").trim()
- if (RELEASE_TAG == TAG_NAME) {
- if (OVERWRITE == 'true') {
- echo "${RELEASE_TAG} tag already exists, deleting"
- sshagent([CREDENTIALS_ID]) {
- sh "git push --delete origin ${RELEASE_TAG} && true"
- }
- } else {
- error "${RELEASE_TAG} tag already exists"
- }
- //# Always delete local tag if exists
- sh """
- git tag --delete ${RELEASE_TAG} && true
- """
- }
- sh '''
- sed -i 's|<suppress files="generated" checks=".*"/>|<suppress files="generated" checks=".*"/><suppress files="unpacked-src" checks=".*"/>|g' etc/config/checkstyle-suppressions.xml
- '''
- }
- stage('Check previous stagings') {
- if (DRY_RUN == 'true') {
- echo DRY_RUN + ' ------'
- } else {
- if (OVERWRITE == 'true') {
- STAGING_PREV_NAME = sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging nexus-staging:rc-list | awk '/\\[INFO] $STAGING_NAME_PATTERN[ ]+CLOSED[ ]+$STAGING_DESC[ ]*\$/ {if(a){a = \$2\",\"a} else{a = \$2}}END{print a}'").trim()
- echo 'Previously closed staging name: ' + STAGING_PREV_NAME
- }
-
- STAGING_OPEN_NAME = sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging nexus-staging:rc-list | awk '/$STAGING_NAME_PATTERN OPEN / {if(a){a = \$2\",\"a} else{a = \$2}}END{print a}'").trim()
-
- if (!STAGING_OPEN_NAME?.trim()) {
- echo 'No currently open stagings'
- } else {
- echo 'Currently open redundand staging: ' + STAGING_OPEN_NAME + ', immediately closing'
- sh """
- OPEN_STAGINGS=${STAGING_OPEN_NAME}
- mvn -B -q -Pstaging nexus-staging:rc-drop -DstagingRepositoryId=\${OPEN_STAGINGS}
- """
- }
- }
- }
- /*
- stage('Open new staging') {
- if (DRY_RUN == 'true') {
- echo DRY_RUN + ' ------'
- } else {
- STAGING_NAME = sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging -DstagingProfileId=${STAGING_PROFILE_ID} -DstagingDescription=${STAGING_DESC} nexus-staging:rc-open | awk '/\\[INFO] Opened / {print \$3}'").trim()
- echo 'New staging name: '+STAGING_NAME
- }
- }*/
- stage("Build ${PROJECT_NAME}") {
- echo env.JAVA_HOME
- echo '-[ Run maven release ]---------------------------------------------------------'
- echo '-[ Set Release version ]-------------------------------------------------------'
- sh """
- cd ${RELEASE_FOLDER}
- mvn -B -V -Pstaging versions:set -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false
- cd bom
- mvn -B -V -Pstaging versions:set -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false
- cd ..
- """
- echo '-[ Update Copyright years ]----------------------------------------------------'
- sh '''#!/bin/bash -e
-
- export CURRENT_YEAR=`date '+%Y'`
- export SED_CMD_LINE='sed -i "s#, 20.. Oracle and/or its affiliates#, ${CURRENT_YEAR} Oracle and/or its affiliates#g"'
-
- git status --porcelain --untracked-files=no > modified_pom.log
- cp modified_pom.log list_of_poms.txt
- sed -i "s| M |$SED_CMD_LINE |g" modified_pom.log
- sed -i "s| M ||g" list_of_poms.txt
-
- bash modified_pom.log
-
- echo ${CURRENT_YEAR} current year
-
- while IFS= read -r path_to_pom
- do
- export CP_YEAR=`grep -o 'Copyright (c) 20.. Oracle and/or its affiliates' ${path_to_pom} | awk '{print $3}'`
- [[ -z ${CP_YEAR} ]] && CP_YEAR=${CURRENT_YEAR} || echo ${CP_YEAR}
- [[ ${CP_YEAR} == ${CURRENT_YEAR} ]] || ( sed -i "s#Copyright (c) ${CP_YEAR} Oracle and/or its affiliates#Copyright (c) ${CP_YEAR}, ${CURRENT_YEAR} Oracle and/or its affiliates#g" ${path_to_pom} ; echo ${path_to_pom} )
- unset CP_YEAR
- done < "list_of_poms.txt"
- '''
- echo '-[ Run release build ]---------------------------------------------------------'
- dir(RELEASE_FOLDER) {
- env.JAVA_HOME = JDK_12_HOME
- //
- sh "mvn -am -Pstaging --projects core-server,core-client,media/jaxb,inject/hk2,ext/wadl-doclet,core-common${ZX_BRANCH_MODULES} clean install -B -q -V -DskipTests"
- if (RELEASE_BRANCH == '3.0') {
- env.JAVA_HOME = JDK_17_HOME
- sh "mvn clean install -B -q -V -DskipTests -am -Pstaging --projects :jersey-spring6,connectors/helidon-connector"
- }
- env.JAVA_HOME = JDK_8_HOME
- sh "mvn -q -B -V -DskipTests -Ddoclint=none -Dadditionalparam='-Xdoclint:none' -Dcheckstyle.skip " +
- //" -DstagingDescription='${STAGING_DESC}' -DstagingRepositoryId='${STAGING_NAME}' "+
- " -Poss-release,staging -U -C ${TARGET} ${DEPLOY_TARGET}"
-
- sh "mvn -Poss-release,staging --projects core-server,core-client,media/jaxb,inject/hk2,ext/wadl-doclet,core-common install gpg:sign ${DEPLOY_TARGET} -B -q -V -DskipTests"
- if (RELEASE_BRANCH == '2.x') {
- env.JAVA_HOME = JDK_11_HOME
- sh "mvn -Poss-release,staging --projects connectors/helidon-connector install gpg:sign ${DEPLOY_TARGET} -B -q -V -DskipTests"
- }
- }
- }
- stage('Prepare release') {
- sh '''
- git checkout -- etc/config/checkstyle-suppressions.xml
- '''
- echo '-[ Perform release commit to git ]---------------------------------------------'
- sh "git commit -a -m ${RELEASE_VERSION}"
- sh "git tag -m ${RELEASE_TAG} -a ${RELEASE_TAG}"
- echo '-[ Set next snapshot version ]-------------------------------------------------'
- dir(RELEASE_FOLDER) {
- sh """
- mvn -B -Pstaging versions:set -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false
- cd bom
- mvn -B -Pstaging versions:set -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false
- cd ..
- """
- }
- echo '-[ Perform commit to git ]-----------------------------------------------------'
- sh "git commit -a -m ${NEXT_VERSION}"
- }
- stage('Publish release') {
- if (DRY_RUN == 'true') {
- echo '-[ Prepared branch ]----------------------------------------------------------'
- sh "git branch --list ${NEW_RELEASE_BRANCH}"
- echo '-[ Prepared tag ]-------------------------------------------------------------'
- sh "git tag --list ${NEW_RELEASE_BRANCH}"
- echo '-[ Prepared commits ]---------------------------------------------------------'
- sh 'git log -n 5'
- sshagent([CREDENTIALS_ID]) {
- sh "git push ${GIT_ORIGIN} ${NEW_RELEASE_BRANCH} --dry-run"
- }
- return
- } else {
- sshagent([CREDENTIALS_ID]) {
- sh "git push -f ${GIT_ORIGIN} ${NEW_RELEASE_BRANCH} --follow-tags"
- }
- }
- }
- stage('Find related staging') {
- if (DRY_RUN != 'true') {
- if (!STAGING_NAME?.trim()) {
- try {
- STAGING_NAME =
- sh(returnStdout: true,
- script: "mvn -B --non-recursive -Pstaging nexus-staging:rc-list | awk '/$STAGING_NAME_PATTERN OPEN / {if(a){a = \$2\",\"a} else{a = \$2}}END{print a}'"
- ).trim()
- } catch (Error err) {
- currentBuild.result = 'UNSTABLE'
- }
- }
- echo 'Staging name: ' + STAGING_NAME
- } else {
- echo 'DRY_RUN'
- }
- }
- stage('Close released staging') {
- if (!STAGING_NAME?.trim()) {
- echo 'Nothing to be closed'
- } else {
- sh("mvn -B -q -Pstaging nexus-staging:rc-close -DstagingRepositoryId=${STAGING_NAME} -DstagingDescription='${STAGING_DESC}'")
- }
- }
- stage('Drop redundant staging') {
- if (!STAGING_PREV_NAME?.trim()) {
- echo 'Nothing to be dropped'
- } else {
- try {
- sh("""
- OPEN_STAGINGS=${STAGING_PREV_NAME}
- mvn -B -q -Pstaging nexus-staging:rc-drop -DstagingRepositoryId=\${OPEN_STAGINGS}
- """)
- } catch (Error err) {
- currentBuild.result = 'UNSTABLE'
- }
- }
- }
-}
\ No newline at end of file
diff --git a/etc/scripts/release/Release-After/list-closed-stagings.sh b/etc/scripts/release/Release-After/list-closed-stagings.sh
deleted file mode 100644
index d5f32ca..0000000
--- a/etc/scripts/release/Release-After/list-closed-stagings.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for listing staging from the staging repo.
-#
-# Input Parameters:
-# ----none----
-# Configuration:
-#
-# JDK:
-# (System)
-# Git:
-# ----none----
-#
-#
-
-cat <<EOT >> pom.xml
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v. 2.0, which is available at
- http://www.eclipse.org/legal/epl-2.0.
-
- This Source Code may also be made available under the following Secondary
- Licenses when the conditions for such availability set forth in the
- Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- version 2 with the GNU Classpath Exception, which is available at
- https://www.gnu.org/software/classpath/license.html.
-
- SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-
--->
-
-<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/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.eclipse.ee4j</groupId>
- <artifactId>project</artifactId>
- <version>1.0.9</version>
- <relativePath/>
- </parent>
-
- <groupId>org.glassfish.jersey</groupId>
- <artifactId>release-helper-util</artifactId>
- <version>1.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
-
- <name>Jersey Release Helper</name>
-
- <description>Generated POM for Jersey Release Helper utils</description>
- <url>https://projects.eclipse.org/projects/ee4j.jersey</url>
-
- <scm>
- <connection>scm:git:git://github.com/eclipse-ee4j/jersey</connection>
- <developerConnection>scm:git:git://github.com/eclipse-ee4j/jersey</developerConnection>
- <url>https://github.com/eclipse-ee4j/jersey</url>
- </scm>
-
-</project>
-EOT
-
-MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
-export STAGING_PARAMS='-DnexusUrl=https://jakarta.oss.sonatype.org/ -DserverId=ossrh'
-export STAGING_PLUGIN='org.sonatype.plugins:nexus-staging-maven-plugin:1.6.7'
-
-
-mvn -B ${STAGING_PARAMS} ${STAGING_PLUGIN}:rc-list | grep orgglassfishjersey > closed_stagings.txt || true
-
-
-#
-#
-# Archive the artifacts:
-# closed_stagings.txt
-#
diff --git a/etc/scripts/release/Release-After/populate-documentation.sh b/etc/scripts/release/Release-After/populate-documentation.sh
deleted file mode 100644
index 025e512..0000000
--- a/etc/scripts/release/Release-After/populate-documentation.sh
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/bin/bash -lex
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for api docs publishing. Publishes api docs from the bundle in the Maven Central to the project's site.
-#
-# Input Parameters:
-# RELEASE_VERSION - type: String
-# - example: 3.1.6
-# - description: version for which project info is being published
-# DRY_RUN - type: Boolean
-# - description: If checked nothing is being published/generated
-# WEBSITE_URL - type: String
-# - value: git@github.com:eclipse-ee4j/jersey.github.io.git
-# - description: GitHub url for the project info/apidocs repository.
-# Mandatory and changes only in exceptional cases
-# BRANCH_SPECIFIER - type: String
-# - example: 2.x
-# - description: Branch for which the api docs are being published. Used only in Git commit message
-# UPDATE_LATEST - type: Boolean
-# - description: If checked updates the latest api docs (distinguishes for EE8/EE9/EE10) along
-# with publication into the RELEASE_VERSION folder.
-# Configuration:
-#
-# JDK:
-# oracle-jdk8-latest
-# Git:
-# ----none----
-#
-# SSH agent:
-# GitHub bot SSH
-#
-#
-#
-
-
-#
-# The first shell execution
-#
-
-
-TOOLS_PREFIX=/opt/tools
-#JAVA_PREFIX=/opt/tools/java/oracle
-MVN_HOME=/opt/tools/apache-maven/latest
-#JAVA_HOME=/opt/tools/java/oracle/jdk-8/latest
-PATH=/opt/tools/apache-maven/latest/bin:${JAVA_HOME}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-
-export CENTRAL_URL='https://repo1.maven.org/maven2'
-export STAGING_URL='https://jakarta.oss.sonatype.org/content/repositories/staging'
-
-# !!! if build docbook it's essentially important to turn the pre-release profile ON !!!
-#mvn clean install -Pstaging,pre-release -DskipTests -V -q -e -U -B -f docs/pom.xml -Djersey.version=$RELEASE_VERSION
-# however we download already published docbook from staging/central:
-mkdir -p $WORKSPACE/docs/target/docbook/index
-cd $WORKSPACE/docs/target/docbook/index
-wget -nv ${STAGING_URL}/org/glassfish/jersey/jersey-documentation/${RELEASE_VERSION}/jersey-documentation-${RELEASE_VERSION}-docbook.zip
-unzip -o jersey-documentation-${RELEASE_VERSION}-docbook.zip
-rm jersey-documentation-${RELEASE_VERSION}-docbook.zip
-
-mkdir -p $WORKSPACE/target/site/apidocs
-cd $WORKSPACE/target/site/apidocs
-wget -nv ${STAGING_URL}/org/glassfish/jersey/bundles/apidocs/${RELEASE_VERSION}/apidocs-${RELEASE_VERSION}-javadoc.jar -O apidocs-javadoc.jar
-jar -xf apidocs-javadoc.jar
-rm apidocs-javadoc.jar
-rm -rf META-INF
-
-
-#
-# The second shell execution
-#
-
-
-#!/bin/bash -lex
-
-TOOLS_PREFIX=/opt/tools
-#JAVA_PREFIX=/opt/tools/java/oracle
-MVN_HOME=/opt/tools/apache-maven/latest
-#JAVA_HOME=/opt/tools/java/oracle/jdk-8/latest
-PATH=/opt/tools/apache-maven/latest/bin:${JAVA_HOME}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-
-DIRS="$RELEASE_VERSION"
-if $UPDATE_LATEST;
-then
- if [[ $RELEASE_VERSION == 2* ]] ;
- then
- export DIRS="latest $DIRS"
- elif [[ $RELEASE_VERSION == 3.1* ]] ;
- then
- export DIRS="latest31x $DIRS"
- else
- export DIRS="latest30x $DIRS"
- fi
- echo ${DIRS} for ${RELEASE_VERSION} release
-fi
-
-#export PATH=/opt/csw/bin:$PATH
-WEB_DIR=$WORKSPACE/target/jersey-web
-
-
-function copyDocs {
- APIDOCS_DIR=$WEB_DIR/apidocs/$1
- DOCS_DIR=$WEB_DIR/documentation/$1
-
- #
- # API docs
- #
- if test ! -e $APIDOCS_DIR ; then
- mkdir -p $APIDOCS_DIR
- fi
- cd $APIDOCS_DIR
-
- rm -rf jersey || true
- cp -R $WORKSPACE/target/site/apidocs ./jersey
-
- #
- # user guide
- #
- rm -rf $DOCS_DIR || true
- mkdir -p $DOCS_DIR
- cp -r $WORKSPACE/docs/target/docbook/index/* $DOCS_DIR
- rm $DOCS_DIR/*.fo || true
-}
-
-if test -e $WEB_DIR ; then
- rm -rf $WEB_DIR
-fi
-
-# would couse shallow reject: git clone --depth 1 $WEBSITE_URL $WEB_DIR
-git clone $WEBSITE_URL $WEB_DIR
-
-cd $WEB_DIR
-
-for dir in $DIRS; do
- copyDocs $dir
-done
-
-cd $WEB_DIR
-
-git config --local user.email "jersey-bot@eclipse.org"
-git config --local user.name "jersey-bot"
-git add -A .
-git diff --cached --exit-code || git commit -m "[jenkins] automatic javadoc and documentation update [$RELEASE_VERSION @ $BRANCH_SPECIFIER]"
-
-if [ "$DRY_RUN" = "false" ]; then
- echo "Pushing Web sources to $WEBSITE_URL"
- git push origin master
-else
- echo "Dry run .. not pushing to the master"
- git push origin master --dry-run
-fi
-
-
diff --git a/etc/scripts/release/Release-After/publish-release-notes.sh b/etc/scripts/release/Release-After/publish-release-notes.sh
deleted file mode 100644
index d547134..0000000
--- a/etc/scripts/release/Release-After/publish-release-notes.sh
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for publishing listed stagings from the staging repo into the Maven Central.
-#
-# Input Parameters:
-# VERSION - type: String
-# - example: 3.1.6
-# - description: version for which release notes are being published
-# DRY_RUN - type: Boolean
-# - description: If checked nothing is being published/generated
-# PUBLISH_TO_GITHUB - type: Boolean
-# - description: If checked generated notes are propagated to GitHub
-# Configuration:
-#
-# JDK:
-# oracle-jdk8-latest
-# Git:
-# https://github.com/eclipse-ee4j/jersey
-#
-# Bindings:
-# Username and password (separated):
-# Username Variable:
-# BOT_NAME
-# Password Variable:
-# BOT_PASSWORD
-# Credentials:
-# GitHub bot (username/token)
-#
-#
-#
-
-
-cat <<EOT >> pom.xml
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v. 2.0, which is available at
- http://www.eclipse.org/legal/epl-2.0.
-
- This Source Code may also be made available under the following Secondary
- Licenses when the conditions for such availability set forth in the
- Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- version 2 with the GNU Classpath Exception, which is available at
- https://www.gnu.org/software/classpath/license.html.
-
- SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-
--->
-
-<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/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.eclipse.ee4j</groupId>
- <artifactId>project</artifactId>
- <version>1.0.9</version>
- <relativePath/>
- </parent>
-
- <groupId>org.glassfish.jersey</groupId>
- <artifactId>release-helper-util</artifactId>
- <version>1.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
-
- <name>Jersey Release Helper</name>
-
- <description>Generated POM for Jersey Release Helper utils</description>
- <url>https://projects.eclipse.org/projects/ee4j.jersey</url>
-
- <scm>
- <connection>scm:git:git://github.com/eclipse-ee4j/jersey</connection>
- <developerConnection>scm:git:git://github.com/eclipse-ee4j/jersey</developerConnection>
- <url>https://github.com/eclipse-ee4j/jersey</url>
- </scm>
-
-</project>
-EOT
-
-# Execution environment
-readonly MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-readonly RELEASE_DATE=`date -I`
-
-mkdir -p target
-
-mvn -B -V org.glassfish.jersey.tools.plugins:jersey-release-notes-maven-plugin:1.0.1:release-notes -DskipTests \
--DreleaseVersion=${VERSION} -DgithubLogin=${BOT_NAME} -DgithubPassword=${BOT_PASSWORD} \
--DtemplateFilePath=release-note.html -DreleaseDate=${RELEASE_DATE} \
--DdryRun=${DRY_RUN} -DpublishToGithub=${PUBLISH_TO_GITHUB}
-
-cp -a `pwd`/target/release-notes ${WORKSPACE}
\ No newline at end of file
diff --git a/etc/scripts/release/Release-After/release-note.html b/etc/scripts/release/Release-After/release-note.html
deleted file mode 100644
index f0e5996..0000000
--- a/etc/scripts/release/Release-After/release-note.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<html>
-<!--
-
- Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v. 2.0, which is available at
- http://www.eclipse.org/legal/epl-2.0.
-
- This Source Code may also be made available under the following Secondary
- Licenses when the conditions for such availability set forth in the
- Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- version 2 with the GNU Classpath Exception, which is available at
- https://www.gnu.org/software/classpath/license.html.
-
- SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-
--->
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
- <meta name="google-site-verification" content="OiKukTHVW4bdQqx8Fq0zA2EZ_hI6-yYL-MvkCxBxaFs" />
- <title>Release Notes - Jersey @LATEST_VERSION@</title>
-</head>
-
-<body>
-
-<h1>Release Notes - <a href="/">Jersey</a> @LATEST_VERSION@</h1>
-
-Release date: <strong>@RELEASE_DATE@</strong>
-
-<h2>Previous releases</h2>
-
-<ul>
- <li><a href="2.29.1.html">Jersey 2.29.1 Release Notes</a></li>
- <li><a href="2.29.html">Jersey 2.29 Release Notes</a></li>
- <li><a href="2.28.html">Jersey 2.28 Release Notes</a></li>
- <li><a href="2.25.1.html">Jersey 2.25.1 Release Notes</a></li>
- <li><a href="2.25.html">Jersey 2.25 Release Notes</a></li>
- <li><a href="2.24.1.html">Jersey 2.24.1 Release Notes</a></li>
- <li><a href="2.24.html">Jersey 2.24 Release Notes</a></li>
- <li><a href="2.23.2.html">Jersey 2.23.2 Release Notes</a></li>
- <li><a href="2.23.1.html">Jersey 2.23.1 Release Notes</a></li>
- <li><a href="2.23.html">Jersey 2.23 Release Notes</a></li>
- <li><a href="2.22.2.html">Jersey 2.22.2 Release Notes</a></li>
- <li><a href="2.22.1.html">Jersey 2.22.1 Release Notes</a></li>
- <li><a href="2.22.html">Jersey 2.22 Release Notes</a></li>
- <li><a href="2.21.1.html">Jersey 2.21.1 Release Notes</a></li>
- <li><a href="2.21.html">Jersey 2.21 Release Notes</a></li>
- <li><a href="2.20.html">Jersey 2.20 Release Notes</a></li>
- <li><a href="2.19.html">Jersey 2.19 Release Notes</a></li>
- <li><a href="2.18.html">Jersey 2.18 Release Notes</a></li>
- <li><a href="2.17.html">Jersey 2.17 Release Notes</a></li>
- <li><a href="2.16.html">Jersey 2.16 Release Notes</a></li>
- <li><a href="2.14.html">Jersey 2.14 Release Notes</a></li>
- <li><a href="2.13.html">Jersey 2.13 Release Notes</a></li>
- <li><a href="2.12.html">Jersey 2.12 Release Notes</a></li>
- <li><a href="2.11.html">Jersey 2.11 Release Notes</a></li>
- <li><a href="2.10.1.html">Jersey 2.10.1 Release Notes</a></li>
- <li><a href="2.10.html">Jersey 2.10 Release Notes</a></li>
- <li><a href="2.9.1.html">Jersey 2.9.1 Release Notes</a></li>
- <li><a href="2.9.html">Jersey 2.9 Release Notes</a></li>
- <li><a href="2.8.html">Jersey 2.8 Release Notes</a></li>
- <li><a href="2.7.html">Jersey 2.7 Release Notes</a></li>
- <li><a href="2.6.html">Jersey 2.6 Release Notes</a></li>
- <li><a href="2.5.1.html">Jersey 2.5.1 Release Notes</a></li>
- <li><a href="2.5.html">Jersey 2.5 Release Notes</a></li>
- <li><a href="2.4.1.html">Jersey 2.4.1 Release Notes</a></li>
- <li><a href="2.4.html">Jersey 2.4 Release Notes</a></li>
- <li><a href="2.3.1.html">Jersey 2.3.1 Release Notes</a></li>
- <li><a href="2.3.html">Jersey 2.3 Release Notes</a></li>
- <li><a href="2.2.html">Jersey 2.2 Release Notes</a></li>
- <li><a href="2.1.html">Jersey 2.1 Release Notes</a></li>
- <li><a href="2.0.html">Jersey 2.0 Release Notes</a></li>
-</ul>
-
-</body>
-</html>
diff --git a/etc/scripts/release/Release-After/release-project-info.sh b/etc/scripts/release/Release-After/release-project-info.sh
deleted file mode 100644
index ebfe9b1..0000000
--- a/etc/scripts/release/Release-After/release-project-info.sh
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/bin/bash -lex
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for project info publishing. MUST BE RUN ONLY AFTER THE APIDOCS PUBLISHING.
-#
-# Input Parameters:
-# RELEASE_VERSION - type: String
-# - example: 3.1.6
-# - description: version for which project info is being published
-# DRY_RUN - type: Boolean
-# - description: If checked nothing is being published/generated
-# WEBSITE_URL - type: String
-# - value: git@github.com:eclipse-ee4j/jersey.github.io.git
-# - description: GitHub url for the project info/apidocs repository.
-# Mandatory and changes only in exceptional cases
-# Configuration:
-#
-# JDK:
-# openjdk-jdk11-latest
-# Git:
-# https://github.com/eclipse-ee4j/jersey
-#
-# Branches to build:
-# tags/${RELEASE_VERSION}
-#
-# SSH agent:
-# GitHub bot SSH
-#
-#
-#
-
-
-#
-# The first shell execution
-#
-
-MVN_HOME=/opt/tools/apache-maven/latest
-PATH=${PATH}:${MVN_HOME}/bin:${JAVA_HOME}/bin
-
-mvn clean install -B -V -q -PtestsSkip,checkstyleSkip -Dtests.excluded -DskipTests '-Dmaven.test.skip=true'
-
-mvn -B -V -q -Pproject-info,checkstyleSkip,testsSkip,findbugsSkip,staging site site:stage \
- -DgenerateProjectInfo=true -Dtests.excluded -Ddependency.locations.enabled=false \
- -Dmaven.jxr.skip=true -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true -DskipTests \
- -Dfindbugs.skip=true
-
-#
-# The second shell execution
-#
-
-#!/bin/bash -lex
-
-export PATH=/opt/csw/bin:$PATH
-WEB_DIR=$WORKSPACE/target/jersey-web
-PROJECT_INFO_DIR=$WEB_DIR/project-info/$RELEASE_VERSION
-
-if test -e $WEB_DIR ; then
- rm -rf $WEB_DIR
-fi
-
-# would couse shallow reject: git clone --depth 1 $WEBSITE_SOURCE_URL $WEB_DIR
-git clone $WEBSITE_URL $WEB_DIR
-cd $WEB_DIR
-
-if test ! -e $PROJECT_INFO_DIR ; then
- mkdir -p $PROJECT_INFO_DIR
-fi
-
-cd $PROJECT_INFO_DIR
-
-rm -rf jersey || true
-cp -R $WORKSPACE/target/staging ./jersey
-
-cd $WEB_DIR
-
-git config --local user.email "jersey-bot@eclipse.org"
-git config --local user.name "jersey-bot"
-git add -A .
-#git diff --cached --exit-code ||
-git commit -m "[jenkins] automatic project-info update [$RELEASE_VERSION]"
-
-if [ "$DRY_RUN" = "false" ]; then
- echo Pushing Web sources to $WEBSITE_URL
- git push origin master
-else
- echo "Dry run .. not pushing to the master"
- git push origin master --dry-run
-fi
\ No newline at end of file
diff --git a/etc/scripts/release/Release-After/release-staging-to-central.sh b/etc/scripts/release/Release-After/release-staging-to-central.sh
deleted file mode 100644
index b470730..0000000
--- a/etc/scripts/release/Release-After/release-staging-to-central.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-#
-# This program and the accompanying materials are made available under the
-# terms of the Eclipse Public License v. 2.0, which is available at
-# http://www.eclipse.org/legal/epl-2.0.
-#
-# This Source Code may also be made available under the following Secondary
-# Licenses when the conditions for such availability set forth in the
-# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
-# version 2 with the GNU Classpath Exception, which is available at
-# https://www.gnu.org/software/classpath/license.html.
-#
-# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-#
-
-#
-# script for publishing listed stagings from the staging repo into the Maven Central.
-#
-# Input Parameters:
-# STAGING_REPO_ID - type: String
-# - example: orgglassfishjersey-1226,orgglassfishjersey-1227,orgglassfishjersey-1228,orgglassfishjersey-1229,orgglassfishjersey-1230
-# - description: list all staggings (comma separated) to be published to the Maven Central
-# STAGING_DESC - type: String
-# - example:org.glassfish.jersey:2.42
-# - description: description of what is published. Usually <group.id>:<version>
-# Configuration:
-#
-# JDK:
-# (System)
-# Git:
-# ----none----
-#
-#
-
-cat <<EOT >> pom.xml
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v. 2.0, which is available at
- http://www.eclipse.org/legal/epl-2.0.
-
- This Source Code may also be made available under the following Secondary
- Licenses when the conditions for such availability set forth in the
- Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- version 2 with the GNU Classpath Exception, which is available at
- https://www.gnu.org/software/classpath/license.html.
-
- SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-
--->
-
-<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/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.eclipse.ee4j</groupId>
- <artifactId>project</artifactId>
- <version>1.0.9</version>
- <relativePath/>
- </parent>
-
- <groupId>org.glassfish.jersey</groupId>
- <artifactId>release-helper-util</artifactId>
- <version>1.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
-
- <name>Jersey Release Helper</name>
-
- <description>Generated POM for Jersey Release Helper utils</description>
- <url>https://projects.eclipse.org/projects/ee4j.jersey</url>
-
- <scm>
- <connection>scm:git:git://github.com/eclipse-ee4j/jersey</connection>
- <developerConnection>scm:git:git://github.com/eclipse-ee4j/jersey</developerConnection>
- <url>https://github.com/eclipse-ee4j/jersey</url>
- </scm>
-
-</project>
-EOT
-
-MVN_HOME="/opt/tools/apache-maven/latest/"
-PATH="${MVN_HOME}/bin:${JAVA_HOME}:/bin:${PATH}"
-
-export STAGING_PARAMS='-DnexusUrl=https://jakarta.oss.sonatype.org/ -DserverId=ossrh'
-export STAGING_PLUGIN='org.sonatype.plugins:nexus-staging-maven-plugin:1.6.7'
-
-
-mvn ${STAGING_PARAMS} -B -C -V ${STAGING_PLUGIN}:rc-release -DstagingRepositoryId="${STAGING_REPO_ID}" -DstagingDescription="${STAGING_DESC}"
-
diff --git a/etc/scripts/validation/dependency-convergence.sh b/etc/scripts/validation/dependency-convergence.sh
index 92ffeea..9bcf4fe 100755
--- a/etc/scripts/validation/dependency-convergence.sh
+++ b/etc/scripts/validation/dependency-convergence.sh
@@ -40,5 +40,11 @@
#run validation
mvn ${MVN_ARGS} ${MVN_CLI} -f ${CURRENT_LOCATION}/${VALIDATION_POM} -Djersey.version=${JERSEY_VERSION}
+#save exit status
+export MAVEN_BUILD_RESULT=$?
+
#clean the mess
-rm ${CURRENT_LOCATION}/${TEMP_FILE}
\ No newline at end of file
+rm ${CURRENT_LOCATION}/${TEMP_FILE}
+
+#exit with saved exit stateus
+exit $MAVEN_BUILD_RESULT
diff --git a/examples/oauth-client-twitter/src/main/java/org/glassfish/jersey/examples/oauth/twitterclient/App.java b/examples/oauth-client-twitter/src/main/java/org/glassfish/jersey/examples/oauth/twitterclient/App.java
index 5d39bde..e0b6f77 100644
--- a/examples/oauth-client-twitter/src/main/java/org/glassfish/jersey/examples/oauth/twitterclient/App.java
+++ b/examples/oauth-client-twitter/src/main/java/org/glassfish/jersey/examples/oauth/twitterclient/App.java
@@ -17,7 +17,7 @@
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.List;
import java.util.Properties;
@@ -145,7 +145,7 @@
private static void loadSettings() {
InputStream st = null;
try {
- st = Files.newInputStream(Paths.get(PROPERTIES_FILE_NAME));
+ st = Files.newInputStream(Path.of(PROPERTIES_FILE_NAME));
PROPERTIES.load(st);
} catch (final IOException e) {
// ignore
@@ -178,7 +178,7 @@
private static void storeSettings() {
OutputStream st = null;
try {
- st = Files.newOutputStream(Paths.get(PROPERTIES_FILE_NAME));
+ st = Files.newOutputStream(Path.of(PROPERTIES_FILE_NAME));
PROPERTIES.store(st, null);
} catch (final IOException e) {
// ignore
diff --git a/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java b/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java
index 404c63d..cfd299d 100644
--- a/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java
+++ b/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java
@@ -14,7 +14,7 @@
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
@@ -228,7 +228,7 @@
try {
- final BufferedReader reader = Files.newBufferedReader(Paths.get(felixPolicy));
+ final BufferedReader reader = Files.newBufferedReader(Path.of(felixPolicy));
String line;
final Set<String> cpiNames = new HashSet<String>();
diff --git a/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/App.java b/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/App.java
index 8e922b7..e28fe2d 100644
--- a/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/App.java
+++ b/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/App.java
@@ -18,7 +18,7 @@
import java.nio.file.Files;
import java.nio.file.FileSystems;
import java.nio.file.Path;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
@@ -72,10 +72,10 @@
try {
watcher = FileSystems.getDefault().newWatchService();
- Path srcDir = Paths.get("src/main/java/org/glassfish/jersey/examples/reload");
+ Path srcDir = Path.of("src/main/java/org/glassfish/jersey/examples/reload");
registerWatcher(watcher, srcDir);
- Path configFilePath = Paths.get(".");
+ Path configFilePath = Path.of(".");
registerWatcher(watcher, configFilePath);
} catch (IOException e) {
diff --git a/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/compiler/JavaFile.java b/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/compiler/JavaFile.java
index 2a789ff..5c2b57c 100644
--- a/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/compiler/JavaFile.java
+++ b/examples/reload/src/main/java/org/glassfish/jersey/examples/reload/compiler/JavaFile.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -14,7 +14,7 @@
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import javax.tools.SimpleJavaFileObject;
@@ -47,7 +47,7 @@
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
String filePath = path + File.separator + className.replace('.', '/') + Kind.SOURCE.extension;
- final byte[] bytes = Files.readAllBytes(Paths.get(filePath));
+ final byte[] bytes = Files.readAllBytes(Path.of(filePath));
return new String(bytes);
}
diff --git a/examples/sse-twitter-aggregator/src/main/java/org/glassfish/jersey/examples/aggregator/App.java b/examples/sse-twitter-aggregator/src/main/java/org/glassfish/jersey/examples/aggregator/App.java
index a3e6788..ebde366 100644
--- a/examples/sse-twitter-aggregator/src/main/java/org/glassfish/jersey/examples/aggregator/App.java
+++ b/examples/sse-twitter-aggregator/src/main/java/org/glassfish/jersey/examples/aggregator/App.java
@@ -13,7 +13,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.HashMap;
import java.util.Properties;
import java.util.logging.Level;
@@ -144,7 +144,7 @@
InputStream st = null;
try {
String homeDir = System.getProperty("user.home");
- st = Files.newInputStream(Paths.get(homeDir, TWITTER_PROPERTIES_FILE_NAME));
+ st = Files.newInputStream(Path.of(homeDir, TWITTER_PROPERTIES_FILE_NAME));
properties.load(st);
} catch (IOException e) {
// ignore
@@ -230,7 +230,7 @@
try {
fileStream = webRootPath == null
? App.class.getResourceAsStream(WEB_ROOT + uri)
- : Files.newInputStream(Paths.get(webRootPath, uri));
+ : Files.newInputStream(Path.of(webRootPath, uri));
} catch (IOException e) {
fileStream = null;
}
diff --git a/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyTags.java b/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyTags.java
index d723c7c..29494f4 100644
--- a/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyTags.java
+++ b/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyTags.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -43,6 +43,8 @@
private static final Tag URI_ROOT = Tag.of("uri", "root");
+ private static final Tag URI_UNKNOWN = Tag.of("uri", "UNKNOWN");
+
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None");
private static final Tag STATUS_SERVER_ERROR = Tag.of("status", "500");
@@ -95,7 +97,10 @@
}
}
String matchingPattern = getMatchingPattern(event);
- if (matchingPattern.equals("/")) {
+ if (matchingPattern == null) {
+ return URI_UNKNOWN;
+ }
+ else if (matchingPattern.equals("/")) {
return URI_ROOT;
}
return Tag.of("uri", matchingPattern);
@@ -108,7 +113,9 @@
static String getMatchingPattern(RequestEvent event) {
ExtendedUriInfo uriInfo = event.getUriInfo();
List<UriTemplate> templates = uriInfo.getMatchedTemplates();
-
+ if (templates.isEmpty()) {
+ return null;
+ }
StringBuilder sb = new StringBuilder();
sb.append(uriInfo.getBaseUri().getPath());
for (int i = templates.size() - 1; i >= 0; i--) {
diff --git a/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListener.java b/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListener.java
index cca1d13..0b05442 100644
--- a/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListener.java
+++ b/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -79,7 +79,7 @@
switch (event.getType()) {
case ON_EXCEPTION:
- if (!isNotFoundException(event)) {
+ if (!isClientError(event)) {
break;
}
time(event, containerRequest);
@@ -122,13 +122,14 @@
}
}
- private boolean isNotFoundException(RequestEvent event) {
+ private boolean isClientError(RequestEvent event) {
Throwable t = event.getException();
if (t == null) {
return false;
}
- String className = t.getClass().getCanonicalName();
- return className.equals("jakarta.ws.rs.NotFoundException") || className.equals("jakarta.ws.rs.NotFoundException");
+ String className = t.getClass().getSuperclass().getCanonicalName();
+ return className.equals("jakarta.ws.rs.ClientErrorException")
+ || className.equals("javax.ws.rs.ClientErrorException");
}
private Set<Timer> shortTimers(Set<Timed> timed, RequestEvent event) {
diff --git a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/DefaultJerseyTagsProviderTest.java b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/DefaultJerseyTagsProviderTest.java
index d0445f9..93a9e4d 100644
--- a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/DefaultJerseyTagsProviderTest.java
+++ b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/DefaultJerseyTagsProviderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -51,7 +51,7 @@
@Test
void testRootPath() {
- assertThat(tagsProvider.httpRequestTags(event(200, null, "/", (String[]) null)))
+ assertThat(tagsProvider.httpRequestTags(event(200, null, "/", "/")))
.containsExactlyInAnyOrder(tagsFrom("root", 200, null, "SUCCESS"));
}
@@ -86,21 +86,21 @@
@Test
@SuppressWarnings("serial")
void exceptionsAreMappedCorrectly() {
- assertThat(tagsProvider.httpRequestTags(event(500, new IllegalArgumentException(), "/app", (String[]) null)))
+ assertThat(tagsProvider.httpRequestTags(event(500, new IllegalArgumentException(), "/app", "/")))
.containsExactlyInAnyOrder(tagsFrom("/app", 500, "IllegalArgumentException", "SERVER_ERROR"));
assertThat(tagsProvider.httpRequestTags(
- event(500, new IllegalArgumentException(new NullPointerException()), "/app", (String[]) null)))
+ event(500, new IllegalArgumentException(new NullPointerException()), "/app", "/")))
.containsExactlyInAnyOrder(tagsFrom("/app", 500, "NullPointerException", "SERVER_ERROR"));
- assertThat(tagsProvider.httpRequestTags(event(406, new NotAcceptableException(), "/app", (String[]) null)))
+ assertThat(tagsProvider.httpRequestTags(event(406, new NotAcceptableException(), "/app", "/")))
.containsExactlyInAnyOrder(tagsFrom("/app", 406, "NotAcceptableException", "CLIENT_ERROR"));
assertThat(tagsProvider.httpRequestTags(event(500, new Exception("anonymous") {
- }, "/app", (String[]) null))).containsExactlyInAnyOrder(tagsFrom("/app", 500,
+ }, "/app", "/"))).containsExactlyInAnyOrder(tagsFrom("/app", 500,
"org.glassfish.jersey.micrometer.server.DefaultJerseyTagsProviderTest$1", "SERVER_ERROR"));
}
@Test
void longRequestTags() {
- assertThat(tagsProvider.httpLongRequestTags(event(0, null, "/app", (String[]) null)))
+ assertThat(tagsProvider.httpLongRequestTags(event(0, null, "/app", "/")))
.containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/app"));
}
diff --git a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListenerTest.java b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListenerTest.java
index 96324b2..ce2bc4a 100644
--- a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListenerTest.java
+++ b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/MetricsRequestEventListenerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,7 @@
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
@@ -149,6 +150,11 @@
}
catch (Exception ignored) {
}
+ try {
+ target("produces-text-plain").request(MediaType.APPLICATION_JSON).get();
+ }
+ catch (Exception ignored) {
+ }
assertThat(registry.get(METRIC_NAME)
.tags(tagsFrom("/throws-exception", "500", "SERVER_ERROR", "IllegalArgumentException"))
@@ -164,6 +170,11 @@
.tags(tagsFrom("/throws-mappable-exception", "410", "CLIENT_ERROR", "ResourceGoneException"))
.timer()
.count()).isEqualTo(1);
+
+ assertThat(registry.get(METRIC_NAME)
+ .tags(tagsFrom("UNKNOWN", "406", "CLIENT_ERROR", "NotAcceptableException"))
+ .timer()
+ .count()).isEqualTo(1);
}
private static Iterable<Tag> tagsFrom(String uri, String status, String outcome, String exception) {
diff --git a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/resources/TestResource.java b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/resources/TestResource.java
index 41e529d..36abeb2 100644
--- a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/resources/TestResource.java
+++ b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/resources/TestResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -90,6 +90,13 @@
}
@GET
+ @Path("produces-text-plain")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String producesTextPlain() {
+ return "hello";
+ }
+
+ @GET
@Path("redirect/{status}")
public Response redirect(@PathParam("status") int status) {
if (status == 307) {
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java
index 1e81f52..2b7425f 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2021 Payara Foundation and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -33,7 +33,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.logging.Level;
@@ -66,6 +65,7 @@
import org.glassfish.jersey.client.Initializable;
import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.ext.cdi1x.internal.CdiUtil;
+import org.glassfish.jersey.innate.VirtualThreadUtil;
import org.glassfish.jersey.internal.ServiceFinder;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.inject.InjectionManagerSupplier;
@@ -111,7 +111,7 @@
asyncInterceptorFactories = new ArrayList<>();
config = ConfigProvider.getConfig();
configWrapper = new ConfigWrapper(clientBuilder.getConfiguration());
- executorService = Executors::newCachedThreadPool;
+ executorService = () -> VirtualThreadUtil.withConfig(configWrapper).newCachedThreadPool();
}
@Override
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
index d583419..1fbf420 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,7 +24,7 @@
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.security.AccessController;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -350,7 +350,7 @@
}
return result;
} else if (location.startsWith(FILE_LOCATION)) {
- return Files.newInputStream(Paths.get(URI.create(location)));
+ return Files.newInputStream(Path.of(URI.create(location)));
} else {
throw new IllegalStateException("Location of keystore must start with either classpath: or file:, but is: "
+ location
diff --git a/ext/mvc-thymeleaf/pom.xml b/ext/mvc-thymeleaf/pom.xml
new file mode 100644
index 0000000..be364f3
--- /dev/null
+++ b/ext/mvc-thymeleaf/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<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>
+ <artifactId>project</artifactId>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <version>4.0.99-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>jersey-mvc-thymeleaf</artifactId>
+ <name>jersey-ext-mvc-thymeleaf</name>
+
+ <description>
+ Jersey extension module providing support for Thymeleaf templates.
+ </description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>org.glassfish.jersey.server.mvc.thymeleaf.*;version=${project.version}</Export-Package>
+ </instructions>
+ <unpackBundle>true</unpackBundle>
+ </configuration>
+ </plugin>
+ </plugins>
+ <resources>
+ <resource>
+ <directory>${project.build.directory}/legal</directory>
+ </resource>
+ </resources>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ <version>${servlet6.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <artifactId>jersey-mvc</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.thymeleaf</groupId>
+ <artifactId>thymeleaf</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ </exclusion>
+ </exclusions>
+ <version>${thymeleaf.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafConfigurationFactory.java b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafConfigurationFactory.java
new file mode 100644
index 0000000..aba4aac
--- /dev/null
+++ b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafConfigurationFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.mvc.thymeleaf;
+
+import org.thymeleaf.TemplateEngine;
+
+public interface ThymeleafConfigurationFactory {
+ TemplateEngine getTemplateEngine();
+}
diff --git a/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafDefaultConfigurationFactory.java b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafDefaultConfigurationFactory.java
new file mode 100644
index 0000000..588c475
--- /dev/null
+++ b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafDefaultConfigurationFactory.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.mvc.thymeleaf;
+
+import jakarta.ws.rs.core.Configuration;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+import org.thymeleaf.TemplateEngine;
+import org.thymeleaf.messageresolver.IMessageResolver;
+import org.thymeleaf.messageresolver.StandardMessageResolver;
+import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
+import org.thymeleaf.templateresolver.ITemplateResolver;
+
+import java.util.Map;
+
+/**
+ * Handy {@link ThymeleafConfigurationFactory} that supplies a minimally
+ * configured {@link org.thymeleaf.TemplateEngine } able to
+ * render Thymeleaf templates.
+ * The recommended method to provide custom Thymeleaf engine settings is to
+ * sub-class this class, further customize the
+ * {@link org.thymeleaf.TemplateEngine settings} as desired in that
+ * class, and then register the sub-class with the {@link ThymeleafMvcFeature}
+ * TEMPLATE_OBJECT_FACTORY property.
+ *
+ * @author Dmytro Dovnar (dimonmc@gmail.com)
+ */
+public class ThymeleafDefaultConfigurationFactory implements ThymeleafConfigurationFactory {
+ private final Configuration config;
+ private final TemplateEngine templateEngine;
+
+ public ThymeleafDefaultConfigurationFactory(Configuration config) {
+ this.config = config;
+ this.templateEngine = initTemplateEngine();
+ }
+
+ @Override
+ public TemplateEngine getTemplateEngine() {
+ return templateEngine;
+ }
+
+ private ITemplateResolver getTemplateResolver() {
+ Map<String, Object> properties = config.getProperties();
+ String basePath = (String) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.templateBasePath" + ThymeleafMvcFeature.SUFFIX,
+ String.class, (Map) null);
+ if (basePath == null) {
+ basePath = (String) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.templateBasePath", "", (Map) null);
+ }
+
+ if (basePath != null && !basePath.startsWith("/")) {
+ basePath = "/" + basePath;
+ }
+
+ String templateFileSuffix = (String) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.templateFileSuffix" + ThymeleafMvcFeature.SUFFIX,
+ ".html", (Map) null);
+
+ String templateFileMode = (String) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.templateMode" + ThymeleafMvcFeature.SUFFIX,
+ "HTML5", (Map) null);
+
+ Boolean cacheEnabled = (Boolean) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.caching" + ThymeleafMvcFeature.SUFFIX, Boolean.class, (Map) null);
+ if (cacheEnabled == null) {
+ cacheEnabled = (Boolean) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.caching", false, (Map) null);
+ }
+
+ Long cacheLiveMs = (Long) PropertiesHelper.getValue(properties,
+ "jersey.config.server.mvc.cacheTTLMs" + ThymeleafMvcFeature.SUFFIX, 3600000L, (Map) null);
+
+ ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
+ templateResolver.setPrefix(basePath);
+ templateResolver.setSuffix(templateFileSuffix);
+ templateResolver.setTemplateMode(templateFileMode);
+ templateResolver.setCacheTTLMs(cacheLiveMs);
+ templateResolver.setCacheable(cacheEnabled);
+ return templateResolver;
+ }
+
+ private TemplateEngine initTemplateEngine() {
+ TemplateEngine templateEngine = new TemplateEngine();
+ templateEngine.setTemplateResolver(getTemplateResolver());
+ return templateEngine;
+ }
+
+ private IMessageResolver getMessageResolver() {
+ StandardMessageResolver messageResolver = new StandardMessageResolver();
+ return messageResolver;
+ }
+}
diff --git a/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafMvcFeature.java b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafMvcFeature.java
new file mode 100644
index 0000000..b43b9a6
--- /dev/null
+++ b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafMvcFeature.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.mvc.thymeleaf;
+
+import jakarta.ws.rs.ConstrainedTo;
+import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.Feature;
+import jakarta.ws.rs.core.FeatureContext;
+import org.glassfish.jersey.server.mvc.MvcFeature;
+
+@ConstrainedTo(RuntimeType.SERVER)
+public final class ThymeleafMvcFeature implements Feature {
+ public static final String SUFFIX = ".thymeleaf";
+ public static final String TEMPLATE_BASE_PATH = MvcFeature.TEMPLATE_BASE_PATH + SUFFIX;
+ public static final String CACHE_TEMPLATES = MvcFeature.CACHE_TEMPLATES + SUFFIX;
+ public static final String TEMPLATE_OBJECT_FACTORY = MvcFeature.TEMPLATE_OBJECT_FACTORY + SUFFIX;
+ public static final String ENCODING = MvcFeature.ENCODING + SUFFIX;
+
+ public static final String TEMPLATE_FILE_SUFFIX = "jersey.config.server.mvc.templateFileSuffix" + SUFFIX;
+ public static final String TEMPLATE_MODE = "jersey.config.server.mvc.templateMode" + SUFFIX;
+ public static final String CACHE_TTLMS = "jersey.config.server.mvc.cacheTTLMs" + SUFFIX;
+
+ @Override
+ public boolean configure(FeatureContext context) {
+ final Configuration config = context.getConfiguration();
+
+ if (!config.isRegistered(ThymeleafViewProcessor.class)) {
+ context.register(ThymeleafViewProcessor.class);
+
+ // MvcFeature.
+ if (!config.isRegistered(MvcFeature.class)) {
+ context.register(MvcFeature.class);
+ }
+
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafSuppliedConfigurationFactory.java b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafSuppliedConfigurationFactory.java
new file mode 100644
index 0000000..4f21ce1
--- /dev/null
+++ b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafSuppliedConfigurationFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.mvc.thymeleaf;
+
+import org.thymeleaf.TemplateEngine;
+
+/**
+ * {@link ThymeleafConfigurationFactory} that supplies an unchanged
+ * {@link ThymeleafConfigurationFactory Configuration} as passed-in to
+ * the constructor.
+ * <p/>
+ * Used to support backwards-compatibility in {@link ThymeleafViewProcessor}
+ * to wrap directly-configured {@link org.thymeleaf.TemplateEngine}
+ * objects instead of the recommended {@link ThymeleafDefaultConfigurationFactory}
+ * or a sub-class thereof.
+ *
+ * @author Dmytro Dovnar (dimonmc@gmail.com)
+ */
+public class ThymeleafSuppliedConfigurationFactory implements ThymeleafConfigurationFactory {
+ private final ThymeleafConfigurationFactory configurationFactory;
+
+ public ThymeleafSuppliedConfigurationFactory(ThymeleafConfigurationFactory configurationFactory) {
+ this.configurationFactory = configurationFactory;
+ }
+
+ @Override
+ public TemplateEngine getTemplateEngine() {
+ return configurationFactory.getTemplateEngine();
+ }
+
+}
diff --git a/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafViewProcessor.java b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafViewProcessor.java
new file mode 100644
index 0000000..fc8139c
--- /dev/null
+++ b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/ThymeleafViewProcessor.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.mvc.thymeleaf;
+
+import jakarta.inject.Inject;
+import jakarta.servlet.ServletContext;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.util.collection.Values;
+import org.glassfish.jersey.server.mvc.Viewable;
+import org.glassfish.jersey.server.mvc.spi.AbstractTemplateProcessor;
+import org.thymeleaf.TemplateEngine;
+import org.thymeleaf.context.Context;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * {@link org.glassfish.jersey.server.mvc.spi.TemplateProcessor Template processor} providing support for Thymeleaf templates.
+ *
+ * @author Dmytro Dovnar (dimonmc@gmail.com)
+ */
+public final class ThymeleafViewProcessor extends AbstractTemplateProcessor<TemplateEngine> {
+ private final ThymeleafConfigurationFactory factory;
+
+ /**
+ * Create an instance of this processor with injected {@link jakarta.ws.rs.core.Configuration config}.
+ *
+ * @param config config to configure this processor from.
+ * @param injectionManager injection manager.
+ */
+ @Inject
+ public ThymeleafViewProcessor(Configuration config, InjectionManager injectionManager) {
+ super(config, injectionManager.getInstance(ServletContext.class), "thymeleaf", "html");
+ this.factory = getTemplateObjectFactory(injectionManager::createAndInitialize, ThymeleafConfigurationFactory.class,
+ () -> {
+ ThymeleafConfigurationFactory configuration =
+ getTemplateObjectFactory(
+ injectionManager::createAndInitialize,
+ ThymeleafConfigurationFactory.class, Values.empty());
+ if (configuration == null) {
+ return new ThymeleafDefaultConfigurationFactory(config);
+ } else {
+ return new ThymeleafSuppliedConfigurationFactory(configuration);
+ }
+ });
+ }
+
+ @Override
+ protected TemplateEngine resolve(final String templatePath, final Reader reader) throws Exception {
+ return factory.getTemplateEngine();
+ }
+
+ @Override
+ public void writeTo(final TemplateEngine templateEngine, final Viewable viewable, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream out) throws IOException {
+ Context context = new Context();
+
+ Object model = viewable.getModel();
+ if (!(model instanceof Map)) {
+ context.setVariable("model", viewable.getModel());
+ } else {
+ context.setVariables((Map) viewable.getModel());
+ }
+
+ if (context.containsVariable("lang")) {
+ Object langValue = context.getVariable("lang");
+ if (langValue instanceof Locale) {
+ context.setLocale((Locale) langValue);
+ } else if (langValue instanceof String) {
+ Locale locale = Locale.forLanguageTag((String) langValue);
+ context.setLocale(locale);
+ }
+ }
+
+ Charset encoding = setContentType(mediaType, httpHeaders);
+
+ final Writer writer = new BufferedWriter(new OutputStreamWriter(out, encoding));
+ templateEngine.process(viewable.getTemplateName(), context, writer);
+ }
+}
diff --git a/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/package-info.java b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/package-info.java
new file mode 100644
index 0000000..d8cd7ae
--- /dev/null
+++ b/ext/mvc-thymeleaf/src/main/java/org/glassfish/jersey/server/mvc/thymeleaf/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.mvc.thymeleaf;
diff --git a/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java b/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java
index 79dd79c..b375afe 100644
--- a/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java
+++ b/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,7 +22,7 @@
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -182,7 +182,7 @@
// File-system path.
if (reader == null) {
try {
- reader = new InputStreamReader(Files.newInputStream(Paths.get(template)), encoding);
+ reader = new InputStreamReader(Files.newInputStream(Path.of(template)), encoding);
} catch (final IOException ioe) {
// NOOP.
}
diff --git a/ext/pom.xml b/ext/pom.xml
index 6736b56..054aee3 100644
--- a/ext/pom.xml
+++ b/ext/pom.xml
@@ -50,6 +50,7 @@
<module>mvc-freemarker</module>
<module>mvc-jsp</module>
<module>mvc-mustache</module>
+ <module>mvc-thymeleaf</module>
<module>proxy-client</module>
<module>rx</module>
<module>spring6</module>
diff --git a/ext/spring6/pom.xml b/ext/spring6/pom.xml
index 0c25d5d..441c965 100644
--- a/ext/spring6/pom.xml
+++ b/ext/spring6/pom.xml
@@ -90,6 +90,18 @@
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-util</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-analysis</artifactId>
+ </exclusion>
+ <exclusion>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</exclusion>
diff --git a/ext/spring6/src/main/java/org/glassfish/jersey/server/spring/scope/RequestContextFilter.java b/ext/spring6/src/main/java/org/glassfish/jersey/server/spring/scope/RequestContextFilter.java
index 12ec571..11f7984 100644
--- a/ext/spring6/src/main/java/org/glassfish/jersey/server/spring/scope/RequestContextFilter.java
+++ b/ext/spring6/src/main/java/org/glassfish/jersey/server/spring/scope/RequestContextFilter.java
@@ -98,7 +98,9 @@
final AbstractRequestAttributes attributes =
(AbstractRequestAttributes) requestContext.getProperty(REQUEST_ATTRIBUTES_PROPERTY);
RequestContextHolder.resetRequestAttributes();
- attributes.requestCompleted();
+ if (attributes != null) {
+ attributes.requestCompleted();
+ }
}
} : EMPTY_ATTRIBUTE_CONTROLLER;
}
diff --git a/ext/spring6/src/test/java/org/glassfish/jersey/server/spring/filter/SpringRequestContextFilterTest.java b/ext/spring6/src/test/java/org/glassfish/jersey/server/spring/filter/SpringRequestContextFilterTest.java
new file mode 100644
index 0000000..3e08125
--- /dev/null
+++ b/ext/spring6/src/test/java/org/glassfish/jersey/server/spring/filter/SpringRequestContextFilterTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.server.spring.filter;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.Injections;
+import org.glassfish.jersey.server.spring.scope.RequestContextFilter;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class SpringRequestContextFilterTest {
+ @Test
+ public void testMissingAttributes() throws IOException {
+ WebApplicationContext webAppCtx = (WebApplicationContext) Proxy.newProxyInstance(
+ WebApplicationContext.class.getClassLoader(),
+ new Class[]{WebApplicationContext.class},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return null;
+ }
+ });
+
+ InjectionManager injectionManager = Injections.createInjectionManager();
+ injectionManager.register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(webAppCtx).to(ApplicationContext.class);
+ }
+ });
+ injectionManager.completeRegistration();
+
+ ContainerRequestContext requestContext = (ContainerRequestContext) Proxy.newProxyInstance(
+ ContainerRequestContext.class.getClassLoader(),
+ new Class[]{ContainerRequestContext.class},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return null;
+ }
+ });
+
+ RequestContextFilter filter = new RequestContextFilter(injectionManager);
+ filter.filter(requestContext, (ContainerResponseContext) null);
+ }
+}
diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2BootstrapBinder.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2BootstrapBinder.java
index 7794aa6..f3fd9d7 100644
--- a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2BootstrapBinder.java
+++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2BootstrapBinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -43,6 +43,10 @@
@Override
protected void configure() {
+ // Singletons, install once
+ if (serviceLocator.getService(RequestScope.class) != null) {
+ return;
+ }
install(
// Jersey-like class analyzer that is able to choose the right services' constructor.
new JerseyClassAnalyzer.Binder(serviceLocator),
diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Helper.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Helper.java
index 79cfead..4ff3b46 100644
--- a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Helper.java
+++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Helper.java
@@ -20,8 +20,10 @@
import java.lang.reflect.Type;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Supplier;
+import org.glassfish.hk2.api.Factory;
import org.glassfish.jersey.innate.inject.ClassBinding;
import org.glassfish.jersey.innate.inject.InjectionResolverBinding;
import org.glassfish.jersey.innate.inject.InstanceBinding;
@@ -120,14 +122,25 @@
* @param dc HK2 Dynamic configuration to bind the object.
* @param binding Jersey descriptor as a holder of information about an injection point.
*/
- private static void bindBinding(ServiceLocator locator, DynamicConfiguration dc, Binding<?, ?> binding) {
+ private static <T> void bindBinding(ServiceLocator locator, DynamicConfiguration dc, Binding<T, ?> binding) {
if (ClassBinding.class.isAssignableFrom(binding.getClass())) {
- ActiveDescriptor<?> activeDescriptor = translateToActiveDescriptor((ClassBinding<?>) binding);
- bindBinding(locator, dc, activeDescriptor, binding.getAliases());
+ final Class<?> implClass = binding.getImplementationType();
+ if (Factory.class.isAssignableFrom(implClass)) {
+ final Class<? extends Factory<T>> factoryClass = (Class<? extends Factory<T>>) implClass;
+ bindFactory(locator, binding, (binder) -> binder.bindFactory(factoryClass));
+ } else {
+ ActiveDescriptor<?> activeDescriptor = translateToActiveDescriptor((ClassBinding<?>) binding);
+ bindBinding(locator, dc, activeDescriptor, binding.getAliases());
+ }
} else if (InstanceBinding.class.isAssignableFrom(binding.getClass())) {
- ActiveDescriptor<?> activeDescriptor = translateToActiveDescriptor((InstanceBinding<?>) binding);
- bindBinding(locator, dc, activeDescriptor, binding.getAliases());
+ if (Factory.class.isAssignableFrom(binding.getImplementationType())) {
+ final Factory<?> factory = (Factory) ((InstanceBinding<T>) binding).getService();
+ bindFactory(locator, binding, (binder) -> binder.bindFactory(factory));
+ } else {
+ ActiveDescriptor<?> activeDescriptor = translateToActiveDescriptor((InstanceBinding<?>) binding);
+ bindBinding(locator, dc, activeDescriptor, binding.getAliases());
+ }
} else if (InjectionResolverBinding.class.isAssignableFrom(binding.getClass())) {
InjectionResolverBinding resolverDescriptor = (InjectionResolverBinding) binding;
@@ -233,6 +246,13 @@
ServiceLocatorUtilities.bind(locator, createBinder(bindConsumer));
}
+ private static <T> void bindFactory(ServiceLocator locator,
+ Binding<T, ?> binding,
+ Function<AbstractBinder, ServiceBindingBuilder> builder) {
+ ServiceLocatorUtilities
+ .bind(locator, createBinder((binder) -> setupSupplierFactoryBridge(binding, builder.apply(binder))));
+ }
+
private static void setupSupplierFactoryBridge(Binding<?, ?> binding, ServiceBindingBuilder<?> builder) {
builder.named(binding.getName());
binding.getContracts().forEach(builder::to);
diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Registrables.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Registrables.java
new file mode 100644
index 0000000..6231f74
--- /dev/null
+++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2Registrables.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.hk2;
+
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.innate.inject.spi.ExternalRegistrables;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Hk2Registrables implements ExternalRegistrables {
+ @Override
+ public List<ClassRuntimeTypePair> registrableContracts() {
+ List<ClassRuntimeTypePair> list = new ArrayList<>();
+ list.add(new ClassRuntimeTypePair(AbstractBinder.class, null));
+ return list;
+ }
+}
diff --git a/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.innate.inject.spi.ExternalRegistrables b/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.innate.inject.spi.ExternalRegistrables
new file mode 100644
index 0000000..6f7da1a
--- /dev/null
+++ b/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.innate.inject.spi.ExternalRegistrables
@@ -0,0 +1 @@
+org.glassfish.jersey.inject.hk2.Hk2Registrables
\ No newline at end of file
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
index b11c121..d7b9f9c 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
@@ -31,6 +31,7 @@
import java.lang.annotation.Annotation;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import jakarta.annotation.PostConstruct;
@@ -104,7 +105,13 @@
commonConfig.getRuntimeType(),
CommonProperties.JSON_JACKSON_ENABLED_MODULES, String.class);
- final List<Module> modules = ObjectMapper.findModules();
+ final List<Module> modules;
+ try {
+ modules = ObjectMapper.findModules();
+ } catch (Throwable e) {
+ LOGGER.warning(LocalizationMessages.ERROR_MODULES_NOT_LOADED(e.getMessage()));
+ return Collections.emptyList();
+ }
for (String exludeModuleName : EXCLUDE_MODULE_NAMES) {
modules.removeIf(mod -> mod.getModuleName().contains(exludeModuleName));
}
diff --git a/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties b/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties
index f8b59da..a9144fd 100644
--- a/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties
+++ b/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0, which is available at
@@ -14,4 +14,5 @@
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
#
-error.jackson.streamreadconstraints=Error setting StreamReadConstraints: {0}. Possibly not Jackson 2.15?
\ No newline at end of file
+error.jackson.streamreadconstraints=Error setting StreamReadConstraints: {0}. Possibly not Jackson 2.15?
+error.modules.not.loaded=Jackson modules could not be loaded: {0}
\ No newline at end of file
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java
index 68abedb..00d6aba 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
import jakarta.ws.rs.ext.ContextResolver;
import org.glassfish.jersey.internal.util.PropertiesClass;
+import org.glassfish.jersey.message.internal.ReaderWriter;
/**
* Injectable JavaBean containing the configuration parameters for
@@ -38,12 +39,17 @@
/**
* Default threshold size for buffer.
*/
- public static final int DEFAULT_BUFFER_THRESHOLD = 4096;
+ public static final int DEFAULT_BUFFER_THRESHOLD = ReaderWriter.BUFFER_SIZE;
/**
+ * <p>
* Name of a properties resource that (if found in the classpath
* for this application) will be used to configure the settings returned
* by our getter methods.
+ * </p>
+ * <p>
+ * The resource name is {@code jersey-multipart-config.properties}.
+ * </p>
*/
public static final String MULTI_PART_CONFIG_RESOURCE = "jersey-multipart-config.properties";
@@ -51,7 +57,7 @@
* Name of the resource property for the threshold size (in bytes) above which a body part entity will be
* buffered to disk instead of being held in memory.
*
- * The default value is {@value #DEFAULT_BUFFER_THRESHOLD}.
+ * The default value is {@link #DEFAULT_BUFFER_THRESHOLD}.
*/
public static final String BUFFER_THRESHOLD = "jersey.config.multipart.bufferThreshold";
@@ -61,8 +67,20 @@
public static final int BUFFER_THRESHOLD_MEMORY_ONLY = -1;
/**
+ * <p>
+ * Limit the maximum number of parts the multipart entity can have. If the limit is over,
+ * the error response status {@link jakarta.ws.rs.core.Response.Status#REQUEST_ENTITY_TOO_LARGE} is returned.
+ * </p>
+ * <p>
+ * By default, the number is unlimited.
+ * </p>
+ * @since 2.44
+ */
+ public static final String MAX_PARTS = "jersey.config.multipart.maxParts";
+
+ /**
* Name of the resource property for the directory to store temporary files containing body parts of multipart message that
- * extends allowed memory threshold..
+ * extends allowed memory threshold.
*
* The default value is not set (will be taken from {@code java.io.tmpdir} system property).
*/
@@ -80,6 +98,11 @@
private String tempDir = null;
/**
+ * Maximum number of entity parts allowed.
+ */
+ private int maxParts = Integer.MAX_VALUE;
+
+ /**
* Load and customize (if necessary) the configuration values for the
* {@code jersey-multipart} injection binder.
*
@@ -114,6 +137,15 @@
}
/**
+ * Return maximum number of entity parts allowed.
+ * @return maximum number of parts.
+ * @since 2.44
+ */
+ public int getMaxParts() {
+ return maxParts;
+ }
+
+ /**
* Set the size (in bytes) of the entity of an incoming {@link BodyPart} before it will be buffered to disk.
*
* @param threshold size of body part.
@@ -139,6 +171,17 @@
}
/**
+ * Set the maximum number of received parts of a multipart entity.
+ * @param maxParts The maximum number of entity parts.
+ * @return {@code MultiPartProperties} instance.
+ * @since 2.44
+ */
+ public MultiPartProperties maxParts(int maxParts) {
+ this.maxParts = maxParts;
+ return this;
+ }
+
+ /**
* Configure the values returned by this instance's getters based on
* the contents of a properties resource, if it exists on the classpath
* for this application.
@@ -169,6 +212,9 @@
if (props.containsKey(TEMP_DIRECTORY)) {
this.tempDir = props.getProperty(TEMP_DIRECTORY);
}
+ if (props.contains(MAX_PARTS)) {
+ this.maxParts = Integer.parseInt(props.getProperty(MAX_PARTS));
+ }
} catch (final IOException e) {
throw new IllegalArgumentException(e);
} finally {
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java
index 6c834d9..277855b 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -234,7 +236,13 @@
@Override
public Object apply(ContainerRequest request) {
// Return the field value for the field specified by the sourceName property.
- final List<FormDataBodyPart> parts = getEntity(request).getFields(parameter.getSourceName());
+ final String sourceName = parameter.getAnnotations().length == 1
+ ? parameter.getSourceName()
+ : Arrays.stream(parameter.getAnnotations())
+ .filter(ann -> FormDataParam.class.isInstance(ann))
+ .map(ann -> FormDataParam.class.cast(ann))
+ .findFirst().get().value();
+ final List<FormDataBodyPart> parts = getEntity(request).getFields(sourceName);
final FormDataBodyPart part = parts != null ? parts.get(0) : null;
final MediaType mediaType = part != null ? part.getMediaType() : MediaType.TEXT_PLAIN_TYPE;
@@ -396,44 +404,48 @@
} else {
return null;
}
- } else if (parameter.getSourceAnnotation().annotationType() == FormDataParam.class) {
- final String paramName = parameter.getSourceName();
- if (paramName == null || paramName.isEmpty()) {
- // Invalid query parameter name
- return null;
- }
+ } else {
+ for (Annotation sourceAnnotation : parameter.getAnnotations()) {
+ if (sourceAnnotation.annotationType() == FormDataParam.class) {
+ final String paramName = ((FormDataParam) sourceAnnotation).value(); // sourceName refers to the last anno
+ if (paramName == null || paramName.isEmpty()) {
+ // Invalid query parameter name
+ return null;
+ }
- if (Collection.class == rawType || List.class == rawType) {
- final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
+ if (Collection.class == rawType || List.class == rawType) {
+ final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
- if (FormDataBodyPart.class == clazz) {
- // Return a collection of form data body part.
- return new ListFormDataBodyPartValueProvider(paramName);
- } else if (FormDataContentDisposition.class == clazz) {
- // Return a collection of form data content disposition.
- return new ListFormDataContentDispositionProvider(paramName);
- } else {
- // Return a collection of specific type.
- return new FormDataParamValueProvider(parameter, get(parameter));
+ if (FormDataBodyPart.class == clazz) {
+ // Return a collection of form data body part.
+ return new ListFormDataBodyPartValueProvider(paramName);
+ } else if (FormDataContentDisposition.class == clazz) {
+ // Return a collection of form data content disposition.
+ return new ListFormDataContentDispositionProvider(paramName);
+ } else {
+ // Return a collection of specific type.
+ return new FormDataParamValueProvider(parameter, get(parameter));
+ }
+ } else if (FormDataBodyPart.class == rawType) {
+ return new FormDataBodyPartProvider(paramName);
+ } else if (FormDataContentDisposition.class == rawType) {
+ return new FormDataContentDispositionProvider(paramName);
+ } else if (File.class == rawType) {
+ return new FileProvider(paramName);
+ } else {
+ return new FormDataParamValueProvider(parameter, get(parameter));
+ }
+ } else if (FormParam.class.equals(sourceAnnotation.annotationType())) {
+ final String paramName = ((FormParam) sourceAnnotation).value();
+ if (Collection.class == rawType || List.class == rawType) {
+ final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
+ if (EntityPart.class.equals(clazz)) {
+ return new ListEntityPartValueProvider(paramName);
+ }
+ } else if (EntityPart.class.equals(rawType)) {
+ return new EntityPartValueProvider(paramName);
+ }
}
- } else if (FormDataBodyPart.class == rawType) {
- return new FormDataBodyPartProvider(paramName);
- } else if (FormDataContentDisposition.class == rawType) {
- return new FormDataContentDispositionProvider(paramName);
- } else if (File.class == rawType) {
- return new FileProvider(paramName);
- } else {
- return new FormDataParamValueProvider(parameter, get(parameter));
- }
- } else if (FormParam.class.equals(parameter.getSourceAnnotation().annotationType())) {
- final String paramName = parameter.getSourceName();
- if (Collection.class == rawType || List.class == rawType) {
- final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
- if (EntityPart.class.equals(clazz)) {
- return new ListEntityPartValueProvider(paramName);
- }
- } else if (EntityPart.class.equals(rawType)) {
- return new EntityPartValueProvider(paramName);
}
}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
index c867078..edb80bd 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -28,6 +28,7 @@
import java.util.logging.Logger;
import jakarta.ws.rs.BadRequestException;
+import jakarta.ws.rs.ClientErrorException;
import jakarta.ws.rs.ConstrainedTo;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.RuntimeType;
@@ -36,6 +37,7 @@
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.MessageBodyReader;
import jakarta.ws.rs.ext.Providers;
@@ -79,6 +81,7 @@
*/
private Provider<MessageBodyWorkers> messageBodyWorkers;
private final MIMEConfig mimeConfig;
+ private final int maxParts;
/**
* Accepts constructor injection of the configuration parameters for this
@@ -98,6 +101,8 @@
properties = new MultiPartProperties();
}
+ maxParts = properties.getMaxParts();
+
this.messageBodyWorkers = messageBodyWorkers;
mimeConfig = createMimeConfig(properties);
}
@@ -205,7 +210,12 @@
fileNameFix = userAgent != null && userAgent.contains(" MSIE ");
}
- for (final MIMEPart mimePart : getMimeParts(mimeMessage)) {
+ final List<MIMEPart> mimeParts = getMimeParts(mimeMessage);
+ if (mimeParts.size() > maxParts) {
+ throw new ClientErrorException(Response.Status.REQUEST_ENTITY_TOO_LARGE);
+ }
+
+ for (final MIMEPart mimePart : mimeParts) {
final BodyPart bodyPart = formData ? new FormDataBodyPart(fileNameFix) : new BodyPart();
// Configure providers.
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/OrderParamTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/OrderParamTest.java
new file mode 100644
index 0000000..23cc7a8
--- /dev/null
+++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/OrderParamTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.media.multipart.internal;
+
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.message.internal.ReaderWriter;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.model.ParamQualifier;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class OrderParamTest extends JerseyTest {
+ @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @ParamQualifier
+ public static @interface AnnoWithValue {
+ String value() default "";
+ }
+
+ @Path("/order")
+ public static class OrderTestResource {
+ @POST
+ @Path("/dataAfter")
+ @Consumes(value = MediaType.MULTIPART_FORM_DATA)
+ public String orderBefore(@FormDataParam("file") @AnnoWithValue("xxx") InputStream inputStream) throws IOException {
+ return ReaderWriter.readFromAsString(inputStream, MediaType.TEXT_PLAIN_TYPE);
+ }
+
+ @POST
+ @Path("/dataBefore")
+ @Consumes(value = MediaType.MULTIPART_FORM_DATA)
+ public String orderAfter(@AnnoWithValue("zzz") @FormDataParam("file") InputStream inputStream) throws IOException {
+ return ReaderWriter.readFromAsString(inputStream, MediaType.TEXT_PLAIN_TYPE);
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(OrderTestResource.class).register(MultiPartFeature.class);
+ }
+
+ @Test
+ public void testOrder() {
+ final String MSG = "Hello";
+ FormDataMultiPart multiPart = new FormDataMultiPart();
+ multiPart.field("file", MSG, MediaType.TEXT_PLAIN_TYPE);
+ try (Response response = target("order")
+ .register(MultiPartFeature.class)
+ .path("dataBefore").request()
+ .post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ assertEquals(200, response.getStatus());
+ assertEquals(MSG, response.readEntity(String.class));
+ }
+
+ try (Response response = target("order")
+ .register(MultiPartFeature.class)
+ .path("dataAfter").request()
+ .post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ assertEquals(200, response.getStatus());
+ assertEquals(MSG, response.readEntity(String.class));
+ }
+ }
+}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/RestrictionsTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/RestrictionsTest.java
new file mode 100644
index 0000000..9906f11
--- /dev/null
+++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/RestrictionsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.media.multipart.internal;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.media.multipart.MultiPartProperties;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+public class RestrictionsTest extends JerseyTest {
+ @Path("/")
+ public static class RestrictionsTestResource {
+ @POST
+ @Path("max.parts")
+ public String postMaxPart(@FormDataParam("part1") String part1, @FormDataParam("part2") String part2) {
+ return part1 + part2;
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(RestrictionsTestResource.class)
+ .register(MultiPartFeature.class)
+ .register(new MultiPartProperties().maxParts(2).resolver());
+ }
+
+ @Override
+ protected void configureClient(ClientConfig config) {
+ config.register(MultiPartFeature.class);
+ }
+
+ @Test
+ public void testPassNumberOfParts() {
+ FormDataMultiPart multiPart = new FormDataMultiPart();
+ multiPart.field("part1", "he", MediaType.TEXT_PLAIN_TYPE);
+ multiPart.field("part2", "llo", MediaType.TEXT_PLAIN_TYPE);
+ try (Response r = target("max.parts").request().post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ Assertions.assertEquals(200, r.getStatus());
+ Assertions.assertEquals("hello", r.readEntity(String.class));
+ }
+ }
+
+ @Test
+ public void testFailsNumberOfParts() {
+ FormDataMultiPart multiPart = new FormDataMultiPart();
+ multiPart.field("part1", "he", MediaType.TEXT_PLAIN_TYPE);
+ multiPart.field("part2", "llo", MediaType.TEXT_PLAIN_TYPE);
+ multiPart.field("part3", "!", MediaType.TEXT_PLAIN_TYPE);
+ try (Response r = target("max.parts").request().post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ Assertions.assertEquals(Response.Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode(), r.getStatus());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 281d5a7..08c6cbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -142,6 +142,9 @@
<contributor>
<name>Stepan Vavra</name>
</contributor>
+ <contributor>
+ <name>Dmytro Dovnar</name>
+ </contributor>
</contributors>
<licenses>
@@ -305,7 +308,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
- <version>2.5</version>
+ <version>${clean.mvn.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -313,6 +316,8 @@
<version>${compiler.mvn.plugin.version}</version>
<inherited>true</inherited>
<configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
<compilerArguments>
<!--<Werror />-->
<!-- TODO work towards eliminating all warnings in order to be able to enable the -Xlint option -->
@@ -423,12 +428,10 @@
junit.jupiter.execution.parallel.mode.default=same_thread
</configurationParameters>
</properties>
- <systemProperties>
- <property>
- <name>jersey.config.test.container.port</name>
- <value>${jersey.config.test.container.port}</value>
- </property>
- </systemProperties>
+ <systemPropertyVariables>
+ <jersey.config.test.container.port>${jersey.config.test.container.port}
+ </jersey.config.test.container.port>
+ </systemPropertyVariables>
<threadCount>124</threadCount>
</configuration>
<dependencies>
@@ -468,7 +471,7 @@
<doctitle>Jersey ${jersey.version} API Documentation</doctitle>
<windowtitle>Jersey ${jersey.version} API</windowtitle>
<bottom>
- <![CDATA[Copyright © 2007-2023,
+ <![CDATA[Copyright © 2007-2024,
<a href="http://www.oracle.com">Oracle</a>
and/or its affiliates.
All Rights Reserved. Use is subject to license terms.]]>
@@ -479,7 +482,7 @@
<link>https://eclipse-ee4j.github.io/jersey.github.io/apidocs/latest/jersey/</link>
</links>
<excludePackageNames>
- *.internal.*:*.innate.*:*.tests.*
+ *.innate:*.innate.*:*.tests:*.tests.*
</excludePackageNames>
<includeDependencySources>false</includeDependencySources>
<dependencySourceIncludes>
@@ -544,11 +547,6 @@
</configuration>
</plugin>
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-site-plugin</artifactId>
- <version>${site.mvn.plugin.version}</version>
- </plugin>
- <plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec.mvn.plugin.version}</version>
@@ -635,12 +633,10 @@
<skipTests>${skip.tests}</skipTests>
<skipITs>${skip.tests}</skipITs>
<argLine>${failsafe.coverage.argline}</argLine>
- <systemProperties>
- <property>
- <name>jersey.config.test.container.port</name>
- <value>${jersey.config.test.container.port}</value>
- </property>
- </systemProperties>
+ <systemPropertyVariables>
+ <jersey.config.test.container.port>${jersey.config.test.container.port}
+ </jersey.config.test.container.port>
+ </systemPropertyVariables>
</configuration>
<executions>
<execution>
@@ -793,60 +789,10 @@
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
- <version>1.10.12</version>
+ <version>${mvn.ant.version}</version>
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.fortasoft</groupId>
- <artifactId>gradle-maven-plugin</artifactId>
- <version>1.0.8</version>
- </plugin>
- <plugin>
- <groupId>com.github.wvengen</groupId>
- <artifactId>proguard-maven-plugin</artifactId>
- <version>${proguard.mvn.plugin.version}</version>
- <dependencies>
- <dependency>
- <groupId>net.sf.proguard</groupId>
- <artifactId>proguard-base</artifactId>
- <version>6.2.2</version><!-- transitive dependency version increased from 5.0 -->
- <scope>runtime</scope>
- </dependency>
- </dependencies>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <inherited>true</inherited>
- <configuration>
- <source>${java.version}</source>
- <target>${java.version}</target>
- </configuration>
- <executions>
- <!-- when module.info
- <execution>
- <id>default-compile</id>
- <configuration>
- compile everything to ensure module-info contains right entries
- <release>11</release>
- </configuration>
- </execution>
- -->
- <execution>
- <id>base-compile</id>
- <goals>
- <goal>compile</goal>
- </goals>
- <!-- recompile everything for target VM except the module-info.java -->
- <configuration>
- <excludes>
- <exclude>module-info.java</exclude>
- </excludes>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</pluginManagement>
<plugins>
@@ -895,7 +841,6 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
- <version>${buildhelper.mvn.plugin.version}</version>
<configuration>
<portNames>
<portName>jersey.config.test.container.port</portName>
@@ -959,7 +904,6 @@
<properties>
<!-- <release.tests.args>-Dskip.tests=true</release.tests.args>-->
<skip.tests>true</skip.tests>
- <skip.e2e>true</skip.e2e>
</properties>
</profile>
<profile>
@@ -1118,14 +1062,6 @@
<version>${moxy.version}</version>
</dependency>
</dependencies>
- <repositories>
- <repository>
- <id>eclipselink.repository</id>
- <name>Eclipse Maven Repository</name>
- <url>https://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo</url>
- <layout>default</layout>
- </repository>
- </repositories>
</profile>
<profile>
<id>securityOff</id>
@@ -1143,7 +1079,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
- <version>3.4.5</version>
+ <version>${project.info.reports.mvn.plugin.version}</version>
<reportSets>
<reportSet>
<reports>
@@ -1164,6 +1100,37 @@
</distributionManagement>
</profile>
<profile>
+ <id>sbom</id>
+ <activation>
+ <property>
+ <name>!skipSBOM</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.cyclonedx</groupId>
+ <artifactId>cyclonedx-maven-plugin</artifactId>
+ <version>${cyclonedx.mvn.plugin.version}</version>
+ <inherited>true</inherited>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>makeAggregateBom</goal>
+ </goals>
+ <configuration>
+ <!-- <schemaVersion>1.4</schemaVersion>-->
+ <projectType>framework</projectType>
+ <excludeTestProject>true</excludeTestProject>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
<id>sonar</id>
<properties>
<!-- Sonar/Reporting settings (heavily inspired at http://www.aheritier.net/maven-failsafe-sonar-and-jacoco-are-in-a-boat/ -->
@@ -1304,51 +1271,6 @@
</build>
</profile>
<profile>
- <!--
- Profile is aimed to run the build on travis
- due to travis limitations for output (max 4MB) this profile is used along with grep which reduces
- the output.
- However some e2e tests produce output which is not grepped (thus is not visible) and run longer than
- 10 minutes which results in the whole build is being murdered by Travis because of death suspection
-
- the whole build is run as clean install but excludes several e2e tests because of the not grepped output
- -->
- <id>travis_e2e_skip</id>
- <properties>
- <skip.e2e>true</skip.e2e>
- </properties>
- </profile>
- <profile>
- <!--
- Profile is aimed to run the build on travis
- due to travis limitations for output (max 4MB) this profile is used to run e2e tests only.
-
- the only thing which is happen using profile is run of e2e tests (with additional build)
- everything is already build using travis_e2e_skip profile
-
- the whole build is run as test -Ptravis_e2e
- -->
- <id>travis_e2e</id>
- <properties>
- <skip.e2e>false</skip.e2e>
- <skip.tests>true</skip.tests>
- </properties>
- </profile>
- <profile>
- <!-- Use -Peclipse_repo to use SNAPSHOTs stored in Eclipse's Nexus instance ("Nightly Builds") -->
- <id>eclipse_repo</id>
- <repositories>
- <repository>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <id>repo.jaxrs-api.eclipse.org</id>
- <name>JAX-RS API Repository - Snapshots</name>
- <url>https://repo.eclipse.org/content/repositories/jax-rs-api-snapshots</url>
- </repository>
- </repositories>
- </profile>
- <profile>
<id>license_check</id>
<pluginRepositories>
<pluginRepository>
@@ -1371,7 +1293,7 @@
<plugin>
<groupId>org.eclipse.dash</groupId>
<artifactId>license-tool-plugin</artifactId>
- <version>1.0.2</version>
+ <version>1.1.0</version>
<executions>
<execution>
<id>license-check</id>
@@ -1424,20 +1346,20 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
- <version>3.4.1</version>
+ <version>${javadoc.mvn.plugin.version}</version>
<!-- Run this plugin report sets only in the main Jersey pom -->
<inherited>false</inherited>
<configuration>
<doctitle>Jersey ${jersey.version} API Documentation</doctitle>
<windowtitle>Jersey ${jersey.version} API</windowtitle>
<bottom>
- <![CDATA[Copyright © 2007-2023,
+ <![CDATA[Copyright © 2007-2024,
<a href="http://www.oracle.com">Oracle</a>
and/or its affiliates.
All Rights Reserved. Use is subject to license terms.]]>
</bottom>
<excludePackageNames>
- com.sun.ws.rs.ext:*.examples.*:*.internal.*:*.tests.*
+ com.sun.ws.rs.ext:*.examples.*:*.innate:*.innate.*:*.tests:*.tests.*
</excludePackageNames>
<links>
<link>https://jax-rs.github.io/apidocs/2.1</link>
@@ -1477,7 +1399,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
- <version>2.3</version>
+ <version>${jxr.mvn.plugin.version}</version>
<reportSets>
<reportSet>
<reports>
@@ -2121,7 +2043,6 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- <release.tests.args>-Dmaven.test.skip=false</release.tests.args>-->
<!-- <release.preparationGoals>clean install</release.preparationGoals>-->
- <skip.e2e>false</skip.e2e>
<skip.tests>false</skip.tests>
<xdk.absolute.path />
<surefire.security.argline />
@@ -2132,13 +2053,15 @@
<!-- Versions of Maven plugins -->
<antrun.mvn.plugin.version>3.1.0</antrun.mvn.plugin.version>
+ <mvn.ant.version>1.10.14</mvn.ant.version>
<assembly.mvn.plugin.version>3.7.1</assembly.mvn.plugin.version>
+ <clean.mvn.plugin.version>3.3.2</clean.mvn.plugin.version>
<enforcer.mvn.plugin.version>3.4.1</enforcer.mvn.plugin.version>
<exec.mvn.plugin.version>3.2.0</exec.mvn.plugin.version>
<buildhelper.mvn.plugin.version>3.5.0</buildhelper.mvn.plugin.version>
<buildnumber.mvn.plugin.version>3.2.0</buildnumber.mvn.plugin.version>
<checkstyle.mvn.plugin.version>3.3.1</checkstyle.mvn.plugin.version>
- <checkstyle.version>10.14.2</checkstyle.version>
+ <checkstyle.version>10.16.0</checkstyle.version>
<compiler.mvn.plugin.version>3.13.0</compiler.mvn.plugin.version>
<!--
Special version of the compiler plugin just for the jersey-common. All versions above
@@ -2147,24 +2070,24 @@
but the jersey-common module which has to have the separate version for OSGi reasons.
-->
<compiler.common.mvn.plugin.version>3.9.0</compiler.common.mvn.plugin.version>
+ <cyclonedx.mvn.plugin.version>2.8.0</cyclonedx.mvn.plugin.version>
<dependency.mvn.plugin.version>3.6.1</dependency.mvn.plugin.version>
- <deploy.mvn.plugin.version>3.1.1</deploy.mvn.plugin.version>
+ <deploy.mvn.plugin.version>3.1.2</deploy.mvn.plugin.version>
<ear.mvn.plugin.version>3.3.0</ear.mvn.plugin.version>
<failsafe.mvn.plugin.version>3.2.5</failsafe.mvn.plugin.version>
<felix.mvn.plugin.version>5.1.9</felix.mvn.plugin.version>
<findbugs.mvn.plugin.version>3.0.5</findbugs.mvn.plugin.version>
<gfembedded.mvn.plugin.version>5.1</gfembedded.mvn.plugin.version>
- <install.mvn.plugin.version>3.1.1</install.mvn.plugin.version>
+ <install.mvn.plugin.version>3.1.2</install.mvn.plugin.version>
<istack.mvn.plugin.version>4.2.0</istack.mvn.plugin.version>
- <jar.mvn.plugin.version>3.3.0</jar.mvn.plugin.version>
+ <jar.mvn.plugin.version>3.4.1</jar.mvn.plugin.version>
<javadoc.mvn.plugin.version>3.6.3</javadoc.mvn.plugin.version>
<jxr.mvn.plugin.version>3.3.2</jxr.mvn.plugin.version>
<paxexam.mvn.plugin.version>1.2.4</paxexam.mvn.plugin.version>
- <proguard.mvn.plugin.version>2.6.1</proguard.mvn.plugin.version>
+ <project.info.reports.mvn.plugin.version>3.5.0</project.info.reports.mvn.plugin.version>
<resources.mvn.plugin.version>3.3.1</resources.mvn.plugin.version>
- <shade.mvn.plugin.version>3.5.2</shade.mvn.plugin.version>
- <site.mvn.plugin.version>3.12.1</site.mvn.plugin.version>
- <source.mvn.plugin.version>3.3.0</source.mvn.plugin.version>
+ <shade.mvn.plugin.version>3.5.3</shade.mvn.plugin.version>
+ <source.mvn.plugin.version>3.3.1</source.mvn.plugin.version>
<surefire.mvn.plugin.version>3.2.5</surefire.mvn.plugin.version>
<war.mvn.plugin.version>3.4.0</war.mvn.plugin.version>
<wiremock.mvn.plugin.version>2.11.0</wiremock.mvn.plugin.version>
@@ -2183,7 +2106,7 @@
<aspectj.weaver.version>1.9.22</aspectj.weaver.version>
<!-- <bnd.plugin.version>2.3.6</bnd.plugin.version>-->
<bouncycastle.version>1.70</bouncycastle.version>
- <commons.io.version>2.15.1</commons.io.version>
+ <commons.io.version>2.16.1</commons.io.version>
<commons.codec.version>1.16.1</commons.codec.version>
<!-- <commons-lang3.version>3.3.2</commons-lang3.version>-->
<commons.logging.version>1.3.1</commons.logging.version>
@@ -2193,8 +2116,8 @@
<felix.framework.version>7.0.5</felix.framework.version>
<findbugs.glassfish.version>1.7</findbugs.glassfish.version>
<freemarker.version>2.3.32</freemarker.version>
- <gae.version>2.0.25</gae.version>
- <groovy.version>4.0.20</groovy.version>
+ <gae.version>2.0.26</gae.version>
+ <groovy.version>4.0.21</groovy.version>
<gson.version>2.10.1</gson.version>
<!--versions, extracted here due to maven-enforcer-plugin -->
@@ -2214,10 +2137,10 @@
<helidon.jersey.connector.version>3.2.6</helidon.jersey.connector.version>
<smallrye.config.version>3.7.1</smallrye.config.version>
- <guava.version>31.1-jre</guava.version>
+ <guava.version>33.1.0-jre</guava.version>
<hamcrest.version>2.2</hamcrest.version>
- <xmlunit.version>2.9.1</xmlunit.version>
- <httpcore.version>4.5.14</httpcore.version>
+ <xmlunit.version>2.10.0</xmlunit.version>
+ <httpclient.version>4.5.14</httpclient.version>
<httpclient5.version>5.3.1</httpclient5.version>
<jackson.version>2.17.0</jackson.version>
<javassist.version>3.30.2-GA</javassist.version>
@@ -2228,10 +2151,11 @@
<junit4.version>4.13.2</junit4.version>
<junit5.version>5.10.2</junit5.version>
<junit-platform-suite.version>1.10.2</junit-platform-suite.version>
+ <junit-platform-suite.legacy.version>1.10.0</junit-platform-suite.legacy.version>
<kryo.version>4.0.3</kryo.version>
- <mockito.version>3.12.4</mockito.version> <!-- CQ 17673 -->
- <mustache.version>0.9.11</mustache.version>
- <netty.version>4.1.108.Final</netty.version>
+ <mockito.version>4.11.0</mockito.version> <!-- CQ 17673 -->
+ <mustache.version>0.9.12</mustache.version>
+ <netty.version>4.1.109.Final</netty.version>
<opentracing.version>0.33.0</opentracing.version>
<osgi.version>6.0.0</osgi.version>
<osgi.framework.version>1.10.0</osgi.framework.version>
@@ -2249,10 +2173,12 @@
<servlet4.version>4.0.3</servlet4.version>
<servlet6.version>6.1.0-M2</servlet6.version>
- <slf4j.version>2.0.12</slf4j.version>
+ <simple.version>6.0.1</simple.version>
+ <slf4j.version>2.0.13</slf4j.version>
<spring6.version>6.0.18</spring6.version>
<testng.version>7.9.0</testng.version>
<testng6.version>6.9.13.6</testng6.version>
+ <thymeleaf.version>3.1.2.RELEASE</thymeleaf.version>
<!-- Jakartified, eligible for CQ -->
<weld.version>6.0.0.Beta1</weld.version>
<weld3.version>3.1.9.Final</weld3.version>
@@ -2262,7 +2188,7 @@
<xerces.version>2.12.2</xerces.version>
<!-- Graal VM -->
- <graalvm.version>20.3.13</graalvm.version>
+ <graalvm.version>20.3.14</graalvm.version>
<!-- do not need CQs (below this line till the end of version properties)-->
<gf.impl.version>7.0.13</gf.impl.version>
diff --git a/test-framework/core/src/main/java/org/glassfish/jersey/test/JerseyTest.java b/test-framework/core/src/main/java/org/glassfish/jersey/test/JerseyTest.java
index 243466c..fe85e9c 100644
--- a/test-framework/core/src/main/java/org/glassfish/jersey/test/JerseyTest.java
+++ b/test-framework/core/src/main/java/org/glassfish/jersey/test/JerseyTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -621,6 +621,7 @@
if (!isConcurrent() || activeThreadCount.getAndIncrement() == 0) {
registerLogHandlerIfEnabled();
final TestContainer testContainer = createTestContainer(context);
+ testContainer.configureContainer();
// Set current instance of test container and start it.
setTestContainer(testContainer);
diff --git a/test-framework/core/src/main/java/org/glassfish/jersey/test/spi/TestContainer.java b/test-framework/core/src/main/java/org/glassfish/jersey/test/spi/TestContainer.java
index 68a5bf8..d2a0030 100644
--- a/test-framework/core/src/main/java/org/glassfish/jersey/test/spi/TestContainer.java
+++ b/test-framework/core/src/main/java/org/glassfish/jersey/test/spi/TestContainer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -54,4 +54,13 @@
* Stop the container.
*/
public void stop();
+
+ /**
+ * optional method to configure container before it's being started
+ *
+ * @since 2.44
+ */
+ default void configureContainer() {
+
+ }
}
diff --git a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/RunnerMojo.groovy b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/RunnerMojo.groovy
index b04c36b..865afb7 100644
--- a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/RunnerMojo.groovy
+++ b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/RunnerMojo.groovy
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,7 +23,7 @@
import org.apache.maven.project.MavenProject
import java.nio.file.Files
-import java.nio.file.Paths
+import java.nio.file.Path
import java.util.regex.Pattern
/**
@@ -96,7 +96,7 @@
def command = string.split(" +(?=((.*?(?<!\\\\)'){2})*[^']*\$)")
- return command?.length > 0 && Files.exists(Paths.get(command[0])) ? command : ["sh"]
+ return command?.length > 0 && Files.exists(Path.of(command[0])) ? command : ["sh"]
}
abstract Map commonEnvironment()
@@ -184,8 +184,8 @@
sb.append(System.lineSeparator())
def matcher = Pattern.compile("(#![^\r\n]*)(.*)", Pattern.DOTALL).matcher(new String(shellContent))
def string = matcher.matches() ? matcher.replaceFirst("\$1${sb.toString()}\$2") : sb.append(shellContent).toString()
- Paths.get(scriptsDirectory).toFile().mkdirs()
- def reExecutableShell = Paths.get(scriptsDirectory, Paths.get(shell).fileName.toString())
+ Path.of(scriptsDirectory).toFile().mkdirs()
+ def reExecutableShell = Path.of(scriptsDirectory, Path.of(shell).fileName.toString())
Files.write(reExecutableShell, string.bytes)
getLog().info("Re-executable shell written to: $reExecutableShell")
} catch (Exception e) {
diff --git a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/gf4/AbstractGlassfishRunnerMojo.groovy b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/gf4/AbstractGlassfishRunnerMojo.groovy
index c72b020..9d8a6ba 100644
--- a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/gf4/AbstractGlassfishRunnerMojo.groovy
+++ b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/gf4/AbstractGlassfishRunnerMojo.groovy
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,7 +22,7 @@
import org.codehaus.gmavenplus.mojo.AbstractGroovyMojo
import org.glassfish.jersey.test.maven.runner.RunnerMojo
-import java.nio.file.Paths
+import java.nio.file.Path
/**
* Abstract class for all Glassfish4 related mojos.
*
@@ -58,8 +58,8 @@
@Override
void execute() throws MojoExecutionException, MojoFailureException {
- asHome = Paths.get(asHome).isAbsolute() ? asHome : Paths.get(distDir, distSubdir, asHome)
- logFile = Paths.get(logFile).isAbsolute()? logFile : Paths.get(asHome, "domains", domain, "logs", logFile)
+ asHome = Path.of(asHome).isAbsolute() ? asHome : Path.of(distDir, distSubdir, asHome)
+ logFile = Path.of(logFile).isAbsolute()? logFile : Path.of(asHome, "domains", domain, "logs", logFile)
executeRunner()
}
diff --git a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/tomcat/AbstractTomcatRunnerMojo.groovy b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/tomcat/AbstractTomcatRunnerMojo.groovy
index d98b59d..2b041e8 100644
--- a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/tomcat/AbstractTomcatRunnerMojo.groovy
+++ b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/tomcat/AbstractTomcatRunnerMojo.groovy
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,7 +22,7 @@
import org.codehaus.gmavenplus.mojo.AbstractGroovyMojo
import org.glassfish.jersey.test.maven.runner.RunnerMojo
-import java.nio.file.Paths
+import java.nio.file.Path
/**
* Abstract class for all Tomcat related mojos.
*
@@ -47,8 +47,8 @@
@Override
void execute() throws MojoExecutionException, MojoFailureException {
- catalinaHome = Paths.get(catalinaHome).isAbsolute() ? catalinaHome : Paths.get(distDir, distSubdir, catalinaHome)
- logFile = logFile ?: Paths.get(catalinaHome, "logs", "catalina.out").toString()
+ catalinaHome = Path.of(catalinaHome).isAbsolute() ? catalinaHome : Path.of(distDir, distSubdir, catalinaHome)
+ logFile = logFile ?: Path.of(catalinaHome, "logs", "catalina.out").toString()
executeRunner()
}
diff --git a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/wls/AbstractWlsRunnerMojo.groovy b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/wls/AbstractWlsRunnerMojo.groovy
index 3fa9ffd..6232472 100644
--- a/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/wls/AbstractWlsRunnerMojo.groovy
+++ b/test-framework/maven/container-runner-maven-plugin/src/main/groovy/org/glassfish/jersey/test/maven/runner/wls/AbstractWlsRunnerMojo.groovy
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,7 +22,7 @@
import org.codehaus.gmavenplus.mojo.AbstractGroovyMojo
import org.glassfish.jersey.test.maven.runner.RunnerMojo
-import java.nio.file.Paths
+import java.nio.file.Path
/**
* Abstract class for all Weblogic related mojos.
@@ -52,8 +52,8 @@
@Override
void execute() throws MojoExecutionException, MojoFailureException {
- mwHome = Paths.get(mwHome).isAbsolute() ? mwHome : Paths.get(distDir, distSubdir, mwHome)
- logFile = logFile ?: Paths.get(mwHome, domain, "wls.log").toString()
+ mwHome = Path.of(mwHome).isAbsolute() ? mwHome : Path.of(distDir, distSubdir, mwHome)
+ logFile = logFile ?: Path.of(mwHome, domain, "wls.log").toString()
executeRunner()
}
diff --git a/test-framework/memleak-test-common/src/main/java/org/glassfish/jersey/test/memleak/common/MemoryLeakUtils.java b/test-framework/memleak-test-common/src/main/java/org/glassfish/jersey/test/memleak/common/MemoryLeakUtils.java
index d519d3f..ecfe68e 100644
--- a/test-framework/memleak-test-common/src/main/java/org/glassfish/jersey/test/memleak/common/MemoryLeakUtils.java
+++ b/test-framework/memleak-test-common/src/main/java/org/glassfish/jersey/test/memleak/common/MemoryLeakUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,7 +23,7 @@
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
@@ -121,7 +121,7 @@
throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, IOException {
conditionallyInitHotSpotDiagnosticMXBean();
try {
- java.nio.file.Files.deleteIfExists(Paths.get(fileName));
+ java.nio.file.Files.deleteIfExists(Path.of(fileName));
} catch (IOException e) {
// do nothing and try to go further
}
diff --git a/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java b/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java
index 5c35746..1af49d5 100644
--- a/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java
+++ b/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java
@@ -17,11 +17,13 @@
package org.glassfish.jersey.test.jetty;
import java.net.URI;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.ws.rs.core.UriBuilder;
+import org.eclipse.jetty.server.HttpConnectionFactory;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.test.DeploymentContext;
@@ -42,16 +44,21 @@
*/
public class JettyTestContainerFactory implements TestContainerFactory {
+ private final Map<String, Object> propertiesMap;
+
private static class JettyTestContainer implements TestContainer {
private static final Logger LOGGER = Logger.getLogger(JettyTestContainer.class.getName());
+ private final Map<String, Object> propertiesMap;
+
private URI baseUri;
private final Server server;
-
- private JettyTestContainer(final URI baseUri, final DeploymentContext context) {
+ private JettyTestContainer(final URI baseUri, final DeploymentContext context, final Map<String, Object> propertiesMap) {
final URI base = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build();
+ this.propertiesMap = propertiesMap;
+
if (!"/".equals(base.getRawPath())) {
throw new TestContainerException(String.format(
"Cannot deploy on %s. Jetty HTTP container only supports deployment on root path.",
@@ -69,6 +76,26 @@
}
@Override
+ public void configureContainer() {
+
+ if (propertiesMap == null
+ || !propertiesMap.containsKey(JettyTestContainerProperties.HEADER_SIZE)) {
+ return;
+ }
+
+ for (Connector c : server.getConnectors()) {
+ c.getConnectionFactory(HttpConnectionFactory.class)
+ .getHttpConfiguration().setRequestHeaderSize(
+ (Integer) propertiesMap.get(JettyTestContainerProperties.HEADER_SIZE));
+ c.getConnectionFactory(HttpConnectionFactory.class)
+ .getHttpConfiguration().setResponseHeaderSize(
+ (Integer) propertiesMap.get(JettyTestContainerProperties.HEADER_SIZE));
+ c.getConnectionFactory(HttpConnectionFactory.class);
+ }
+
+ }
+
+ @Override
public ClientConfig getClientConfig() {
return null;
}
@@ -123,6 +150,14 @@
@Override
public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException {
- return new JettyTestContainer(baseUri, context);
+ return new JettyTestContainer(baseUri, context, propertiesMap);
}
-}
+
+ public JettyTestContainerFactory() {
+ this(null);
+ }
+
+ public JettyTestContainerFactory(Map<String, Object> properties) {
+ this.propertiesMap = properties;
+ }
+}
\ No newline at end of file
diff --git a/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerProperties.java b/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerProperties.java
new file mode 100644
index 0000000..beabef2
--- /dev/null
+++ b/test-framework/providers/jetty/src/main/java/org/glassfish/jersey/test/jetty/JettyTestContainerProperties.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.test.jetty;
+
+import org.glassfish.jersey.internal.util.PropertiesClass;
+
+/**
+ * Properties which relates only to Jetty test container configuration
+ *
+ * @since 2.44
+ */
+@PropertiesClass
+public class JettyTestContainerProperties {
+
+ /**
+ * Parameter which allows settings custom header size for request and response.
+ *
+ * @since 2.44
+ */
+ public static final String HEADER_SIZE = "jersey.test.jetty.container.header.size";
+
+}
diff --git a/test-framework/providers/jetty/src/main/java11/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java b/test-framework/providers/jetty/src/main/java11/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java
new file mode 100644
index 0000000..16be885
--- /dev/null
+++ b/test-framework/providers/jetty/src/main/java11/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.test.jetty;
+
+import java.util.Map;
+import jakarta.ws.rs.ProcessingException;
+import org.glassfish.jersey.jetty.internal.LocalizationMessages;
+import org.glassfish.jersey.test.DeploymentContext;
+import org.glassfish.jersey.test.spi.TestContainer;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+
+import java.net.URI;
+
+public class JettyTestContainerFactory implements TestContainerFactory {
+
+ public JettyTestContainerFactory() {
+ }
+
+ public JettyTestContainerFactory(Map<String, Object> properties) {
+ }
+
+
+ @Override
+ public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException {
+ throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED());
+ }
+}
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml
index b7f6cf3..0e3b819 100644
--- a/tests/e2e-client/pom.xml
+++ b/tests/e2e-client/pom.xml
@@ -59,7 +59,6 @@
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
<systemPropertyVariables>
<sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders>
</systemPropertyVariables>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java
index 1f18b80..ffb8b1f 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -28,11 +28,8 @@
import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
@@ -66,9 +63,10 @@
private static Server server;
@BeforeAll
- public static void startExpect100ContinueTestServer() {
+ private static void startExpect100ContinueTestServer() {
server = new Server(portNumber);
- server.setHandler(new Expect100ContinueTestHandler());
+ server.setDefaultHandler(new Expect100ContinueTestHandler());
+ server.setDynamic(true);
try {
server.start();
} catch (Exception e) {
@@ -77,31 +75,28 @@
}
@AfterAll
- public static void stopExpect100ContinueTestServer() {
+ private static void stopExpect100ContinueTestServer() {
try {
server.stop();
} catch (Exception e) {
}
}
- private static Client client;
- @BeforeEach
- public void beforeEach() {
+ @BeforeAll
+ private static void initClient() {
final ClientConfig config = new ClientConfig();
- this.configureClient(config);
+ config.connectorProvider(new NettyConnectorProvider());
client = ClientBuilder.newClient(config);
}
- private Client client() {
- return client;
+ @AfterAll
+ private static void stopClient() {
+ client.close();
}
+ private static Client client;
public WebTarget target(String path) {
- return client().target(String.format("http://localhost:%d", portNumber)).path(path);
- }
-
- protected void configureClient(ClientConfig config) {
- config.connectorProvider(new NettyConnectorProvider());
+ return client.target(String.format("http://localhost:%d", portNumber)).path(path);
}
@Test
@@ -234,6 +229,11 @@
callback.succeeded();
return true;
}
+ if (!expected && !failed) {
+ response.reset();
+ callback.succeeded();
+ return true;
+ }
response.write(true, ByteBuffer.wrap("\n\r".getBytes()), callback);
callback.failed(new ProcessingException(""));
diff --git a/tests/e2e-entity/pom.xml b/tests/e2e-entity/pom.xml
index 0aae7a7..e4f8195 100644
--- a/tests/e2e-entity/pom.xml
+++ b/tests/e2e-entity/pom.xml
@@ -41,7 +41,6 @@
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
</configuration>
<executions>
<execution>
diff --git a/tests/e2e-inject/hk2/pom.xml b/tests/e2e-inject/hk2/pom.xml
index 06db8b2..ee0ae6f 100644
--- a/tests/e2e-inject/hk2/pom.xml
+++ b/tests/e2e-inject/hk2/pom.xml
@@ -36,6 +36,11 @@
<type>pom</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
diff --git a/tests/e2e-inject/hk2/src/test/java/org/glassfish/jersey/tests/e2e/inject/hk2/HK2FactoryBindingTest.java b/tests/e2e-inject/hk2/src/test/java/org/glassfish/jersey/tests/e2e/inject/hk2/HK2FactoryBindingTest.java
new file mode 100644
index 0000000..d0bb564
--- /dev/null
+++ b/tests/e2e-inject/hk2/src/test/java/org/glassfish/jersey/tests/e2e/inject/hk2/HK2FactoryBindingTest.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.hk2;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.InjectionManagerClientProvider;
+import org.glassfish.jersey.inject.hk2.AbstractBinder;
+import org.glassfish.jersey.internal.inject.Injectee;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.process.internal.RequestScoped;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.annotation.Priority;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.Priorities;
+import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.Feature;
+import jakarta.ws.rs.core.FeatureContext;
+import jakarta.ws.rs.core.GenericType;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Map;
+import java.util.function.Supplier;
+
+public class HK2FactoryBindingTest {
+
+ public static interface ConfigurationProperties {
+ Map<String, Object> getProperties();
+ }
+
+ public static class ConfigurationPropertiesFactory implements org.glassfish.hk2.api.Factory<ConfigurationProperties> {
+
+ private final Configuration configuration;
+
+ @Inject
+ public ConfigurationPropertiesFactory(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public ConfigurationProperties provide() {
+ return new ConfigurationProperties() {
+ @Override
+ public Map<String, Object> getProperties() {
+ return configuration.getProperties();
+ }
+ };
+ }
+
+ @Override
+ public void dispose(ConfigurationProperties configurationProperties) {
+
+ }
+ }
+
+ @Priority(Priorities.USER)
+ public static class ConfigurationPropertiesFilter implements ClientRequestFilter {
+ @Inject
+ ConfigurationProperties properties;
+
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ requestContext.abortWith(Response.ok(properties.getProperties().get(PROPERTY_NAME)).build());
+ }
+ }
+
+ private static final String PROPERTY_NAME = "TEST_PROPERTY";
+ private static final String PROPERTY_VALUE = "HELLO_PROPERTY";
+
+ @Test
+ public void testFactoryClassBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(ConfigurationPropertiesFactory.class).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationPropertiesFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ @Test
+ public void testFactoryInstanceBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(new ConfigurationPropertiesFactory(config)).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationPropertiesFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ static final class ConfigurationPropertiesImpl implements ConfigurationProperties {
+ private final Configuration configuration;
+ @Inject
+ public ConfigurationPropertiesImpl(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return configuration.getProperties();
+ }
+ }
+
+ static class ConfigurationPropertiesSupplier implements Supplier<ConfigurationPropertiesImpl> {
+ private final Configuration configuration;
+
+ @Inject
+ ConfigurationPropertiesSupplier(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public ConfigurationPropertiesImpl get() {
+ return new ConfigurationPropertiesImpl(configuration);
+ }
+ }
+
+ @Test
+ public void testSupplierJerseyInstanceBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bindFactory(() -> new ConfigurationPropertiesImpl(config)).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationPropertiesFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ @Test
+ public void testSupplierJerseyClassBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bindFactory(ConfigurationPropertiesSupplier.class).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationPropertiesFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ public static interface ConfigurationPropertiesProvider {
+ Map<String, Object> getProperties();
+
+ ConfigurationProperties getConfigurationProperties();
+ }
+
+ public static class ConfigurationPropertiesProviderImpl implements ConfigurationPropertiesProvider {
+ private final Configuration configuration;
+ @Inject
+ public ConfigurationPropertiesProviderImpl(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return configuration.getProperties();
+ }
+
+ @Override
+ public ConfigurationProperties getConfigurationProperties() {
+ return new ConfigurationPropertiesImpl(configuration);
+ }
+ }
+
+ public static class ConfigurationPropertiesProviderSupplier implements Supplier<ConfigurationProperties> {
+ final ConfigurationPropertiesProvider impl;
+
+ @Inject
+ public ConfigurationPropertiesProviderSupplier(ConfigurationPropertiesProvider impl) {
+ this.impl = impl;
+ }
+
+ @Override
+ public ConfigurationProperties get() {
+ return impl.getConfigurationProperties();
+ }
+ }
+
+ public static class ConfigurationProperties2Filter implements ClientRequestFilter {
+ @Inject
+ ConfigurationProperties properties;
+
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ requestContext.abortWith(Response.ok(properties.getProperties().get(PROPERTY_NAME)).build());
+ }
+ }
+
+ @Test
+ public void testSupplierOfProviderClassBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(ConfigurationPropertiesProviderImpl.class).to(ConfigurationPropertiesProvider.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ bindFactory(ConfigurationPropertiesProviderSupplier.class).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationProperties2Filter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ @Test
+ public void testFactoryHk2ClassBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
+ @Override
+ protected void configure() {
+ bindFactory(ConfigurationPropertiesFactory.class).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationPropertiesFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ @Test
+ public void testFactoryHk2InstanceBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
+ @Override
+ protected void configure() {
+ bindFactory(new ConfigurationPropertiesFactory(config)).to(ConfigurationProperties.class).proxy(true)
+ .proxyForSameScope(false).in(RequestScoped.class);
+ }
+ }).register(ConfigurationPropertiesFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ static @interface ConfigurationPropertiesInject {
+
+ }
+
+ static class ConfigurationPropertiesInjectResolver implements InjectionResolver<ConfigurationPropertiesInject> {
+
+ private final InjectionManager injectionManager;
+
+ ConfigurationPropertiesInjectResolver(InjectionManager injectionManager) {
+ this.injectionManager = injectionManager;
+ }
+
+ @Override
+ public Object resolve(Injectee injectee) {
+ if (injectee.getRequiredType() == ConfigurationProperties.class) {
+ return new ConfigurationPropertiesImpl(injectionManager.getInstance(Configuration.class));
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isConstructorParameterIndicator() {
+ return false;
+ }
+
+ @Override
+ public boolean isMethodParameterIndicator() {
+ return false;
+ }
+
+ @Override
+ public Class<ConfigurationPropertiesInject> getAnnotation() {
+ return ConfigurationPropertiesInject.class;
+ }
+ }
+
+ public static class ConfigurationPropertiesInjectFilter implements ClientRequestFilter {
+ @ConfigurationPropertiesInject
+ ConfigurationProperties properties;
+
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ requestContext.abortWith(Response.ok(properties.getProperties().get(PROPERTY_NAME)).build());
+ }
+ }
+
+ @Test
+ public void testInjectionResolverBinding() {
+ ClientConfig config = new ClientConfig();
+ config.property(PROPERTY_NAME, PROPERTY_VALUE);
+ String response = ClientBuilder.newClient(config).register(new Feature() {
+ @Override
+ public boolean configure(FeatureContext context) {
+ final InjectionManager injectionManager = InjectionManagerClientProvider.getInjectionManager(context);
+ context.register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(new ConfigurationPropertiesInjectResolver(injectionManager))
+ //.to(ConfigurationProperties.class)
+ .to(new GenericType<ConfigurationProperties>(){})
+ .in(Singleton.class);
+ }
+ });
+ return true;
+ }
+ }).register(ConfigurationPropertiesInjectFilter.class).target("http://test.com").request().get(String.class);
+ Assertions.assertEquals(PROPERTY_VALUE, response);
+ }
+}
diff --git a/tests/e2e-jdk-specifics/pom.xml b/tests/e2e-jdk-specifics/pom.xml
new file mode 100644
index 0000000..55dd6c2
--- /dev/null
+++ b/tests/e2e-jdk-specifics/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<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.glassfish.jersey.tests</groupId>
+ <artifactId>project</artifactId>
+ <version>4.0.99-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>e2e-jdk-specifics</artifactId>
+ <name>jersey-tests-e2e-specifics</name>
+ <packaging>jar</packaging>
+
+ <description>Jersey E2E tests for testing JDK 17+ specifics</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <forkCount>1</forkCount>
+ <reuseForks>false</reuseForks>
+ <enableAssertions>false</enableAssertions>
+ <argLine>
+ ${http.patch.addopens}
+ </argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-bundle</artifactId>
+ <type>pom</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-suite</artifactId>
+ <version>${junit-platform-suite.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>jdk15-</id>
+ <activation>
+ <jdk>[8, 16)</jdk>
+ </activation>
+ <properties>
+ <http.patch.addopens> </http.patch.addopens>
+ </properties>
+ </profile>
+ <profile>
+ <id>jdk16+</id>
+ <activation>
+ <jdk>[16, )</jdk>
+ </activation>
+ <properties>
+ <http.patch.addopens>--add-opens java.base/java.net=ALL-UNNAMED</http.patch.addopens>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/tests/e2e-jdk-specifics/src/test/java/org/glassfish/jersey/tests/e2e/jdk17/HttpPatchTest.java b/tests/e2e-jdk-specifics/src/test/java/org/glassfish/jersey/tests/e2e/jdk17/HttpPatchTest.java
new file mode 100644
index 0000000..c949958
--- /dev/null
+++ b/tests/e2e-jdk-specifics/src/test/java/org/glassfish/jersey/tests/e2e/jdk17/HttpPatchTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.jdk17;
+
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.HttpMethod;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+public class HttpPatchTest extends JerseyTest {
+
+ public static final String PATCH_ENTITY = "HelloPatch";
+
+ @Target({ElementType.METHOD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @HttpMethod(HttpMethod.PATCH)
+ public @interface PATCH {
+
+ }
+
+ @Path("/")
+ public static class HttpPatchResource {
+ @PATCH
+ public String patchEcho(String entity) {
+ return entity;
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(HttpPatchResource.class);
+ }
+
+ @Test
+ void testPatchWithHttpUrlConnector() {
+ try (Response response = target()
+ .property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true)
+ .request().method(HttpMethod.PATCH, Entity.text(PATCH_ENTITY))) {
+ MatcherAssert.assertThat(200, Matchers.equalTo(response.getStatus()));
+ response.bufferEntity();
+ System.out.println(response.readEntity(String.class));
+ MatcherAssert.assertThat(PATCH_ENTITY, Matchers.equalTo(response.readEntity(String.class)));
+ }
+ }
+}
diff --git a/tests/e2e-jdk-specifics/src/test/java/org/glassfish/jersey/tests/e2e/jdk21/ThreadFactoryUsageTest.java b/tests/e2e-jdk-specifics/src/test/java/org/glassfish/jersey/tests/e2e/jdk21/ThreadFactoryUsageTest.java
new file mode 100644
index 0000000..6739ba9
--- /dev/null
+++ b/tests/e2e-jdk-specifics/src/test/java/org/glassfish/jersey/tests/e2e/jdk21/ThreadFactoryUsageTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.jdk21;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.innate.VirtualThreadSupport;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.core.Response;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+public class ThreadFactoryUsageTest {
+ @Test
+ public void testThreadFactory() throws ExecutionException, InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ ThreadFactory threadFactory = VirtualThreadSupport.allowVirtual(true).getThreadFactory();
+ ThreadFactory countDownThreadFactory = r -> {
+ countDownLatch.countDown();
+ return threadFactory.newThread(r);
+ };
+
+ CompletionStage<Response> r = ClientBuilder.newClient()
+ .property(CommonProperties.THREAD_FACTORY, countDownThreadFactory)
+ .property(CommonProperties.USE_VIRTUAL_THREADS, true)
+ .register((ClientRequestFilter) requestContext -> requestContext.abortWith(Response.ok().build()))
+ .target("http://localhost:58080/test").request().rx().get();
+
+ MatcherAssert.assertThat(r.toCompletableFuture().get().getStatus(), Matchers.is(200));
+ countDownLatch.await(10, TimeUnit.SECONDS);
+ MatcherAssert.assertThat(countDownLatch.getCount(), Matchers.is(0L));
+ }
+}
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml
index e55a2a2..9adafc5 100644
--- a/tests/e2e-server/pom.xml
+++ b/tests/e2e-server/pom.xml
@@ -41,7 +41,6 @@
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
</configuration>
<executions>
<execution>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ChunkedInputOutputTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ChunkedInputOutputTest.java
index 64c0422..f8dab62 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ChunkedInputOutputTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ChunkedInputOutputTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -61,13 +61,33 @@
@Path("/test")
public static class TestResource {
/**
+ * Get chunk stream with a queue capacity of 2.
+ *
+ * @return chunk stream.
+ */
+ @GET
+ @Path("/testWithBuilder")
+ public ChunkedOutput<String> getWithBuilder() {
+ return getOutput(ChunkedOutput.<String>builder(String.class).queueCapacity(2)
+ .chunkDelimiter("\r\n".getBytes()).build());
+ }
+
+ /**
* Get chunk stream.
*
* @return chunk stream.
*/
@GET
public ChunkedOutput<String> get() {
- final ChunkedOutput<String> output = new ChunkedOutput<>(String.class, "\r\n");
+ return getOutput(new ChunkedOutput<>(String.class, "\r\n"));
+ }
+
+ /**
+ * Get chunk stream.
+ *
+ * @return chunk stream.
+ */
+ private ChunkedOutput<String> getOutput(ChunkedOutput<String> output) {
new Thread() {
@Override
@@ -183,6 +203,19 @@
}
/**
+ * Test retrieving chunked response stream as a single response string, when a builder with capacity is used.
+ *
+ * @throws Exception in case of a failure during the test execution.
+ */
+ @Test
+ public void testChunkedOutputToSingleStringWithBuilder() throws Exception {
+ final String response = target().path("test/testWithBuilder").request().get(String.class);
+
+ assertEquals("test\r\ntest\r\ntest\r\n", response,
+ "Unexpected value of chunked response unmarshalled as a single string.");
+ }
+
+ /**
* Test retrieving chunked response stream sequentially as individual chunks using chunked input.
*
* @throws Exception in case of a failure during the test execution.
diff --git a/tests/e2e-testng/pom.xml b/tests/e2e-testng/pom.xml
index 2d5ec2c..39438c4 100644
--- a/tests/e2e-testng/pom.xml
+++ b/tests/e2e-testng/pom.xml
@@ -46,7 +46,6 @@
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
</configuration>
<dependencies>
<dependency>
diff --git a/tests/e2e-tls/pom.xml b/tests/e2e-tls/pom.xml
index f59026b..9aa5f85 100644
--- a/tests/e2e-tls/pom.xml
+++ b/tests/e2e-tls/pom.xml
@@ -40,8 +40,6 @@
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
- <enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
<systemPropertyVariables>
<sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders>
<jdk.httpclient.allowRestrictedHeaders>Host</jdk.httpclient.allowRestrictedHeaders>
@@ -51,6 +49,24 @@
</property>
</systemPropertyVariables>
</configuration>
+ <executions>
+ <execution>
+ <id>HttpsPatch</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>**/HttpsPatchTest.java</include>
+ </includes>
+ <systemPropertyVariables>
+ <jersey.added.opens>true</jersey.added.opens>
+ </systemPropertyVariables>
+ <!-- Allow HTTP PATCH by property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true) -->
+ <argLine>${http.patch.addopens}</argLine>
+ </configuration>
+ </execution>
+ </executions>
</plugin>
</plugins>
</build>
@@ -125,6 +141,10 @@
<properties>
<!-- https://bugs.openjdk.java.net/browse/JDK-8211426 -->
<surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline>
+ <http.patch.addopens>
+ --add-opens java.base/java.net=ALL-UNNAMED
+ --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED
+ </http.patch.addopens>
</properties>
</project>
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
index a7aff99..9c64c2d 100644
--- a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
@@ -72,10 +72,29 @@
ClientConfig clientConfig = new ClientConfig();
clientConfig.connectorProvider(provider);
clientConfig.property(ClientProperties.SNI_HOST_NAME, "www.host1.com");
- serverTest(clientConfig, provider, "www.host1.com");
+ serverTest(clientConfig, provider, "www.host1.com", "www.host1.com");
}
- public void serverTest(ClientConfig clientConfig, ConnectorProvider provider, String hostName) {
+ @ParameterizedTest
+ @MethodSource("getConnectors")
+ public void sniHostNamePropertyTest(ConnectorProvider provider) {
+ ClientConfig clientConfig = new ClientConfig();
+ clientConfig.connectorProvider(provider);
+ clientConfig.property(ClientProperties.SNI_HOST_NAME, "www.host3.com");
+ serverTest(clientConfig, provider, "www.host4.com", "www.host3.com");
+ }
+
+ @ParameterizedTest
+ @MethodSource("getConnectors")
+ public void turnOffSniTest(ConnectorProvider provider) {
+ ClientConfig clientConfig = new ClientConfig();
+ clientConfig.connectorProvider(provider);
+ clientConfig.property(ClientProperties.SNI_HOST_NAME, LOCALHOST);
+ serverTest(clientConfig, provider, "www.host4.com", null);
+ }
+
+
+ public void serverTest(ClientConfig clientConfig, ConnectorProvider provider, String hostName, String resultHostName) {
String newHostName = replaceWhenHostNotKnown(hostName);
final List<SNIServerName> serverNames = new LinkedList<>();
final String[] requestHostName = new String[1];
@@ -119,12 +138,14 @@
server.stop();
- if (serverNames.isEmpty()) {
+ if (resultHostName != null && serverNames.isEmpty()) {
throw new IllegalStateException("ServerNames are empty");
+ } else if (resultHostName == null) {
+ return;
}
String clientSniName = new String(serverNames.get(0).getEncoded());
- if (!hostName.equals(clientSniName)) {
+ if (!resultHostName.equals(clientSniName)) {
throw new IllegalStateException("Unexpected client SNI name " + clientSniName);
}
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslContextPerRequestTest.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslContextPerRequestTest.java
index 944f284..d2564e9 100644
--- a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslContextPerRequestTest.java
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslContextPerRequestTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -53,10 +53,8 @@
import java.util.function.Supplier;
import java.util.stream.Stream;
-public class SslContextPerRequestTest extends JerseyTest {
+public class SslContextPerRequestTest extends SslParentTest {
- private SSLContext serverSslContext;
- private SSLParameters serverSslParameters;
private static final String MESSAGE = "Message for Netty with SSL";
@Override
@@ -77,33 +75,6 @@
return new ResourceConfig(TestResource.class);
}
- @Override
- protected URI getBaseUri() {
- return UriBuilder
- .fromUri("https://localhost")
- .port(getPort())
- .build();
- }
-
- @Override
- protected Optional<SSLContext> getSslContext() {
- if (serverSslContext == null) {
- serverSslContext = SslUtils.createServerSslContext();
- }
-
- return Optional.of(serverSslContext);
- }
-
- @Override
- protected Optional<SSLParameters> getSslParameters() {
- if (serverSslParameters == null) {
- serverSslParameters = new SSLParameters();
- serverSslParameters.setNeedClientAuth(false);
- }
-
- return Optional.of(serverSslParameters);
- }
-
public static Stream<ConnectorProvider> connectorProviders() {
return Stream.of(
new HttpUrlConnectorProvider(),
@@ -168,43 +139,4 @@
String s = target.request().get(String.class);
Assertions.assertEquals(MESSAGE, s);
}
-
- private static class SslUtils {
-
- private static final String SERVER_IDENTITY_PATH = "server-identity.jks";
- private static final char[] SERVER_IDENTITY_PASSWORD = "secret".toCharArray();
-
- private static final String CLIENT_TRUSTSTORE_PATH = "client-truststore.jks";
- private static final char[] CLIENT_TRUSTSTORE_PASSWORD = "secret".toCharArray();
-
- private static final String KEYSTORE_TYPE = "PKCS12";
-
- private SslUtils() {}
-
- public static SSLContext createServerSslContext() {
- return new SslContextClientBuilder()
- .keyStore(getKeyStore(SERVER_IDENTITY_PATH, SERVER_IDENTITY_PASSWORD), SERVER_IDENTITY_PASSWORD)
- .get();
- }
-
- public static Supplier<SSLContext> createClientSslContext() {
- return new SslContextClientBuilder()
- .trustStore(getKeyStore(CLIENT_TRUSTSTORE_PATH, CLIENT_TRUSTSTORE_PASSWORD));
-
- }
-
- private static KeyStore getKeyStore(String path, char[] keyStorePassword) {
- try (InputStream inputStream = getResource(path)) {
- KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
- keyStore.load(inputStream, keyStorePassword);
- return keyStore;
- } catch (Exception e) {
- throw new ProcessingException(e);
- }
- }
-
- private static InputStream getResource(String path) {
- return SslUtils.class.getClassLoader().getResourceAsStream(path);
- }
- }
}
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslParentTest.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslParentTest.java
new file mode 100644
index 0000000..abfe245
--- /dev/null
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SslParentTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.tls;
+
+import org.glassfish.jersey.client.SslContextClientBuilder;
+import org.glassfish.jersey.test.JerseyTest;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.UriBuilder;
+import java.io.InputStream;
+import java.net.URI;
+import java.security.KeyStore;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+public class SslParentTest extends JerseyTest {
+
+ protected SSLContext serverSslContext;
+ protected SSLParameters serverSslParameters;
+
+ @Override
+ protected Optional<SSLContext> getSslContext() {
+ if (serverSslContext == null) {
+ serverSslContext = SslUtils.createServerSslContext();
+ }
+
+ return Optional.of(serverSslContext);
+ }
+
+ @Override
+ protected Optional<SSLParameters> getSslParameters() {
+ if (serverSslParameters == null) {
+ serverSslParameters = new SSLParameters();
+ serverSslParameters.setNeedClientAuth(false);
+ }
+
+ return Optional.of(serverSslParameters);
+ }
+
+ @Override
+ protected URI getBaseUri() {
+ return UriBuilder
+ .fromUri("https://localhost")
+ .port(getPort())
+ .build();
+ }
+
+ protected static class SslUtils {
+
+ private static final String SERVER_IDENTITY_PATH = "server-identity.jks";
+ private static final char[] SERVER_IDENTITY_PASSWORD = "secret".toCharArray();
+
+ private static final String CLIENT_TRUSTSTORE_PATH = "client-truststore.jks";
+ private static final char[] CLIENT_TRUSTSTORE_PASSWORD = "secret".toCharArray();
+
+ private static final String KEYSTORE_TYPE = "PKCS12";
+
+ private SslUtils() {}
+
+ public static SSLContext createServerSslContext() {
+ return new SslContextClientBuilder()
+ .keyStore(getKeyStore(SERVER_IDENTITY_PATH, SERVER_IDENTITY_PASSWORD), SERVER_IDENTITY_PASSWORD)
+ .get();
+ }
+
+ public static Supplier<SSLContext> createClientSslContext() {
+ return new SslContextClientBuilder()
+ .trustStore(getKeyStore(CLIENT_TRUSTSTORE_PATH, CLIENT_TRUSTSTORE_PASSWORD));
+
+ }
+
+ private static KeyStore getKeyStore(String path, char[] keyStorePassword) {
+ try (InputStream inputStream = getResource(path)) {
+ KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
+ keyStore.load(inputStream, keyStorePassword);
+ return keyStore;
+ } catch (Exception e) {
+ throw new ProcessingException(e);
+ }
+ }
+
+ private static InputStream getResource(String path) {
+ return SslUtils.class.getClassLoader().getResourceAsStream(path);
+ }
+ }
+}
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/patch/HttpsPatchTest.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/patch/HttpsPatchTest.java
new file mode 100644
index 0000000..37b63c8
--- /dev/null
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/patch/HttpsPatchTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package org.glassfish.jersey.tests.e2e.tls.patch;
+
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.tests.e2e.tls.SslParentTest;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import javax.net.ssl.SSLContext;
+import jakarta.ws.rs.HttpMethod;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.function.Supplier;
+
+public class HttpsPatchTest extends SslParentTest {
+
+ public static final String PATCH_ENTITY = "HelloPatch";
+
+ @Target({ElementType.METHOD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @HttpMethod(HttpMethod.PATCH)
+ public @interface PATCH {
+
+ }
+
+ @Path("/")
+ public static class HttpPatchResource {
+ @PATCH
+ public String patchEcho(String entity) {
+ return entity;
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(HttpPatchResource.class);
+ }
+
+ @Test
+ void testPatchWithHttpUrlConnector() {
+ String value = System.getProperty("jersey.added.opens");
+ if (null == value) {
+ System.out.println("JDK add-opens not set - exiting...");
+ return;
+ }
+
+ Supplier<SSLContext> clientSslContext = SslUtils.createClientSslContext();
+ try (Response response = target()
+ .property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true)
+ .property(ClientProperties.SSL_CONTEXT_SUPPLIER, clientSslContext)
+ .request().method(HttpMethod.PATCH, Entity.text(PATCH_ENTITY))) {
+ MatcherAssert.assertThat(200, Matchers.equalTo(response.getStatus()));
+ response.bufferEntity();
+ System.out.println(response.readEntity(String.class));
+ MatcherAssert.assertThat(PATCH_ENTITY, Matchers.equalTo(response.readEntity(String.class)));
+ }
+ }
+}
diff --git a/tests/e2e/pom.xml b/tests/e2e/pom.xml
index fe6a81d..698ba28 100644
--- a/tests/e2e/pom.xml
+++ b/tests/e2e/pom.xml
@@ -41,10 +41,10 @@
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
<excludes>
<!--TODO remove after jakartification-->
<exclude>org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java</exclude>
+ <exclude>org/glassfish/jersey/tests/e2e/inject/SingleRequestScopeInjectionTest.java</exclude>
</excludes>
</configuration>
</plugin>
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/inject/SingleRequestScopeInjectionTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/inject/SingleRequestScopeInjectionTest.java
new file mode 100644
index 0000000..2c4cc35
--- /dev/null
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/inject/SingleRequestScopeInjectionTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject;
+
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.util.collection.Ref;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.jetty.JettyTestContainerFactory;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+import org.junit.jupiter.api.Test;
+
+import jakarta.inject.Inject;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.DynamicFeature;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.FeatureContext;
+import jakarta.ws.rs.core.GenericType;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class SingleRequestScopeInjectionTest extends JerseyTest {
+ @Path("hello")
+ public static class HelloResource {
+ @GET
+ public String getHello() {
+ return "Hello World!";
+ }
+ }
+ @Override
+ protected Application configure() {
+ ResourceConfig resourceConfig = new ResourceConfig(HelloResource.class);
+ resourceConfig.register(new InjectedFilterRegistrar(InjectedFilter.class));
+ return resourceConfig;
+ }
+ @Override
+ protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+ return new JettyTestContainerFactory();
+ }
+ @Test
+ public void test() {
+ final String hello = target("hello").request().get(String.class);
+ assertEquals("Hello World!", hello);
+ }
+ public static class InjectedFilter implements ContainerRequestFilter {
+ @Inject
+ private InjectionManager injectionManager;
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ Ref<HttpServletRequest> requestRef =
+ injectionManager.getInstance((new GenericType<Ref<HttpServletRequest>>() {}).getType());
+ if (requestRef == null || requestRef.get() == null) {
+ throw new IllegalStateException("Request not injected");
+ }
+ }
+ }
+ public static class InjectedFilterRegistrar implements DynamicFeature {
+ private final Class<?> filterToRegister;
+ public InjectedFilterRegistrar(Class<?> filterToRegister) {
+ this.filterToRegister = filterToRegister;
+ }
+ @Override
+ public void configure(ResourceInfo resourceInfo, FeatureContext context) {
+ context.register(filterToRegister);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/integration/jersey-2421/src/test/java/org/glassfish/jersey/tests/integration/jersey2421/Jersey2421Test.java b/tests/integration/jersey-2421/src/test/java/org/glassfish/jersey/tests/integration/jersey2421/Jersey2421Test.java
index bae7758..79be107 100644
--- a/tests/integration/jersey-2421/src/test/java/org/glassfish/jersey/tests/integration/jersey2421/Jersey2421Test.java
+++ b/tests/integration/jersey-2421/src/test/java/org/glassfish/jersey/tests/integration/jersey2421/Jersey2421Test.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -38,7 +38,6 @@
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
-import org.glassfish.jersey.message.internal.NullOutputStream;
import org.glassfish.jersey.message.internal.OutboundMessageContext;
import org.junit.jupiter.api.Test;
@@ -61,7 +60,7 @@
request.setStreamProvider(new OutboundMessageContext.StreamProvider() {
@Override
public OutputStream getOutputStream(final int contentLength) throws IOException {
- return new NullOutputStream();
+ return OutputStream.nullOutputStream();
}
});
request.writeEntity();
diff --git a/tests/integration/jersey-2794/src/test/java/org/glassfish/jersey/tests/integration/jersey2794/Jersey2794ITCase.java b/tests/integration/jersey-2794/src/test/java/org/glassfish/jersey/tests/integration/jersey2794/Jersey2794ITCase.java
index 80eca2d..ce9ccdc 100644
--- a/tests/integration/jersey-2794/src/test/java/org/glassfish/jersey/tests/integration/jersey2794/Jersey2794ITCase.java
+++ b/tests/integration/jersey-2794/src/test/java/org/glassfish/jersey/tests/integration/jersey2794/Jersey2794ITCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,7 +23,6 @@
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;
@@ -104,7 +103,7 @@
private int matchingTempFiles(final String tempDir) throws IOException {
AtomicInteger count = new AtomicInteger(0);
- Files.walkFileTree(Paths.get(tempDir), new SimpleFileVisitor<Path>() {
+ Files.walkFileTree(Path.of(tempDir), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (file.getFileName().startsWith("MIME") && file.getFileName().endsWith("tmp")) {
diff --git a/tests/integration/jersey-2846/src/test/java/org/glassfish/jersey/tests/integration/jersey2846/Jersey2846ITCase.java b/tests/integration/jersey-2846/src/test/java/org/glassfish/jersey/tests/integration/jersey2846/Jersey2846ITCase.java
index 4286aef..6b37da0 100644
--- a/tests/integration/jersey-2846/src/test/java/org/glassfish/jersey/tests/integration/jersey2846/Jersey2846ITCase.java
+++ b/tests/integration/jersey-2846/src/test/java/org/glassfish/jersey/tests/integration/jersey2846/Jersey2846ITCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,7 +20,6 @@
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
@@ -124,7 +123,7 @@
private int matchingTempFiles(final String tempDir) throws IOException {
AtomicInteger count = new AtomicInteger(0);
- Files.walkFileTree(Paths.get(tempDir), new SimpleFileVisitor<Path>() {
+ Files.walkFileTree(Path.of(tempDir), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path name = file.getFileName();
diff --git a/tests/integration/servlet-tests/pom.xml b/tests/integration/servlet-tests/pom.xml
index 0ec8128..042b903 100644
--- a/tests/integration/servlet-tests/pom.xml
+++ b/tests/integration/servlet-tests/pom.xml
@@ -48,6 +48,7 @@
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-external</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
diff --git a/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorFilter.java b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorFilter.java
new file mode 100644
index 0000000..856e2ef
--- /dev/null
+++ b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorFilter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.integration.servlettests;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+import java.io.IOException;
+
+import static org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource.ERROR_MESSAGE;
+
+public class PostProcessingErrorFilter implements Filter {
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ Filter.super.init(filterConfig);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException {
+
+ try {
+ chain.doFilter(request, response);
+ } catch (ServletException ex) {
+ //post-processing attempt
+ final Throwable orig = ex.getRootCause();
+ if (orig.getMessage().equalsIgnoreCase(ERROR_MESSAGE)) {
+ response.getWriter().print(ERROR_MESSAGE);
+ response.getWriter().flush();
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+ Filter.super.destroy();
+ }
+}
diff --git a/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorResource.java b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorResource.java
new file mode 100644
index 0000000..b9d3451
--- /dev/null
+++ b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorResource.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.integration.servlettests;
+
+import jakarta.servlet.http.HttpServlet;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.Response;
+
+@Path("postprocessing")
+public class PostProcessingErrorResource extends HttpServlet {
+
+ static final String ERROR_MESSAGE = "Must be post processed";
+ @GET
+ public Response getException() {
+ throw new ProcessingException(ERROR_MESSAGE);
+ }
+
+}
diff --git a/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml b/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml
index 5d9d99e..813b221 100644
--- a/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml
+++ b/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -157,4 +157,31 @@
<filter-name>custom404</filter-name>
<url-pattern>/custom404/*</url-pattern>
</filter-mapping>
+
+ <!-- post process errors (40*, 50*) -->
+ <filter>
+ <filter-name>PostProcessFilter</filter-name>
+ <filter-class>org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorFilter</filter-class>
+ </filter>
+ <servlet>
+ <servlet-name>PostProcessServlet</servlet-name>
+ <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>jersey.config.server.provider.classnames</param-name>
+ <param-value>org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource</param-value>
+ </init-param>
+ <init-param>
+ <param-name>jersey.config.server.response.setStatusOverSendError</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>PostProcessServlet</servlet-name>
+ <url-pattern>/postProcess/*</url-pattern>
+ </servlet-mapping>
+ <filter-mapping>
+ <filter-name>PostProcessFilter</filter-name>
+ <url-pattern>/postProcess/*</url-pattern>
+ </filter-mapping>
</web-app>
diff --git a/tests/integration/servlet-tests/src/test/java/org/glassfish/jersey/tests/integration/servlettests/PostProcesingITCase.java b/tests/integration/servlet-tests/src/test/java/org/glassfish/jersey/tests/integration/servlettests/PostProcesingITCase.java
new file mode 100644
index 0000000..dbab315
--- /dev/null
+++ b/tests/integration/servlet-tests/src/test/java/org/glassfish/jersey/tests/integration/servlettests/PostProcesingITCase.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.integration.servlettests;
+
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.external.ExternalTestContainerFactory;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+import org.junit.jupiter.api.Test;
+
+import java.util.Locale;
+
+import static org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource.ERROR_MESSAGE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class PostProcesingITCase extends JerseyTest {
+
+ @Override
+ protected Application configure() {
+ // dummy resource config
+ return new ResourceConfig();
+ }
+
+ @Override
+ protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+ return new ExternalTestContainerFactory();
+ }
+
+ @Test
+ public void testPostProcessingLocale() {
+ final Response response = target()
+ .path("postProcess/postprocessing")
+ .request().get();
+ assertEquals(ERROR_MESSAGE, response.readEntity(String.class));
+ }
+
+}
diff --git a/tests/integration/tracing-support/pom.xml b/tests/integration/tracing-support/pom.xml
index 50a9f2a..eb33aa5 100644
--- a/tests/integration/tracing-support/pom.xml
+++ b/tests/integration/tracing-support/pom.xml
@@ -43,13 +43,42 @@
<artifactId>jersey-test-framework-provider-external</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.config.file>${project.build.testOutputDirectory}/logging.properties</java.util.logging.config.file>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
+<!-- <configuration>-->
+<!-- <!–-->
+<!-- Since Jetty 11 for some reason is not possibly to properly set responseHeaderSize property-->
+<!-- which should be jetty.response.header.size with adjusted value 16192. The property however-->
+<!-- is never recognized by the plugin so resulting in the-->
+<!-- org.eclipse.jetty.http.BadMessageException: 500: Response header too large-->
+<!-- exception. For this reason the test is being excluded.-->
+<!-- –>-->
+<!-- <testExcludes>-->
+<!-- <testExclude>-->
+<!-- org/glassfish/jersey/tests/integration/tracing/AllTracingSupportITCase.java-->
+<!-- </testExclude>-->
+<!-- </testExcludes>-->
+<!-- </configuration> -->
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git a/tests/integration/tracing-support/src/test/java/org/glassfish/jersey/tests/integration/tracing/TracingMatchResourceMethodTest.java b/tests/integration/tracing-support/src/test/java/org/glassfish/jersey/tests/integration/tracing/TracingMatchResourceMethodTest.java
new file mode 100644
index 0000000..6afcd91
--- /dev/null
+++ b/tests/integration/tracing-support/src/test/java/org/glassfish/jersey/tests/integration/tracing/TracingMatchResourceMethodTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.integration.tracing;
+
+import org.glassfish.jersey.message.internal.TracingLogger;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.server.TracingConfig;
+import org.glassfish.jersey.server.internal.ServerTraceEvent;
+import org.glassfish.jersey.test.JerseyTest;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+public class TracingMatchResourceMethodTest extends JerseyTest {
+ GatheringHandler handler = new GatheringHandler();
+ Logger logger;
+
+ @Path("/echo")
+ public static class TracingMatchResourceMethodResource {
+ @Path("echo")
+ @POST
+ public String echo(String entity) {
+ return entity;
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(TracingMatchResourceMethodResource.class)
+ .property(ServerProperties.TRACING, TracingConfig.ALL.name())
+ .property(ServerProperties.TRACING_THRESHOLD, TracingLogger.Level.VERBOSE.name());
+ }
+
+ @Test
+ public void testEcho() {
+ logger = Logger.getLogger("org.glassfish.jersey.tracing.general");
+ logger.addHandler(handler);
+
+ try (Response r = target("echo").path("echo").request().post(Entity.entity("ECHO", MediaType.TEXT_PLAIN_TYPE))) {
+ MatcherAssert.assertThat(r.getStatus(), Matchers.equalTo(200));
+ MatcherAssert.assertThat(r.readEntity(String.class), Matchers.equalTo("ECHO"));
+ }
+
+ List<LogRecord> matched = handler.logRecords.stream()
+ .filter(logRecord -> logRecord.getMessage().startsWith(ServerTraceEvent.MATCH_RESOURCE_METHOD.name()))
+ .collect(Collectors.toList());
+ MatcherAssert.assertThat(matched.size(), Matchers.equalTo(1));
+ }
+
+ private static class GatheringHandler extends Handler {
+
+ List<LogRecord> logRecords = new ArrayList<>();
+
+ @Override
+ public void publish(LogRecord record) {
+ logRecords.add(record);
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ }
+ }
+}
diff --git a/tests/performance/jmx-client/src/main/java/org/glassfish/jersey/tests/performance/jmxclient/Main.java b/tests/performance/jmx-client/src/main/java/org/glassfish/jersey/tests/performance/jmxclient/Main.java
index 05391bc..ba18aae 100644
--- a/tests/performance/jmx-client/src/main/java/org/glassfish/jersey/tests/performance/jmxclient/Main.java
+++ b/tests/performance/jmx-client/src/main/java/org/glassfish/jersey/tests/performance/jmxclient/Main.java
@@ -80,6 +80,6 @@
private static void writeResult(double resultValue, String propertiesFile) throws IOException {
Properties resultProps = new Properties();
resultProps.put("YVALUE", Double.toString(resultValue));
- resultProps.store(Files.newOutputStream(Paths.get(propertiesFile)), null);
+ resultProps.store(Files.newOutputStream(Path.of(propertiesFile)), null);
}
}
diff --git a/tests/pom.xml b/tests/pom.xml
index 299e542..2025a8a 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -42,6 +42,7 @@
<module>e2e-core-common</module>
<module>e2e-entity</module>
<module>e2e-inject</module>
+ <module>e2e-jdk-specifics</module>
<module>e2e-server</module>
<module>e2e-testng</module>
<module>e2e-tls</module>
diff --git a/tests/release-test/src/test/resources/non-bom-pom-deps.xml b/tests/release-test/src/test/resources/non-bom-pom-deps.xml
index 7ced6b0..e3aca57 100644
--- a/tests/release-test/src/test/resources/non-bom-pom-deps.xml
+++ b/tests/release-test/src/test/resources/non-bom-pom-deps.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,7 +24,7 @@
<parent>
<groupId>org.eclipse.ee4j</groupId>
<artifactId>project</artifactId>
- <version>1.0.8</version>
+ <version>1.0.9</version>
</parent>
<groupId>org.glassfish.jersey.tests</groupId>
diff --git a/tests/release-test/src/test/resources/release-test-pom.xml b/tests/release-test/src/test/resources/release-test-pom.xml
index 4fac652..58966b3 100644
--- a/tests/release-test/src/test/resources/release-test-pom.xml
+++ b/tests/release-test/src/test/resources/release-test-pom.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,7 +24,7 @@
<parent>
<groupId>org.eclipse.ee4j</groupId>
<artifactId>project</artifactId>
- <version>1.0.8</version>
+ <version>1.0.9</version>
</parent>
<groupId>org.glassfish.jersey.tests</groupId>
diff --git a/tools/jersey-doc-modulelist-maven-plugin/pom.xml b/tools/jersey-doc-modulelist-maven-plugin/pom.xml
index daeea61..876adef 100644
--- a/tools/jersey-doc-modulelist-maven-plugin/pom.xml
+++ b/tools/jersey-doc-modulelist-maven-plugin/pom.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,7 +24,7 @@
<parent>
<groupId>org.eclipse.ee4j</groupId>
<artifactId>project</artifactId>
- <version>1.0.8</version>
+ <version>1.0.9</version>
</parent>
<groupId>org.glassfish.jersey.tools.plugins</groupId>
diff --git a/tools/jersey-release-notes-maven-plugin/pom.xml b/tools/jersey-release-notes-maven-plugin/pom.xml
index e9a819d..fa51932 100644
--- a/tools/jersey-release-notes-maven-plugin/pom.xml
+++ b/tools/jersey-release-notes-maven-plugin/pom.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,7 +24,7 @@
<parent>
<groupId>org.eclipse.ee4j</groupId>
<artifactId>project</artifactId>
- <version>1.0.8</version>
+ <version>1.0.9</version>
</parent>
<groupId>org.glassfish.jersey.tools.plugins</groupId>
diff --git a/tools/jersey-release-notes-maven-plugin/src/main/java/org/glassfish/jersey/tools/plugins/releasenotes/ReleaseNotesMojo.java b/tools/jersey-release-notes-maven-plugin/src/main/java/org/glassfish/jersey/tools/plugins/releasenotes/ReleaseNotesMojo.java
index eec3df2..1ddf887 100644
--- a/tools/jersey-release-notes-maven-plugin/src/main/java/org/glassfish/jersey/tools/plugins/releasenotes/ReleaseNotesMojo.java
+++ b/tools/jersey-release-notes-maven-plugin/src/main/java/org/glassfish/jersey/tools/plugins/releasenotes/ReleaseNotesMojo.java
@@ -33,7 +33,7 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -172,12 +172,12 @@
String releaseVersion, String releaseDate,
String releaseNotesFilePath,
Boolean dryRun, Log log) throws IOException {
- if (Files.notExists(Paths.get(templateFilePath))) {
+ if (Files.notExists(Path.of(templateFilePath))) {
log.warn(String.format("There is no source template file at the given location:%s", templateFilePath));
return;
}
final List<String> notesLines = new ArrayList<>();
- final List<String> lines = Files.readAllLines(Paths.get(templateFilePath), Charset.defaultCharset());
+ final List<String> lines = Files.readAllLines(Path.of(templateFilePath), Charset.defaultCharset());
for (final String line : lines) {
if (line.contains(RELEASE_DATE_PATTERN)) {
notesLines.add(line.replace(RELEASE_DATE_PATTERN, releaseDate));
@@ -197,8 +197,8 @@
}
if (Boolean.FALSE.equals(dryRun)) {
log.info(String.format("Storing release notes to file %s/%s.html", releaseNotesFilePath, releaseVersion));
- Files.createDirectories(Paths.get(releaseNotesFilePath));
- Files.write(Paths.get(String.format("%s/%s.html", releaseNotesFilePath, releaseVersion)), notesLines, Charset.defaultCharset());
+ Files.createDirectories(Path.of(releaseNotesFilePath));
+ Files.write(Path.of(String.format("%s/%s.html", releaseNotesFilePath, releaseVersion)), notesLines, Charset.defaultCharset());
} else {
log.info("Prepared release notes are not stored to file due to dryRun mode");
log.info(String.format("File path to store release notes is: %s/%s.html", releaseNotesFilePath, releaseVersion));