Merge remote-tracking branch 'origin/master' into 'origin/3.x' Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
diff --git a/NOTICE.md b/NOTICE.md index 6f2a9ea..1cbac9a 100644 --- a/NOTICE.md +++ b/NOTICE.md
@@ -65,7 +65,7 @@ * License: Apache License, 2.0 * Copyright (C) 2009 The JSR-330 Expert Group -Javassist Version 3.25.0-GA +Javassist Version 3.29.0-GA * License: Apache License, 2.0 * Project: http://www.javassist.org/ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. @@ -95,7 +95,7 @@ * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS * Copyright: Eric Rowell -org.objectweb.asm Version 9.3 +org.objectweb.asm Version 9.4 * License: Modified BSD (https://asm.ow2.io/license.html) * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.
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 fdfbccf..264c453 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
@@ -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 @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.Socket; import java.net.URI; import java.util.ArrayList; import java.util.LinkedList; @@ -46,6 +47,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import org.glassfish.jersey.client.ClientProperties; @@ -53,6 +55,7 @@ import org.glassfish.jersey.client.ClientResponse; import org.glassfish.jersey.client.RequestEntityProcessing; import org.glassfish.jersey.client.innate.ClientProxy; +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.util.PropertiesHelper; @@ -103,6 +106,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.io.ChunkedOutputStream; import org.apache.http.io.SessionOutputBuffer; +import org.apache.http.protocol.HttpContext; import org.apache.http.util.TextUtils; import org.apache.http.util.VersionInfo; @@ -180,6 +184,7 @@ class ApacheConnector implements Connector { private static final Logger LOGGER = Logger.getLogger(ApacheConnector.class.getName()); + private static final String JERSEY_REQUEST_ATTR_NAME = "JerseyRequestAttribute"; private static final VersionInfo vi; private static final String release; @@ -255,10 +260,16 @@ } } + final boolean useSystemProperties = + PropertiesHelper.isProperty(config.getProperties(), ApacheClientProperties.USE_SYSTEM_PROPERTIES); + final SSLContext sslContext = client.getSslContext(); final HttpClientBuilder clientBuilder = HttpClientBuilder.create(); - clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext)); + if (useSystemProperties) { + clientBuilder.useSystemProperties(); + } + clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext, useSystemProperties)); clientBuilder.setConnectionManagerShared( PropertiesHelper.getValue(config.getProperties(), ApacheClientProperties.CONNECTION_MANAGER_SHARED, false, null)); clientBuilder.setSSLContext(sslContext); @@ -337,7 +348,8 @@ private HttpClientConnectionManager getConnectionManager(final Client client, final Configuration config, - final SSLContext sslContext) { + final SSLContext sslContext, + final boolean useSystemProperties) { final Object cmObject = config.getProperties().get(ApacheClientProperties.CONNECTION_MANAGER); // Connection manager from configuration. @@ -355,9 +367,6 @@ } } - final boolean useSystemProperties = - PropertiesHelper.isProperty(config.getProperties(), ApacheClientProperties.USE_SYSTEM_PROPERTIES); - // Create custom connection manager. return createConnectionManager( client, @@ -381,15 +390,15 @@ final LayeredConnectionSocketFactory sslSocketFactory; if (sslContext != null) { - sslSocketFactory = new SSLConnectionSocketFactory( + sslSocketFactory = new SniSSLConnectionSocketFactory( sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier); } else { if (useSystemProperties) { - sslSocketFactory = new SSLConnectionSocketFactory( + sslSocketFactory = new SniSSLConnectionSocketFactory( (SSLSocketFactory) SSLSocketFactory.getDefault(), supportedProtocols, supportedCipherSuites, hostnameVerifier); } else { - sslSocketFactory = new SSLConnectionSocketFactory( + sslSocketFactory = new SniSSLConnectionSocketFactory( SSLContexts.createDefault(), hostnameVerifier); } @@ -450,14 +459,16 @@ public ClientResponse apply(final ClientRequest clientRequest) throws ProcessingException { final HttpUriRequest request = getUriHttpRequest(clientRequest); final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(clientRequest, request); + final HttpHost httpHost = getHost(request); try { final CloseableHttpResponse response; final HttpClientContext context = HttpClientContext.create(); + if (preemptiveBasicAuth) { final AuthCache authCache = new BasicAuthCache(); final BasicScheme basicScheme = new BasicScheme(); - authCache.put(getHost(request), basicScheme); + authCache.put(httpHost, basicScheme); context.setAuthCache(authCache); } @@ -468,7 +479,8 @@ context.setCredentialsProvider(credentialsProvider); } - response = client.execute(getHost(request), request, context); + context.setAttribute(JERSEY_REQUEST_ATTR_NAME, clientRequest); + response = client.execute(httpHost, request, context); HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, clientRequest.getHeaders(), this.getClass().getName(), clientRequest.getConfiguration()); @@ -821,4 +833,56 @@ return super.createOutputStream(len, outbuffer); } } + + private static final class SniSSLConnectionSocketFactory extends SSLConnectionSocketFactory { + + private final ThreadLocal<HttpContext> httpContexts = new ThreadLocal<>(); + + public SniSSLConnectionSocketFactory(final SSLContext sslContext, + final String[] supportedProtocols, + final String[] supportedCipherSuites, + final HostnameVerifier hostnameVerifier) { + super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier); + } + + public SniSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketFactory, + final String[] supportedProtocols, + final String[] supportedCipherSuites, + final HostnameVerifier hostnameVerifier) { + super(socketFactory, supportedProtocols, supportedCipherSuites, hostnameVerifier); + } + + public SniSSLConnectionSocketFactory( + final SSLContext sslContext, final HostnameVerifier hostnameVerifier) { + super(sslContext, hostnameVerifier); + } + + @Override + public Socket createLayeredSocket( + final Socket socket, + final String target, + final int port, + final HttpContext context) throws IOException { + httpContexts.set(context); + try { + return super.createLayeredSocket(socket, target, port, context); + } finally { + httpContexts.remove(); + } + } + + @Override + protected void prepareSocket(SSLSocket socket) throws IOException { + HttpContext context = httpContexts.get(); + + if (context != null) { + Object objectRequest = context.getAttribute(JERSEY_REQUEST_ATTR_NAME); + if (objectRequest != null) { + ClientRequest clientRequest = (ClientRequest) objectRequest; + SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(clientRequest).build(); + sniConfig.setSNIServerName(socket); + } + } + } + } }
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 9e4e9ac..f7c30a9 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
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.Socket; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -46,8 +47,10 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import org.apache.hc.client5.http.AuthenticationStrategy; import org.apache.hc.client5.http.ConnectionKeepAliveStrategy; import org.apache.hc.client5.http.HttpRequestRetryStrategy; import org.apache.hc.client5.http.auth.AuthCache; @@ -65,6 +68,7 @@ import org.apache.hc.client5.http.impl.auth.BasicAuthCache; import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; @@ -86,6 +90,7 @@ import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy; import org.apache.hc.core5.http.io.entity.AbstractHttpEntity; import org.apache.hc.core5.http.io.entity.BufferedHttpEntity; +import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.ssl.SSLContexts; import org.apache.hc.core5.util.TextUtils; import org.apache.hc.core5.util.Timeout; @@ -95,6 +100,7 @@ import org.glassfish.jersey.client.ClientResponse; import org.glassfish.jersey.client.RequestEntityProcessing; import org.glassfish.jersey.client.innate.ClientProxy; +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.util.PropertiesHelper; @@ -176,6 +182,7 @@ class Apache5Connector implements Connector { private static final Logger LOGGER = Logger.getLogger(Apache5Connector.class.getName()); + private static final String JERSEY_REQUEST_ATTR_NAME = "JerseyRequestAttribute"; private static final VersionInfo vi; private static final String release; @@ -251,10 +258,17 @@ } } + final boolean useSystemProperties = + PropertiesHelper.isProperty(config.getProperties(), Apache5ClientProperties.USE_SYSTEM_PROPERTIES); + final SSLContext sslContext = client.getSslContext(); final HttpClientBuilder clientBuilder = HttpClientBuilder.create(); - clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext)); + if (useSystemProperties) { + clientBuilder.useSystemProperties(); + } + + clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext, useSystemProperties)); clientBuilder.setConnectionManagerShared( PropertiesHelper.getValue( config.getProperties(), @@ -341,7 +355,8 @@ private HttpClientConnectionManager getConnectionManager(final Client client, final Configuration config, - final SSLContext sslContext) { + final SSLContext sslContext, + final boolean useSystemProperties) { final Object cmObject = config.getProperties().get(Apache5ClientProperties.CONNECTION_MANAGER); // Connection manager from configuration. @@ -359,9 +374,6 @@ } } - final boolean useSystemProperties = - PropertiesHelper.isProperty(config.getProperties(), Apache5ClientProperties.USE_SYSTEM_PROPERTIES); - // Create custom connection manager. return createConnectionManager( client, @@ -385,15 +397,15 @@ final LayeredConnectionSocketFactory sslSocketFactory; if (sslContext != null) { - sslSocketFactory = new SSLConnectionSocketFactory( + sslSocketFactory = new SniSSLConnectionSocketFactory( sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier); } else { if (useSystemProperties) { - sslSocketFactory = new SSLConnectionSocketFactory( + sslSocketFactory = new SniSSLConnectionSocketFactory( (SSLSocketFactory) SSLSocketFactory.getDefault(), supportedProtocols, supportedCipherSuites, hostnameVerifier); } else { - sslSocketFactory = new SSLConnectionSocketFactory( + sslSocketFactory = new SniSSLConnectionSocketFactory( SSLContexts.createDefault(), hostnameVerifier); } @@ -458,12 +470,7 @@ try { final CloseableHttpResponse response; final HttpClientContext context = HttpClientContext.create(); - if (preemptiveBasicAuth) { - final AuthCache authCache = new BasicAuthCache(); - final BasicScheme basicScheme = new BasicScheme(); - authCache.put(getHost(request), basicScheme); - context.setAuthCache(authCache); - } + final HttpHost httpHost = getHost(request); // If a request-specific CredentialsProvider exists, use it instead of the default one CredentialsProvider credentialsProvider = @@ -472,7 +479,18 @@ context.setCredentialsProvider(credentialsProvider); } - response = client.execute(getHost(request), request, context); + if (preemptiveBasicAuth) { + final AuthCache authCache = new BasicAuthCache(); + final BasicScheme basicScheme = new BasicScheme(); + final AuthScope authScope = new AuthScope(httpHost); + basicScheme.initPreemptive(credentialsProvider.getCredentials(authScope, context)); + context.resetAuthExchange(httpHost, basicScheme); + authCache.put(httpHost, basicScheme); // must be after initPreemptive + context.setAuthCache(authCache); + } + + context.setAttribute(JERSEY_REQUEST_ATTR_NAME, clientRequest); + response = client.execute(httpHost, request, context); HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, clientRequest.getHeaders(), this.getClass().getName(), clientRequest.getConfiguration()); @@ -798,4 +816,77 @@ ); } } + + private static final class SniSSLConnectionSocketFactory extends SSLConnectionSocketFactory { + + private final ThreadLocal<HttpContext> httpContexts = new ThreadLocal<>(); + + public SniSSLConnectionSocketFactory(final SSLContext sslContext, + final String[] supportedProtocols, + final String[] supportedCipherSuites, + final HostnameVerifier hostnameVerifier) { + super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier); + } + + public SniSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketFactory, + final String[] supportedProtocols, + final String[] supportedCipherSuites, + final HostnameVerifier hostnameVerifier) { + super(socketFactory, supportedProtocols, supportedCipherSuites, hostnameVerifier); + } + + public SniSSLConnectionSocketFactory( + final SSLContext sslContext, final HostnameVerifier hostnameVerifier) { + super(sslContext, hostnameVerifier); + } + + /* Pre 5.2 */ + @Override + public Socket createLayeredSocket( + final Socket socket, + final String target, + final int port, + final HttpContext context) throws IOException { + httpContexts.set(context); + try { + return super.createLayeredSocket(socket, target, port, context); + } finally { + httpContexts.remove(); + } + } + + /* Post 5.2 */ + public Socket createLayeredSocket( + final Socket socket, + final String target, + final int port, + final Object attachment, + final HttpContext context) throws IOException { + httpContexts.set(context); + try { + return super.createLayeredSocket(socket, target, port, attachment, context); + } finally { + httpContexts.remove(); + } + } + + @Override + protected void prepareSocket(SSLSocket socket) throws IOException { + HttpContext context = httpContexts.get(); + + if (context != null) { + Object objectRequest = context.getAttribute(JERSEY_REQUEST_ATTR_NAME); + if (objectRequest != null) { + ClientRequest clientRequest = (ClientRequest) objectRequest; + SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(clientRequest).build(); + sniConfig.setSNIServerName(socket); + + final int socketTimeout = ((ClientRequest) objectRequest).resolveProperty(ClientProperties.READ_TIMEOUT, -1); + if (socketTimeout >= 0) { + socket.setSoTimeout(socketTimeout); + } + } + } + } + } }
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java index 39fb0ab..422d919 100644 --- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java +++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 Public License v. 2.0, which is available at @@ -19,6 +19,7 @@ import java.net.CookiePolicy; import java.net.URI; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,6 +31,7 @@ import org.glassfish.jersey.SslConfigurator; import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.innate.http.SSLParamConfigurator; import org.glassfish.jersey.jdk.connector.JdkConnectorProperties; /** @@ -57,6 +59,7 @@ private final int responseTimeout; private final int connectTimeout; private final ProxyConfiguration proxyConfiguration; + private final AtomicReference<SSLParamConfigurator> sniConfigs = new AtomicReference<>(null); ConnectorConfiguration(Client client, Configuration config) { final Map<String, Object> properties = config.getProperties(); @@ -170,6 +173,14 @@ return proxyConfiguration; } + void setSniConfig(SSLParamConfigurator sniConfig) { + this.sniConfigs.compareAndSet(null, sniConfig); + } + + SSLParamConfigurator getSniConfig() { + return sniConfigs.get(); + } + @Override public String toString() { return "ConnectorConfiguration{"
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java index 2330dd4..d9ea76e 100644 --- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java +++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.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 Public License v. 2.0, which is available at @@ -199,7 +199,8 @@ } - socket = new SslFilter(transportFilter, sslContext, uri.getHost(), configuration.getHostnameVerifier()); + socket = new SslFilter(transportFilter, sslContext, uri.getHost(), + configuration.getHostnameVerifier(), configuration.getSniConfig()); } else { socket = new TransportFilter(INPUT_BUFFER_SIZE, configuration.getThreadPoolConfig(), configuration.getContainerIdleTimeout());
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java index 28c7500..b20f00c 100644 --- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java +++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 Public License v. 2.0, which is available at @@ -16,7 +16,11 @@ package org.glassfish.jersey.jdk.connector.internal; +import org.glassfish.jersey.client.innate.http.SSLParamConfigurator; + import java.net.CookieManager; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; @@ -45,10 +49,16 @@ } void send(HttpRequest httpRequest, CompletionHandler<HttpResponse> completionHandler) { + final Map<String, List<Object>> headers = new HashMap<>(); + httpRequest.getHeaders().forEach((k, v) -> headers.put(k, (List) v)); + final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().uri(httpRequest.getUri()).headers(headers).build(); + connectorConfiguration.setSniConfig(sniConfig); + final DestinationConnectionPool.DestinationKey destinationKey = new DestinationConnectionPool.DestinationKey( - httpRequest.getUri()); + sniConfig.getSNIUri()); DestinationConnectionPool destinationConnectionPool = destinationPools.get(destinationKey); + if (destinationConnectionPool == null) { synchronized (this) { // check again while holding the lock
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java index 85f4541..979a9ce 100644 --- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java +++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java
@@ -1,5 +1,5 @@ /* - * 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 Public License v. 2.0, which is available at @@ -16,6 +16,8 @@ package org.glassfish.jersey.jdk.connector.internal; +import org.glassfish.jersey.client.innate.http.SSLParamConfigurator; + import java.nio.ByteBuffer; import java.nio.Buffer; import java.util.LinkedList; @@ -26,7 +28,6 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLParameters; /** @@ -87,7 +88,8 @@ SslFilter(Filter<ByteBuffer, ByteBuffer, ?, ?> downstreamFilter, SSLContext sslContext, String serverHost, - HostnameVerifier customHostnameVerifier) { + HostnameVerifier customHostnameVerifier, + SSLParamConfigurator sniConfig) { super(downstreamFilter); this.serverHost = serverHost; sslEngine = sslContext.createSSLEngine(serverHost, -1); @@ -100,11 +102,11 @@ * when {@link SslEngineConfigurator} supports Java 7. */ if (customHostnameVerifier == null) { - SSLParameters sslParameters = sslEngine.getSSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - sslEngine.setSSLParameters(sslParameters); + sniConfig.setEndpointIdentificationAlgorithm(sslEngine); } + sniConfig.setSNIServerName(sslEngine); + applicationInputBuffer = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize()); networkOutputBuffer = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize()); }
diff --git a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java index 5d205ce..ef13997 100644 --- a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java +++ b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.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,10 +23,12 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.SocketException; +import java.net.URI; import java.nio.ByteBuffer; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -41,7 +43,9 @@ import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; + import org.glassfish.jersey.SslConfigurator; +import org.glassfish.jersey.client.innate.http.SSLParamConfigurator; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExecutionCondition; @@ -391,7 +395,10 @@ .keyStorePassword("asdfgh"); TransportFilter transportFilter = new TransportFilter(17_000, ThreadPoolConfig.defaultConfig(), 100_000); - final SslFilter sslFilter = new SslFilter(transportFilter, sslConfig.createSSLContext(), host, customHostnameVerifier); + final SSLParamConfigurator sslParamConfigurator = SSLParamConfigurator.builder() + .uri(URI.create("Https://" + host)).headers(Collections.emptyMap()).build(); + final SslFilter sslFilter = new SslFilter( + transportFilter, sslConfig.createSSLContext(), host, customHostnameVerifier, sslParamConfigurator); // exceptions errors that occur before SSL handshake has finished are thrown from this method final AtomicReference<Throwable> exception = new AtomicReference<>();
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java index 5d52e76..5a776b6 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -83,6 +83,7 @@ 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.http.SSLParamConfigurator; import org.glassfish.jersey.client.spi.AsyncConnectorCallback; import org.glassfish.jersey.client.spi.Connector; import org.glassfish.jersey.message.internal.OutboundMessageContext; @@ -278,17 +279,20 @@ (String[]) null, /* enable default protocols */ false /* true if the first write request shouldn't be encrypted */ ); - int port = requestUri.getPort(); - SslHandler sslHandler = jdkSslContext.newHandler(ch.alloc(), requestUri.getHost(), - port <= 0 ? 443 : port, executorService); + + final int port = requestUri.getPort(); + final SSLParamConfigurator sslConfig = SSLParamConfigurator.builder() + .request(jerseyRequest).setSNIAlways(true).build(); + final SslHandler sslHandler = jdkSslContext.newHandler( + ch.alloc(), sslConfig.getSNIHostName(), port <= 0 ? 443 : port, executorService + ); if (ClientProperties.getValue(config.getProperties(), NettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION, true)) { - SSLEngine sslEngine = sslHandler.engine(); - SSLParameters sslParameters = sslEngine.getSSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - sslEngine.setSSLParameters(sslParameters); + sslConfig.setEndpointIdentificationAlgorithm(sslHandler.engine()); } + sslConfig.setSNIServerName(sslHandler.engine()); + p.addLast(sslHandler); } @@ -374,7 +378,9 @@ setHeaders(jerseyRequest, nettyRequest.headers()); // host header - http 1.1 - nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost()); + if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) { + nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost()); + } if (jerseyRequest.hasEntity()) { // guard against prematurely closed channel
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java index f675270..3a1cf69 100644 --- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java +++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.fail; import java.net.URI; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import jakarta.ws.rs.GET; @@ -37,12 +38,20 @@ import org.glassfish.jersey.netty.connector.internal.RedirectException; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class FollowRedirectsTest extends JerseyTest { private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName()); - private static final String TEST_URL = "http://localhost:9998/test"; + private static final String TEST_URL = "http://localhost:%d/test"; + private static final AtomicReference<String> TEST_URL_REF = new AtomicReference<>(); + + @BeforeEach + public void before() { + final String url = String.format(TEST_URL, getPort()); + TEST_URL_REF.set(url); + } @Path("/test") public static class RedirectResource { @@ -54,19 +63,19 @@ @GET @Path("redirect") public Response redirect() { - return Response.seeOther(URI.create(TEST_URL)).build(); + return Response.seeOther(URI.create(TEST_URL_REF.get())).build(); } @GET @Path("loop") public Response loop() { - return Response.seeOther(URI.create(TEST_URL + "/loop")).build(); + return Response.seeOther(URI.create(TEST_URL_REF.get() + "/loop")).build(); } @GET @Path("redirect2") public Response redirect2() { - return Response.seeOther(URI.create(TEST_URL + "/redirect")).build(); + return Response.seeOther(URI.create(TEST_URL_REF.get() + "/redirect")).build(); } }
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 4f769f2..3886ea9 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
@@ -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 @@ -21,6 +21,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import jakarta.ws.rs.RuntimeType; import jakarta.ws.rs.core.UriBuilder; import com.sun.net.httpserver.HttpServer; @@ -37,7 +38,7 @@ public abstract class AbstractJdkHttpServerTester { public static final String CONTEXT = ""; - private final int DEFAULT_PORT = 9998; + private final int DEFAULT_PORT = 0; // rather JDK server choose than 9998 private static final Logger LOGGER = Logger.getLogger(AbstractJdkHttpServerTester.class.getName()); @@ -47,6 +48,9 @@ * @return The HTTP port of the URI */ protected final int getPort() { + if (server != null) { + return server.getAddress().getPort(); + } final String value = AccessController.doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { @@ -68,10 +72,20 @@ return DEFAULT_PORT; } + private final int getPort(RuntimeType runtimeType) { + switch (runtimeType) { + case SERVER: + return getPort(); + case CLIENT: + return server.getAddress().getPort(); + default: + throw new IllegalStateException("Unexpected runtime type"); + } + } private volatile HttpServer server; public UriBuilder getUri() { - return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT); + return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); } public void startServer(Class... resources) { @@ -79,18 +93,18 @@ config.register(LoggingFeature.class); final URI baseUri = getBaseUri(); server = JdkHttpServerFactory.createHttpServer(baseUri, config); - LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress()); } 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: " + baseUri); + LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress()); } public URI getBaseUri() { - return UriBuilder.fromUri("http://localhost/").port(getPort()).build(); + return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build(); } public void stopServer() {
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 0ad2944..472d5ed 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
@@ -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 @@ -116,7 +116,7 @@ // access the https server with not configured client final Client client = ClientBuilder.newBuilder().newClient(); try { - client.target(httpsUri).path("testHttps").request().get(String.class); + client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class); } catch (final ProcessingException e) { throw e.getCause(); } @@ -136,8 +136,8 @@ server.start(); final Client client = ClientBuilder.newBuilder().newClient(); - try { - client.target(httpsUri).path("testHttps").request().get(String.class); + try { + client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class); } catch (final ProcessingException e) { throw e.getCause(); } @@ -173,7 +173,7 @@ final SSLContext clientSslContext = getClientSslContext(); final Client client = ClientBuilder.newBuilder().sslContext(clientSslContext).build(); - final String response = client.target(httpsUri).path("testHttps").request().get(String.class); + final String response = client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class); assertEquals("test", response); } @@ -216,6 +216,11 @@ return sslConfigServer.createSSLContext(); } + + private URI updatePort(URI uri) { + return UriBuilder.fromUri(httpsUri).port(server.getAddress().getPort()).build(); + } + @AfterEach public void tearDown() { if (server != null) {
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 1d7cac2..3a953e1 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,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 @@ -21,6 +21,7 @@ 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; @@ -42,7 +43,7 @@ private static final Logger LOGGER = Logger.getLogger(AbstractJettyServerTester.class.getName()); public static final String CONTEXT = ""; - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; // rather Jetty choose than 9998 /** * Get the port to be used for test application deployments. @@ -71,10 +72,21 @@ 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()).path(CONTEXT); + return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); } public void startServer(Class... resources) { @@ -82,17 +94,17 @@ 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: " + baseUri); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI()); } 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: " + baseUri); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI()); } public URI getBaseUri() { - return UriBuilder.fromUri("http://localhost/").port(getPort()).build(); + return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build(); } public void stopServer() {
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 d36c54f..3543e50 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
@@ -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 @@ -21,6 +21,7 @@ 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.internal.util.PropertiesHelper; @@ -39,7 +40,7 @@ public abstract class AbstractSimpleServerTester { public static final String CONTEXT = ""; - private final int DEFAULT_PORT = 9998; + private final int DEFAULT_PORT = 0; // rather SimpleFramework server choose than 9998 private static final Logger LOGGER = Logger.getLogger(AbstractSimpleServerTester.class.getName()); @@ -72,10 +73,20 @@ return DEFAULT_PORT; } + private final int getPort(RuntimeType runtimeType) { + switch (runtimeType) { + case SERVER: + return getPort(); + case CLIENT: + return server.getPort(); + default: + throw new IllegalStateException("Unexpected runtime type"); + } + } private volatile SimpleServer server; public UriBuilder getUri() { - return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT); + return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT); } public void startServer(Class... resources) { @@ -83,21 +94,21 @@ 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); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort()); } 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); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort()); } 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); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort()); } public void startServer(ResourceConfig config, int count, int select) { @@ -108,7 +119,7 @@ } public URI getBaseUri() { - return UriBuilder.fromUri("http://localhost/").port(getPort()).build(); + return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build(); } public void setDebug(boolean enable) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java b/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java index 72374cc..8ecbfaa 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.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 @@ -43,10 +43,15 @@ @ConstrainedTo(RuntimeType.CLIENT) class ChunkedInputReader implements MessageBodyReader<ChunkedInput> { + private final Provider<MessageBodyWorkers> messageBodyWorkers; + private final Provider<PropertiesDelegate> propertiesDelegateProvider; + @Inject - private Provider<MessageBodyWorkers> messageBodyWorkers; - @Inject - private Provider<PropertiesDelegate> propertiesDelegateProvider; + public ChunkedInputReader(Provider<MessageBodyWorkers> messageBodyWorkers, + Provider<PropertiesDelegate> propertiesDelegateProvider) { + this.messageBodyWorkers = messageBodyWorkers; + this.propertiesDelegateProvider = propertiesDelegateProvider; + } @Override public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
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 43737f1..4dca460 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
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -35,6 +35,7 @@ import org.glassfish.jersey.CommonProperties; import org.glassfish.jersey.ExtendedConfig; import org.glassfish.jersey.client.internal.LocalizationMessages; +import org.glassfish.jersey.client.innate.inject.NonInjectionManager; import org.glassfish.jersey.client.internal.inject.ParameterUpdaterConfigurator; import org.glassfish.jersey.client.spi.Connector; import org.glassfish.jersey.client.spi.ConnectorProvider; @@ -410,7 +411,7 @@ final State runtimeCfgState = this.copy(); runtimeCfgState.markAsShared(); - InjectionManager injectionManager = Injections.createInjectionManager(); + final InjectionManager injectionManager = findInjectionManager(); injectionManager.register(new ClientBinder(runtimeCfgState.getProperties())); final ClientBootstrapBag bootstrapBag = new ClientBootstrapBag(); @@ -471,6 +472,14 @@ return crt; } + private final InjectionManager findInjectionManager() { + try { + return Injections.createInjectionManager(RuntimeType.CLIENT); + } catch (IllegalStateException ise) { + return new NonInjectionManager(true); + } + } + @Override public boolean equals(final Object o) { if (this == o) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java b/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java index 7b99abd..8d773a6 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.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 @@ -49,10 +49,15 @@ * @author Martin Matula */ public final class EncodingFilter implements ClientRequestFilter { - @Inject - private InjectionManager injectionManager; + + private final InjectionManager injectionManager; private volatile List<Object> supportedEncodings = null; + @Inject + public EncodingFilter(InjectionManager injectionManager) { + this.injectionManager = injectionManager; + } + @Override public void filter(ClientRequestContext request) throws IOException { if (getSupportedEncodings().isEmpty()) {
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 new file mode 100644 index 0000000..33ef0b6 --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
@@ -0,0 +1,190 @@ +/* + * 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.client.innate.http; + +import org.glassfish.jersey.client.ClientRequest; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; +import jakarta.ws.rs.core.UriBuilder; +import java.net.InetAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * A unified routines to configure {@link SSLParameters}. + * To be reused in connectors. + */ +public final class SSLParamConfigurator { + private final URI uri; + private final Map<String, List<Object>> httpHeaders; + private final Optional<SniConfigurator> sniConfigurator; + + /** + * Builder of the {@link SSLParamConfigurator} instance. + */ + public static final class Builder { + private ClientRequest clientRequest; + private URI uri; + private Map<String, List<Object>> httpHeaders; + private boolean setAlways = false; + + /** + * Sets the {@link ClientRequest} instance. + * @param clientRequest the {@link ClientRequest} + * @return the builder instance + */ + public Builder request(ClientRequest clientRequest) { + this.clientRequest = clientRequest; + this.httpHeaders = null; + this.uri = null; + return this; + } + + /** + * Sets the HTTP request {@link URI} instance. + * @param uri The request uri + * @return the builder instance + */ + public Builder uri(URI uri) { + this.clientRequest = null; + this.uri = uri; + return this; + } + + /** + * Sets the HTTP request headers + * @param httpHeaders the http request headers + * @return the builder instance + */ + public Builder headers(Map<String, List<Object>> httpHeaders) { + this.clientRequest = null; + this.httpHeaders = httpHeaders; + return this; + } + + /** + * Sets SNI only when {@link jakarta.ws.rs.core.HttpHeaders#HOST} differs from the request host name if set to + * {@code false}. Default is {@code false}. + * @param setAlways set SNI always (default) + * @return the builder instance + */ + public Builder setSNIAlways(boolean setAlways) { + this.setAlways = setAlways; + return this; + } + + /** + * Builds the {@link SSLParamConfigurator} instance. + * @return the configured {@link SSLParamConfigurator} instance. + */ + public SSLParamConfigurator build() { + return new SSLParamConfigurator(this); + } + } + + private SSLParamConfigurator(SSLParamConfigurator.Builder builder) { + this.uri = builder.clientRequest != null ? builder.clientRequest.getUri() : builder.uri; + this.httpHeaders = builder.clientRequest != null ? builder.clientRequest.getHeaders() : builder.httpHeaders; + sniConfigurator = SniConfigurator.createWhenHostHeader(uri, httpHeaders, builder.setAlways); + } + + /** + * Create a new instance of TlsSupport class + **/ + public static SSLParamConfigurator.Builder builder() { + return new SSLParamConfigurator.Builder(); + } + + /** + * Get the host name either set by the request URI or by + * {@link jakarta.ws.rs.core.HttpHeaders#HOST} header if it differs from HTTP request host name. + * @return the hostName the {@link SSLEngine} is to use. + */ + public String getSNIHostName() { + return sniConfigurator.isPresent() ? sniConfigurator.get().getHostName() : uri.getHost(); + } + + /** + * Replaces hostname within the {@link ClientRequest} uri with a resolved IP address. Should the hostname be not known, + * the original request URI is returned. The purpose of this method is to replace the host with the IP so that + * {code HttpUrlConnection} does not replace user defined {@link javax.net.ssl.SNIHostName} with the host from the request + * uri. + * @return the request uri with ip address of the resolved host. + */ + public URI toIPRequestUri() { + String host = uri.getHost(); + try { + InetAddress ip = InetAddress.getByName(host); + return UriBuilder.fromUri(uri).host(ip.getHostAddress()).build(); + } catch (UnknownHostException e) { + return uri; + } + } + + /** + * Return true iff SNI is to be set, i.e. + * {@link jakarta.ws.rs.core.HttpHeaders#HOST} header if it differs from HTTP request host name. + * @return Return {@code true} when {@link javax.net.ssl.SNIHostName} is to be set. + */ + public boolean isSNIRequired() { + return sniConfigurator.isPresent(); + } + + /** + * Get the request URI or altered by {@link jakarta.ws.rs.core.HttpHeaders#HOST} header. + * @return The possibly altered request URI. + * @see #getSNIHostName() + */ + public URI getSNIUri() { + return sniConfigurator.isPresent() ? UriBuilder.fromUri(uri).host(getSNIHostName()).build() : uri; + } + + /** + * 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 sslEngine the {@link SSLEngine} the {@link SSLParameters} are set for. + */ + public void setSNIServerName(SSLEngine sslEngine) { + sniConfigurator.ifPresent(sni -> sni.setServerNames(sslEngine)); + } + + + /** + * 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 sslSocket the {@link SSLSocket} the {@link SSLParameters} are set for. + */ + public void setSNIServerName(SSLSocket sslSocket) { + sniConfigurator.ifPresent(sni -> sni.setServerNames(sslSocket)); + } + + /** + * 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) + */ + public void setEndpointIdentificationAlgorithm(SSLEngine sslEngine) { + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + sslEngine.setSSLParameters(sslParameters); + } +}
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 new file mode 100644 index 0000000..39a339d --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.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.client.innate.http; + +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; +import jakarta.ws.rs.core.HttpHeaders; +import java.net.URI; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * A unified routines to set {@link SNIHostName} for the {@link javax.net.ssl.SSLContext}. + * To be reused in connectors. + */ +final class SniConfigurator { + private final String hostName; + private SniConfigurator(String hostName) { + this.hostName = hostName; + } + + /** + * Get the hostName from the {@link HttpHeaders#HOST} header. + * @return + */ + String getHostName() { + return hostName; + } + + /** + * Create ClientSNI when {@link HttpHeaders#HOST} is set different from the request URI host (or {@code whenDiffer}.is false). + * @param hostUri the Uri of the HTTP request + * @param headers the HttpHeaders + * @param whenDiffer create {@SniConfigurator only when different from the request URI host} + * @return ClientSNI or empty when {@link HttpHeaders#HOST} + */ + static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, Map<String, List<Object>> headers, boolean whenDiffer) { + List<Object> hostHeaders = headers.get(HttpHeaders.HOST); + if (hostHeaders == null || hostHeaders.get(0) == null) { + return Optional.empty(); + } + + final String hostHeader = hostHeaders.get(0).toString(); + final String trimmedHeader; + if (hostHeader != null) { + int index = hostHeader.indexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ; + final String trimmedHeader0 = index != -1 ? hostHeader.substring(0, index).trim() : hostHeader.trim(); + trimmedHeader = trimmedHeader0.isEmpty() ? hostHeader : trimmedHeader0; + } else { + return Optional.empty(); + } + + final String hostUriString = hostUri.getHost(); + if (!whenDiffer && hostUriString.equals(trimmedHeader)) { + return Optional.empty(); + } + + return Optional.of(new SniConfigurator(trimmedHeader)); + } + + /** + * Set {@link SNIServerName} for the given {@link SSLEngine} SSLParameters. + * @param sslEngine + */ + void setServerNames(SSLEngine sslEngine) { + SSLParameters sslParameters = sslEngine.getSSLParameters(); + updateSSLParameters(sslParameters); + sslEngine.setSSLParameters(sslParameters); + } + + /** + * Set {@link SNIServerName} for the given {@link SSLSocket} SSLParameters. + * @param sslSocket + */ + void setServerNames(SSLSocket sslSocket) { + SSLParameters sslParameters = sslSocket.getSSLParameters(); + updateSSLParameters(sslParameters); + sslSocket.setSSLParameters(sslParameters); + } + + private SSLParameters updateSSLParameters(SSLParameters sslParameters) { + SNIHostName serverName = new SNIHostName(hostName); + List<SNIServerName> serverNames = new LinkedList<>(); + serverNames.add(serverName); + + sslParameters.setServerNames(serverNames); + + return sslParameters; + } + +}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/package-info.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/package-info.java new file mode 100644 index 0000000..bbedce0 --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/package-info.java
@@ -0,0 +1,21 @@ +/* + * 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 + */ + +/** + * Jersey client MOST INTERNAL http related classes/interfaces. + * Shall not be used outside of Jersey. The module shall not be exported to outside of Jersey. + */ +package org.glassfish.jersey.client.innate.http; \ No newline at end of file
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 new file mode 100644 index 0000000..7062bab --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
@@ -0,0 +1,1029 @@ +/* + * 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.client.innate.inject; + +import org.glassfish.jersey.client.internal.LocalizationMessages; +import org.glassfish.jersey.internal.inject.Binder; +import org.glassfish.jersey.internal.inject.Binding; +import org.glassfish.jersey.internal.inject.ClassBinding; +import org.glassfish.jersey.internal.inject.DisposableSupplier; +import org.glassfish.jersey.internal.inject.ForeignDescriptor; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.InstanceBinding; +import org.glassfish.jersey.internal.inject.PerThread; +import org.glassfish.jersey.internal.inject.ServiceHolder; +import org.glassfish.jersey.internal.inject.ServiceHolderImpl; +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.Value; +import org.glassfish.jersey.internal.util.collection.Values; +import org.glassfish.jersey.process.internal.RequestScope; +import org.glassfish.jersey.process.internal.RequestScoped; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import jakarta.inject.Singleton; +import jakarta.ws.rs.ConstrainedTo; +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +@ConstrainedTo(RuntimeType.CLIENT) +public final class NonInjectionManager implements InjectionManager { + private static final Logger logger = Logger.getLogger(NonInjectionManager.class.getName()); + + private final MultivaluedMap<Class<?>, InstanceBinding<?>> instanceBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Class<?>, ClassBinding<?>> contractBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Class<?>, SupplierInstanceBinding<?>> supplierInstanceBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Class<?>, SupplierClassBinding<?>> supplierClassBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Type, InstanceBinding<?>> instanceTypeBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Type, ClassBinding<?>> contractTypeBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Type, SupplierInstanceBinding<?>> supplierTypeInstanceBindings = new MultivaluedHashMap<>(); + private final MultivaluedMap<Type, SupplierClassBinding<?>> supplierTypeClassBindings = new MultivaluedHashMap<>(); + + private final MultivaluedMap<DisposableSupplier, Object> disposableSupplierObjects = new MultivaluedHashMap<>(); + + private final Instances instances = new Instances(); + private final Types types = new Types(); + + private volatile boolean isRequestScope = false; + private volatile boolean shutdown = false; + + /** + * A class that holds singleton instances and thread-scope instances. Provides thread safe access to singletons + * and thread-scope instances. The instances are created for Type (ParametrizedType) and for a Class. + * @param <TYPE> the type for which the instance is created, either Class, or ParametrizedType (for instance + * Provider<SomeClass>). + */ + private class TypedInstances<TYPE> { + private final MultivaluedMap<TYPE, InstanceContext<?>> singletonInstances = new MultivaluedHashMap<>(); + private final ThreadLocal<MultivaluedMap<TYPE, InstanceContext<?>>> threadInstances = new ThreadLocal<>(); + private final List<Object> threadPredestroyables = Collections.synchronizedList(new LinkedList<>()); + + private <T> List<InstanceContext<?>> _getSingletons(TYPE clazz) { + List<InstanceContext<?>> si; + synchronized (singletonInstances) { + si = singletonInstances.get(clazz); + } + return si; + } + + @SuppressWarnings("unchecked") + <T> T _addSingleton(TYPE clazz, T instance, Binding<?, ?> binding, Annotation[] qualifiers) { + synchronized (singletonInstances) { + // check existing singleton with a qualifier already created by another thread io a meantime + List<InstanceContext<?>> values = singletonInstances.get(clazz); + if (values != null) { + List<InstanceContext<?>> qualified + = values.stream() + .filter(ctx -> ctx.hasQualifiers(qualifiers)) + .collect(Collectors.toList()); + if (!qualified.isEmpty()) { + return (T) qualified.get(0).instance; + } + } + singletonInstances.add(clazz, new InstanceContext<>(instance, binding, qualifiers)); + threadPredestroyables.add(instance); + return instance; + } + } + + @SuppressWarnings("unchecked") + <T> T addSingleton(TYPE clazz, T t, Binding<?, ?> binding, Annotation[] instanceQualifiers) { + T t2 = _addSingleton(clazz, t, binding, instanceQualifiers); + if (t2 == t) { + for (Type contract : binding.getContracts()) { + if (!clazz.equals(contract) && isClass(contract)) { + _addSingleton((TYPE) contract, t, binding, instanceQualifiers); + } + } + } + return t2; + } + + private List<InstanceContext<?>> _getThreadInstances(TYPE clazz) { + MultivaluedMap<TYPE, InstanceContext<?>> ti = threadInstances.get(); + List<InstanceContext<?>> list = ti == null ? null : new LinkedList<>(); + if (ti != null) { + return ti.get(clazz); + } + return list; + } + + private <T> void _addThreadInstance(TYPE clazz, T instance, Binding<T, ?> binding, Annotation[] qualifiers) { + MultivaluedMap<TYPE, InstanceContext<?>> map = threadInstances.get(); + if (map == null) { + map = new MultivaluedHashMap<>(); + threadInstances.set(map); + } + map.add(clazz, new InstanceContext<>(instance, binding, qualifiers)); + threadPredestroyables.add(instance); + } + + <T> void addThreadInstance(TYPE clazz, T t, Binding<T, ?> binding, Annotation[] instanceQualifiers) { + _addThreadInstance(clazz, t, binding, instanceQualifiers); + for (Type contract : binding.getContracts()) { + if (!clazz.equals(contract) && isClass(contract)) { + _addThreadInstance((TYPE) contract, t, binding, instanceQualifiers); + } + } + } + + private <T> List<T> getInstances(TYPE clazz, Annotation[] annotations) { + List<InstanceContext<?>> i = _getContexts(clazz); + return InstanceContext.toInstances(i, annotations); + } + + <T> List<InstanceContext<?>> getContexts(TYPE clazz, Annotation[] annotations) { + List<InstanceContext<?>> i = _getContexts(clazz); + return InstanceContext.filterInstances(i, annotations); + } + + private <T> List<InstanceContext<?>> _getContexts(TYPE clazz) { + List<InstanceContext<?>> si = _getSingletons(clazz); + List<InstanceContext<?>> ti = _getThreadInstances(clazz); + if (si == null && ti != null) { + si = ti; + } else if (ti != null) { + si.addAll(ti); + } + return si; + } + + <T> T getInstance(TYPE clazz, Annotation[] annotations) { + List<T> i = getInstances(clazz, annotations); + if (i != null) { + checkUnique(i); + return i.get(0); + } + return null; + } + + void dispose() { + singletonInstances.forEach((clazz, instances) -> instances.forEach(instance -> preDestroy(instance.getInstance()))); + threadPredestroyables.forEach(NonInjectionManager.this::preDestroy); + } + } + + private class Instances extends TypedInstances<Class<?>> { + } + + private class Types extends TypedInstances<Type> { + } + + public NonInjectionManager() { + } + + public NonInjectionManager(boolean warning) { + if (warning) { + logger.warning(LocalizationMessages.NONINJECT_FALLBACK()); + } else { + logger.log(Level.FINER, LocalizationMessages.NONINJECT_FALLBACK()); + } + } + + @Override + public void completeRegistration() { + instances._addSingleton(InjectionManager.class, this, new InjectionManagerBinding(), null); + } + + @Override + public void shutdown() { + shutdown = true; + + disposableSupplierObjects.forEach((supplier, objects) -> objects.forEach(supplier::dispose)); + disposableSupplierObjects.clear(); + + instances.dispose(); + types.dispose(); + } + + @Override + public boolean isShutdown() { + return shutdown; + } + + private void checkShutdown() { + if (shutdown) { + throw new IllegalStateException(LocalizationMessages.NONINJECT_SHUTDOWN()); + } + } + + @Override + public void register(Binding binding) { + checkShutdown(); + if (InstanceBinding.class.isInstance(binding)) { + InstanceBinding instanceBinding = (InstanceBinding) binding; + Class<?> mainType = binding.getImplementationType(); + if (!instanceBindings.containsKey(mainType)) { // the class could be registered twice, for reader & for writer + instanceBindings.add(mainType, (InstanceBinding) binding); + } + for (Type type : (Iterable<Type>) instanceBinding.getContracts()) { + if (isClass(type)) { + if (!mainType.equals(type)) { + instanceBindings.add((Class<?>) type, instanceBinding); + } + } else { + instanceTypeBindings.add(type, instanceBinding); + } + } + } else if (ClassBinding.class.isInstance(binding)) { + ClassBinding<?> contractBinding = (ClassBinding<?>) binding; + Class<?> mainType = binding.getImplementationType(); + if (!contractBindings.containsKey(mainType)) { // the class could be registered twice, for reader & for writer + contractBindings.add(mainType, contractBinding); + } + for (Type type : contractBinding.getContracts()) { + if (isClass(type)) { + if (!mainType.equals(type)) { + contractBindings.add((Class<?>) type, contractBinding); + } + } else { + contractTypeBindings.add(type, contractBinding); + } + } + } else if (SupplierInstanceBinding.class.isInstance(binding)) { + SupplierInstanceBinding<?> supplierBinding = (SupplierInstanceBinding<?>) binding; + for (Type type : supplierBinding.getContracts()) { + if (isClass(type)) { + supplierInstanceBindings.add((Class<?>) type, supplierBinding); + } else { + supplierTypeInstanceBindings.add(type, supplierBinding); + } + } + } else if (SupplierClassBinding.class.isInstance(binding)) { + SupplierClassBinding<?> supplierBinding = (SupplierClassBinding<?>) binding; + for (Type type : supplierBinding.getContracts()) { + if (isClass(type)) { + supplierClassBindings.add((Class<?>) type, supplierBinding); + } else { + supplierTypeClassBindings.add(type, supplierBinding); + } + } + } + } + + @Override + public void register(Iterable<Binding> descriptors) { + checkShutdown(); + for (Binding binding : descriptors) { + register(binding); + } + } + + @Override + public void register(Binder binder) { + checkShutdown(); + binder.getBindings().stream().iterator().forEachRemaining(this::register); + } + + @Override + public void register(Object provider) throws IllegalArgumentException { + throw new UnsupportedOperationException("Register " + provider); + } + + @Override + public boolean isRegistrable(Class<?> clazz) { + return false; // for external creators + } + + @Override + public <T> List<ServiceHolder<T>> getAllServiceHolders(Class<T> contractOrImpl, Annotation... qualifiers) { + checkShutdown(); + + ClassBindings<T> classBindings = classBindings(contractOrImpl, qualifiers); + return classBindings.getAllServiceHolders(qualifiers); + } + + @Override + public <T> T getInstance(Class<T> contractOrImpl, Annotation... qualifiers) { + checkShutdown(); + + ClassBindings<T> classBindings = classBindings(contractOrImpl, qualifiers); + classBindings.matchQualifiers(qualifiers); + return classBindings.getInstance(); + } + + @Override + public <T> T getInstance(Class<T> contractOrImpl, String classAnalyzer) { + throw new UnsupportedOperationException("getInstance(Class, String)"); + } + + @Override + public <T> T getInstance(Class<T> contractOrImpl) { + checkShutdown(); + + T instance = instances.getInstance(contractOrImpl, null); + if (instance != null) { + return instance; + } + return create(contractOrImpl); + } + + @Override + @SuppressWarnings("unchecked") + public <T> T getInstance(Type contractOrImpl) { + checkShutdown(); + + if (ParameterizedType.class.isInstance(contractOrImpl)) { + T instance = types.getInstance(contractOrImpl, null); + if (instance != null) { + return instance; + } + + TypeBindings<T> typeBindings = typeBindings(contractOrImpl); + return typeBindings.getInstance(); + } else if (isClass(contractOrImpl)) { + return getInstance((Class<? extends T>) contractOrImpl); + } + throw new IllegalStateException(LocalizationMessages.NONINJECT_UNSATISFIED(contractOrImpl)); + } + + private static boolean isClass(Type type) { + return Class.class.isAssignableFrom(type.getClass()); + } + + @Override + public Object getInstance(ForeignDescriptor foreignDescriptor) { + throw new UnsupportedOperationException("getInstance(ForeignDescriptor foreignDescriptor) "); + } + + @Override + public ForeignDescriptor createForeignDescriptor(Binding binding) { + throw new UnsupportedOperationException("createForeignDescriptor(Binding binding) "); + } + + @Override + public <T> List<T> getAllInstances(Type contractOrImpl) { + checkShutdown(); + + if (!isClass(contractOrImpl)) { + TypeBindings<T> typeBindings = typeBindings(contractOrImpl); + return typeBindings.allInstances(); + } + + @SuppressWarnings("unchecked") + ClassBindings<T> classBindings = classBindings((Class<T>) contractOrImpl); + return classBindings.allInstances(); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T create(Class<T> createMe) { + checkShutdown(); + + if (InjectionManager.class.equals(createMe)) { + return (T) this; + } + if (RequestScope.class.equals(createMe)) { + if (!isRequestScope) { + isRequestScope = true; + return (T) new NonInjectionRequestScope(); + } else { + throw new IllegalStateException(LocalizationMessages.NONINJECT_REQUESTSCOPE_CREATED()); + } + } + + ClassBindings<T> classBindings = classBindings(createMe); + return classBindings.create(); + } + + private <T> T justCreate(Class<T> createMe) { + T result = null; + try { + Constructor<T> mostArgConstructor = findConstructor(createMe); + if (mostArgConstructor != null) { + int argCount = mostArgConstructor.getParameterCount(); + if (argCount == 0) { + ensureAccessible(mostArgConstructor); + result = mostArgConstructor.newInstance(); + } else if (argCount > 0) { + Object[] args = getArguments(mostArgConstructor, argCount); + if (args != null) { + ensureAccessible(mostArgConstructor); + result = mostArgConstructor.newInstance(args); + } + } + } + if (result == null) { + throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_CONSTRUCTOR(createMe.getName())); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + + inject(result); + return result; + } + + private static <T> Constructor<T> findConstructor(Class<T> forClass) { + Constructor<T>[] constructors = (Constructor<T>[]) forClass.getDeclaredConstructors(); + Constructor<T> mostArgConstructor = null; + int argCount = -1; + for (Constructor<T> constructor : constructors) { + if (constructor.isAnnotationPresent(Inject.class) || constructor.getParameterCount() == 0) { + if (constructor.getParameterCount() > argCount) { + mostArgConstructor = constructor; + argCount = constructor.getParameterCount(); + } + } + } + return mostArgConstructor; + } + + private Object[] getArguments(Executable executable, int argCount) { + if (executable == null) { + return null; + } + Object[] args = new Object[argCount]; + for (int i = 0; i != argCount; i++) { + Type type = executable.getAnnotatedParameterTypes()[i].getType(); + args[i] = isClass(type) ? getInstance((Class<?>) type) : getInstance(type); + } + return args; + } + + private static void ensureAccessible(Executable executable) { + try { + if (!executable.isAccessible()) { + executable.setAccessible(true); + } + } catch (Exception e) { + // consume. It will fail later with invoking the executable + } + } + + private void checkUnique(List<?> list) { + if (list.size() != 1) { + throw new IllegalStateException(LocalizationMessages.NONINJECT_AMBIGUOUS_SERVICES(list.get(0))); + } + } + + @Override + public <T> T createAndInitialize(Class<T> createMe) { + return justCreate(createMe); + } + + @Override + public void inject(Object injectMe) { + Method postConstruct = getAnnotatedMethod(injectMe, PostConstruct.class); + if (postConstruct != null) { + ensureAccessible(postConstruct); + try { + postConstruct.invoke(injectMe); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } + + @Override + public void inject(Object injectMe, String classAnalyzer) { + throw new UnsupportedOperationException("inject(Object injectMe, String classAnalyzer)"); + } + + @Override + public void preDestroy(Object preDestroyMe) { + Method preDestroy = getAnnotatedMethod(preDestroyMe, PreDestroy.class); + if (preDestroy != null) { + ensureAccessible(preDestroy); + try { + preDestroy.invoke(preDestroyMe); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } + + private static Method getAnnotatedMethod(Object object, Class<? extends Annotation> annotation) { + Class<?> clazz = object.getClass(); + for (Method method : clazz.getMethods()) { + if (method.isAnnotationPresent(annotation) + && /* do not invoke interceptors */ method.getParameterCount() == 0) { + return method; + } + } + return null; + } + + /** + * Some {@link Binding} requires the proxy to be created rather than just the instance, + * for instance a proxy of an instance supplied by a supplier that is not known at a time of the proxy creation. + * @param createProxy the nullable {@link Binding#isProxiable()} information + * @param iface the type of which the proxy is created + * @param supplier the reference to the supplier + * @param <T> the type the supplier should supply + * @return The proxy for the instance supplied by a supplier or the instance if not required to be proxied. + */ + @SuppressWarnings("unchecked") + private <T> T createSupplierProxyIfNeeded(Boolean createProxy, Class<T> iface, Supplier<T> supplier) { + if (createProxy != null && createProxy && iface.isInterface()) { + T proxy = (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, new InvocationHandler() { + final SingleRegisterSupplier<T> singleSupplierRegister = new SingleRegisterSupplier<>(supplier); + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + T t = singleSupplierRegister.get(); + Object ret = method.invoke(t, args); + return ret; + } + }); + return proxy; + } else { + return registerDisposableSupplierAndGet(supplier); + } + } + + /** + * A holder class making sure the Supplier (especially the {@link DisposableSupplier}) supplying the instance + * supplies (and is registered for being disposed at the end of the lifecycle) only once. + * @param <T> + */ + private class SingleRegisterSupplier<T> { + private final LazyValue<T> once; + + private SingleRegisterSupplier(Supplier<T> supplier) { + once = Values.lazy((Value<T>) () -> registerDisposableSupplierAndGet(supplier)); + } + + T get() { + return once.get(); + } + } + + private <T> T registerDisposableSupplierAndGet(Supplier<T> supplier) { + T instance = supplier.get(); + if (DisposableSupplier.class.isInstance(supplier)) { + disposableSupplierObjects.add((DisposableSupplier<T>) supplier, instance); + } + return instance; + } + + /** + * Create {@link ClassBindings} instance containing bindings and instances for the given Type. + * @param clazz the given class. + * @param instancesQualifiers The qualifiers the expected instances of the given class should have. + * @param <T> Expected return class type. + * @return the {@link ClassBindings}. + */ + @SuppressWarnings("unchecked") + private <T> ClassBindings<T> classBindings(Class<T> clazz, Annotation... instancesQualifiers) { + ClassBindings<T> classBindings = new ClassBindings<>(clazz, instancesQualifiers); + List<InstanceBinding<?>> ib = instanceBindings.get(clazz); + if (ib != null) { + ib.forEach(binding -> classBindings.instanceBindings.add((InstanceBinding<T>) binding)); + } + List<SupplierInstanceBinding<?>> sib = supplierInstanceBindings.get(clazz); + if (sib != null) { + sib.forEach(binding -> classBindings.supplierInstanceBindings.add((SupplierInstanceBinding<T>) binding)); + } + List<ClassBinding<?>> cb = contractBindings.get(clazz); + if (cb != null) { + cb.forEach(binding -> classBindings.classBindings.add((ClassBinding<T>) binding)); + } + List<SupplierClassBinding<?>> scb = supplierClassBindings.get(clazz); + if (scb != null) { + scb.forEach(binding -> classBindings.supplierClassBindings.add((SupplierClassBinding<T>) binding)); + } + return classBindings; + } + + /** + * Create {@link TypeBindings} instance containing bindings and instances for the given Type. + * @param type the given type. + * @param <T> Expected return type. + * @return the {@link TypeBindings}. + */ + @SuppressWarnings("unchecked") + private <T> TypeBindings<T> typeBindings(Type type) { + TypeBindings<T> typeBindings = new TypeBindings<>(type); + List<InstanceBinding<?>> ib = instanceTypeBindings.get(type); + if (ib != null) { + ib.forEach(binding -> typeBindings.instanceBindings.add((InstanceBinding<T>) binding)); + } + List<SupplierInstanceBinding<?>> sib = supplierTypeInstanceBindings.get(type); + if (sib != null) { + sib.forEach(binding -> typeBindings.supplierInstanceBindings.add((SupplierInstanceBinding<T>) binding)); + } + List<ClassBinding<?>> cb = contractTypeBindings.get(type); + if (cb != null) { + cb.forEach(binding -> typeBindings.classBindings.add((ClassBinding<T>) binding)); + } + List<SupplierClassBinding<?>> scb = supplierTypeClassBindings.get(type); + if (scb != null) { + scb.forEach(binding -> typeBindings.supplierClassBindings.add((SupplierClassBinding<T>) binding)); + } + return typeBindings; + } + + /** + * <p> + * A class that contains relevant bindings for a given TYPE, filtered from all registered bindings. + * The TYPE is either Type (ParametrizedType) or Class. + * </p> + * <p> + * The class also filters any bindings for which the singleton or thread-scoped instance already is created. + * The class either provides the existing instance, or all instances of the TYPE, or {@link ServiceHolder}s. + * </p> + * @param <X> The expected return type for the TYPE. + * @param <TYPE> The Type for which a {@link Binding} has been created. + */ + private abstract class XBindings<X, TYPE> { + + protected final List<InstanceBinding<X>> instanceBindings = new LinkedList<>(); + protected final List<SupplierInstanceBinding<X>> supplierInstanceBindings = new LinkedList<>(); + protected final List<ClassBinding<X>> classBindings = new LinkedList<>(); + protected final List<SupplierClassBinding<X>> supplierClassBindings = new LinkedList<>(); + + protected final TYPE type; + protected final Annotation[] instancesQualifiers; + protected final TypedInstances<TYPE> instances; + + protected XBindings(TYPE type, Annotation[] instancesQualifiers, TypedInstances<TYPE> instances) { + this.type = type; + this.instancesQualifiers = instancesQualifiers; + this.instances = instances; + } + + int size() { + return instanceBindings.size() + + supplierInstanceBindings.size() + + classBindings.size() + + supplierClassBindings.size(); + } + + private void _checkUnique() { + if (size() > 1) { + throw new IllegalStateException(LocalizationMessages.NONINJECT_AMBIGUOUS_SERVICES(type)); + } + } + + void filterBinding(Binding binding) { + if (InstanceBinding.class.isInstance(binding)) { + instanceBindings.remove(binding); + } else if (ClassBinding.class.isInstance(binding)) { + classBindings.remove(binding); + } else if (SupplierInstanceBinding.class.isInstance(binding)) { + supplierInstanceBindings.remove(binding); + } else if (SupplierClassBinding.class.isInstance(binding)) { + supplierClassBindings.remove(binding); + } + } + + /** + * Match the binging qualifiers + * @param bindingQualifiers the qualifiers registered with the bindings + */ + void matchQualifiers(Annotation... bindingQualifiers) { + if (bindingQualifiers != null) { + _filterRequested(instanceBindings, bindingQualifiers); + _filterRequested(classBindings, bindingQualifiers); + _filterRequested(supplierInstanceBindings, bindingQualifiers); + _filterRequested(supplierClassBindings, bindingQualifiers); + } + } + + @SuppressWarnings("unchecked") + private void _filterRequested(List<? extends Binding<?, ?>> bindingList, Annotation... requestedQualifiers) { + for (Iterator<? extends Binding> bindingIterator = bindingList.iterator(); bindingIterator.hasNext();) { + Binding<X, ?> binding = bindingIterator.next(); + classLoop: + for (Annotation requestedQualifier : requestedQualifiers) { + for (Annotation bindingQualifier : binding.getQualifiers()) { + if (requestedQualifier.annotationType().isInstance(bindingQualifier)) { + continue classLoop; + } + } + bindingIterator.remove(); + } + } + } + + protected boolean _isPerThread(Class<? extends Annotation> scope) { + return RequestScoped.class.equals(scope) || PerThread.class.equals(scope); + } + + private X _getInstance(InstanceBinding<X> instanceBinding) { + return instanceBinding.getService(); + } + + private X _create(SupplierInstanceBinding<X> binding) { + Supplier<X> supplier = binding.getSupplier(); + X t = registerDisposableSupplierAndGet(supplier); + if (Singleton.class.equals(binding.getScope())) { + _addInstance(t, binding); + } else if (_isPerThread(binding.getScope())) { + _addThreadInstance(t, binding); + } + return t; + } + + X create() { + _checkUnique(); + if (!instanceBindings.isEmpty()) { + return _getInstance(instanceBindings.get(0)); + } else if (!supplierInstanceBindings.isEmpty()) { + return _create(supplierInstanceBindings.get(0)); + } else if (!classBindings.isEmpty()) { + return _createAndStore(classBindings.get(0)); + } else if (!supplierClassBindings.isEmpty()) { + return _create(supplierClassBindings.get(0)); + } + + throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_BINDING(type)); + } + + protected X getInstance() { + X instance = instances.getInstance(type, instancesQualifiers); + if (instance != null) { + return instance; + } + return create(); + } + + List<X> allInstances() { + List<X> list = new LinkedList<>(); + List<InstanceContext<?>> instanceContextList; + + instanceContextList = instances.getContexts(type, instancesQualifiers); + if (instanceContextList != null) { + instanceContextList.forEach(instanceContext -> filterBinding(instanceContext.getBinding())); + instanceContextList.forEach(instanceContext -> list.add((X) instanceContext.getInstance())); + } + + list.addAll(instanceBindings.stream() + .map(this::_getInstance) + .collect(Collectors.toList())); + + list.addAll(classBindings.stream() + .map(this::_createAndStore) + .collect(Collectors.toList())); + + list.addAll(supplierInstanceBindings.stream() + .map(this::_create) + .collect(Collectors.toList())); + + list.addAll(supplierClassBindings.stream() + .map(this::_create) + .collect(Collectors.toList())); + + return list; + } + + protected abstract X _create(SupplierClassBinding<X> binding); + + protected abstract X _createAndStore(ClassBinding<X> binding); + + protected <T> T _addInstance(TYPE type, T instance, Binding<?, ?> binding) { + return instances.addSingleton(type, instance, binding, instancesQualifiers); + } + + protected void _addThreadInstance(TYPE type, Object instance, Binding binding) { + instances.addThreadInstance(type, instance, binding, instancesQualifiers); + } + + protected <T> T _addInstance(T instance, Binding<?, ?> binding) { + return instances.addSingleton(type, instance, binding, instancesQualifiers); + } + + protected void _addThreadInstance(Object instance, Binding binding) { + instances.addThreadInstance(type, instance, binding, instancesQualifiers); + } + } + + + private class ClassBindings<T> extends XBindings<T, Class<?>> { + private ClassBindings(Class<T> clazz, Annotation[] instancesQualifiers) { + super(clazz, instancesQualifiers, NonInjectionManager.this.instances); + } + + @SuppressWarnings("unchecked") + List<ServiceHolder<T>> getAllServiceHolders(Annotation... qualifiers) { + matchQualifiers(qualifiers); + + List<ServiceHolder<T>> holders = new LinkedList<>(); + List<InstanceContext<?>> instanceContextList; + + instanceContextList = instances.getContexts(type, qualifiers); + + if (instanceContextList != null) { + instanceContextList.forEach(instanceContext -> filterBinding(instanceContext.getBinding())); + instanceContextList.forEach(instanceContext -> holders.add(new ServiceHolderImpl<T>( + (T) instanceContext.getInstance(), + (Class<T>) instanceContext.getInstance().getClass(), + instanceContext.getBinding().getContracts(), + instanceContext.getBinding().getRank() == null ? 0 : instanceContext.getBinding().getRank()) + )); + } + + List<ServiceHolder<T>> instanceBindingHolders = instanceBindings.stream() + .map(this::_serviceHolder) + .collect(Collectors.toList()); + holders.addAll(instanceBindingHolders); + + List<ServiceHolder<T>> classBindingHolders = classBindings.stream() + .filter(binding -> NonInjectionManager.this.findConstructor(binding.getService()) != null) + .map(this::_serviceHolder) + .collect(Collectors.toList()); + holders.addAll(classBindingHolders); + + return holders; + } + + private <T> ServiceHolderImpl<T> _serviceHolder(InstanceBinding<T> binding) { + return new ServiceHolderImpl<T>( + binding.getService(), + binding.getImplementationType(), + binding.getContracts(), + binding.getRank() == null ? 0 : binding.getRank()); + } + + private <T> ServiceHolderImpl<T> _serviceHolder(ClassBinding<T> binding) { + return new ServiceHolderImpl<T>( + NonInjectionManager.this.create(binding.getService()), + binding.getImplementationType(), + binding.getContracts(), + binding.getRank() == null ? 0 : binding.getRank()); + } + + protected T _create(SupplierClassBinding<T> binding) { + Supplier<T> supplier = instances.getInstance(binding.getSupplierClass(), null); + if (supplier == null) { + supplier = justCreate(binding.getSupplierClass()); + if (Singleton.class.equals(binding.getSupplierScope())) { + supplier = instances.addSingleton(binding.getSupplierClass(), supplier, binding, null); + } else if (_isPerThread(binding.getSupplierScope())) { + instances.addThreadInstance(binding.getSupplierClass(), supplier, binding, null); + } + } + + T t = createSupplierProxyIfNeeded(binding.isProxiable(), (Class<T>) type, supplier); + if (Singleton.class.equals(binding.getScope())) { + t = _addInstance(type, t, binding); + } else if (_isPerThread(binding.getScope())) { + _addThreadInstance(type, t, binding); + } + return t; + } + + protected T _createAndStore(ClassBinding<T> binding) { + T result = justCreate(binding.getService()); + result = _addInstance(binding.getService(), result, binding); + return result; + } + } + + private class TypeBindings<T> extends XBindings<T, Type> { + private TypeBindings(Type type) { + super(type, null, types); + } + + protected T _create(SupplierClassBinding<T> binding) { + Supplier<T> supplier = justCreate(binding.getSupplierClass()); + + T t = registerDisposableSupplierAndGet(supplier); + if (Singleton.class.equals(binding.getScope())) { + t = _addInstance(type, t, binding); + } else if (_isPerThread(binding.getScope())) { + _addThreadInstance(type, t, binding); + } + return t; + } + + @Override + protected T _createAndStore(ClassBinding<T> binding) { + T result = justCreate(binding.getService()); + result = _addInstance(type, result, binding); + return result; + } + + @SuppressWarnings("unchecked") + @Override + T create() { + if (ParameterizedType.class.isInstance(type)) { + ParameterizedType pt = (ParameterizedType) type; + if (Provider.class.equals(pt.getRawType())) { + return (T) new Provider<Object>() { + final SingleRegisterSupplier<Object> supplier = new SingleRegisterSupplier<>(new Supplier<Object>() { + @Override + public Object get() { + Type actualTypeArgument = pt.getActualTypeArguments()[0]; + if (isClass(actualTypeArgument)) { + return NonInjectionManager.this.getInstance((Class<? extends T>) actualTypeArgument); + } else { + return NonInjectionManager.this.getInstance(actualTypeArgument); + } + } + }); + + @Override + public Object get() { + return supplier.get(); //Not disposable + } + }; + } + } + return super.create(); + } + } + + /** + * A triplet of created instance, the registered {@link Binding} that prescribed the creation of the instance + * and {@link Annotation qualifiers} the instance was created with. + * @param <T> type of the instance. + * @see NonInjectionManager#getInstance(Class, Annotation[]) + */ + private static class InstanceContext<T> { + private final T instance; + private final Binding<?, ?> binding; + private final Annotation[] createdWithQualifiers; + + private InstanceContext(T instance, Binding<?, ?> binding, Annotation[] qualifiers) { + this.instance = instance; + this.binding = binding; + this.createdWithQualifiers = qualifiers; + } + + public Binding<?, ?> getBinding() { + return binding; + } + + public T getInstance() { + return instance; + } + + @SuppressWarnings("unchecked") + static <T> List<T> toInstances(List<InstanceContext<?>> instances, Annotation[] qualifiers) { + return instances != null + ? instances.stream() + .filter(instance -> instance.hasQualifiers(qualifiers)) + .map(pair -> (T) pair.getInstance()) + .collect(Collectors.toList()) + : null; + } + + private static List<InstanceContext<?>> filterInstances(List<InstanceContext<?>> instances, Annotation... qualifiers) { + return instances != null + ? instances.stream() + .filter(instance -> instance.hasQualifiers(qualifiers)) + .collect(Collectors.toList()) + : null; + } + + private boolean hasQualifiers(Annotation[] requested) { + if (requested != null) { + classLoop: + for (Annotation req : requested) { + if (createdWithQualifiers != null) { + for (Annotation cur : createdWithQualifiers) { + if (cur.annotationType().isInstance(req)) { + continue classLoop; + } + } + return false; + } + } + } + return true; + } + } + + /** + * Singleton Binding this {@link NonInjectionManager} was supposed to be created based upon. + */ + private static final class InjectionManagerBinding extends Binding<InjectionManager, Binding<?, ?>> { + } + +}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionRequestScope.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionRequestScope.java new file mode 100644 index 0000000..258780d --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionRequestScope.java
@@ -0,0 +1,91 @@ +/* + * 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.client.innate.inject; + +import org.glassfish.jersey.internal.util.ExtendedLogger; +import org.glassfish.jersey.internal.util.LazyUid; +import org.glassfish.jersey.process.internal.RequestScope; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class NonInjectionRequestScope extends RequestScope { + @Override + public org.glassfish.jersey.process.internal.RequestContext createContext() { + return new Instance(); + } + + /** + * Implementation of the request scope instance. + */ + public static final class Instance implements org.glassfish.jersey.process.internal.RequestContext { + + private static final ExtendedLogger logger = new ExtendedLogger(Logger.getLogger(Instance.class.getName()), Level.FINEST); + + /* + * Scope instance UUID. + * + * For performance reasons, it's only generated if toString() method is invoked, + * e.g. as part of some low-level logging. + */ + private final LazyUid id = new LazyUid(); + + /** + * Holds the number of snapshots of this scope. + */ + private final AtomicInteger referenceCounter; + + private Instance() { + this.referenceCounter = new AtomicInteger(1); + } + + /** + * Get a "new" reference of the scope instance. This will increase + * the internal reference counter which prevents the scope instance + * to be destroyed until a {@link #release()} method is explicitly + * called (once per each {@code getReference()} method call). + * + * @return referenced scope instance. + */ + @Override + public NonInjectionRequestScope.Instance getReference() { + // TODO: replace counter with a phantom reference + reference queue-based solution + referenceCounter.incrementAndGet(); + return this; + } + + + /** + * Release a single reference to the current request scope instance. + * <p> + * Once all instance references are released, the instance will be recycled. + */ + @Override + public void release() { + referenceCounter.decrementAndGet(); + } + + @Override + public String toString() { + return "Instance{" + + "id=" + id + + ", referenceCounter=" + referenceCounter + + '}'; + } + } +}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java index 31a3583..c7e0ac2 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022 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 @@ -21,10 +21,13 @@ import java.io.InputStream; import java.lang.reflect.Field; import java.net.HttpURLConnection; +import java.net.InetAddress; import java.net.ProtocolException; +import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URI; import java.net.URISyntaxException; +import java.net.UnknownHostException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -42,6 +45,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.client.Client; @@ -55,6 +59,7 @@ import org.glassfish.jersey.client.JerseyClient; import org.glassfish.jersey.client.RequestEntityProcessing; import org.glassfish.jersey.client.innate.ClientProxy; +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.util.PropertiesHelper; @@ -315,11 +320,35 @@ } } + /** + * Secure connection if necessary. + * <p/> + * Provided implementation sets {@link HostnameVerifier} and {@link SSLSocketFactory} to give connection, if that + * is an instance of {@link HttpsURLConnection}. + * + * @param clientRequest the actual client request. + * @param uc http connection to be secured. + */ + private void secureConnection( + final ClientRequest clientRequest, final HttpURLConnection uc, final SSLParamConfigurator sniConfig) { + secureConnection(clientRequest.getClient(), uc); // keep this for compatibility + + if (sniConfig.isSNIRequired() && uc instanceof HttpsURLConnection) { // set SNI + HttpsURLConnection suc = (HttpsURLConnection) uc; + SniSSLSocketFactory socketFactory = new SniSSLSocketFactory(suc.getSSLSocketFactory()); + socketFactory.setSniConfig(sniConfig); + suc.setSSLSocketFactory(socketFactory); + } + } + private ClientResponse _apply(final ClientRequest request) throws IOException { final HttpURLConnection uc; - Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(request); + final Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(request); + final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(request).build(); + final URI sniUri = sniConfig.isSNIRequired() ? sniConfig.toIPRequestUri() : request.getUri(); + proxy.ifPresent(clientProxy -> ClientProxy.setBasicAuthorizationHeader(request.getHeaders(), proxy.get())); - uc = this.connectionFactory.getConnection(request.getUri().toURL(), proxy.isPresent() ? proxy.get().proxy() : null); + uc = this.connectionFactory.getConnection(sniUri.toURL(), proxy.isPresent() ? proxy.get().proxy() : null); uc.setDoInput(true); final String httpMethod = request.getMethod(); @@ -335,7 +364,7 @@ uc.setReadTimeout(request.resolveProperty(ClientProperties.READ_TIMEOUT, uc.getReadTimeout())); - secureConnection(request.getClient(), uc); + secureConnection(request, uc, sniConfig); final Object entity = request.getEntity(); Exception storedException = null; @@ -559,4 +588,84 @@ public String getName() { return "HttpUrlConnection " + AccessController.doPrivileged(PropertiesHelper.getSystemProperty("java.version")); } + + private static class SniSSLSocketFactory extends SSLSocketFactory { + private final SSLSocketFactory socketFactory; + private ThreadLocal<SSLParamConfigurator> sniConfigs = new ThreadLocal<>(); + + public void setSniConfig(SSLParamConfigurator sniConfigs) { + this.sniConfigs.set(sniConfigs); + } + + private SniSSLSocketFactory(SSLSocketFactory socketFactory) { + this.socketFactory = socketFactory; + } + + @Override + public String[] getDefaultCipherSuites() { + return socketFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return socketFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { + Socket superSocket = socketFactory.createSocket(socket, s, i, b); + setSNIServerName(superSocket); + return superSocket; + } + + @Override + public Socket createSocket(String s, int i) throws IOException, UnknownHostException { + Socket superSocket = socketFactory.createSocket(s, i); + setSNIServerName(superSocket); + return superSocket; + } + + @Override + public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException { + Socket superSocket = socketFactory.createSocket(s, i, inetAddress, i1); + setSNIServerName(superSocket); + return superSocket; + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + Socket superSocket = socketFactory.createSocket(inetAddress, i); + setSNIServerName(superSocket); + return superSocket; + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { + Socket superSocket = socketFactory.createSocket(inetAddress, i, inetAddress1, i1); + setSNIServerName(superSocket); + return superSocket; + } + + @Override + public Socket createSocket(Socket s, InputStream consumed, boolean autoClose) throws IOException { + Socket superSocket = socketFactory.createSocket(s, consumed, autoClose); + setSNIServerName(superSocket); + return superSocket; + } + + @Override + public Socket createSocket() throws IOException { + Socket superSocket = socketFactory.createSocket(); + setSNIServerName(superSocket); + return superSocket; + } + + private void setSNIServerName(Socket superSocket) { + SSLParamConfigurator sniConfig = this.sniConfigs.get(); + if (null != sniConfig && SSLSocket.class.isInstance(superSocket)) { + sniConfig.setSNIServerName((SSLSocket) superSocket); + } + this.sniConfigs.remove(); + } + } }
diff --git a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties index e66ceab..ee80184 100644 --- a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties +++ b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
@@ -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 @@ -48,7 +48,14 @@ Using default cached thread pool. negative.chunk.size=Negative chunked HTTP transfer coding chunk size value specified in the client configuration property: [{0}] \ Reverting to programmatically set default: [{1}] -negative.input.parameter="Input parameter {0} must not be negative." +negative.input.parameter="Input parameter {0} must not be negative1." +noninject.ambiguous.services=Ambiguous providing services ${0}. +noninject.fallback=Falling back to injection-less client. +noninject.no.constructor=No applicable constructor for ${0} found. +noninject.no.binding=No binding found for ${0}. +noninject.requestscope.created=RequestScope already created. +noninject.shutdown=InjectionManager is already shutdown. +noninject.unsatisfied=Unsatisfied dependency for ${0}. null.connector.provider=ConnectorProvider must not be set to null. null.executor.service=ExecutorService must not be set to null. null.input.parameter=Input method parameter {0} must not be null.
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 8ab88e7..aaa88c9 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
@@ -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 @@ -112,7 +112,7 @@ } @Provider - public class MyProvider implements ContextResolver<String> { + public static class MyProvider implements ContextResolver<String> { @Override public String getContext(final Class<?> type) {
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java b/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java index 05ac6ea..a985579 100644 --- a/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java +++ b/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022 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 @@ -272,8 +272,12 @@ } public static class CustomProvider implements ClientRequestFilter { + private final CustomContract customContract; + @Inject - private CustomContract customContract; + CustomProvider(CustomContract customContract) { + this.customContract = customContract; + } @Override public void filter(ClientRequestContext requestContext) throws IOException {
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java b/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java index d7643aa..515bb83 100644 --- a/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java +++ b/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.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 @@ -34,7 +34,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -71,7 +70,6 @@ } @Test - @Disabled("TODO JAX-RS 2.1") public void testNewClientExecutor() throws Exception { testClient(ClientBuilder.newBuilder() .executorService(executor)
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java index 2df0307..deafb62 100644 --- a/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java +++ b/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -22,13 +22,13 @@ import org.junit.jupiter.api.Test; import jakarta.annotation.Priority; +import jakarta.inject.Inject; import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.client.Invocation; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.Response; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -263,8 +263,12 @@ } private static class InjectedPreInvocationInterceptor implements PreInvocationInterceptor { - @Context - Configuration configuration; + private final Configuration configuration; + + @Inject + public InjectedPreInvocationInterceptor(Configuration configuration) { + this.configuration = configuration; + } @Override public void beforeRequest(ClientRequestContext requestContext) {
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java b/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java index bc5c722..57c7d24 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.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 @@ -62,12 +62,18 @@ } } + private final Provider<MessageBodyWorkers> workers; + private final Provider<ContextResolvers> resolvers; + private final Provider<ExceptionMappers> mappers; + @Inject - private Provider<MessageBodyWorkers> workers; - @Inject - private Provider<ContextResolvers> resolvers; - @Inject - private Provider<ExceptionMappers> mappers; + public JaxrsProviders(Provider<MessageBodyWorkers> workers, + Provider<ContextResolvers> resolvers, + Provider<ExceptionMappers> mappers) { + this.workers = workers; + this.resolvers = resolvers; + this.mappers = mappers; + } @Override public <T> MessageBodyReader<T> getMessageBodyReader(Class<T> type,
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java index 19177cf..1750dd8 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.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,6 +20,8 @@ import java.util.List; import java.util.Optional; +import jakarta.ws.rs.ConstrainedTo; +import jakarta.ws.rs.RuntimeType; import jakarta.ws.rs.WebApplicationException; import org.glassfish.jersey.internal.LocalizationMessages; @@ -36,22 +38,32 @@ public class Injections { /** - * Creates a {@link InjectionManager} without parent and initial binder. + * Creates an {@link InjectionManager} without parent and initial binder. * - * @return a injection manager with all the bindings. + * @return an injection manager with all the bindings. */ public static InjectionManager createInjectionManager() { - return lookupInjectionManagerFactory().create(); + return lookupInjectionManagerFactory(RuntimeType.SERVER).create(); + } + + /** + * Creates an {@link InjectionManager} without parent and initial binder. + * @param type {@link RuntimeType} the {@link InjectionManagerFactory} must be {@link ConstrainedTo} if annotated. + * + * @return an injection manager with all the bindings. + */ + public static InjectionManager createInjectionManager(RuntimeType type) { + return lookupInjectionManagerFactory(type).create(); } /** * Creates a {@link InjectionManager} with initial binder that is immediately registered. * * @param binder custom the {@link Binder binder}. - * @return a injection manager with all the bindings. + * @return an injection manager with all the bindings. */ public static InjectionManager createInjectionManager(Binder binder) { - InjectionManagerFactory injectionManagerFactory = lookupInjectionManagerFactory(); + InjectionManagerFactory injectionManagerFactory = lookupInjectionManagerFactory(RuntimeType.SERVER); InjectionManager injectionManager = injectionManagerFactory.create(); injectionManager.register(binder); return injectionManager; @@ -66,11 +78,11 @@ * @return an injection manager with all the bindings. */ public static InjectionManager createInjectionManager(Object parent) { - return lookupInjectionManagerFactory().create(parent); + return lookupInjectionManagerFactory(RuntimeType.SERVER).create(parent); } - private static InjectionManagerFactory lookupInjectionManagerFactory() { - return lookupService(InjectionManagerFactory.class) + private static InjectionManagerFactory lookupInjectionManagerFactory(RuntimeType type) { + return lookupService(InjectionManagerFactory.class, type) .orElseThrow(() -> new IllegalStateException(LocalizationMessages.INJECTION_MANAGER_FACTORY_NOT_FOUND())); } @@ -80,12 +92,17 @@ * * @param clazz type of service to look for. * @param <T> type of service to look for. + * @param type {@link RuntimeType} the {@link InjectionManagerFactory} must be {@link ConstrainedTo} if annotated. * @return instance of service with highest priority or {@code null} if service of given type cannot be found. * @see jakarta.annotation.Priority */ - private static <T> Optional<T> lookupService(final Class<T> clazz) { + private static <T> Optional<T> lookupService(final Class<T> clazz, RuntimeType type) { List<RankedProvider<T>> providers = new LinkedList<>(); for (T provider : ServiceFinder.find(clazz)) { + ConstrainedTo constrain = provider.getClass().getAnnotation(ConstrainedTo.class); + if (constrain != null && type != constrain.value()) { + continue; + } providers.add(new RankedProvider<>(provider)); } providers.sort(new RankedComparator<>(RankedComparator.Order.DESCENDING));
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java index d30f655..8d6a8ef 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.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 @@ -22,11 +22,11 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.inject.Inject; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.MessageBodyReader; @@ -95,7 +95,8 @@ private final Provider<SAXParserFactory> spf; - public SaxSourceReader(@Context Provider<SAXParserFactory> spf) { + @Inject + public SaxSourceReader(Provider<SAXParserFactory> spf) { this.spf = spf; } @@ -135,7 +136,8 @@ private final Provider<DocumentBuilderFactory> dbf; - public DomSourceReader(@Context Provider<DocumentBuilderFactory> dbf) { + @Inject + public DomSourceReader(Provider<DocumentBuilderFactory> dbf) { this.dbf = dbf; } @@ -176,8 +178,9 @@ private final Provider<SAXParserFactory> saxParserFactory; private final Provider<TransformerFactory> transformerFactory; - public SourceWriter(@Context Provider<SAXParserFactory> spf, - @Context Provider<TransformerFactory> tf) { + @Inject + public SourceWriter(Provider<SAXParserFactory> spf, + Provider<TransformerFactory> tf) { this.saxParserFactory = spf; this.transformerFactory = tf; }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java index c8c9684..e85d57a 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.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 @@ -319,7 +319,7 @@ private void accept(final ClassVisitor classVisitor, final int parsingOptions) { final int originalVersion = getMajorVersion(b); - if (originalVersion == WARN_VERSION + 1) { + if (originalVersion > WARN_VERSION) { // temporarily downgrade version to bypass check in ASM setMajorVersion(WARN_VERSION, b); LOGGER.warning("Unsupported class file major version " + originalVersion);
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml index 1ba38d2..e19ffe0 100644 --- a/docs/src/main/docbook/client.xml +++ b/docs/src/main/docbook/client.xml
@@ -1087,8 +1087,22 @@ <para> See javadoc of the &jersey.client.HttpAuthenticationFeature; for more details. </para> - </section> + </section> + <section> + <title><anchor xml:id="SNI"/>Server Name Indication (SNI) Support</title> + <para> + When using SSL/TLS protocols for the connection, <literal>SNIHostName</literal> is set automatically + based on the host name in the HTTPS request. + </para> + <para> + There might be use-cases where the <literal>SNIHostName</literal> is required to be set for other host + than the host specified in the HTTPS request. For those cases, when the HTTP header <literal>Host</literal> + is set, the <literal>SNIHostName</literal> is set for the host specified in the <literal>Host</literal> header. + Note that only <literal>Apache Connector, JDK Connector, Netty connector</literal>, and the default + <literal>HttpUrlConnector</literal> do support this feature. + </para> + </section> </section>
diff --git a/etc/config/copyright-exclude b/etc/config/copyright-exclude index 987175b..9577477 100644 --- a/etc/config/copyright-exclude +++ b/etc/config/copyright-exclude
@@ -69,6 +69,7 @@ /tests/e2e/server/mvc/MvcEncodingTest/MustacheResource.mustache /test/resources/org/glassfish/jersey/server/config/jaxrs-components /tests/e2e-entity/src/test/resources/org/glassfish/jersey/tests/e2e/entity/xxe.txt +/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
diff --git a/examples/NOTICE.md b/examples/NOTICE.md index 84c7087..4e60279 100644 --- a/examples/NOTICE.md +++ b/examples/NOTICE.md
@@ -43,6 +43,11 @@ * Copyright: 2009, Red Hat, Inc. and/or its affiliates, and individual contributors * by the @authors tag. +Hibernate Validator CDI, 6.2.4.Final +* License: Apache License, 2.0 +* Project: https://beanvalidation.org/ +* Repackaged in org.glassfish.jersey.server.validation.internal.hibernate + Bootstrap v3.3.7 * License: MIT license (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Project: http://getbootstrap.com @@ -61,12 +66,12 @@ * License: Apache License, 2.0 * Copyright (C) 2009 The JSR-330 Expert Group -Javassist Version 3.25.0-GA +Javassist Version 3.29.0-GA * License: Apache License, 2.0 * Project: http://www.javassist.org/ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. -Jackson JAX-RS Providers Version 2.11.3 +Jackson JAX-RS Providers Version 2.14.1 * License: Apache License, 2.0 * Project: https://github.com/FasterXML/jackson-jaxrs-providers * Copyright: (c) 2009-2011 FasterXML, LLC. All rights reserved unless otherwise indicated. @@ -91,7 +96,7 @@ * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS * Copyright: Eric Rowell -org.objectweb.asm Version 9.0 +org.objectweb.asm Version 9.4 * License: Modified BSD (https://asm.ow2.io/license.html) * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.
diff --git a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java index 3a69f66..b5c0943 100644 --- a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java +++ b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.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 @@ -51,9 +51,7 @@ @Singleton final class EntityInspectorImpl implements EntityInspector { private final List<EntityProcessor> entityProcessors; - - @Inject - private EntityGraphProvider graphProvider; + private final EntityGraphProvider graphProvider; /** * Constructor expecting {@link InjectionManager} to be injected. @@ -61,10 +59,11 @@ * @param injectionManager injection manager to be injected. */ @Inject - public EntityInspectorImpl(final InjectionManager injectionManager) { + public EntityInspectorImpl(final InjectionManager injectionManager, EntityGraphProvider graphProvider) { Spliterator<EntityProcessor> entities = Providers.getAllProviders(injectionManager, EntityProcessor.class, new RankedComparator<>()).spliterator(); this.entityProcessors = StreamSupport.stream(entities, false).collect(Collectors.toList()); + this.graphProvider = graphProvider; } @Override
diff --git a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java index 5f911e3..9eb5933 100644 --- a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java +++ b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018 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 @@ -17,7 +17,12 @@ package org.glassfish.jersey.message.filtering; import org.glassfish.jersey.message.filtering.spi.AbstractObjectProvider; +import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider; +import org.glassfish.jersey.message.filtering.spi.EntityInspector; import org.glassfish.jersey.message.filtering.spi.ObjectGraph; +import org.glassfish.jersey.message.filtering.spi.ScopeProvider; + +import jakarta.inject.Inject; /** * {@link org.glassfish.jersey.message.filtering.spi.ObjectProvider Object provider} and @@ -28,6 +33,13 @@ */ final class ObjectGraphProvider extends AbstractObjectProvider<ObjectGraph> { + @Inject + public ObjectGraphProvider(ScopeProvider scopeProvider, + EntityInspector entityInspector, + EntityGraphProvider graphProvider) { + super(scopeProvider, entityInspector, graphProvider); + } + @Override public ObjectGraph transform(final ObjectGraph graph) { return graph;
diff --git a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java index ac3422b..ce354db 100644 --- a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java +++ b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020 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 @@ -46,15 +46,18 @@ private final Cache<EntityContext, T> filteringObjects = CacheBuilder.newBuilder().maximumSize(PROVIDER_CACHE_SIZE).build(); - @Inject private ScopeProvider scopeProvider; - - @Inject private EntityInspector entityInspector; - - @Inject private EntityGraphProvider graphProvider; + public AbstractObjectProvider(ScopeProvider scopeProvider, + EntityInspector entityInspector, + EntityGraphProvider graphProvider) { + this.scopeProvider = scopeProvider; + this.entityInspector = entityInspector; + this.graphProvider = graphProvider; + } + @Override public final T getFilteringObject(final Type genericType, final boolean forWriter, final Annotation... annotations) { return getFilteringObject(FilteringHelper.getEntityClass(genericType), forWriter, annotations);
diff --git a/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java b/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java index db18e3b..8458471 100644 --- a/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java +++ b/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.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 @@ -22,13 +22,13 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.inject.Inject; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; @@ -72,7 +72,10 @@ public static class MessageProvider implements MessageBodyReader<MetaInf>, MessageBodyWriter<MetaInf> { - @Context + @Inject + MessageProvider(Configuration configuration) { + this.config = configuration; + } private Configuration config; @Override
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java index d38a41e..23b3ca5 100644 --- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java +++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020 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 @@ -45,7 +45,7 @@ form.param(formParamName, v.toString()); } } else { - form.param(formParamName, resolvedValue.toString()); + form.param(formParamName, resolvedValue == null ? null : resolvedValue.toString()); } return form; }
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java index 5b45ea4..9c1e9f9 100644 --- a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java +++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.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. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -96,7 +96,7 @@ @Test public void testProxyCreated() { - MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders()); + MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null)); InjecteeImpl injectee = new InjecteeImpl(); injectee.setRequiredType(Providers.class); injectee.setParent(FIELDS[0]); @@ -108,7 +108,7 @@ @Test public void testProxyCached() { - MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders()); + MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null)); InjecteeImpl injectee1 = new InjecteeImpl(); injectee1.setRequiredType(Providers.class); injectee1.setParent(FIELDS[0]); @@ -125,7 +125,7 @@ @Test public void testProxyCacheNotMismatched() { - MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders()); + MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders(null, null, null)); InjecteeImpl injectee1 = new InjecteeImpl(); injectee1.setRequiredType(Providers.class); injectee1.setParent(FIELDS[0]);
diff --git a/incubator/injectless-client/pom.xml b/incubator/injectless-client/pom.xml new file mode 100644 index 0000000..d1a31cf --- /dev/null +++ b/incubator/injectless-client/pom.xml
@@ -0,0 +1,58 @@ +<?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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.glassfish.jersey.incubator</groupId> + <artifactId>project</artifactId> + <version>3.0.99-SNAPSHOT</version> + </parent> + + <artifactId>jersey-injectless-client</artifactId> + <packaging>jar</packaging> + <name>jersey-inject-injectless-client</name> + + <description>Client side support of no injection mechanism</description> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-client</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <inherited>true</inherited> + <extensions>true</extensions> + </plugin> + </plugins> + </build> +</project>
diff --git a/incubator/injectless-client/src/main/java/org/glassfish/jersey/inject/injectless/NonInjectionManagerFactory.java b/incubator/injectless-client/src/main/java/org/glassfish/jersey/inject/injectless/NonInjectionManagerFactory.java new file mode 100644 index 0000000..61e6455 --- /dev/null +++ b/incubator/injectless-client/src/main/java/org/glassfish/jersey/inject/injectless/NonInjectionManagerFactory.java
@@ -0,0 +1,47 @@ +/* + * 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.inject.injectless; + +import org.glassfish.jersey.client.innate.inject.NonInjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManagerFactory; + +import jakarta.annotation.Priority; +import jakarta.inject.Inject; +import jakarta.ws.rs.ConstrainedTo; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.RuntimeType; + +/** + * <p> + * This {@link InjectionManagerFactory} implementation provides a special {@link InjectionManager}. The highest priority + * of this injection manager is not to require any DI container. It is designed for pure REST client performing a request + * without a further requirements for performing injections in the customer client classes, such a filter or a provider. + * It means the customer classes do not have any injection points defined by {@link Inject} or {@link Context}. + * </p> + * <p> + * Using this injection manager does not prevent using any Jersey modules (such as Jersey-Media-Jackson module) from working + * with the client. + * </p> + */ +@Priority(15) +@ConstrainedTo(RuntimeType.CLIENT) +public class NonInjectionManagerFactory implements InjectionManagerFactory { + @Override + public InjectionManager create(Object parent) { + return new NonInjectionManager(false); + } +}
diff --git a/incubator/injectless-client/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory b/incubator/injectless-client/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory new file mode 100644 index 0000000..8473fa4 --- /dev/null +++ b/incubator/injectless-client/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
@@ -0,0 +1 @@ +org.glassfish.jersey.inject.injectless.NonInjectionManagerFactory \ No newline at end of file
diff --git a/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java b/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java index afd77b1..124e7b2 100644 --- a/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java +++ b/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java
@@ -1,5 +1,5 @@ /* - * 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 Public License v. 2.0, which is available at @@ -23,11 +23,10 @@ import java.lang.reflect.Type; import java.util.Optional; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.ContextResolver; @@ -55,7 +54,8 @@ private final ContextResolver<Kryo> contextResolver; private final Optional<KryoPool> kryoPool; - public KryoMessageBodyProvider(@Context Providers providers) { + @Inject + public KryoMessageBodyProvider(Providers providers) { final MediaType mediaType = new MediaType("application", "x-kryo"); contextResolver = providers.getContextResolver(Kryo.class, mediaType); kryoPool = getKryoPool();
diff --git a/incubator/pom.xml b/incubator/pom.xml index e82e47b..65f0a44 100644 --- a/incubator/pom.xml +++ b/incubator/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2022 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 @@ -40,6 +40,7 @@ <module>declarative-linking</module> <module>gae-integration</module> <module>html-json</module> + <module>injectless-client</module> <module>kryo</module> <module>open-tracing</module> </modules>
diff --git a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java index da6526d..a71e486 100644 --- a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java +++ b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.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 @@ -97,7 +97,7 @@ @Test public void testProxyCreated() { - MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders()); + MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null)); InjecteeImpl injectee = new InjecteeImpl(); injectee.setRequiredType(Providers.class); injectee.setParent(FIELDS[0]); @@ -109,7 +109,7 @@ @Test public void testProxyCached() { - MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders()); + MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null)); InjecteeImpl injectee1 = new InjecteeImpl(); injectee1.setRequiredType(Providers.class); injectee1.setParent(FIELDS[0]); @@ -126,7 +126,7 @@ @Test public void testProxyCacheNotMismatched() { - MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders()); + MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders(null, null, null)); InjecteeImpl injectee1 = new InjecteeImpl(); injectee1.setRequiredType(Providers.class); injectee1.setParent(FIELDS[0]);
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java index 441023f..76e8750 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.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 @@ -39,6 +39,7 @@ import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.NoContentException; @@ -120,12 +121,12 @@ } }; - public AbstractCollectionJaxbProvider(Providers ps) { - super(ps); + public AbstractCollectionJaxbProvider(Providers ps, Configuration config) { + super(ps, config); } - public AbstractCollectionJaxbProvider(Providers ps, MediaType mt) { - super(ps, mt); + public AbstractCollectionJaxbProvider(Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); } @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java index ec53720..63cd318 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.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 @@ -27,6 +27,7 @@ import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.NoContentException; @@ -67,8 +68,8 @@ * * @param providers JAX-RS providers. */ - public AbstractJaxbElementProvider(Providers providers) { - super(providers); + public AbstractJaxbElementProvider(Providers providers, Configuration config) { + super(providers, config); } /** @@ -77,8 +78,8 @@ * @param providers JAX-RS providers. * @param resolverMediaType JAXB component context resolver media type to be used. */ - public AbstractJaxbElementProvider(Providers providers, MediaType resolverMediaType) { - super(providers, resolverMediaType); + public AbstractJaxbElementProvider(Providers providers, MediaType resolverMediaType, Configuration config) { + super(providers, resolverMediaType, config); } @Override
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 eac25ae..1d3c5c5 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
@@ -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 @@ -25,7 +25,6 @@ import java.util.logging.Logger; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.ContextResolver; import jakarta.ws.rs.ext.Providers; @@ -71,8 +70,8 @@ * * @param providers JAX-RS providers. */ - public AbstractJaxbProvider(final Providers providers) { - this(providers, null); + public AbstractJaxbProvider(final Providers providers, final Configuration config) { + this(providers, null, config); } /** @@ -81,7 +80,7 @@ * @param providers JAX-RS providers. * @param resolverMediaType JAXB component context resolver media type to be used. */ - public AbstractJaxbProvider(final Providers providers, final MediaType resolverMediaType) { + public AbstractJaxbProvider(final Providers providers, final MediaType resolverMediaType, final Configuration config) { this.jaxrsProviders = providers; fixedResolverMediaType = resolverMediaType != null; @@ -112,10 +111,10 @@ this.mtUnmarshaller = null; this.mtMarshaller = null; } + setConfiguration(config); } // TODO This provider should be registered and configured via a feature. - @Context public void setConfiguration(final Configuration config) { formattedOutput = Values.lazy(new Value<Boolean>() {
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java index fa12ef9..afc9dc9 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.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 @@ -26,6 +26,7 @@ import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.NoContentException; @@ -69,8 +70,8 @@ * * @param providers JAX-RS providers. */ - public AbstractRootElementJaxbProvider(Providers providers) { - super(providers); + public AbstractRootElementJaxbProvider(Providers providers, Configuration config) { + super(providers, config); } /** @@ -79,8 +80,8 @@ * @param providers JAX-RS providers. * @param resolverMediaType JAXB component context resolver media type to be used. */ - public AbstractRootElementJaxbProvider(Providers providers, MediaType resolverMediaType) { - super(providers, resolverMediaType); + public AbstractRootElementJaxbProvider(Providers providers, MediaType resolverMediaType, Configuration config) { + super(providers, resolverMediaType, config); } @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java index e327214..00bac95 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.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 @@ -39,11 +39,11 @@ */ // TODO This provider should be registered and configured via a feature. @Inject - public DocumentBuilderFactoryInjectionProvider(final Configuration config) { + public DocumentBuilderFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) { super(config); + this.injectionManager = injectionManager; } - @Inject private InjectionManager injectionManager; @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java index 9a27215..4fbfcf1 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.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 @@ -55,10 +55,14 @@ @Singleton public final class DocumentProvider extends AbstractMessageReaderWriterProvider<Document> { + private final Provider<DocumentBuilderFactory> dbf; + private final Provider<TransformerFactory> tf; + @Inject - private Provider<DocumentBuilderFactory> dbf; - @Inject - private Provider<TransformerFactory> tf; + public DocumentProvider(Provider<DocumentBuilderFactory> dbf, Provider<TransformerFactory> tf) { + this.dbf = dbf; + this.tf = tf; + } @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java index 24f862a..c629439 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.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 @@ -50,11 +50,11 @@ */ // TODO This provider should be registered and configured via a feature. @Inject - public SaxParserFactoryInjectionProvider(final Configuration config) { + public SaxParserFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) { super(config); + this.injectionManager = injectionManager; } - @Inject private InjectionManager injectionManager; @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java index a647e6e..213c4ac 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.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 @@ -45,11 +45,11 @@ */ // TODO This provider should be registered and configured via a feature. @Inject - public TransformerFactoryInjectionProvider(final Configuration config) { + public TransformerFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) { super(config); + this.injectionManager = injectionManager; } - @Inject private InjectionManager injectionManager; @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java index bf26f3d..4f0af6f 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.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 @@ -24,9 +24,10 @@ import java.util.logging.Level; import java.util.logging.Logger; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.Providers; @@ -50,14 +51,14 @@ private final Provider<XMLInputFactory> xif; - XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps) { - super(ps); + XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps, Configuration config) { + super(ps, config); this.xif = xif; } - XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps, MediaType mt) { - super(ps, mt); + XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); this.xif = xif; } @@ -71,8 +72,9 @@ @Singleton public static final class App extends XmlCollectionJaxbProvider { - public App(@Context Provider<XMLInputFactory> xif, @Context Providers ps) { - super(xif, ps, MediaType.APPLICATION_XML_TYPE); + @Inject + public App(Provider<XMLInputFactory> xif, Providers ps, Configuration config) { + super(xif, ps, MediaType.APPLICATION_XML_TYPE, config); } } @@ -85,8 +87,9 @@ @Singleton public static final class Text extends XmlCollectionJaxbProvider { - public Text(@Context Provider<XMLInputFactory> xif, @Context Providers ps) { - super(xif, ps, MediaType.TEXT_XML_TYPE); + @Inject + public Text(Provider<XMLInputFactory> xif, Providers ps, Configuration config) { + super(xif, ps, MediaType.TEXT_XML_TYPE, config); } } @@ -99,8 +102,9 @@ @Singleton public static final class General extends XmlCollectionJaxbProvider { - public General(@Context Provider<XMLInputFactory> xif, @Context Providers ps) { - super(xif, ps); + @Inject + public General(Provider<XMLInputFactory> xif, Providers ps, Configuration config) { + super(xif, ps, config); } @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java index 99aacb3..24bb77e 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021 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 @@ -38,11 +38,11 @@ */ // TODO This provider should be registered and configured via a feature. @Inject - public XmlInputFactoryInjectionProvider(final Configuration config) { + public XmlInputFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) { super(config); + this.injectionManager = injectionManager; } - @Inject private InjectionManager injectionManager; @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java index 6ea3eee..10b3646 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.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 @@ -20,9 +20,10 @@ import java.io.OutputStream; import java.nio.charset.Charset; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.Providers; @@ -44,14 +45,14 @@ private final Provider<SAXParserFactory> spf; - public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps) { - super(ps); + public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(ps, config); this.spf = spf; } - public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt) { - super(ps, mt); + public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); this.spf = spf; } @@ -65,8 +66,9 @@ @Singleton public static final class App extends XmlJaxbElementProvider { - public App(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps, MediaType.APPLICATION_XML_TYPE); + @Inject + public App(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, MediaType.APPLICATION_XML_TYPE, config); } } @@ -79,8 +81,9 @@ @Singleton public static final class Text extends XmlJaxbElementProvider { - public Text(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps, MediaType.TEXT_XML_TYPE); + @Inject + public Text(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, MediaType.TEXT_XML_TYPE, config); } } @@ -93,8 +96,9 @@ @Singleton public static final class General extends XmlJaxbElementProvider { - public General(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps); + @Inject + public General(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, config); } @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java index 1f08d4e..397b9ae 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.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 @@ -18,9 +18,10 @@ import java.io.InputStream; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.Providers; @@ -45,14 +46,14 @@ // Delay construction of factory private final Provider<SAXParserFactory> spf; - XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps) { - super(ps); + XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(ps, config); this.spf = spf; } - XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt) { - super(ps, mt); + XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); this.spf = spf; } @@ -67,8 +68,9 @@ @Singleton public static final class App extends XmlRootElementJaxbProvider { - public App(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps, MediaType.APPLICATION_XML_TYPE); + @Inject + public App(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, MediaType.APPLICATION_XML_TYPE, config); } } @@ -82,8 +84,9 @@ @Singleton public static final class Text extends XmlRootElementJaxbProvider { - public Text(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps, MediaType.TEXT_XML_TYPE); + @Inject + public Text(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, MediaType.TEXT_XML_TYPE, config); } } @@ -97,8 +100,9 @@ @Singleton public static final class General extends XmlRootElementJaxbProvider { - public General(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps); + @Inject + public General(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, config); } @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java index 9a8593c..76e61a1 100644 --- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java +++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.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 @@ -22,12 +22,13 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.inject.Inject; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.NoContentException; @@ -53,14 +54,14 @@ private final Provider<SAXParserFactory> spf; - XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps) { - super(ps); + XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(ps, config); this.spf = spf; } - XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt) { - super(ps, mt); + XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); this.spf = spf; } @@ -79,8 +80,9 @@ @Singleton public static final class App extends XmlRootObjectJaxbProvider { - public App(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps, MediaType.APPLICATION_XML_TYPE); + @Inject + public App(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, MediaType.APPLICATION_XML_TYPE, config); } } @@ -93,8 +95,9 @@ @Singleton public static final class Text extends XmlRootObjectJaxbProvider { - public Text(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps, MediaType.TEXT_XML_TYPE); + @Inject + public Text(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, MediaType.TEXT_XML_TYPE, config); } } @@ -107,8 +110,9 @@ @Singleton public static final class General extends XmlRootObjectJaxbProvider { - public General(@Context Provider<SAXParserFactory> spf, @Context Providers ps) { - super(spf, ps); + @Inject + public General(Provider<SAXParserFactory> spf, Providers ps, Configuration config) { + super(spf, ps, config); } @Override
diff --git a/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java b/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java index a0b4c26..2285de0 100644 --- a/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java +++ b/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.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 @@ -48,7 +48,7 @@ public void stringReaderDoesNotReadExternalDtds() { Provider<SAXParserFactory> saxParserFactoryProvider = new Provider<SAXParserFactory>() { - final SaxParserFactoryInjectionProvider spf = new SaxParserFactoryInjectionProvider( + final SaxParserFactoryInjectionProvider spf = new SaxParserFactoryInjectionProvider(null, new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL)); @Override
diff --git a/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java b/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java index efc7c81..c2ffe9e 100644 --- a/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java +++ b/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.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 @@ -23,10 +23,15 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbException; + import org.glassfish.jersey.jsonb.LocalizationMessages; import org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider; import org.glassfish.jersey.message.internal.EntityInputStream; +import jakarta.inject.Inject; import jakarta.json.bind.Jsonb; import jakarta.json.bind.JsonbBuilder; import jakarta.json.bind.JsonbException; @@ -34,7 +39,6 @@ import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.NoContentException; @@ -55,9 +59,10 @@ private static final String JSON = "json"; private static final String PLUS_JSON = "+json"; - private Providers providers; + private final Providers providers; - public JsonBindingProvider(@Context Providers providers) { + @Inject + public JsonBindingProvider(Providers providers) { this.providers = providers; }
diff --git a/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java b/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java index a35dfad..ec86d03 100644 --- a/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java +++ b/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,11 +23,11 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.NoContentException; @@ -56,7 +56,8 @@ private Providers providers; - public JsonGsonProvider(@Context Providers providers) { + @Inject + public JsonGsonProvider(Providers providers) { this.providers = providers; }
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java index 527f1db..4f14ea7 100644 --- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java +++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
@@ -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 @@ -25,19 +25,24 @@ import java.util.Arrays; import java.util.List; import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; import jakarta.inject.Singleton; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.ext.Providers; /** * Entity Data provider based on Jackson JSON provider. */ @Singleton public class DefaultJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider { - - @Context private Configuration commonConfig; + @Inject + public DefaultJacksonJaxbJsonProvider(Providers providers, Configuration config) { + this.commonConfig = config; + _providers = providers; + } + //do not register JaxbAnnotationModule because it brakes default annotations processing private static final String[] EXCLUDE_MODULE_NAMES = {"JaxbAnnotationModule", "JakartaXmlBindAnnotationModule"};
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java index 815b45e..486ec09 100644 --- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java +++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java
@@ -1,5 +1,5 @@ /* - * 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 Public License v. 2.0, which is available at @@ -22,12 +22,14 @@ import java.lang.reflect.Method; import java.lang.reflect.Type; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.inject.Singleton; +import jakarta.ws.rs.ext.Providers; import org.glassfish.jersey.internal.util.ReflectionHelper; import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.EndpointConfigBase; @@ -57,8 +59,15 @@ @Singleton public final class FilteringJacksonJaxbJsonProvider extends DefaultJacksonJaxbJsonProvider { + private final Provider<ObjectProvider<FilterProvider>> provider; + @Inject - private Provider<ObjectProvider<FilterProvider>> provider; + public FilteringJacksonJaxbJsonProvider(Provider<ObjectProvider<FilterProvider>> provider, + Providers providers, Configuration config) { + super(providers, config); + this.provider = provider; + } + @Override protected JsonEndpointConfig _configForWriting(final ObjectMapper mapper, final Annotation[] annotations,
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java index d341486..b4b37f4 100644 --- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java +++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
@@ -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,6 +23,8 @@ import java.util.Stack; import org.glassfish.jersey.message.filtering.spi.AbstractObjectProvider; +import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider; +import org.glassfish.jersey.message.filtering.spi.EntityInspector; import org.glassfish.jersey.message.filtering.spi.ObjectGraph; import com.fasterxml.jackson.core.JsonGenerator; @@ -35,12 +37,22 @@ import com.fasterxml.jackson.databind.ser.PropertyFilter; import com.fasterxml.jackson.databind.ser.PropertyWriter; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import org.glassfish.jersey.message.filtering.spi.ScopeProvider; + +import jakarta.inject.Inject; /** * @author Michal Gajdos */ final class JacksonObjectProvider extends AbstractObjectProvider<FilterProvider> { + @Inject + public JacksonObjectProvider(ScopeProvider scopeProvider, + EntityInspector entityInspector, + EntityGraphProvider graphProvider) { + super(scopeProvider, entityInspector, graphProvider); + } + @Override public FilterProvider transform(final ObjectGraph graph) { // Root entity.
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java index dc68332..9b7beb9 100644 --- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java +++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -55,6 +55,9 @@ private static class TestJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider { @Inject + public TestJacksonJaxbJsonProvider(Configuration configuration) { + this.configuration = configuration; + } private Configuration configuration; @PostConstruct
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java index 51ec8ad..e8c3ac6 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.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 @@ -24,9 +24,10 @@ import java.lang.reflect.Type; import java.nio.charset.Charset; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.Providers; @@ -47,12 +48,12 @@ */ public class JettisonJaxbElementProvider extends AbstractJaxbElementProvider { - JettisonJaxbElementProvider(Providers ps) { - super(ps); + JettisonJaxbElementProvider(Providers ps, Configuration config) { + super(ps, config); } - JettisonJaxbElementProvider(Providers ps, MediaType mt) { - super(ps, mt); + JettisonJaxbElementProvider(Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); } @Override @@ -69,8 +70,9 @@ @Consumes("application/json") public static final class App extends JettisonJaxbElementProvider { - public App(@Context Providers ps) { - super(ps, MediaType.APPLICATION_JSON_TYPE); + @Inject + public App(Providers ps, Configuration config) { + super(ps, MediaType.APPLICATION_JSON_TYPE, config); } } @@ -78,8 +80,9 @@ @Consumes("*/*") public static final class General extends JettisonJaxbElementProvider { - public General(@Context Providers ps) { - super(ps); + @Inject + public General(Providers ps, Configuration config) { + super(ps, config); } @Override
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java index 8f6395b..61380c1 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.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 @@ -28,9 +28,10 @@ import java.util.logging.Level; import java.util.logging.Logger; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.Providers; @@ -54,12 +55,12 @@ */ public class JettisonListElementProvider extends AbstractCollectionJaxbProvider { - JettisonListElementProvider(Providers ps) { - super(ps); + JettisonListElementProvider(Providers ps, Configuration config) { + super(ps, config); } - JettisonListElementProvider(Providers ps, MediaType mt) { - super(ps, mt); + JettisonListElementProvider(Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); } @Override @@ -75,9 +76,9 @@ @Produces("application/json") @Consumes("application/json") public static final class App extends JettisonListElementProvider { - - public App(@Context Providers ps) { - super(ps, MediaType.APPLICATION_JSON_TYPE); + @Inject + public App(Providers ps, Configuration config) { + super(ps, MediaType.APPLICATION_JSON_TYPE, config); } } @@ -85,8 +86,9 @@ @Consumes("*/*") public static final class General extends JettisonListElementProvider { - public General(@Context Providers ps) { - super(ps); + @Inject + public General(Providers ps, Configuration config) { + super(ps, config); } @Override
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java index 71e4810..b43ea1d 100644 --- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java +++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.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 @@ -24,9 +24,10 @@ import java.lang.reflect.Type; import java.nio.charset.Charset; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.Providers; @@ -48,12 +49,12 @@ */ public class JettisonRootElementProvider extends AbstractRootElementJaxbProvider { - JettisonRootElementProvider(Providers ps) { - super(ps); + JettisonRootElementProvider(Providers ps, Configuration config) { + super(ps, config); } - JettisonRootElementProvider(Providers ps, MediaType mt) { - super(ps, mt); + JettisonRootElementProvider(Providers ps, MediaType mt, Configuration config) { + super(ps, mt, config); } @Override @@ -69,18 +70,18 @@ @Produces("application/json") @Consumes("application/json") public static final class App extends JettisonRootElementProvider { - - public App(@Context Providers ps) { - super(ps, MediaType.APPLICATION_JSON_TYPE); + @Inject + public App(Providers ps, Configuration config) { + super(ps, MediaType.APPLICATION_JSON_TYPE, config); } } @Produces("*/*") @Consumes("*/*") public static final class General extends JettisonRootElementProvider { - - public General(@Context Providers ps) { - super(ps); + @Inject + public General(Providers ps, Configuration config) { + super(ps, config); } @Override
diff --git a/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java b/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java index a5d4b7d..0e33d25 100644 --- a/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java +++ b/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.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 @@ -20,9 +20,12 @@ import java.util.Map; import java.util.Set; +import jakarta.inject.Inject; import jakarta.xml.bind.JAXBException; import org.glassfish.jersey.message.filtering.spi.AbstractObjectProvider; +import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider; +import org.glassfish.jersey.message.filtering.spi.EntityInspector; import org.glassfish.jersey.message.filtering.spi.ObjectGraph; import org.eclipse.persistence.jaxb.JAXBContext; @@ -30,6 +33,7 @@ import org.eclipse.persistence.jaxb.JAXBHelper; import org.eclipse.persistence.jaxb.Subgraph; import org.eclipse.persistence.jaxb.TypeMappingInfo; +import org.glassfish.jersey.message.filtering.spi.ScopeProvider; /** * @author Michal Gajdos @@ -47,6 +51,13 @@ } } + @Inject + public MoxyObjectProvider(ScopeProvider scopeProvider, + EntityInspector entityInspector, + EntityGraphProvider graphProvider) { + super(scopeProvider, entityInspector, graphProvider); + } + @Override public org.eclipse.persistence.jaxb.ObjectGraph transform(final ObjectGraph graph) { return createObjectGraph(graph.getEntityClass(), graph);
diff --git a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java index b7f3f09..6d07e04 100644 --- a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java +++ b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.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 @@ -26,9 +26,9 @@ import java.util.Map; import java.util.Set; +import jakarta.inject.Inject; import jakarta.inject.Singleton; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.ContextResolver; @@ -77,11 +77,13 @@ return propertyNames; } - @Context - private Providers providers; + private final Configuration config; - @Context - private Configuration config; + @Inject + public ConfigurableMoxyJsonProvider(Providers providers, Configuration config) { + this.providers = providers; + this.config = config; + } private MoxyJsonConfig globalConfig;
diff --git a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java index ac0a0a8..2a0ef42 100644 --- a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java +++ b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.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 @@ -19,12 +19,14 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.inject.Singleton; +import jakarta.ws.rs.ext.Providers; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Unmarshaller; @@ -41,9 +43,15 @@ */ @Singleton public class FilteringMoxyJsonProvider extends ConfigurableMoxyJsonProvider { + private final Provider<ObjectProvider<ObjectGraph>> provider; @Inject - private Provider<ObjectProvider<ObjectGraph>> provider; + public FilteringMoxyJsonProvider(Provider<ObjectProvider<ObjectGraph>> provider, + Providers providers, + Configuration config) { + super(providers, config); + this.provider = provider; + } @Override protected void preWriteTo(final Object object, final Class<?> type, final Type genericType, final Annotation[] annotations,
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java index 6d1f0f4..d8d4762 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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 @@ -32,7 +32,6 @@ import jakarta.ws.rs.Consumes; import jakarta.ws.rs.RuntimeType; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; @@ -77,16 +76,15 @@ * Injectable helper to look up appropriate {@link MessageBodyReader}s * for our body parts. */ - @Inject private Provider<MessageBodyWorkers> messageBodyWorkers; - private final MIMEConfig mimeConfig; /** * Accepts constructor injection of the configuration parameters for this * application. */ - public MultiPartReaderClientSide(@Context final Providers providers) { + @Inject + public MultiPartReaderClientSide(final Providers providers, Provider<MessageBodyWorkers> messageBodyWorkers) { final ContextResolver<MultiPartProperties> contextResolver = providers.getContextResolver(MultiPartProperties.class, MediaType.WILDCARD_TYPE); @@ -98,6 +96,7 @@ properties = new MultiPartProperties(); } + this.messageBodyWorkers = messageBodyWorkers; mimeConfig = createMimeConfig(properties); }
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java index 0662c04..59c4c58 100644 --- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java +++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.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 @@ -23,7 +23,6 @@ import jakarta.ws.rs.ConstrainedTo; import jakarta.ws.rs.RuntimeType; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.MessageBodyReader; @@ -34,6 +33,7 @@ import jakarta.inject.Singleton; import org.glassfish.jersey.media.multipart.MultiPart; +import org.glassfish.jersey.message.MessageBodyWorkers; import org.glassfish.jersey.server.CloseableService; import org.jvnet.mimepull.MIMEParsingException; @@ -52,9 +52,10 @@ private final Provider<CloseableService> closeableServiceProvider; @Inject - public MultiPartReaderServerSide(@Context final Providers providers, - final Provider<CloseableService> closeableServiceProvider) { - super(providers); + public MultiPartReaderServerSide(final Providers providers, + final Provider<CloseableService> closeableServiceProvider, + final Provider<MessageBodyWorkers> messageBodyWorkers) { + super(providers, messageBodyWorkers); this.closeableServiceProvider = closeableServiceProvider; }
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 4e155f8..5237d7e 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
@@ -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 @@ -27,9 +27,9 @@ import java.util.List; import java.util.Map; +import jakarta.inject.Inject; import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; @@ -64,7 +64,8 @@ */ private final Providers providers; - public MultiPartWriter(@Context final Providers providers) { + @Inject + public MultiPartWriter(final Providers providers) { this.providers = providers; }
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java index cf5db6a..91ea8ba 100644 --- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java +++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.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 @@ -31,7 +31,6 @@ import org.glassfish.jersey.internal.PropertiesDelegate; import org.glassfish.jersey.message.MessageBodyWorkers; -import org.glassfish.jersey.message.MessageUtils; import org.glassfish.jersey.message.internal.ReaderInterceptorExecutor; /** @@ -41,10 +40,14 @@ */ class EventInputReader implements MessageBodyReader<EventInput> { + private final Provider<MessageBodyWorkers> messageBodyWorkers; + private final Provider<PropertiesDelegate> propertiesDelegateProvider; + @Inject - private Provider<MessageBodyWorkers> messageBodyWorkers; - @Inject - private Provider<PropertiesDelegate> propertiesDelegateProvider; + EventInputReader(Provider<MessageBodyWorkers> messageBodyWorkers, Provider<PropertiesDelegate> propertiesDelegateProvider) { + this.messageBodyWorkers = messageBodyWorkers; + this.propertiesDelegateProvider = propertiesDelegateProvider; + } @Override public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java index d4401f6..93eb446 100644 --- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java +++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.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 @@ -49,8 +49,12 @@ private static final Logger LOGGER = Logger.getLogger(InboundEventReader.class.getName()); private static final byte[] EOL_DATA = new byte[] {'\n'}; + private final Provider<MessageBodyWorkers> messageBodyWorkers; + @Inject - private Provider<MessageBodyWorkers> messageBodyWorkers; + InboundEventReader(Provider<MessageBodyWorkers> messageBodyWorkers) { + this.messageBodyWorkers = messageBodyWorkers; + } private enum State { SKIPPING_PREPENDED_EMPTY_EVENTS,
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 b0ba040..18d9546 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, 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 @@ -52,8 +52,12 @@ private static final byte[] DATA_LEAD = "data: ".getBytes(UTF8); private static final byte[] EOL = {'\n'}; + private final Provider<MessageBodyWorkers> workersProvider; + @Inject - private Provider<MessageBodyWorkers> workersProvider; + public OutboundEventWriter(Provider<MessageBodyWorkers> workersProvider) { + this.workersProvider = workersProvider; + } @Override public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
diff --git a/pom.xml b/pom.xml index 10b3e20..32adba3 100644 --- a/pom.xml +++ b/pom.xml
@@ -428,6 +428,12 @@ junit.jupiter.execution.parallel.mode.default=same_thread </configurationParameters> </properties> + <systemProperties> + <property> + <name>jersey.config.test.container.port</name> + <value>${jersey.config.test.container.port}</value> + </property> + </systemProperties> <threadCount>124</threadCount> </configuration> <dependencies> @@ -629,6 +635,12 @@ <skipTests>${skip.tests}</skipTests> <skipITs>${skip.tests}</skipITs> <argLine>${failsafe.coverage.argline}</argLine> + <systemProperties> + <property> + <name>jersey.config.test.container.port</name> + <value>${jersey.config.test.container.port}</value> + </property> + </systemProperties> </configuration> <executions> <execution> @@ -853,6 +865,26 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <version>${buildhelper.mvn.plugin.version}</version> + <configuration> + <portNames> + <portName>jersey.config.test.container.port</portName> + <portName>jersey.config.test.container.stop.port</portName> + </portNames> + </configuration> + <executions> + <execution> + <id>reserve-port</id> + <phase>process-test-classes</phase> <!-- pre-integration-test --> + <goals> + <goal>reserve-network-port</goal> + </goals> + </execution> + </executions> + </plugin> </plugins> <extensions> <extension> @@ -1450,7 +1482,7 @@ <doctitle>Jersey ${jersey.version} API Documentation</doctitle> <windowtitle>Jersey ${jersey.version} API</windowtitle> <bottom> - <![CDATA[Copyright © 2007-2022, + <![CDATA[Copyright © 2007-2023, <a href="http://www.oracle.com">Oracle</a> and/or its affiliates. All Rights Reserved. Use is subject to license terms.]]> @@ -2222,7 +2254,7 @@ <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.13</httpclient.version> - <httpclient5.version>5.1.3</httpclient5.version> + <httpclient5.version>5.2.1</httpclient5.version> <jackson.version>2.14.1</jackson.version> <javassist.version>3.29.0-GA</javassist.version> <jboss.logging.version>3.4.2.Final</jboss.logging.version>
diff --git a/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java b/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java index eab1cb1..b3d466a 100644 --- a/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java +++ b/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.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 @@ -48,11 +48,14 @@ @Priority(Priorities.AUTHENTICATION) class OAuth1ClientFilter implements ClientRequestFilter { - @Inject private Provider<OAuth1Signature> oAuthSignature; + private Provider<MessageBodyWorkers> messageBodyWorkers; @Inject - private Provider<MessageBodyWorkers> messageBodyWorkers; + public OAuth1ClientFilter(Provider<OAuth1Signature> oAuthSignature, Provider<MessageBodyWorkers> messageBodyWorkers) { + this.oAuthSignature = oAuthSignature; + this.messageBodyWorkers = messageBodyWorkers; + } @Override public void filter(ClientRequestContext request) throws IOException {
diff --git a/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java b/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java index bed3cee..6a54ce1 100644 --- a/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java +++ b/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.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 @@ -354,11 +354,15 @@ static class DefaultTokenMessageBodyReader implements MessageBodyReader<TokenResult> { // Provider here prevents circular dependency error from HK2 (workers inject providers and this provider inject workers) - @Inject - private Provider<MessageBodyWorkers> workers; + private final Provider<MessageBodyWorkers> workers; + private final Provider<PropertiesDelegate> propertiesDelegateProvider; @Inject - private Provider<PropertiesDelegate> propertiesDelegateProvider; + public DefaultTokenMessageBodyReader(Provider<MessageBodyWorkers> workers, + Provider<PropertiesDelegate> propertiesDelegateProvider) { + this.propertiesDelegateProvider = propertiesDelegateProvider; + this.workers = workers; + } private static Iterable<ReaderInterceptor> EMPTY_INTERCEPTORS = new ArrayList<>();
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml index 8dae6fa..35dd31c 100644 --- a/tests/e2e-client/pom.xml +++ b/tests/e2e-client/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - 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 @@ -46,6 +46,25 @@ <sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders> </systemPropertyVariables> </configuration> + <executions> + <execution> + <id>WithHK2</id> + <goals> + <goal>test</goal> + </goals> + <configuration> + <excludes> + <exclude>**/NonInjectionManagerTest.java</exclude> + </excludes> + <systemPropertyVariables> + <jersey.injectionmanager.hk2>true</jersey.injectionmanager.hk2> + </systemPropertyVariables> + <classpathDependencyExcludes> + <classpathDependencyExclude>org.glassfish.jersey.incubator:jersey-injectless-client</classpathDependencyExclude> + </classpathDependencyExcludes> + </configuration> + </execution> + </executions> </plugin> </plugins> </build> @@ -161,6 +180,12 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.glassfish.jersey.incubator</groupId> + <artifactId>jersey-injectless-client</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.glassfish.jersey.test-framework</groupId>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java index a0d90fb..a1a6418 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -20,6 +20,7 @@ import org.glassfish.jersey.test.JerseyTest; import org.junit.jupiter.api.Test; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; @@ -43,7 +44,6 @@ import jakarta.ws.rs.ext.WriterInterceptor; import jakarta.ws.rs.ext.WriterInterceptorContext; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -74,10 +74,13 @@ } public static class HttpHeadersFilter implements ClientRequestFilter { - - @Context HttpHeaders headers; + @Inject + public HttpHeadersFilter(HttpHeaders headers) { + this.headers = headers; + } + @Override public void filter(ClientRequestContext requestContext) throws IOException { requestContext.abortWith(Response.ok(headers.getHeaderString(HEADER_NAME)).build()); @@ -85,10 +88,13 @@ } public static class HttpHeadersResponseFilter implements ClientResponseFilter { - - @Context HttpHeaders headers; + @Inject + public HttpHeadersResponseFilter(HttpHeaders headers) { + this.headers = headers; + } + private static int headerValue = 0; public int getHeaderValue() { @@ -103,9 +109,13 @@ @Produces(MediaType.TEXT_PLAIN) public static class StringWriter implements MessageBodyWriter<String> { - @Context HttpHeaders headers; + @Inject + public StringWriter(HttpHeaders headers) { + this.headers = headers; + } + @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; @@ -122,10 +132,13 @@ @Consumes({MediaType.TEXT_PLAIN}) public static class StringReader implements MessageBodyReader<String> { - - @Context HttpHeaders headers; + @Inject + public StringReader(HttpHeaders headers) { + this.headers = headers; + } + @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; @@ -140,10 +153,13 @@ } public static class HttpHeadersReaderInterceptor implements ReaderInterceptor { - - @Context HttpHeaders headers; + @Inject + public HttpHeadersReaderInterceptor(HttpHeaders headers) { + this.headers = headers; + } + @Override public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException { context.getInputStream().close(); @@ -153,10 +169,13 @@ } public static class HttpHeadersWriterInterceptor implements WriterInterceptor { - - @Context HttpHeaders headers; + @Inject + public HttpHeadersWriterInterceptor(HttpHeaders headers) { + this.headers = headers; + } + @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { OutputStreamWriter osw = new OutputStreamWriter(context.getOutputStream()); @@ -177,7 +196,7 @@ @Test public void testHttpHeadersInjectionInResponseFilter() { final String value = "1"; - final HttpHeadersResponseFilter filter = new HttpHeadersResponseFilter(); + final HttpHeadersResponseFilter filter = new HttpHeadersResponseFilter(null); final String response = target().register(HttpHeadersResponseFilter.class).request().header(HEADER_NAME, value) .buildPost(Entity.entity(value, MediaType.TEXT_PLAIN_TYPE)).invoke(String.class); assertThat(response, is(value));
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java index 7cf59c2..e42453b 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.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 @@ -22,6 +22,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; @@ -30,7 +31,6 @@ import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.ContextResolver; @@ -73,10 +73,13 @@ @Provider @Produces(ProviderType) public static class ProvidersInjectedWriter implements MessageBodyWriter<String> { - - @Context Providers providers; + @Inject + public ProvidersInjectedWriter(Providers providers) { + this.providers = providers; + } + @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == String.class; @@ -105,9 +108,13 @@ @Consumes(ProviderType) public static class ProvidersInjectedReader implements MessageBodyReader<String> { - @Context Providers providers; + @Inject + ProvidersInjectedReader(Providers providers) { + this.providers = providers; + } + @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == String.class; @@ -132,9 +139,13 @@ @Produces(ConfigurationTYPE) public static class ConfigurationInjectedWriter implements MessageBodyWriter<String> { - @Context Configuration configuration; + @Inject + public ConfigurationInjectedWriter(Configuration configuration) { + this.configuration = configuration; + } + @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == String.class; @@ -158,10 +169,13 @@ @Provider @Consumes(ConfigurationTYPE) public static class ConfigurationInjectedReader implements MessageBodyReader<String> { - - @Context Configuration configuration; + @Inject + public ConfigurationInjectedReader(Configuration configuration) { + this.configuration = configuration; + } + @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == String.class;
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/NonInjectionManagerTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/NonInjectionManagerTest.java new file mode 100644 index 0000000..d547792 --- /dev/null +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/NonInjectionManagerTest.java
@@ -0,0 +1,74 @@ +/* + * 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.tests.e2e.client; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.core.Response; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.glassfish.jersey.inject.injectless.NonInjectionManagerFactory; + +public class NonInjectionManagerTest { + @Test + public void testNonInjectionManagerIsUsed() { + String value = System.getProperty("jersey.injectionmanager.hk2"); + if ("true".equals(value)) { + return; + } + + Records records = new Records(); + Logger logger = Logger.getLogger(new NonInjectionManagerFactory().create(null).getClass().getName()); + Level oldLevel = logger.getLevel(); + logger.setLevel(Level.FINEST); + logger.addHandler(records); + + ClientBuilder.newClient().register((ClientRequestFilter) requestContext -> { + requestContext.abortWith(Response.ok().build()); + }).target("http://localhost:9998/nevermind").request().get(); + + logger.removeHandler(records); + logger.setLevel(oldLevel); + + LogRecord warning = records.records.get(0); + Assertions.assertTrue(warning.getMessage().contains("injection-less")); + } + + private static class Records extends Handler { + private List<LogRecord> records = new LinkedList<>(); + @Override + public void publish(LogRecord record) { + records.add(record); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } +}
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java index d53685e..78ce436 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.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 @@ -71,9 +71,12 @@ @Produces("text/plain") public static class ScopedMessageEntityProvider extends AbstractMessageReaderWriterProvider<Message> { + private final Provider<ClientRequest> clientRequestProvider; @Inject - private Provider<ClientRequest> clientRequestProvider; + public ScopedMessageEntityProvider(Provider<ClientRequest> clientRequestProvider) { + this.clientRequestProvider = clientRequestProvider; + } @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
diff --git a/tests/e2e-entity/pom.xml b/tests/e2e-entity/pom.xml index 7e0c7db..06324ed 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, 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 @@ -43,6 +43,19 @@ <enableAssertions>false</enableAssertions> <skipTests>${skip.e2e}</skipTests> </configuration> + <executions> + <execution> + <id>WithHK2</id> + <goals> + <goal>test</goal> + </goals> + <configuration> + <classpathDependencyExcludes> + <classpathDependencyExclude>org.glassfish.jersey.incubator:jersey-injectless-client</classpathDependencyExclude> + </classpathDependencyExcludes> + </configuration> + </execution> + </executions> </plugin> </plugins> </build> @@ -171,6 +184,13 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.glassfish.jersey.incubator</groupId> + <artifactId>jersey-injectless-client</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + + <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> <scope>test</scope>
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java index fe6c3df..b76f67a 100644 --- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java +++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.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 @@ -52,8 +52,12 @@ private static final Logger LOGGER = Logger.getLogger(FilteringMessageBodyProvider.class.getName()); + private final jakarta.inject.Provider<ObjectProvider<ObjectGraph>> provider; + @Inject - private jakarta.inject.Provider<ObjectProvider<ObjectGraph>> provider; + public FilteringMessageBodyProvider(jakarta.inject.Provider<ObjectProvider<ObjectGraph>> provider) { + this.provider = provider; + } @Override public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml index a3760af..57873f4 100644 --- a/tests/e2e-server/pom.xml +++ b/tests/e2e-server/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - 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 @@ -43,6 +43,19 @@ <enableAssertions>false</enableAssertions> <skipTests>${skip.e2e}</skipTests> </configuration> + <executions> + <execution> + <id>WithHK2</id> + <goals> + <goal>test</goal> + </goals> + <configuration> + <classpathDependencyExcludes> + <classpathDependencyExclude>org.glassfish.jersey.incubator:jersey-injectless-client</classpathDependencyExclude> + </classpathDependencyExcludes> + </configuration> + </execution> + </executions> </plugin> </plugins> </build> @@ -179,6 +192,13 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.glassfish.jersey.incubator</groupId> + <artifactId>jersey-injectless-client</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + + <dependency> <groupId>org.glassfish.jersey.test-framework</groupId> <artifactId>jersey-test-framework-util</artifactId> <scope>test</scope>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java index 43d18e0..b771c54 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.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 @@ -33,6 +33,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.LogRecord; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @@ -63,6 +64,11 @@ */ public class ManagedClientExecutorTest extends JerseyTest { + public ManagedClientExecutorTest() { + // The tests need to run on port 9998, since @Uri() annotation needs a constant String with a port + System.setProperty(TestProperties.CONTAINER_PORT, "9998"); + } + @Override protected ResourceConfig configure() { enable(TestProperties.LOG_TRAFFIC); @@ -213,11 +219,15 @@ */ public static class SchedulerThreadNameReader implements MessageBodyReader<SchedulerThreadName> { - @Inject - ScheduledExecutorServiceProvider injectedProvider; + private final ScheduledExecutorServiceProvider injectedProvider; + private final ScheduledExecutorService injectedService; @Inject - ScheduledExecutorService injectedService; + public SchedulerThreadNameReader(ScheduledExecutorService injectedService, + ScheduledExecutorServiceProvider injectedProvider) { + this.injectedProvider = injectedProvider; + this.injectedService = injectedService; + } @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { @@ -256,8 +266,15 @@ @Test public void testManagedClientExecutor() { - final String response = target().path("test/executor").request().get(String.class); - Assertions.assertEquals("foo-executor-service-0", response); + try { + final String response = target().path("test/executor").request().get(String.class); + Assertions.assertEquals("foo-executor-service-0", response); + } catch (Exception e) { + for (LogRecord record : getLoggedRecords()) { + System.out.println(record.getMessage()); + } + } + } @Test
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java index e2830bd..8aa3801 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.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 @@ -19,6 +19,7 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.LogRecord; +import java.util.stream.Collectors; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @@ -101,8 +102,13 @@ private void _test(final String path) throws Exception { assertThat(target(path).request().get().getStatus(), equalTo(500)); - final List<LogRecord> loggedRecords = getLoggedRecords(); + final List<LogRecord> loggedRecords = getLoggedRecords() + .stream() + .filter(log -> log.getSourceClassName().equals(LOGGER_NAME)) // Skip warnings from outside of Validation + .collect(Collectors.toList()); assertThat(loggedRecords.size(), equalTo(1)); assertThat(loggedRecords.get(0).getThrown(), instanceOf(ValidationException.class)); } + + private static final String LOGGER_NAME = "org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper"; }
diff --git a/tests/e2e-tls/pom.xml b/tests/e2e-tls/pom.xml new file mode 100644 index 0000000..1ae746c --- /dev/null +++ b/tests/e2e-tls/pom.xml
@@ -0,0 +1,140 @@ +<?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> + <groupId>org.glassfish.jersey.tests</groupId> + <artifactId>project</artifactId> + <version>3.0.99-SNAPSHOT</version> + </parent> + + <artifactId>e2e-tls</artifactId> + <name>jersey-tests-e2e-tls</name> + <packaging>jar</packaging> + + <description>Jersey E2E SSL/TLS tests</description> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <forkCount>1</forkCount> + <reuseForks>false</reuseForks> + <enableAssertions>false</enableAssertions> + <skipTests>${skip.e2e}</skipTests> + <systemPropertyVariables> + <sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders> + <property> + <name>ssl.debug</name> + <value>true</value> + </property> + </systemPropertyVariables> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-bundle</artifactId> + <type>pom</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework</groupId> + <artifactId>jersey-test-framework-util</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-suite</artifactId> + <version>${junit-platform-suite.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.specto</groupId> + <artifactId>hoverfly-java-junit5</artifactId> + <version>0.14.0</version> + <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.connectors</groupId> + <artifactId>jersey-apache5-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-grizzly-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jetty-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.connectors</groupId> + <artifactId>jersey-jdk-connector</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.security</groupId> + <artifactId>oauth1-signature</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <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> + <properties> + <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 --> + <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline> + </properties> + </profile> + </profiles> + +</project>
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/ClientHelloTestServer.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/ClientHelloTestServer.java new file mode 100644 index 0000000..703d1c8 --- /dev/null +++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/ClientHelloTestServer.java
@@ -0,0 +1,147 @@ +/* + * 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.tests.e2e.tls; + +import org.glassfish.jersey.tests.e2e.tls.explorer.SSLCapabilities; +import org.glassfish.jersey.tests.e2e.tls.explorer.SSLExplorer; + +import javax.net.ServerSocketFactory; +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIMatcher; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class ClientHelloTestServer { + private ServerSocket serverSocket; + private Thread serverThread; + private volatile State state = State.NONE; + + private enum State { + NONE, + INIT, + STARTED, + STOPPED + } + + protected ServerSocketFactory getServerSocketFactory() { + return ServerSocketFactory.getDefault(); + } + + protected void afterHandshake(Socket socket, SSLCapabilities capabilities) { + + } + + public void init(int port) { + ServerSocketFactory factory = getServerSocketFactory(); + try { + serverSocket = factory.createServerSocket(port); + + state = State.INIT; + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void start() { + if (state != State.INIT) { + System.out.println("Server has not been initialized"); + } + Thread thread = new Thread(() -> { + while (state == State.INIT) { + Socket socket = null; + try { + socket = serverSocket.accept(); + + inspect(socket); + } catch (SocketException e) { + if (!e.getMessage().equals("Interrupted function call: accept failed")) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + serverThread = thread; + thread.start(); + } + + public void stop() { + try { + state = State.STOPPED; + serverSocket.close(); + serverThread.join(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void inspect(Socket socket) throws IOException { + InputStream ins = socket.getInputStream(); + + byte[] buffer = new byte[0xFF]; + int position = 0; + SSLCapabilities capabilities = null; + +// Read the header of TLS record + while (position < SSLExplorer.RECORD_HEADER_SIZE) { + int count = SSLExplorer.RECORD_HEADER_SIZE - position; + int n = ins.read(buffer, position, count); + if (n < 0) { + throw new IOException("unexpected end of stream!"); + } + position += n; + } + +// Get the required size to explore the SSL capabilities + int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position); + if (buffer.length < recordLength) { + buffer = Arrays.copyOf(buffer, recordLength); + } + + while (position < recordLength) { + int count = recordLength - position; + int n = ins.read(buffer, position, count); + if (n < 0) { + throw new IOException("unexpected end of stream!"); + } + position += n; + } + +// Explore + capabilities = SSLExplorer.explore(buffer, 0, recordLength); + if (capabilities != null) { + System.out.println("Record version: " + capabilities.getRecordVersion()); + System.out.println("Hello version: " + capabilities.getHelloVersion()); + } + + afterHandshake(socket, capabilities); + } +}
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 new file mode 100644 index 0000000..1e8d893 --- /dev/null +++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.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.tests.e2e.tls; + +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.jdk.connector.JdkConnectorProvider; +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; + +import javax.net.ssl.SNIServerName; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import java.io.IOException; +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"; + + + static { + // 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() + }; + } + + @ParameterizedTest + @MethodSource("getConnectors") + public void server1Test(ConnectorProvider provider) { + ClientConfig clientConfig = new ClientConfig(); + clientConfig.connectorProvider(provider); + serverTest(clientConfig, "www.host1.com"); + } + + public void serverTest(ClientConfig clientConfig, String hostName) { + String newHostName = replaceWhenHostNotKnown(hostName); + final List<SNIServerName> serverNames = new LinkedList<>(); + final String[] requestHostName = new String[1]; + ClientHelloTestServer server = new ClientHelloTestServer() { + @Override + protected void afterHandshake(Socket socket, SSLCapabilities capabilities) { + serverNames.addAll(capabilities.getServerNames()); + } + }; + server.init(PORT); + server.start(); + + clientConfig.property(ClientProperties.READ_TIMEOUT, 2000); + clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 2000); + try (Response r = ClientBuilder.newClient(clientConfig) + .register(new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestHostName[0] = requestContext.getUri().getHost(); + } + }) + .target("https://" + (newHostName.equals(LOCALHOST) ? LOCALHOST : "www.host0.com") + ":" + PORT) + .path("host") + .request() + .header(HttpHeaders.HOST, hostName + ":8080") + .get()) { + // empty + } catch (Exception e) { + Throwable cause = e; + while (cause != null + && !SocketTimeoutException.class.isInstance(cause) + && TimeoutException.class.isInstance(cause)) { + cause = cause.getCause(); + } + if (cause == null && /*IOE*/ !e.getMessage().contains("Stream closed")) { + throw e; + } + } + + server.stop(); + + if (serverNames.isEmpty()) { + throw new IllegalStateException("ServerNames are empty"); + } + + String clientSniName = new String(serverNames.get(0).getEncoded()); + if (!hostName.equals(clientSniName)) { + throw new IllegalStateException("Unexpected client SNI name " + clientSniName); + } + + if (!LOCALHOST.equals(newHostName) && requestHostName[0].equals(hostName)) { + throw new IllegalStateException("The HTTP Request is made with the same"); + } + + System.out.append("Found expected Client SNI ").println(serverNames.get(0)); + } + + /* + * The method checks whether the JDK-dependent property "jdk.net.hosts.file" works. + * If it does, the request is made with the hostname, so that the 3rd party client has + * the request with the hostname. If a real address is returned or UnknownHostException + * is thrown, the property did not work and the request needs to use 127.0.0.1. + */ + private static String replaceWhenHostNotKnown(String hostName) { + try { + InetAddress inetAddress = InetAddress.getByName(hostName); + return LOCALHOST.equals(inetAddress.getHostAddress()) ? hostName : LOCALHOST; + } catch (UnknownHostException e) { + return LOCALHOST; + } + } +}
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLCapabilities.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLCapabilities.java new file mode 100644 index 0000000..e21b86a --- /dev/null +++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLCapabilities.java
@@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, 2023 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: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.glassfish.jersey.tests.e2e.tls.explorer; + +import java.nio.ByteBuffer; +import java.util.List; +import javax.net.ssl.SNIServerName; + +/** + * Encapsulates the security capabilities of an SSL/TLS connection. + * <P> + * The security capabilities are the list of ciphersuites to be accepted in + * an SSL/TLS handshake, the record version, the hello version, and server + * name indication, etc., of an SSL/TLS connection. + * <P> + * <code>SSLCapabilities</code> can be retrieved by exploring the network + * data of an SSL/TLS connection via {@link SSLExplorer#explore(ByteBuffer)} + * or {@link SSLExplorer#explore(byte[], int, int)}. + * + * @see SSLExplorer + */ +public abstract class SSLCapabilities { + + /** + * Returns the record version of an SSL/TLS connection + * + * @return a non-null record version + */ + public abstract String getRecordVersion(); + + /** + * Returns the hello version of an SSL/TLS connection + * + * @return a non-null hello version + */ + public abstract String getHelloVersion(); + + /** + * Returns a <code>List</code> containing all {@link SNIServerName}s + * of the server name indication. + * + * @return a non-null immutable list of {@link SNIServerName}s + * of the server name indication parameter, may be empty + * if no server name indication. + * + * @see SNIServerName + */ + public abstract List<SNIServerName> getServerNames(); +} +
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLExplorer.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLExplorer.java new file mode 100644 index 0000000..71c1f4e --- /dev/null +++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLExplorer.java
@@ -0,0 +1,627 @@ +package org.glassfish.jersey.tests.e2e.tls.explorer; + +/* + * Copyright (c) 2013, 2023 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: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLProtocolException; +import javax.net.ssl.StandardConstants; +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Instances of this class acts as an explorer of the network data of an + * SSL/TLS connection. + */ +public final class SSLExplorer { + + // Private constructor prevents construction outside this class. + private SSLExplorer() { + } + + /** + * The header size of TLS/SSL records. + * <P> + * The value of this constant is {@value}. + */ + public static final int RECORD_HEADER_SIZE = 0x05; + + /** + * Returns the required number of bytes in the {@code source} + * {@link ByteBuffer} necessary to explore SSL/TLS connection. + * <P> + * This method tries to parse as few bytes as possible from + * {@code source} byte buffer to get the length of an + * SSL/TLS record. + * <P> + * This method accesses the {@code source} parameter in read-only + * mode, and does not update the buffer's properties such as capacity, + * limit, position, and mark values. + * + * @param source + * a {@link ByteBuffer} containing + * inbound or outbound network data for an SSL/TLS connection. + * @throws BufferUnderflowException if less than {@code RECORD_HEADER_SIZE} + * bytes remaining in {@code source} + * @return the required size in byte to explore an SSL/TLS connection + */ + public static int getRequiredSize(ByteBuffer source) { + + ByteBuffer input = source.duplicate(); + + // Do we have a complete header? + if (input.remaining() < RECORD_HEADER_SIZE) { + throw new BufferUnderflowException(); + } + + // Is it a handshake message? + byte firstByte = input.get(); + byte secondByte = input.get(); + byte thirdByte = input.get(); + if ((firstByte & 0x80) != 0 && thirdByte == 0x01) { + // looks like a V2ClientHello + // return (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2; + return RECORD_HEADER_SIZE; // Only need the header fields + } else { + return (((input.get() & 0xFF) << 8) | (input.get() & 0xFF)) + 5; + } + } + + /** + * Returns the required number of bytes in the {@code source} byte array + * necessary to explore SSL/TLS connection. + * <P> + * This method tries to parse as few bytes as possible from + * {@code source} byte array to get the length of an + * SSL/TLS record. + * + * @param source + * a byte array containing inbound or outbound network data for + * an SSL/TLS connection. + * @param offset + * the start offset in array {@code source} at which the + * network data is read from. + * @param length + * the maximum number of bytes to read. + * + * @throws BufferUnderflowException if less than {@code RECORD_HEADER_SIZE} + * bytes remaining in {@code source} + * @return the required size in byte to explore an SSL/TLS connection + */ + public static int getRequiredSize(byte[] source, + int offset, int length) throws IOException { + + ByteBuffer byteBuffer = + ByteBuffer.wrap(source, offset, length).asReadOnlyBuffer(); + return getRequiredSize(byteBuffer); + } + + /** + * Launch and explore the security capabilities from byte buffer. + * <P> + * This method tries to parse as few records as possible from + * {@code source} byte buffer to get the {@link SSLCapabilities} + * of an SSL/TLS connection. + * <P> + * Please NOTE that this method must be called before any handshaking + * occurs. The behavior of this method is not defined in this release + * if the handshake has begun, or has completed. + * <P> + * This method accesses the {@code source} parameter in read-only + * mode, and does not update the buffer's properties such as capacity, + * limit, position, and mark values. + * + * @param source + * a {@link ByteBuffer} containing + * inbound or outbound network data for an SSL/TLS connection. + * + * @throws IOException on network data error + * @throws BufferUnderflowException if not enough source bytes available + * to make a complete exploration. + * + * @return the explored {@link SSLCapabilities} of the SSL/TLS + * connection + */ + public static SSLCapabilities explore(ByteBuffer source) + throws IOException { + + ByteBuffer input = source.duplicate(); + + // Do we have a complete header? + if (input.remaining() < RECORD_HEADER_SIZE) { + throw new BufferUnderflowException(); + } + + // Is it a handshake message? + byte firstByte = input.get(); + byte secondByte = input.get(); + byte thirdByte = input.get(); + if ((firstByte & 0x80) != 0 && thirdByte == 0x01) { + // looks like a V2ClientHello + return exploreV2HelloRecord(input, + firstByte, secondByte, thirdByte); + } else if (firstByte == 22) { // 22: handshake record + return exploreTLSRecord(input, + firstByte, secondByte, thirdByte); + } else { + throw new SSLException("Not handshake record"); + } + } + + /** + * Launch and explore the security capabilities from byte array. + * <P> + * Please NOTE that this method must be called before any handshaking + * occurs. The behavior of this method is not defined in this release + * if the handshake has begun, or has completed. Once handshake has + * begun, or has completed, the security capabilities can not and + * should not be launched with this method. + * + * @param source + * a byte array containing inbound or outbound network data for + * an SSL/TLS connection. + * @param offset + * the start offset in array {@code source} at which the + * network data is read from. + * @param length + * the maximum number of bytes to read. + * + * @throws IOException on network data error + * @throws BufferUnderflowException if not enough source bytes available + * to make a complete exploration. + * @return the explored {@link SSLCapabilities} of the SSL/TLS + * connection + * + * @see #explore(ByteBuffer) + */ + public static SSLCapabilities explore(byte[] source, + int offset, int length) throws IOException { + ByteBuffer byteBuffer = + ByteBuffer.wrap(source, offset, length).asReadOnlyBuffer(); + return explore(byteBuffer); + } + + /* + * uint8 V2CipherSpec[3]; + * struct { + * uint16 msg_length; // The highest bit MUST be 1; + * // the remaining bits contain the length + * // of the following data in bytes. + * uint8 msg_type; // MUST be 1 + * Version version; + * uint16 cipher_spec_length; // It cannot be zero and MUST be a + * // multiple of the V2CipherSpec length. + * uint16 session_id_length; // This field MUST be empty. + * uint16 challenge_length; // SHOULD use a 32-byte challenge + * V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length]; + * opaque session_id[V2ClientHello.session_id_length]; + * opaque challenge[V2ClientHello.challenge_length; + * } V2ClientHello; + */ + private static SSLCapabilities exploreV2HelloRecord( + ByteBuffer input, byte firstByte, byte secondByte, + byte thirdByte) throws IOException { + + // We only need the header. We have already had enough source bytes. + // int recordLength = (firstByte & 0x7F) << 8) | (secondByte & 0xFF); + try { + // Is it a V2ClientHello? + if (thirdByte != 0x01) { + throw new SSLException( + "Unsupported or Unrecognized SSL record"); + } + + // What's the hello version? + byte helloVersionMajor = input.get(); + byte helloVersionMinor = input.get(); + + // 0x00: major version of SSLv20 + // 0x02: minor version of SSLv20 + // + // SNIServerName is an extension, SSLv20 doesn't support extension. + return new SSLCapabilitiesImpl((byte) 0x00, (byte) 0x02, + helloVersionMajor, helloVersionMinor, + Collections.<SNIServerName>emptyList()); + } catch (BufferUnderflowException bufe) { + throw new SSLProtocolException( + "Invalid handshake record"); + } + } + + /* + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + * + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; + */ + private static SSLCapabilities exploreTLSRecord( + ByteBuffer input, byte firstByte, byte secondByte, + byte thirdByte) throws IOException { + + // Is it a handshake message? + if (firstByte != 22) { // 22: handshake record + throw new SSLException("Not handshake record"); + } + + // We need the record version to construct SSLCapabilities. + byte recordMajorVersion = secondByte; + byte recordMinorVersion = thirdByte; + + // Is there enough data for a full record? + int recordLength = getInt16(input); + if (recordLength > input.remaining()) { + throw new BufferUnderflowException(); + } + + // We have already had enough source bytes. + try { + return exploreHandshake(input, + recordMajorVersion, recordMinorVersion, recordLength); + } catch (BufferUnderflowException bufe) { + throw new SSLProtocolException( + "Invalid handshake record"); + } + } + + /* + * enum { + * hello_request(0), client_hello(1), server_hello(2), + * certificate(11), server_key_exchange (12), + * certificate_request(13), server_hello_done(14), + * certificate_verify(15), client_key_exchange(16), + * finished(20) + * (255) + * } HandshakeType; + * + * struct { + * HandshakeType msg_type; + * uint24 length; + * select (HandshakeType) { + * case hello_request: HelloRequest; + * case client_hello: ClientHello; + * case server_hello: ServerHello; + * case certificate: Certificate; + * case server_key_exchange: ServerKeyExchange; + * case certificate_request: CertificateRequest; + * case server_hello_done: ServerHelloDone; + * case certificate_verify: CertificateVerify; + * case client_key_exchange: ClientKeyExchange; + * case finished: Finished; + * } body; + * } Handshake; + */ + private static SSLCapabilities exploreHandshake( + ByteBuffer input, byte recordMajorVersion, + byte recordMinorVersion, int recordLength) throws IOException { + + // What is the handshake type? + byte handshakeType = input.get(); + if (handshakeType != 0x01) { // 0x01: client_hello message + throw new IllegalStateException("Not initial handshaking"); + } + + // What is the handshake body length? + int handshakeLength = getInt24(input); + + // Theoretically, a single handshake message might span multiple + // records, but in practice this does not occur. + if (handshakeLength > (recordLength - 4)) { // 4: handshake header size + throw new SSLException("Handshake message spans multiple records"); + } + + input = input.duplicate(); + input.limit(handshakeLength + input.position()); + return exploreClientHello(input, + recordMajorVersion, recordMinorVersion); + } + + /* + * struct { + * uint32 gmt_unix_time; + * opaque random_bytes[28]; + * } Random; + * + * opaque SessionID<0..32>; + * + * uint8 CipherSuite[2]; + * + * enum { null(0), (255) } CompressionMethod; + * + * struct { + * ProtocolVersion client_version; + * Random random; + * SessionID session_id; + * CipherSuite cipher_suites<2..2^16-2>; + * CompressionMethod compression_methods<1..2^8-1>; + * select (extensions_present) { + * case false: + * struct {}; + * case true: + * Extension extensions<0..2^16-1>; + * }; + * } ClientHello; + */ + private static SSLCapabilities exploreClientHello( + ByteBuffer input, + byte recordMajorVersion, + byte recordMinorVersion) throws IOException { + + List<SNIServerName> snList = Collections.<SNIServerName>emptyList(); + + // client version + byte helloMajorVersion = input.get(); + byte helloMinorVersion = input.get(); + + // ignore random + int position = input.position(); + input.position(position + 32); // 32: the length of Random + + // ignore session id + ignoreByteVector8(input); + + // ignore cipher_suites + ignoreByteVector16(input); + + // ignore compression methods + ignoreByteVector8(input); + + if (input.remaining() > 0) { + snList = exploreExtensions(input); + } + + return new SSLCapabilitiesImpl( + recordMajorVersion, recordMinorVersion, + helloMajorVersion, helloMinorVersion, snList); + } + + /* + * struct { + * ExtensionType extension_type; + * opaque extension_data<0..2^16-1>; + * } Extension; + * + * enum { + * server_name(0), max_fragment_length(1), + * client_certificate_url(2), trusted_ca_keys(3), + * truncated_hmac(4), status_request(5), (65535) + * } ExtensionType; + */ + private static List<SNIServerName> exploreExtensions(ByteBuffer input) + throws IOException { + + int length = getInt16(input); // length of extensions + while (length > 0) { + int extType = getInt16(input); // extenson type + int extLen = getInt16(input); // length of extension data + + if (extType == 0x00) { // 0x00: type of server name indication + return exploreSNIExt(input, extLen); + } else { // ignore other extensions + ignoreByteVector(input, extLen); + } + + length -= extLen + 4; + } + + return Collections.<SNIServerName>emptyList(); + } + + /* + * struct { + * NameType name_type; + * select (name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + private static List<SNIServerName> exploreSNIExt(ByteBuffer input, + int extLen) throws IOException { + + Map<Integer, SNIServerName> sniMap = new LinkedHashMap<>(); + + int remains = extLen; + if (extLen >= 2) { // "server_name" extension in ClientHello + int listLen = getInt16(input); // length of server_name_list + if (listLen == 0 || listLen + 2 != extLen) { + throw new SSLProtocolException( + "Invalid server name indication extension"); + } + + remains -= 2; // 0x02: the length field of server_name_list + while (remains > 0) { + int code = getInt8(input); // name_type + int snLen = getInt16(input); // length field of server name + if (snLen > remains) { + throw new SSLProtocolException( + "Not enough data to fill declared vector size"); + } + byte[] encoded = new byte[snLen]; + input.get(encoded); + + SNIServerName serverName; + switch (code) { + case StandardConstants.SNI_HOST_NAME: + if (encoded.length == 0) { + throw new SSLProtocolException( + "Empty HostName in server name indication"); + } + serverName = new SNIHostName(encoded); + break; + default: + serverName = new UnknownServerName(code, encoded); + } + // check for duplicated server name type + if (sniMap.put(serverName.getType(), serverName) != null) { + throw new SSLProtocolException("Duplicated server name of type " + serverName.getType()); + } + + remains -= encoded.length + 3; // NameType: 1 byte + // HostName length: 2 bytes + } + } else if (extLen == 0) { // "server_name" extension in ServerHello + throw new SSLProtocolException( + "Not server name indication extension in client"); + } + + if (remains != 0) { + throw new SSLProtocolException( + "Invalid server name indication extension"); + } + + return Collections.<SNIServerName>unmodifiableList( + new ArrayList<>(sniMap.values())); + } + + private static int getInt8(ByteBuffer input) { + return input.get(); + } + + private static int getInt16(ByteBuffer input) { + return ((input.get() & 0xFF) << 8) | (input.get() & 0xFF); + } + + private static int getInt24(ByteBuffer input) { + return ((input.get() & 0xFF) << 16) | ((input.get() & 0xFF) << 8) | (input.get() & 0xFF); + } + + private static void ignoreByteVector8(ByteBuffer input) { + ignoreByteVector(input, getInt8(input)); + } + + private static void ignoreByteVector16(ByteBuffer input) { + ignoreByteVector(input, getInt16(input)); + } + + private static void ignoreByteVector24(ByteBuffer input) { + ignoreByteVector(input, getInt24(input)); + } + + private static void ignoreByteVector(ByteBuffer input, int length) { + if (length != 0) { + int position = input.position(); + input.position(position + length); + } + } + + private static class UnknownServerName extends SNIServerName { + UnknownServerName(int code, byte[] encoded) { + super(code, encoded); + } + } + + private static final class SSLCapabilitiesImpl extends SSLCapabilities { + private static final Map<Integer, String> versionMap = new HashMap<>(5); + + private final String recordVersion; + private final String helloVersion; + List<SNIServerName> sniNames; + + static { + versionMap.put(0x0002, "SSLv2Hello"); + versionMap.put(0x0300, "SSLv3"); + versionMap.put(0x0301, "TLSv1"); + versionMap.put(0x0302, "TLSv1.1"); + versionMap.put(0x0303, "TLSv1.2"); + } + + SSLCapabilitiesImpl(byte recordMajorVersion, byte recordMinorVersion, + byte helloMajorVersion, byte helloMinorVersion, + List<SNIServerName> sniNames) { + + int version = (recordMajorVersion << 8) | recordMinorVersion; + this.recordVersion = versionMap.get(version) != null + ? versionMap.get(version) + : unknownVersion(recordMajorVersion, recordMinorVersion); + + version = (helloMajorVersion << 8) | helloMinorVersion; + this.helloVersion = versionMap.get(version) != null + ? versionMap.get(version) + : unknownVersion(helloMajorVersion, helloMinorVersion); + + this.sniNames = sniNames; + } + + @Override + public String getRecordVersion() { + return recordVersion; + } + + @Override + public String getHelloVersion() { + return helloVersion; + } + + @Override + public List<SNIServerName> getServerNames() { + if (!sniNames.isEmpty()) { + return Collections.<SNIServerName>unmodifiableList(sniNames); + } + + return sniNames; + } + + private static String unknownVersion(byte major, byte minor) { + return "Unknown-" + ((int) major) + "." + ((int) minor); + } + } +} +
diff --git a/tests/e2e-tls/src/test/resources/hosts b/tests/e2e-tls/src/test/resources/hosts new file mode 100644 index 0000000..438ebb6 --- /dev/null +++ b/tests/e2e-tls/src/test/resources/hosts
@@ -0,0 +1,19 @@ +# +# 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 + +127.0.0.1 www.host0.com +127.0.0.1 www.host1.com +127.0.0.1 www.host2.com +127.0.0.1 www.host3.com \ No newline at end of file
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java index 661cb46..d3d7fa9 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.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 @@ -21,6 +21,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; @@ -32,7 +33,6 @@ import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.Configuration; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; @@ -75,9 +75,13 @@ @Provider @Produces("text/plain") public static class OverridingStringProvider implements MessageBodyWriter<String> { + private final Configuration config; - @Context - private Configuration config; + @Inject + public OverridingStringProvider(Configuration config) { + this.config = config; + } + @Override public boolean isWriteable( @@ -120,10 +124,13 @@ @Provider @Produces("text/html") public static class HtmlStringProvider implements MessageBodyWriter<String> { - - @Context private Configuration config; + @Inject + public HtmlStringProvider(Configuration config) { + this.config = config; + } + @Override public boolean isWriteable( final Class<?> type,
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java index 9958cd9..cd54930 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.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 @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.logging.Level; @@ -707,29 +708,36 @@ // --- client request log entry // client added header before request has sent (and logged) - assertThat(getLoggedRecords().get(0).getMessage(), + Iterator<LogRecord> it = getLoggedRecords().iterator(); + LogRecord logRecord = it.next(); + while (logRecord.getLevel() == Level.WARNING) { // Skip any warning at the beginning + logRecord = it.next(); + } + assertThat(logRecord.getMessage(), containsString("1 > custom_header: client/request\n")); // --- container request log entry // container receives header from client request - assertThat(getLoggedRecords().get(1).getMessage(), + logRecord = it.next(); + assertThat(logRecord.getMessage(), containsString("1 > custom_header: client/request\n")); // container has added its own header after logging filter logged message - assertThat(getLoggedRecords().get(1).getMessage(), + assertThat(logRecord.getMessage(), not(containsString("1 > custom_header: container/request\n"))); // --- container response log entry // container added header to the response and it was logged - assertThat(getLoggedRecords().get(2).getMessage(), + assertThat(it.next().getMessage(), containsString("1 < custom_header: container/response\n")); // --- client response log entry // client received header - assertThat(getLoggedRecords().get(3).getMessage(), + logRecord = it.next(); + assertThat(logRecord.getMessage(), containsString("1 < custom_header: container/response\n")); - assertThat(getLoggedRecords().get(3).getMessage(), + assertThat(logRecord.getMessage(), not(containsString("1 < custom_header: client/response\n"))); }
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 cdca445..c6ecc29 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
@@ -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 @@ -22,6 +22,7 @@ import org.glassfish.jersey.ExternalProperties; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.TestProperties; import org.glassfish.jersey.test.jetty.JettyTestContainerFactory; import org.glassfish.jersey.test.spi.TestContainerException; import org.glassfish.jersey.test.spi.TestContainerFactory; @@ -37,9 +38,12 @@ import jakarta.ws.rs.core.Response; public class HttpProxyTest extends JerseyTest { + public HttpProxyTest() { + set(TestProperties.CONTAINER_PORT, 0); + } private static final String PROXY_HOST = "localhost"; - private static final String PROXY_PORT = "9997"; + private static final String PROXY_PORT = "0"; private static boolean proxyHit = false; @Path("resource") @@ -60,7 +64,6 @@ @BeforeEach public void startFakeProxy() { System.setProperty(ExternalProperties.HTTP_PROXY_HOST, PROXY_HOST); - System.setProperty(ExternalProperties.HTTP_PROXY_PORT, PROXY_PORT); Server server = new Server(Integer.parseInt(PROXY_PORT)); server.setHandler(new ProxyHandler(false)); try { @@ -68,6 +71,7 @@ } catch (Exception e) { } + System.setProperty(ExternalProperties.HTTP_PROXY_PORT, String.valueOf(server.getURI().getPort())); } @Override
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java index 7c927f2..1c7d2c0 100644 --- a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java +++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.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 @@ -21,6 +21,7 @@ import jakarta.json.JsonValue; import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; @@ -76,4 +77,10 @@ @Path("content1/{content1}/content0/{content0: [0-9]{4}}") @Produces(MediaType.TEXT_PLAIN) String regex0(@PathParam("content1") String context0, @PathParam("content0") String context1); + + @POST + @Path("formParam") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + String formParam(@FormParam("param") String param); }
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java index dd10f72..56dc5bd 100644 --- a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java +++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.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 @@ -71,4 +71,9 @@ public String regex0(String context0, String context1) { return context0 + "_" + context1; } + + @Override + public String formParam(String param) { + return param; + } }
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java index 24c0308..469b215 100644 --- a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java +++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -56,4 +56,12 @@ assertEquals("Hi", app.sayHi()); } + + @Test + public void testFormParam() throws URISyntaxException { + String response = RestClientBuilder.newBuilder() + .baseUri(new URI("http://localhost:9998")) + .build(ApplicationResource.class).formParam(null); + assertEquals("", response); + } }
diff --git a/tests/pom.xml b/tests/pom.xml index 946aa00..025ebb1 100644 --- a/tests/pom.xml +++ b/tests/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2022 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 @@ -44,6 +44,7 @@ <module>e2e-inject</module> <module>e2e-server</module> <module>e2e-testng</module> + <module>e2e-tls</module> <module>integration</module> <module>jmockit</module> <module>mem-leaks</module> @@ -105,5 +106,14 @@ </plugins> </build> </profile> + <profile> + <id>JDK11+</id> + <activation> + <jdk>[11,)</jdk> + </activation> + <modules> + <module>release-test</module> + </modules> + </profile> </profiles> </project>
diff --git a/tests/release-test/pom.xml b/tests/release-test/pom.xml index 3d58845..f0d9b34 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 Oracle and/or its affiliates. All rights reserved. + 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 @@ -21,10 +21,10 @@ <modelVersion>4.0.0</modelVersion> <parent> - <groupId>org.eclipse.ee4j</groupId> + <groupId>org.glassfish.jersey</groupId> <artifactId>project</artifactId> - <version>1.0.8</version> - <relativePath>../../../pom.xml</relativePath> + <version>3.0.99-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> </parent> <groupId>org.glassfish.jersey.tests</groupId> @@ -36,7 +36,6 @@ <description>Jersey post-release validation tests</description> <properties> - <jersey.version>${jersey.version}</jersey.version> <!-- Must pass using -Djersey.version= --> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <maven.version>3.8.6</maven.version> @@ -54,8 +53,7 @@ <reuseForks>false</reuseForks> <enableAssertions>false</enableAssertions> <includes> - <include>**/DownloadBomPomDependencies.java</include> - <include>**/*Test.class</include> + <include>**/NoticeFilesTest.class</include> </includes> </configuration> </plugin> @@ -117,6 +115,60 @@ <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-transport-http</artifactId> <version>${maven.resolver.version}</version> + <exclusions> + <exclusion> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-common</artifactId> </dependency> </dependencies> + + <profiles> + <profile> + <id>ReleaseTests</id> + <activation> + <property> + <name>jersey.version</name> + </property> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>3.0.0-M7</version> + <configuration> + <forkCount>1</forkCount> + <reuseForks>false</reuseForks> + <enableAssertions>false</enableAssertions> + <includes> + <include>**/DownloadBomPomDependencies.java</include> + <include>**/*Test.class</include> + </includes> + </configuration> + </plugin> + </plugins> + </build> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey</groupId> + <artifactId>jersey-bom</artifactId> + <version>${jersey.version}</version> + <scope>import</scope> + <type>pom</type> + </dependency> + </dependencies> + </dependencyManagement> + <properties> + <jersey.version>${jersey.version}</jersey.version> <!-- Must pass using -Djersey.version= --> + </properties> + </profile> + </profiles> </project>
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java index 43e5327..743d609 100644 --- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java +++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
@@ -1,13 +1,17 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts;
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java index dd31588..3256d48 100644 --- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java +++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java
@@ -1,13 +1,17 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts;
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java index 5df3bc1..b1a7ee3 100644 --- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java +++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
@@ -1,13 +1,17 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts;
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java index 2c5b3a2..68d0a14 100644 --- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java +++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
@@ -1,14 +1,19 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts; import org.apache.maven.model.Dependency; @@ -103,7 +108,7 @@ .filter(dep -> dep.getType().equals("jar")); } - private static Model getModelFromFile(String fileName) throws IOException, XmlPullParserException { + static Model getModelFromFile(String fileName) throws IOException, XmlPullParserException { File pomFile = new File(fileName); return getModelFromFile(pomFile); }
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java index 172c596..5c357fc 100644 --- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java +++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java
@@ -1,14 +1,19 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts; import java.io.IOException; @@ -53,24 +58,24 @@ } @Override - public MessageBuilder append(CharSequence csq) throws IOException { + public MessageBuilder append(CharSequence csq) { builder.append(csq); return this; } - public MessageBuilder append(int i) throws IOException { + public MessageBuilder append(int i) { builder.append(i); return this; } @Override - public MessageBuilder append(CharSequence csq, int start, int end) throws IOException { + public MessageBuilder append(CharSequence csq, int start, int end) { builder.append(csq, start, end); return this; } @Override - public MessageBuilder append(char c) throws IOException { + public MessageBuilder append(char c) { builder.append(c); return this; }
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java index ef31d4e..01ba01e 100644 --- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java +++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
@@ -1,14 +1,19 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts; import org.eclipse.aether.DefaultRepositorySystemSession;
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java index 8da0835..0c77d69 100644 --- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java +++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
@@ -1,13 +1,17 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts; @@ -28,7 +32,7 @@ private static final String BUNDLE_NAME_ATTRIBUTE = "Bundle-Name"; private static final String BUNDLE_VERSION_ATTRIBUTE = "Bundle-Version"; - private static final String [] EXCLUDED_JARS = {"test", "rx-client", "oauth", "weld2-se", "spring", + private static final String[] EXCLUDED_JARS = {"test", "rx-client", "oauth", "weld2-se", "spring", "servlet-portability", /* obsolete */ "helidon-connector", /* Helidon does not contain OSGi headers */ "grizzly-connector", /* Limited maintenance */
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 deef29a..288932a 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
@@ -1,13 +1,17 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * 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, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + * 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.artifacts;
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/NoticeFilesTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/NoticeFilesTest.java new file mode 100644 index 0000000..374aaf7 --- /dev/null +++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/NoticeFilesTest.java
@@ -0,0 +1,211 @@ +/* + * 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.artifacts; + +import org.apache.maven.model.Model; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.glassfish.jersey.message.internal.ReaderWriter; +import org.junit.Assert; +import org.junit.Test; + +import jakarta.ws.rs.core.MediaType; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.regex.Pattern; + +public class NoticeFilesTest { + + @Test + public void test() throws IOException, XmlPullParserException { + Model model = MavenUtil.getModelFromFile("../../pom.xml"); + List<NoticeDependencyVersionPair> mainExpectedNoticeDeps = mainExpectedDependencies(); + + File mainNotice = new File("../../NOTICE.md"); + List<NoticeDependencyVersionPair> mainNoticeDeps = parseNoticeFileVersions(mainNotice); + TestResult testResult = compareDependencies(mainExpectedNoticeDeps, mainNoticeDeps, model, mainNotice.getCanonicalPath()); + + // Nothing to check here, yet +// File commonNotice = new File("../../core-common/src/main/resources/META-INF/NOTICE.markdown"); +// List<NoticeDependencyVersionPair> commonNoticeDeps = parseNoticeFileVersions(mainNotice); +// testResult.append(compareDependencies(expectedNoticeDeps, commonNoticeDeps, model, commonNotice.getCanonicalPath())); + + File serverNotice = new File("../../core-server/src/main/resources/META-INF/NOTICE.markdown"); + List<NoticeDependencyVersionPair> serverNoticeDeps = parseNoticeFileVersions(serverNotice); + List<NoticeDependencyVersionPair> serverExpectedNoticeDeps = serverExpectedDependencies(); + testResult.append( + compareDependencies(serverExpectedNoticeDeps, serverNoticeDeps, model, serverNotice.getCanonicalPath())); + + File jacksonNotice = new File("../../media/json-jackson/src/main/resources/META-INF/NOTICE.markdown"); + List<NoticeDependencyVersionPair> jacksonNoticeDeps = parseNoticeFileVersions(jacksonNotice); + List<NoticeDependencyVersionPair> jacksonExpectedNoticeDeps = jacksonExpectedDependencies(); + testResult.append( + compareDependencies(jacksonExpectedNoticeDeps, jacksonNoticeDeps, model, jacksonNotice.getCanonicalPath())); + + File bvNotice = new File("../../ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown"); + List<NoticeDependencyVersionPair> bvNoticeDeps = parseNoticeFileVersions(bvNotice); + List<NoticeDependencyVersionPair> bvExpectedNoticeDeps = bvExpectedDependencies(); + testResult.append( + compareDependencies(bvExpectedNoticeDeps, bvNoticeDeps, model, bvNotice.getCanonicalPath())); + + File examplesNotice = new File("../../examples/NOTICE.md"); + List<NoticeDependencyVersionPair> examplesNoticeDeps = parseNoticeFileVersions(examplesNotice); + testResult.append( + compareDependencies(mainExpectedNoticeDeps, examplesNoticeDeps, model, examplesNotice.getCanonicalPath())); + + Assert.assertTrue("Some error occurred, see previous messages", testResult.result()); + } + + private TestResult compareDependencies(List<NoticeDependencyVersionPair> expectedDeps, + List<NoticeDependencyVersionPair> actualDeps, + Model model, String noticeName) { + TestResult testResult = new TestResult(); + NextExpected: + for (NoticeDependencyVersionPair expectedDep : expectedDeps) { + for (NoticeDependencyVersionPair actualDep : actualDeps) { + if (expectedDep.dependency.equals(actualDep.dependency)) { + String expectedVersion = findVersionInModel(expectedDep, model); + testResult.ok().append("Expected dependency ").append(expectedDep.dependency).println(" found"); + if (expectedVersion.equals(actualDep.version)) { + testResult.ok().append("Dependency ").append(actualDep.dependency).append(" contains expected version ") + .append(expectedVersion).append(" in ").println(noticeName); + } else { + testResult.exception().append("Dependency ").append(actualDep.dependency).append(" differs version ") + .append(expectedVersion).append(" from ").append(noticeName).append(" version ") + .println(actualDep.version); + } + continue NextExpected; + } + } + testResult.exception().append("Expected dependency ").append(expectedDep.dependency).append(" not found in ") + .println(noticeName); + } + return testResult; + } + + private static String findVersionInModel(NoticeDependencyVersionPair pair, Model model) { + if (pair.version.startsWith("${")) { + String version = pair.version.substring(2, pair.version.length() - 1); + return model.getProperties().getProperty(version); + } else { + return pair.version; + } + } + + private void cat(File path) throws IOException { + StringTokenizer tokenizer = tokenizerFromNoticeFile(path); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (token.trim().length() > 1 && !token.trim().startsWith("*")) { + System.out.println(token); +// String filteredToken = removeUnnecessary(token); +// System.out.println(filteredToken); +// Pattern versionizer = Pattern.compile("([.*])?([\\d])"); +// System.out.println(versionizer.matcher(filteredToken).replaceFirst("$1:$2")); + } + } + } + + private List<NoticeDependencyVersionPair> parseNoticeFileVersions(File path) throws IOException { + List<NoticeDependencyVersionPair> list = new LinkedList<>(); + StringTokenizer tokenizer = tokenizerFromNoticeFile(path); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (token.trim().length() > 1 && !token.trim().startsWith("*")) { + String filteredToken = removeUnnecessary(token); + Pattern versionizer = Pattern.compile("([.*])?([\\d])"); + String[] args = versionizer.matcher(filteredToken).replaceFirst("$1:$2").split(":", 2); + NoticeDependencyVersionPair pair = args.length == 2 + ? new NoticeDependencyVersionPair(args[0], args[1]) + : new NoticeDependencyVersionPair(args[0], ""); + list.add(pair); + } + } + + return list; + } + + private StringTokenizer tokenizerFromNoticeFile(File path) throws IOException { + StringTokenizer tokenizer = new StringTokenizer(getFile(path), "\n"); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (token.trim().startsWith("## Third-party Content")) { + break; + } + } + return tokenizer; + } + + private String getFile(File path) throws IOException { + return ReaderWriter.readFromAsString(new FileInputStream(path), MediaType.TEXT_PLAIN_TYPE); + } + + private String removeUnnecessary(String dependency) { + String filtered = dependency + .replace(" Version ", "").replace(" version ", "") + .replace(" API ", "") + .replace(" v", "") + .replace(", ", "").replace(",", "") + .replace(": ", "").replace(": ", ""); + return filtered; + } + + /** + * Return pair of Notice file dependency name & pom.xml version property name + */ + private List<NoticeDependencyVersionPair> mainExpectedDependencies() { + final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>(); + dependencyPairs.add(new NoticeDependencyVersionPair("org.objectweb.asm", "${asm.version}")); + dependencyPairs.add(new NoticeDependencyVersionPair("org.osgi.core", "${osgi.version}")); + dependencyPairs.add(new NoticeDependencyVersionPair("Jackson JAX-RS Providers", "${jackson.version}")); + dependencyPairs.add(new NoticeDependencyVersionPair("Javassist", "${javassist.version}")); + dependencyPairs.add(new NoticeDependencyVersionPair("Hibernate Validator CDI", "${validation.impl.version}")); + dependencyPairs.add(new NoticeDependencyVersionPair("Bean Validation", "${javax.validation.api.version}")); + return dependencyPairs; + } + + private List<NoticeDependencyVersionPair> serverExpectedDependencies() { + final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>(); + dependencyPairs.add(new NoticeDependencyVersionPair("org.objectweb.asm", "${asm.version}")); + return dependencyPairs; + } + + private List<NoticeDependencyVersionPair> bvExpectedDependencies() { + final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>(); + dependencyPairs.add(new NoticeDependencyVersionPair("Hibernate Validator CDI", "${validation.impl.version}")); + return dependencyPairs; + } + + private List<NoticeDependencyVersionPair> jacksonExpectedDependencies() { + final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>(); + dependencyPairs.add(new NoticeDependencyVersionPair("Jackson JAX-RS Providers", "${jackson.version}")); + return dependencyPairs; + } + + private static class NoticeDependencyVersionPair { + private final String dependency; + private final String version; + + private NoticeDependencyVersionPair(String dependency, String version) { + this.dependency = dependency.trim(); + this.version = version.trim(); + } + } +}