Allow for setting connector provider via properties (#5345)
* Allow for setting connector provider via properties
Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/MetaInfOverrideTest.java b/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/MetaInfOverrideTest.java
new file mode 100644
index 0000000..2b60e14
--- /dev/null
+++ b/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/MetaInfOverrideTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.helidon.connector;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+// The Helidon jar has META-INF set
+// Test of override
+class MetaInfOverrideTest extends JerseyTest {
+
+ @Path("/origin")
+ public static class UserAgentServer {
+ @GET
+ public String get(@Context HttpHeaders headers) {
+ return headers.getHeaderString(HttpHeaders.USER_AGENT);
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(UserAgentServer.class);
+ }
+
+ @Test
+ void defaultMetaInfTest() {
+ try (Response r = target("origin").request().get()) {
+ Assertions.assertEquals(200, r.getStatus());
+ Assertions.assertTrue(r.readEntity(String.class).contains("Helidon"));
+ }
+ }
+
+ @Test
+ void overrideMetaInfTest() {
+ ClientConfig config = new ClientConfig();
+ config.connectorProvider(new HttpUrlConnectorProvider());
+ try (Response r = ClientBuilder.newClient(config).target(target("origin").getUri()).request().get()) {
+ Assertions.assertEquals(200, r.getStatus());
+ r.bufferEntity();
+ System.out.println(r.readEntity(String.class));
+ Assertions.assertTrue(r.readEntity(String.class).contains("HttpUrlConnection"));
+ }
+ }
+
+ @Test
+ void overrideMetaInfByOtherConfigPropertyTest() {
+ ClientConfig config = new ClientConfig();
+ config.property(ClientProperties.CONNECTOR_PROVIDER, "org.glassfish.jersey.client.HttpUrlConnectorProvider");
+ try (Response r = ClientBuilder.newClient(config).target(target("origin").getUri()).request().get()) {
+ Assertions.assertEquals(200, r.getStatus());
+ r.bufferEntity();
+ System.out.println(r.readEntity(String.class));
+ Assertions.assertTrue(r.readEntity(String.class).contains("HttpUrlConnection"));
+ }
+ }
+
+ @Test
+ void overrideMetaInfByThePropertyTest() {
+ try (Response r = ClientBuilder.newBuilder()
+ .property(ClientProperties.CONNECTOR_PROVIDER, "org.glassfish.jersey.client.HttpUrlConnectorProvider")
+ .build()
+ .target(target("origin").getUri()).request().get()) {
+ Assertions.assertEquals(200, r.getStatus());
+ r.bufferEntity();
+ System.out.println(r.readEntity(String.class));
+ Assertions.assertTrue(r.readEntity(String.class).contains("HttpUrlConnection"));
+ }
+ }
+}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
index e5600ce..a1a6371 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 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
@@ -24,6 +24,8 @@
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.internal.util.PropertyAlias;
+import javax.ws.rs.client.ClientBuilder;
+
/**
* Jersey client implementation configuration properties.
*
@@ -444,7 +446,7 @@
EXPECT_100_CONTINUE_THRESHOLD_SIZE = "jersey.config.client.request.expect.100.continue.threshold.size";
/**
- * Default threshold size (64kb) after which which Expect:100-Continue header would be applied before
+ * Default threshold size (64kb) after which Expect:100-Continue header would be applied before
* the main request.
*
* @since 2.32
@@ -463,6 +465,22 @@
*/
public static final String QUERY_PARAM_STYLE = "jersey.config.client.uri.query.param.style";
+ /**
+ * Sets the {@link org.glassfish.jersey.client.spi.ConnectorProvider} class. Overrides the value from META-INF/services.
+ *
+ * <p>
+ * The value MUST be an instance of {@code String}.
+ * </p>
+ * <p>
+ * The property is recognized by {@link ClientBuilder}.
+ * </p>
+ * <p>
+ * The name of the configuration property is <tt>{@value}</tt>.
+ * </p>
+ * @since 2.40
+ */
+ public static final String CONNECTOR_PROVIDER = "jersey.config.client.connector.provider";
+
private ClientProperties() {
// prevents instantiation
}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/JerseyClientBuilder.java b/core-client/src/main/java/org/glassfish/jersey/client/JerseyClientBuilder.java
index 8ad0eea..03d4860 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/JerseyClientBuilder.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/JerseyClientBuilder.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
@@ -16,6 +16,7 @@
package org.glassfish.jersey.client;
+import java.security.AccessController;
import java.security.KeyStore;
import java.util.Collections;
import java.util.LinkedList;
@@ -32,9 +33,13 @@
import javax.net.ssl.SSLContext;
import org.glassfish.jersey.SslConfigurator;
+import org.glassfish.jersey.client.innate.inject.NonInjectionManager;
import org.glassfish.jersey.client.internal.LocalizationMessages;
import org.glassfish.jersey.client.spi.ClientBuilderListener;
+import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.internal.ServiceFinder;
+import org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFactory;
+import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.internal.util.collection.UnsafeValue;
import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.model.internal.RankedComparator;
@@ -186,6 +191,9 @@
@Override
public JerseyClient build() {
+ ExternalPropertiesConfigurationFactory.configure(this.config);
+ setConnectorFromProperties();
+
if (sslContext != null) {
return new JerseyClient(config, sslContext, hostnameVerifier, null);
} else if (sslConfigurator != null) {
@@ -204,6 +212,20 @@
}
}
+ private void setConnectorFromProperties() {
+ final Object connectorClass = config.getProperty(ClientProperties.CONNECTOR_PROVIDER);
+ if (connectorClass != null) {
+ if (String.class.isInstance(connectorClass)) {
+ Class<? extends ConnectorProvider> clazz
+ = AccessController.doPrivileged(ReflectionHelper.classForNamePA((String) connectorClass));
+ final ConnectorProvider connectorProvider = new NonInjectionManager().justCreate(clazz);
+ config.connectorProvider(connectorProvider);
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
@Override
public ClientConfig getConfiguration() {
return config;
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
index 74ccd8c..8bd5112 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
@@ -418,10 +418,31 @@
}
ClassBindings<T> classBindings = classBindings(createMe);
- return classBindings.create();
+ return classBindings.create(true);
}
- private <T> T justCreate(Class<T> createMe) {
+ @Override
+ public <T> T createAndInitialize(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);
+ T t = classBindings.create(false);
+ return t != null ? t : justCreate(createMe);
+ }
+
+ public <T> T justCreate(Class<T> createMe) {
T result = null;
try {
Constructor<T> mostArgConstructor = findConstructor(createMe);
@@ -493,11 +514,6 @@
}
@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) {
@@ -750,7 +766,7 @@
return t;
}
- X create() {
+ X create(boolean throwWhenNoBinding) {
_checkUnique();
if (!instanceBindings.isEmpty()) {
return _getInstance(instanceBindings.get(0));
@@ -762,7 +778,11 @@
return _create(supplierClassBindings.get(0));
}
- throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_BINDING(type));
+ if (throwWhenNoBinding) {
+ throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_BINDING(type));
+ } else {
+ return null;
+ }
}
protected X getInstance() {
@@ -770,7 +790,7 @@
if (instance != null) {
return instance;
}
- return create();
+ return create(true);
}
List<X> allInstances() {
@@ -931,7 +951,7 @@
@SuppressWarnings("unchecked")
@Override
- T create() {
+ T create(boolean throwWhenNoBinding) {
if (ParameterizedType.class.isInstance(type)) {
ParameterizedType pt = (ParameterizedType) type;
if (Provider.class.equals(pt.getRawType())) {
@@ -955,7 +975,7 @@
};
}
}
- return super.create();
+ return super.create(throwWhenNoBinding);
}
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/config/ExternalPropertiesAutoDiscoverable.java b/core-common/src/main/java/org/glassfish/jersey/internal/config/ExternalPropertiesAutoDiscoverable.java
deleted file mode 100644
index e7d0adc..0000000
--- a/core-common/src/main/java/org/glassfish/jersey/internal/config/ExternalPropertiesAutoDiscoverable.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0, which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the
- * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- * version 2 with the GNU Classpath Exception, which is available at
- * https://www.gnu.org/software/classpath/license.html.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- */
-
-package org.glassfish.jersey.internal.config;
-
-import org.glassfish.jersey.internal.spi.AutoDiscoverable;
-
-import javax.annotation.Priority;
-import javax.ws.rs.ConstrainedTo;
-import javax.ws.rs.RuntimeType;
-import javax.ws.rs.core.FeatureContext;
-
-@ConstrainedTo(RuntimeType.CLIENT) //server is configured directly in ResourceConfig
-@Priority(AutoDiscoverable.DEFAULT_PRIORITY)
-public class ExternalPropertiesAutoDiscoverable implements AutoDiscoverable {
- @Override
- public void configure(FeatureContext context) {
- if (!context.getConfiguration().isRegistered(ExternalPropertiesConfigurationFeature.class)) {
- context.register(ExternalPropertiesConfigurationFeature.class);
- }
- }
-}
\ No newline at end of file
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/config/ExternalPropertiesConfigurationFeature.java b/core-common/src/main/java/org/glassfish/jersey/internal/config/ExternalPropertiesConfigurationFeature.java
deleted file mode 100644
index acdab23..0000000
--- a/core-common/src/main/java/org/glassfish/jersey/internal/config/ExternalPropertiesConfigurationFeature.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0, which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the
- * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
- * version 2 with the GNU Classpath Exception, which is available at
- * https://www.gnu.org/software/classpath/license.html.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- */
-
-package org.glassfish.jersey.internal.config;
-
-import javax.ws.rs.core.Feature;
-import javax.ws.rs.core.FeatureContext;
-
-public class ExternalPropertiesConfigurationFeature implements Feature {
-
- @Override
- public boolean configure(FeatureContext configurableContext) {
- return ExternalPropertiesConfigurationFactory.configure(configurableContext);
- }
-
-}
\ No newline at end of file
diff --git a/core-common/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable b/core-common/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable
index abc1825..371b37b 100644
--- a/core-common/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable
+++ b/core-common/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable
@@ -1,2 +1 @@
-org.glassfish.jersey.logging.LoggingFeatureAutoDiscoverable
-org.glassfish.jersey.internal.config.ExternalPropertiesAutoDiscoverable
\ No newline at end of file
+org.glassfish.jersey.logging.LoggingFeatureAutoDiscoverable
\ No newline at end of file
diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index 56fd939..887b689 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- 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
@@ -882,6 +882,21 @@
</entry>
</row>
<row>
+ <entry>&jersey.client.ClientProperties.CONNECTOR_PROVIDER;(Jersey 2.40 or later)</entry>
+ <entry><literal>jersey.config.client.connector.provider</literal></entry>
+ <entry>
+ <para>
+ Sets the &jersey.client.ConnectorProvider; class. Overrides the value from META-INF/services.
+ </para>
+ <para>
+ The value MUST be an instance of &lit.jdk6.String;.
+ </para>
+ <para>
+ The property is recognized by &lit.jaxrs.client.ClientBuilder;.
+ </para>
+ </entry>
+ </row>
+ <row>
<entry>&jersey.client.ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE;</entry>
<entry><literal>jersey.config.client.disableAutoDiscovery</literal></entry>
<entry>
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml
index d9719b6..85e9fd8 100644
--- a/docs/src/main/docbook/client.xml
+++ b/docs/src/main/docbook/client.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- 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
@@ -761,6 +761,16 @@
register &lit.jersey.client.Connector; instances in the Jersey &jersey.client.ClientConfig;. The new
&lit.jersey.client.ConnectorProvider; SPI must be used instead to configure a custom client-side transport connector.
</para>
+ <para>
+ A &jersey.client.ConnectorProvider; can also be set by a property on a &lit.jaxrs.client.ClientBuilder; starting with
+ Jersey 2.40. The following example shows how to setup the custom Grizzly Asynchronous HTTP Client based
+ &lit.jersey.client.ConnectorProvider; in a Jersey client instance:
+ <programlisting language="java" linenumbering="numbered">Client client = ClientBuilder.newBuilder()
+ .property(ClientProperties.CONNECTOR_PROVIDER, "org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider")
+ .build();</programlisting>
+
+ For more information about the property see <xref linkend="appendix-properties"/>.
+ </para>
<section>
<title>Client Connectors Properties</title>
<para>
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent
index a729162..733df58 100644
--- a/docs/src/main/docbook/jersey.ent
+++ b/docs/src/main/docbook/jersey.ent
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
<!--
- Copyright (c) 2010, 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
@@ -336,6 +336,7 @@
<!ENTITY jersey.client.ClientProperties.BUFFER_RESPONSE_ENTITY_ON_EXCEPTION "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#BUFFER_RESPONSE_ENTITY_ON_EXCEPTION'>ClientProperties.BUFFER_RESPONSE_ENTITY_ON_EXCEPTION</link>" >
<!ENTITY jersey.client.ClientProperties.CHUNKED_ENCODING_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#CHUNKED_ENCODING_SIZE'>ClientProperties.CHUNKED_ENCODING_SIZE</link>" >
<!ENTITY jersey.client.ClientProperties.CONNECT_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#CONNECT_TIMEOUT'>ClientProperties.CONNECT_TIMEOUT</link>" >
+<!ENTITY jersey.client.ClientProperties.CONNECTOR_PROVIDER "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#CONNECTOR_PROVIDER'>ClientProperties.CONNECTOR_PROVIDER</link>" >
<!ENTITY jersey.client.ClientProperties.DEFAULT_CHUNK_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#DEFAULT_CHUNK_SIZE'>ClientProperties.DEFAULT_CHUNK_SIZE</link>" >
<!ENTITY jersey.client.ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#FEATURE_AUTO_DISCOVERY_DISABLE'>ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE</link>" >
<!ENTITY jersey.client.ClientProperties.FOLLOW_REDIRECTS "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#FOLLOW_REDIRECTS'>ClientProperties.FOLLOW_REDIRECTS</link>" >
diff --git a/examples/configured-client/README.MD b/examples/configured-client/README.MD
new file mode 100644
index 0000000..94a66be
--- /dev/null
+++ b/examples/configured-client/README.MD
@@ -0,0 +1,40 @@
+[//]: # " Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. "
+[//]: # " "
+[//]: # " This program and the accompanying materials are made available under the "
+[//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
+[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. "
+[//]: # " "
+[//]: # " SPDX-License-Identifier: BSD-3-Clause "
+
+Client Configured by Property File Example
+==========================================
+
+This example demonstrates configuration of a Client using property file.
+The property file microprofile-config.properties is consumed by
+Microprofile Config implementation and the properties from the
+property file are set to Jersey Configuration.
+
+The following properties are defined in `microprofile-config.properties` property file:
+ * jersey.config.client.connector.provider - jersey property name for the connector to be used
+ * entity.value - user defined property to be be sent as an echo message
+
+
+Contents
+--------
+
+The mapping of the URI path space is presented in the following table:
+
+URI path | Resource class | HTTP methods | Notes
+-------------------- | ------------------- |--------------| --------------------------------------------------------
+**_/helloworld_** | HelloWorldResource | POST | Echoes the message sent
+
+Running the Example
+-------------------
+
+Run the example as follows:
+
+> mvn clean compile exec:java
+
+This deploys the example using [Grizzly](http://grizzly.java.net/) container.
+
+- <http://localhost:8080/base/helloworld>
diff --git a/examples/configured-client/pom.xml b/examples/configured-client/pom.xml
new file mode 100644
index 0000000..6206197
--- /dev/null
+++ b/examples/configured-client/pom.xml
@@ -0,0 +1,118 @@
+<?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 Distribution License v. 1.0, which is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.glassfish.jersey.examples</groupId>
+ <artifactId>project</artifactId>
+ <version>2.40-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>configured-client</artifactId>
+ <packaging>jar</packaging>
+ <name>jersey-examples-configured-client</name>
+
+ <description>Jersey client configured by a property file example.</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-grizzly2-http</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.inject</groupId>
+ <artifactId>jersey-hk2</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.connectors</groupId>
+ <artifactId>jersey-apache5-connector</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.ext.microprofile</groupId>
+ <artifactId>jersey-mp-config</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>io.helidon.microprofile.config</groupId>
+ <artifactId>helidon-microprofile-config</artifactId>
+ <version>${helidon.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.eclipse.microprofile.config</groupId>
+ <artifactId>microprofile-config-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+<!-- Instead of helidon-microprofile-config, smallrye-config can be used -->
+<!-- <dependency>-->
+<!-- <groupId>io.smallrye</groupId>-->
+<!-- <artifactId>smallrye-config</artifactId>-->
+<!-- <version>${smallrye.config.version}</version>-->
+<!-- <exclusions>-->
+<!-- <exclusion>-->
+<!-- <groupId>org.eclipse.microprofile.config</groupId>-->
+<!-- <artifactId>microprofile-config-api</artifactId>-->
+<!-- </exclusion>-->
+<!-- </exclusions>-->
+<!-- </dependency>-->
+
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-bundle</artifactId>
+ <type>pom</type>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <mainClass>org.glassfish.jersey.examples.configured.client.App</mainClass>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>pre-release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/examples/configured-client/src/main/java/org/glassfish/jersey/examples/configured/client/App.java b/examples/configured-client/src/main/java/org/glassfish/jersey/examples/configured/client/App.java
new file mode 100644
index 0000000..7190358
--- /dev/null
+++ b/examples/configured-client/src/main/java/org/glassfish/jersey/examples/configured/client/App.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 Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.configured.client;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+
+import org.glassfish.grizzly.http.server.HttpServer;
+
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Hello world!
+ */
+public class App {
+
+ private static final URI BASE_URI = URI.create("http://localhost:8080/base/");
+ public static final String ROOT_PATH = "helloworld";
+ /* package */ static final String ENTITY_PROPERTY = "entity.value";
+
+ public static void main(String[] args) {
+ try {
+ System.out.println("\"Hello World\" Jersey Example App");
+
+ final ResourceConfig resourceConfig = new ResourceConfig(HelloWorldResource.class);
+ final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, resourceConfig, false);
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ server.shutdownNow();
+ }
+ }));
+ server.start();
+
+ WebTarget target = ClientBuilder.newClient().target(BASE_URI);
+ Object entity = target.getConfiguration().getProperty(ENTITY_PROPERTY);
+ Object provider = target.getConfiguration().getProperty(ClientProperties.CONNECTOR_PROVIDER);
+
+ System.out
+ .append(" Application started.\n")
+ .append(" Sending entity \"").append((String) entity).append("\"")
+ .append(" using ").append((String) provider).append(" connector provider")
+ .append(" to echo resource ").append(BASE_URI.toASCIIString()).println(ROOT_PATH);
+
+ try (Response response = target.path(ROOT_PATH).request().post(Entity.entity(entity, MediaType.TEXT_PLAIN_TYPE))) {
+ System.out.append(" Recieved: \"").append(response.readEntity(String.class)).println("\"");
+ }
+
+ server.stop();
+ System.exit(0);
+ } catch (IOException ex) {
+ Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ }
+}
diff --git a/examples/configured-client/src/main/java/org/glassfish/jersey/examples/configured/client/HelloWorldResource.java b/examples/configured-client/src/main/java/org/glassfish/jersey/examples/configured/client/HelloWorldResource.java
new file mode 100644
index 0000000..1c91d66
--- /dev/null
+++ b/examples/configured-client/src/main/java/org/glassfish/jersey/examples/configured/client/HelloWorldResource.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.configured.client;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+
+
+@Path("helloworld")
+public class HelloWorldResource {
+ @Context
+ Configuration configuration;
+
+ @POST
+ @Produces("text/plain")
+ public String postHello(String helloMsg) {
+ return helloMsg;
+ }
+
+ @GET
+ @Path("agent")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getAgent(@Context HttpHeaders headers) {
+ return headers.getHeaderString(HttpHeaders.USER_AGENT);
+ }
+
+}
diff --git a/examples/configured-client/src/main/resources/META-INF/microprofile-config.properties b/examples/configured-client/src/main/resources/META-INF/microprofile-config.properties
new file mode 100644
index 0000000..5c6cbb2
--- /dev/null
+++ b/examples/configured-client/src/main/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Distribution License v. 1.0, which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+jersey.config.client.connector.provider=org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider
+entity.value=Hello World!
\ No newline at end of file
diff --git a/examples/configured-client/src/test/java/org/glassfish/jersey/examples/configured/client/HelloWorldTest.java b/examples/configured-client/src/test/java/org/glassfish/jersey/examples/configured/client/HelloWorldTest.java
new file mode 100644
index 0000000..88f99c2
--- /dev/null
+++ b/examples/configured-client/src/test/java/org/glassfish/jersey/examples/configured/client/HelloWorldTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.configured.client;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.api.parallel.ResourceAccessMode;
+import org.junit.jupiter.api.parallel.ResourceLock;
+
+import static org.glassfish.jersey.examples.configured.client.App.ENTITY_PROPERTY;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class HelloWorldTest extends JerseyTest {
+
+ @Override
+ protected ResourceConfig configure() {
+ // mvn test -Djersey.config.test.container.factory=org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory
+ // mvn test -Djersey.config.test.container.factory=org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory
+ // mvn test -Djersey.config.test.container.factory=org.glassfish.jersey.test.jdkhttp.JdkHttpServerTestContainerFactory
+ // mvn test -Djersey.config.test.container.factory=org.glassfish.jersey.test.simple.SimpleTestContainerFactory
+ enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ return new ResourceConfig(HelloWorldResource.class);
+ }
+
+ @Test
+ @Execution(ExecutionMode.CONCURRENT)
+ @ResourceLock(value = "dummy", mode = ResourceAccessMode.READ)
+ public void testEntity() {
+ WebTarget target = target("helloworld");
+ Object entity = target.getConfiguration().getProperty(ENTITY_PROPERTY);
+ try (Response response = target.request().post(Entity.entity(entity, MediaType.TEXT_PLAIN_TYPE))) {
+ Assertions.assertEquals(200, response.getStatus());
+ String readEntity = response.readEntity(String.class);
+ System.out.println(entity);
+ Assertions.assertEquals(entity, readEntity);
+ }
+ }
+
+ @Test
+ @Execution(ExecutionMode.CONCURRENT)
+ @ResourceLock(value = "dummy", mode = ResourceAccessMode.READ)
+ public void testConnector() {
+ try (Response response = target("helloworld").path("agent").request().get()) {
+ Assertions.assertEquals(200, response.getStatus());
+ String entity = response.readEntity(String.class);
+ System.out.println(entity);
+ Assertions.assertTrue(entity.contains("Apache HttpClient 5"));
+ }
+ }
+}
diff --git a/examples/pom.xml b/examples/pom.xml
index 138e57f..3192e79 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -60,6 +60,7 @@
<module>cdi-webapp</module>
<module>clipboard</module>
<module>clipboard-programmatic</module>
+ <module>configured-client</module>
<module>declarative-linking</module>
<module>entity-filtering</module>
<module>entity-filtering-selectable</module>