Merge remote-tracking branch 'origin/master' into 3.x
diff --git a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/StressTest.java b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/StressTest.java
deleted file mode 100644
index fa8414b..0000000
--- a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/StressTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2021 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.jdk.connector.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.List;
-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 jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.core.Application;
-import jakarta.ws.rs.core.Response;
-
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder;
-import org.glassfish.jersey.jdk.connector.JdkConnectorProvider;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.test.JerseyTest;
-import org.glassfish.jersey.test.TestProperties;
-import org.junit.Test;
-
-public class StressTest extends JerseyTest {
-
- private static final int PARALLELISM = 50;
- private static final int ITERATIONS = 1000;
-
- @Path("/test")
- public static class TestResource {
-
- @GET
- public String test() {
- return "test";
- }
- }
-
- @Override
- protected Application configure() {
- enable(TestProperties.LOG_TRAFFIC);
- enable(TestProperties.DUMP_ENTITY);
- return new ResourceConfig(TestResource.class);
- }
-
- @Override
- protected void configureClient(ClientConfig config) {
- config.connectorProvider(new JdkConnectorProvider());
- }
-
- @Test
- public void randomnessStatus200() throws InterruptedException, ExecutionException {
- ExecutorService executor = Executors.newFixedThreadPool(PARALLELISM,
- new ThreadFactoryBuilder().setNameFormat("client-%d").build());
- for (int i = 0; i < ITERATIONS; i++) {
- System.out.println("Iteration " + i);
- List<Future<Response>> responses = new ArrayList<>();
- for (int j = 0; j < 100; j++) {
- Future<Response> future = executor.submit(() -> target("/test").request().get());
- responses.add(future);
- }
- for (Future<Response> response : responses) {
- assertEquals(200, response.get().getStatus());
- }
- }
- executor.shutdown();
- assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
- }
-}
diff --git a/connectors/jetty-connector/pom.xml b/connectors/jetty-connector/pom.xml
index 8be410e..234e0ae 100644
--- a/connectors/jetty-connector/pom.xml
+++ b/connectors/jetty-connector/pom.xml
@@ -107,6 +107,19 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ ${jetty.osgi.version},
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java
index ef2c8be..b6817dc 100644
--- a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java
+++ b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java
@@ -86,6 +86,24 @@
"jersey.config.jetty.client.syncListenerResponseMaxSize";
/**
+ * Total timeout interval for request/response conversation, in milliseconds.
+ * Opposed to {@link org.glassfish.jersey.client.ClientProperties#READ_TIMEOUT}.
+ * <p>
+ * The value MUST be an instance convertible to {@link java.lang.Integer}. The
+ * value of zero (0) is equivalent to an interval of infinity.
+ * </p>
+ * <p>
+ * The default value is zero (infinity).
+ * </p>
+ * <p>
+ * The name of the configuration property is <tt>{@value}</tt>.
+ * </p>
+ *
+ * @since 2.37
+ */
+ public static final String TOTAL_TIMEOUT = "jersey.config.jetty.client.totalTimeout";
+
+ /**
* Get the value of the specified property.
*
* If the property is not set or the real value type is not compatible with the specified value type, returns {@code null}.
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java
index c2b881d..33749a2 100644
--- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java
+++ b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -323,8 +323,14 @@
request.followRedirects(clientRequest.resolveProperty(ClientProperties.FOLLOW_REDIRECTS, true));
final Object readTimeout = clientRequest.resolveProperty(ClientProperties.READ_TIMEOUT, -1);
if (readTimeout != null && readTimeout instanceof Integer && (Integer) readTimeout > 0) {
- request.timeout((Integer) readTimeout, TimeUnit.MILLISECONDS);
+ request.idleTimeout((Integer) readTimeout, TimeUnit.MILLISECONDS);
}
+
+ final Object totalTimeout = clientRequest.resolveProperty(JettyClientProperties.TOTAL_TIMEOUT, -1);
+ if (totalTimeout != null && totalTimeout instanceof Integer && (Integer) totalTimeout > 0) {
+ request.timeout((Integer) totalTimeout, TimeUnit.MILLISECONDS);
+ }
+
return request;
}
diff --git a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
index 5922920..e1ea028 100644
--- a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
+++ b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2022 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,30 +16,37 @@
package org.glassfish.jersey.jetty.connector;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
+import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.StreamingOutput;
+import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
-
import org.junit.Test;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
/**
* @author Martin Matula
@@ -65,6 +72,48 @@
}
return "GET";
}
+
+ /**
+ * Long-running streaming request
+ *
+ * @param count number of packets send
+ * @param pauseMillis pause between each packets
+ */
+ @GET
+ @Path("stream")
+ public Response streamsWithDelay(@QueryParam("start") @DefaultValue("0") int startMillis, @QueryParam("count") int count,
+ @QueryParam("pauseMillis") int pauseMillis) {
+ StreamingOutput streamingOutput = streamSlowly(startMillis, count, pauseMillis);
+
+ return Response.ok(streamingOutput)
+ .build();
+ }
+ }
+
+ private static StreamingOutput streamSlowly(int startMillis, int count, int pauseMillis) {
+
+ return output -> {
+ try {
+ TimeUnit.MILLISECONDS.sleep(startMillis);
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ output.write("begin\n".getBytes(StandardCharsets.UTF_8));
+ output.flush();
+ for (int i = 0; i < count; i++) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(pauseMillis);
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ output.write(("message " + i + "\n").getBytes(StandardCharsets.UTF_8));
+ output.flush();
+ }
+ output.write("end".getBytes(StandardCharsets.UTF_8));
+ };
}
@Override
@@ -121,4 +170,74 @@
c.close();
}
}
+
+ /**
+ * Test accessing an operation that is streaming slowly
+ *
+ * @throws ProcessingException in case of a test error.
+ */
+ @Test
+ public void testSlowlyStreamedContentDoesNotReadTimeout() throws Exception {
+
+ int count = 5;
+ int pauseMillis = 50;
+
+ final Response response = target("test")
+ .property(ClientProperties.READ_TIMEOUT, 100L)
+ .property(CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER, "-1")
+ .path("stream")
+ .queryParam("count", count)
+ .queryParam("pauseMillis", pauseMillis)
+ .request().get();
+
+ assertTrue(response.readEntity(String.class).contains("end"));
+ }
+
+ @Test
+ public void testSlowlyStreamedContentDoesTotalTimeout() throws Exception {
+
+ int count = 5;
+ int pauseMillis = 50;
+
+ try {
+ target("test")
+ .property(JettyClientProperties.TOTAL_TIMEOUT, 100L)
+ .property(CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER, "-1")
+ .path("stream")
+ .queryParam("count", count)
+ .queryParam("pauseMillis", pauseMillis)
+ .request().get();
+
+ fail("This operation should trigger total timeout");
+ } catch (ProcessingException e) {
+ assertEquals(TimeoutException.class, e.getCause().getClass());
+ }
+ }
+
+ /**
+ * Test accessing an operation that is streaming slowly
+ *
+ * @throws ProcessingException in case of a test error.
+ */
+ @Test
+ public void testSlowToStartStreamedContentDoesReadTimeout() throws Exception {
+
+ int start = 150;
+ int count = 5;
+ int pauseMillis = 50;
+
+ try {
+ target("test")
+ .property(ClientProperties.READ_TIMEOUT, 100L)
+ .property(CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER, "-1")
+ .path("stream")
+ .queryParam("start", start)
+ .queryParam("count", count)
+ .queryParam("pauseMillis", pauseMillis)
+ .request().get();
+ fail("This operation should trigger idle timeout");
+ } catch (ProcessingException e) {
+ assertEquals(TimeoutException.class, e.getCause().getClass());
+ }
+ }
}
diff --git a/connectors/netty-connector/pom.xml b/connectors/netty-connector/pom.xml
index 1805490..f206f96 100644
--- a/connectors/netty-connector/pom.xml
+++ b/connectors/netty-connector/pom.xml
@@ -67,6 +67,11 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ </plugin>
</plugins>
</build>
diff --git a/containers/jetty-http/pom.xml b/containers/jetty-http/pom.xml
index 8ffde3c..62a849c 100644
--- a/containers/jetty-http/pom.xml
+++ b/containers/jetty-http/pom.xml
@@ -80,6 +80,14 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<inherited>true</inherited>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ ${jetty.osgi.version},
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
</plugin>
</plugins>
diff --git a/containers/jetty-servlet/pom.xml b/containers/jetty-servlet/pom.xml
index 373d004..ef1cff9 100644
--- a/containers/jetty-servlet/pom.xml
+++ b/containers/jetty-servlet/pom.xml
@@ -66,6 +66,7 @@
<instructions>
<Import-Package>
jakarta.servlet.*;version="[5.0,7.0)",
+ ${jetty.osgi.version},
*
</Import-Package>
</instructions>
diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index 6f258ca..938e440 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -1825,6 +1825,23 @@
</para>
</entry>
</row>
+ <row>
+ <entry>&jersey.jetty.JettyClientProperties.TOTAL_TIMEOUT;</entry>
+ <entry><literal>jersey.config.jetty.client.totalTimeout</literal></entry>
+ <entry>
+ <para>
+ Total timeout interval for request/response conversation, in milliseconds.
+ Opposed to &jersey.client.ClientProperties.READ_TIMEOUT;.
+ </para>
+ <para>
+ The value MUST be an instance convertible to <literal>Integer</literal>.
+ The value of zero <literal>0</literal> is equivalent to an interval of infinity.
+ </para>
+ <para>
+ The default value is <literal>0</literal> (infinity).
+ </para>
+ </entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent
index 2f91101..e947990 100644
--- a/docs/src/main/docbook/jersey.ent
+++ b/docs/src/main/docbook/jersey.ent
@@ -472,6 +472,7 @@
<!ENTITY jersey.jetty.JettyClientProperties.DISABLE_COOKIES "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/connector/JettyClientProperties.html#DISABLE_COOKIES'>JettyClientProperties.DISABLE_COOKIES</link>" >
<!ENTITY jersey.jetty.JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/connector/JettyClientProperties.html#PREEMPTIVE_BASIC_AUTHENTICATION'>JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION</link>" >
<!ENTITY jersey.jetty.JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/connector/JettyClientProperties.html#SYNC_LISTENER_RESPONSE_MAX_SIZE'>JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE</link>" >
+<!ENTITY jersey.jetty.JettyClientProperties.TOTAL_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/connector/JettyClientProperties.html#TOTAL_TIMEOUT'>JettyClientProperties.TOTAL_TIMEOUT</link>" >
<!ENTITY jersey.jetty.JettyConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/connector/JettyConnectorProvider.html'>JettyConnectorProvider</link>">
<!ENTITY jersey.jetty.JettyHttpContainer "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/JettyHttpContainer.html'>JettyHttpContainer</link>">
<!ENTITY jersey.jetty.JettyHttpContainerFactory "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/JettyHttpContainerFactory.html'>JettyHttpContainerFactory</link>">
diff --git a/incubator/declarative-linking/pom.xml b/incubator/declarative-linking/pom.xml
index 97d9d54..df798a3 100644
--- a/incubator/declarative-linking/pom.xml
+++ b/incubator/declarative-linking/pom.xml
@@ -190,6 +190,11 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/incubator/kryo/pom.xml b/incubator/kryo/pom.xml
index 3911bf8..66d26bb 100644
--- a/incubator/kryo/pom.xml
+++ b/incubator/kryo/pom.xml
@@ -78,5 +78,21 @@
<directory>${project.build.directory}/legal</directory>
</resource>
</resources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ com.esotericsoftware.kryo.*;version="!",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
</build>
</project>
diff --git a/pom.xml b/pom.xml
index edfec7e..bdde4d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2246,6 +2246,7 @@
<jaxb.ri.version>3.0.2</jaxb.ri.version>
<jaxrs.api.spec.version>3.0</jaxrs.api.spec.version>
<jaxrs.api.impl.version>3.0.0</jaxrs.api.impl.version>
+ <jetty.osgi.version>org.eclipse.jetty.*;version="[11,15)"</jetty.osgi.version>
<jetty.version>11.0.9</jetty.version>
<jetty.plugin.version>11.0.9</jetty.plugin.version>
<jetty.servlet.api.25.version>6.1.14</jetty.servlet.api.25.version>
diff --git a/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java b/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java
index 14fa3bc..15eef57 100644
--- a/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java
+++ b/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2022 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
@@ -52,7 +52,7 @@
public class MonitoringEventListenerTest extends JerseyTest {
- private static final long TIMEOUT = 500;
+ private static final long TIMEOUT = 1000;
private static final String MBEAN_EXCEPTION =
"org.glassfish.jersey:type=MonitoringEventListenerTest,subType=Global,exceptions=ExceptionMapper";
@@ -116,6 +116,7 @@
resourceConfig.property(ServerProperties.MONITORING_ENABLED, true);
resourceConfig.property(ServerProperties.MONITORING_STATISTICS_ENABLED, true);
resourceConfig.property(ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED, true);
+ // Scheduler will process 1000 events per second
resourceConfig.property(ServerProperties.MONITORING_STATISTICS_REFRESH_INTERVAL, 1);
resourceConfig.setApplicationName("MonitoringEventListenerTest");
return resourceConfig;
@@ -126,17 +127,18 @@
final Long ERRORS_BEFORE_FAIL = 10L;
// Send some requests to process some statistics.
request(ERRORS_BEFORE_FAIL);
- // Give some time to the scheduler to collect data.
+ // Give some time to process events
Thread.sleep(TIMEOUT);
- // All events were consumed by scheduler
+ // Verify the exceptionMapperEvents is empty, because no event of this type was sent yet
queueIsEmpty();
- // Make the scheduler to fail. No more statistics are collected.
+ // Sending one event that will make an internal error in the scheduler.
+ // No new events will be pushed in the queues after this.
makeFailure();
- // Sending again requests
+ // Sending again requests. These events will not be processed, so they will not be counted for statistics.
request(20);
+ // The expectation is that the scheduler is not going to process previous events because there was a failure before.
+ // We give some time before checking that no new errors are registered.
Thread.sleep(TIMEOUT);
- // No new events should be accepted because scheduler is not working.
- queueIsEmpty();
Long monitoredErrors = mappedErrorsFromJMX(MBEAN_EXCEPTION);
assertEquals(ERRORS_BEFORE_FAIL, monitoredErrors);
}